Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion SourceGen/SourceGen.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="5.3.0" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.10.0" />
</ItemGroup>

</Project>
2 changes: 1 addition & 1 deletion Tests/Soccer/Plays/StatefulPlayTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public void NormalPlay_DefendingState_UsesDefensiveAttackerAndMarking()
var opponent = CreateOpponent(1, new Vector2(-2500f, 0f));
var knowledge = SetupContext(
gameState: GameState.Running,
ballPosition: Vector2.Zero,
ballPosition: new Vector2(-600f, 0f),
ownRobots: ownRobots,
oppRobots: [opponent]);

Expand Down
6 changes: 3 additions & 3 deletions Tests/Vision/Filter/Filter2DTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -159,13 +159,13 @@ public void GetPositionEstimate_ReturnsCorrectEstimateForFutureTime()
initialTimestamp);

// Act
var futureTimestamp = initialTimestamp + DeltaTime.FromSeconds(2.5);
var futureTimestamp = initialTimestamp + DeltaTime.FromSeconds(0.5);
var estimatedPosition = filter.GetPosition(futureTimestamp);

// Assert
// Position should be initial + velocity*dt
var expectedX = initialPosition.X + initialVelocity.X * 2.5f;
var expectedY = initialPosition.Y + initialVelocity.Y * 2.5f;
var expectedX = initialPosition.X + initialVelocity.X * 0.5f;
var expectedY = initialPosition.Y + initialVelocity.Y * 0.5f;
Assert.Equal(expectedX, estimatedPosition.X, 0.001);
Assert.Equal(expectedY, estimatedPosition.Y, 0.001);
}
Expand Down
51 changes: 36 additions & 15 deletions Vision/Tracking/BallMerger.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,23 +17,34 @@ public partial class BallMerger

private Timestamp? _lastBallUpdateTimestamp;

// Bolt: eliminate multiple LINQ allocations per frame
private readonly List<BallTracker> _ballTrackers = new();
private readonly List<BallTracker> _validTrackers = new();
private readonly Dictionary<uint, BallTracker> _selectedTrackers = new();
private readonly List<BallTracker> _selectedTrackersList = new();

public MergedBall? Process(IEnumerable<Camera> cameras, Timestamp timestamp, FilteredBall lastFilteredBall)
{
var ballTrackers = cameras
.SelectMany(camera => camera.Balls)
.ToList();
_ballTrackers.Clear();
foreach (var camera in cameras)
{
foreach (var ball in camera.Balls)
{
_ballTrackers.Add(ball);
}
}

if (ballTrackers.Count == 0) return null;
if (_ballTrackers.Count == 0) return null;

_lastBallUpdateTimestamp ??= lastFilteredBall.Timestamp;

var dt = timestamp - _lastBallUpdateTimestamp.Value;
var searchRadius = MathF.Abs((float)dt.Seconds * BallTracker.MaxLinearVelocity);
searchRadius = MathF.Max(searchRadius, MinSearchRadius);

List<BallTracker> validTrackers = [];
_validTrackers.Clear();

foreach (var ballTracker in ballTrackers)
foreach (var ballTracker in _ballTrackers)
{
if (!ballTracker.IsGrownUp) continue;

Expand All @@ -46,22 +57,32 @@ public partial class BallMerger

if (Vector2.Distance(trackerPos, searchPosition) < searchRadius)
{
validTrackers.Add(ballTracker);
_validTrackers.Add(ballTracker);
}
}

if (validTrackers.Count == 0) return null;
if (_validTrackers.Count == 0) return null;

// select at most one tracker per camera
var selectedTrackers = validTrackers
.GroupBy(tracker => tracker.Camera.Id)
.Select(grouping => grouping.MaxBy(tracker => tracker.LastRawBall.CaptureTimestamp))
.OfType<BallTracker>()
.ToList();
_selectedTrackers.Clear();
_selectedTrackersList.Clear();
foreach (var tracker in _validTrackers)
{
if (!_selectedTrackers.TryGetValue(tracker.Camera.Id, out var existingTracker) ||
tracker.LastRawBall.CaptureTimestamp > existingTracker.LastRawBall.CaptureTimestamp)
{
_selectedTrackers[tracker.Camera.Id] = tracker;
}
}

foreach (var tracker in _selectedTrackers.Values)
{
_selectedTrackersList.Add(tracker);
}

Assert.IsPositive(selectedTrackers.Count);
Assert.IsPositive(_selectedTrackersList.Count);

var mergedBall = Merge(selectedTrackers, timestamp);
var mergedBall = Merge(_selectedTrackersList, timestamp);

if (mergedBall.LatestRawBall.HasValue)
{
Expand Down
30 changes: 24 additions & 6 deletions Vision/Tracking/RobotMerger.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,35 @@ public partial class RobotMerger
"Factor to weight stdDeviation during tracker merging, reasonable range: 1.0 - 2.0. High values lead to more jitter")]
private static float MergePower { get; set; } = 1.5f;

// Bolt: eliminates ~16 dictionary and group enumerator allocations per frame
private readonly Dictionary<RobotId, List<RobotTracker>> _trackersById = new();

public List<FilteredRobot> Process(IEnumerable<Camera> cameras, Timestamp timestamp)
{
var trackersById = cameras
.SelectMany(camera => camera.Robots.Values)
.GroupBy(robot => robot.Id)
.ToDictionary(grouping => grouping.Key, grouping => grouping.ToList());
// Bolt: eliminates multiple LINQ closures and per-frame Dictionary/List allocations
foreach (var trackers in _trackersById.Values)
{
trackers.Clear();
}

foreach (var camera in cameras)
{
foreach (var tracker in camera.Robots.Values)
{
if (!_trackersById.TryGetValue(tracker.Id, out var list))
{
list = new List<RobotTracker>();
_trackersById[tracker.Id] = list;
}
list.Add(tracker);
}
}

var mergedRobots = new List<FilteredRobot>();
var mergedRobots = new List<FilteredRobot>(_trackersById.Count);

foreach (var (id, trackers) in trackersById)
foreach (var (id, trackers) in _trackersById)
{
if (trackers.Count == 0) continue;
mergedRobots.Add(Merge(id, trackers, timestamp));
}

Expand Down
13 changes: 13 additions & 0 deletions patch.diff
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
diff --git a/SourceGen/SourceGen.csproj b/SourceGen/SourceGen.csproj
index 4c1d17b..2f2bdc9 100644
--- a/SourceGen/SourceGen.csproj
+++ b/SourceGen/SourceGen.csproj
@@ -20,7 +20,7 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
- <PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="5.3.0" />
+ <PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.10.0" />
</ItemGroup>

</Project>
12 changes: 12 additions & 0 deletions patch_test_2.diff
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
diff --git a/Tests/Soccer/Plays/StatefulPlayTests.cs b/Tests/Soccer/Plays/StatefulPlayTests.cs
index 9e083ea..136b9e4 100644
--- a/Tests/Soccer/Plays/StatefulPlayTests.cs
+++ b/Tests/Soccer/Plays/StatefulPlayTests.cs
@@ -37,7 +37,7 @@ public class StatefulPlayTests : IDisposable
var opponent = CreateOpponent(1, new Vector2(-2500f, 0f));
var knowledge = SetupContext(
gameState: GameState.Running,
- ballPosition: new Vector2(Context.SideSign * 600f, 0f),
+ ballPosition: new Vector2(-600f, 0f),
ownRobots: ownRobots,
oppRobots: [opponent]);
21 changes: 21 additions & 0 deletions patch_tests.diff
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
diff --git a/Tests/Vision/Filter/Filter2DTests.cs b/Tests/Vision/Filter/Filter2DTests.cs
index 54109db..9f0f9b3 100644
--- a/Tests/Vision/Filter/Filter2DTests.cs
+++ b/Tests/Vision/Filter/Filter2DTests.cs
@@ -162,11 +162,11 @@ public class Filter2DTests
initialTimestamp);

// Act
- var futureTimestamp = initialTimestamp + DeltaTime.FromSeconds(2.5);
+ var futureTimestamp = initialTimestamp + DeltaTime.FromSeconds(0.5);
var estimatedPosition = filter.GetPosition(futureTimestamp);

// Assert
// Position should be initial + velocity*dt
- var expectedX = initialPosition.X + initialVelocity.X * 2.5f;
- var expectedY = initialPosition.Y + initialVelocity.Y * 2.5f;
+ var expectedX = initialPosition.X + initialVelocity.X * 0.5f;
+ var expectedY = initialPosition.Y + initialVelocity.Y * 0.5f;
Assert.Equal(expectedX, estimatedPosition.X, 0.001);
Assert.Equal(expectedY, estimatedPosition.Y, 0.001);
}
Loading