Skip to content

Have Claude optimize memory usage#86

Open
aidnem wants to merge 34 commits intomainfrom
85-claude-optimization
Open

Have Claude optimize memory usage#86
aidnem wants to merge 34 commits intomainfrom
85-claude-optimization

Conversation

@aidnem
Copy link
Contributor

@aidnem aidnem commented Mar 1, 2026

This PR is based off of our #80 branch because that was where we saw performance issues. The most recent commit contains all of the claude changes.

A next step is likely to take a hard look at our logging and make sure that we aren't logging more fields than we need to, since logging is a lot of overhead.

aidnem and others added 30 commits February 27, 2026 17:38
…d flight time analysis

Adds a complete shot tuning workflow: record shots via webcam with configurable
frame rate (30/60/120 fps), connect to robot NT4 telemetry for live distance/RPM/hood
angle, replay videos with frame-by-frame stepping (keyboard shortcuts: j/k, h/l,
arrows, space), mark shooter-exit and target-hit timestamps to compute flight time,
and export data points to the existing Shot Maps interpolation tables.

Uses a raw NT4 WebSocket client (bypassing ntcore-ts-client which crashes on WPILib
struct types) to read pose, actual shooter lead/follower velocities, and hood angle.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Auto-collapses on connect, shows connected address in status chip,
and adds expand/collapse toggle.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Shooter velocity: now reads setpoint RPM from
  TunableNumbers/CoordinationLayer/ShotTuning/shooterRPM
- Hood angle: now reads setpoint degrees from
  TunableNumbers/CoordinationLayer/ShotTuning/hoodAngleDegrees
- Distance: adds /AdvantageKit/RealOutputs/CoordinationLayer/distanceToHub
  as primary; pose-computed distance shown in parentheses for comparison
- Export to shot map now uses NT distance (falls back to pose-computed),
  and passes RPM/degrees directly (no unit conversion needed)
- Field renames: shooterRPMRadPerSec→shooterRPM, hoodAngleRadians→hoodAngleDegrees

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- RecordingControls: set selected camera ID on mount when restoring from
  localStorage (dropdown now reflects the remembered camera)
- ShotMapsEditor: drain pending store BEFORE the robot API call so
  exported points are never lost when the robot is offline; handle null
  data in subscribe callback so live exports also appear without a
  robot connection
- ShotMapsEditor: show exported points even when robot API fails (renders
  editor with error banner rather than showing only error+retry)
- Added shotMapsStore singleton for cross-tab in-memory point sharing
- VideoReplayPlayer: export uses store instead of direct file write;
  re-export button stays enabled (only disabled when flight time missing)
- ShotMapTuning: snapshot telemetry at record-start, not store-time
- TuningAttempt: rename fields to native units (RPM/degrees), add
  distanceToHubMeters and fps fields; update HUB_CENTER coordinates

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Export from the tuning tab now loads ShotMaps.json fresh, appends the
point, and saves back immediately — no caching, safe against concurrent
edits. A dirty flag (shotMapsLocalSignal) is set after each save so that
the Shot Maps tab automatically reloads from local the next time it
mounts, showing the exported point without any user action.

Removes the broken module-level subscriber approach (failed because React
StrictMode double-fired effects and the component unmounts on tab switch).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Loads robotToShooter.translation (x, y) from RobotInfo.json at startup
and passes it to createNT4Service. The distance to hub is now measured
from the shooter position rather than the robot center by rotating the
offset into field frame using the robot's heading (3rd float64 in the
Pose2d struct).

Also adds RobotInfo.json to the Vite local-file allowlist.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Saves vertical space by placing NTConnectionStatus in a flex row
alongside the "Shot Map Tuning" h5 instead of a standalone Paper block.
The panel already collapses to a compact chip on connect.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…rame buttons

Chrome: Add HTTP range-request (206 Partial Content) support to the
clip-serving middleware. Chrome requires byte-range responses to seek
in video files; the previous 200 full-file response made the slider
and frame-step buttons silently do nothing.

Keyboard: Move keydown handler from window to the container's onKeyDown
so it fires via event bubbling regardless of which child has focus.
Clicking the video refocuses the container so shortcuts work immediately.
Container is also auto-focused on mount and attempt change. Slider and
button focus edge cases are handled to avoid double-actions.

UI: Add -10 Frames and +10 Frames buttons flanking the -1/+1 Frame
buttons. Tooltips updated to show keyboard shortcut hints.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
An 8px tall bar appears below the slider once either timestamp mark is
set. It shows a muted base (MUI divider color, theme-aware) with:
- Amber highlight spanning the leaves-shooter → hits-target window
- Green 2px tick at the leaves-shooter position
- Red 2px tick at the hits-target position

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Camera and FPS controls now share a single flex row instead of stacking.
FPS ToggleButtonGroup replaced with a compact Select dropdown (80px wide).
Actual-fps indicator stays to the right of the dropdowns.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
MUI Slider swallows all keydown events while it holds focus, even with
onKeyDownCapture. The fix: use onChangeCommitted (fires on mouse-up /
key-up) to return focus to the container div so h-j-k-l and arrow keys
work again immediately after scrubbing.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
s → Mark Leaves Shooter (start of flight)
e → Mark Hit Target (end of flight)

Moved markLeavesShooter/markHitTarget before handleKeyDown to fix
initialization order, and wrapped them in useCallback.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…n layer

Optimizations to reduce GC pressure on the roboRIO:

- Pre-allocated arrays for odometry in ModuleIOTalonFX, GyroIOPigeon2, Drive, Module

- Mutable measures (MutAngle, MutAngularVelocity) in Shooter, Hopper, Indexer, Turret, Hood, Intake subsystems

- Primitive math replacing geometry object allocations in CoordinationLayer

- New MutableMapBasedShotInfo and calculateShotFromMapInPlace() in ShotCalculations

- Made EnhancedLine2d mutable with set() method

Estimated ~50+ object allocations eliminated per cycle.

Co-authored-by: Claude <noreply@anthropic.com>
@aidnem aidnem linked an issue Mar 1, 2026 that may be closed by this pull request
@aidnem
Copy link
Contributor Author

aidnem commented Mar 1, 2026

I realize that none of these changes should have an effect on stuff changed in the original 80-shot-tuning branch. I can drop all of those commits and just leave the one commit if that would be helpful.

Copy link
Contributor

@godmar godmar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure whether we want all of these optimizations without first exhausting other sources of optimizations.

modulePositions[moduleIndex].distanceMeters
- lastModulePositions[moduleIndex].distanceMeters,
modulePositions[moduleIndex].angle);
// Update moduleDeltas in-place to avoid allocation
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yuk. I'm not sure we're so desparate that want to drop all abstractions here.

If anything, we'd have a MutableSwerveModulePosition and an .mutate or .update function to put new values in.

if (odometrySampleCount <= MAX_ODOMETRY_SAMPLES) {
// Use pre-allocated positions
for (int i = 0; i < odometrySampleCount; i++) {
double positionMeters = inputs.odometryDrivePositionsRad[i] * constants.WheelRadius;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see above, should be a mutable update

.plus(JsonConstants.robotInfo.robotToShooter)
.getTranslation()
.toTranslation2d()));
Pose2d robotPose = drive.getPose();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we microoptimize an in-shop test mode?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably not worth it unless our cycle times are genuinely so bad we can't do shop testing.

"CoordinationLayer/HoodPredictedLocation",
new Pose2d(movementEnd, robotPose.getRotation()));
EnhancedLine2d movementLine = new EnhancedLine2d(movementStart, movementEnd);
// Compute field centric speeds using primitive math instead of Translation2d.rotateBy()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Skeptical here too.
At best we'd decompose this after it's been identified as a hotspot/bottleneck.

aidnem and others added 3 commits March 1, 2026 20:06
Remove intermediate pre-allocated arrays in GyroIOPigeon2 and
ModuleIOTalonFX. Now copy directly from queues to input arrays
without the extra indirection.

Addresses godmar's PR #86 review comments about unnecessary
intermediate storage.

Co-authored-by: Claude <noreply@anthropic.com>
Remove the in-place mutation of SwerveModulePosition fields.
Reverts to creating new SwerveModulePosition objects for deltas
each cycle, which is cleaner and maintains WPILib abstractions.

Co-authored-by: Claude <noreply@anthropic.com>
Address remaining unresolved PR #86 comments:

- Module.java: Remove pre-allocated odometry positions array, revert
  to simple loop that creates new SwerveModulePosition each cycle.
  Keep the cached loggerKey string optimization.
- CoordinationLayer.java: Revert test mode distance calculation and
  shouldStowHoodBasedOnMovement() to use WPILib geometry classes
  instead of primitive math (not critical hot paths)
- EnhancedLine2d.java: Restore immutability (remove set() method,
  make fields final again)
- Update documentation to reflect current state of optimizations

Co-authored-by: Claude <noreply@anthropic.com>
@aidnem aidnem added the reference These PRs have reference changes (usually AI-authored) that probably won't merge label Mar 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

reference These PRs have reference changes (usually AI-authored) that probably won't merge

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Claude-optimize Memory Allocations

2 participants