Skip to content

refactor(subsystems): remove all advantagekit abstractions#18

Open
Baconing wants to merge 2 commits intomasterfrom
subsystems-remove-io
Open

refactor(subsystems): remove all advantagekit abstractions#18
Baconing wants to merge 2 commits intomasterfrom
subsystems-remove-io

Conversation

@Baconing
Copy link
Member

@Baconing Baconing commented Mar 17, 2026

the robot doesnt work in simulation and the abstractions are causing trouble so

Summary by CodeRabbit

Release Notes

  • Refactor

    • Simplified internal subsystem architecture by removing IO abstraction layers across drive, collector, shooter, turntable, and vision subsystems
    • Consolidated drive initialization logic and integrated vision handling directly
    • Removed deprecated logging utilities
  • Chores

    • Removed replay watch build task
    • Updated drive command configuration to use generic Command instead of specialized variant

the robot doesnt work in simulation and the abstractions are causing trouble so
the robot doesnt work in simulation and the abstractions are causing trouble so
@Baconing Baconing requested a review from Trip-kun March 17, 2026 17:49
@Baconing Baconing self-assigned this Mar 17, 2026
@coderabbitai
Copy link

coderabbitai bot commented Mar 17, 2026

Walkthrough

This PR removes the IO abstraction pattern across multiple subsystems (Collector, Shooter, Turntable, Drive, Vision), replacing them with direct hardware dependencies. It also removes logging-related utility classes and a Gradle task, and simplifies command initialization in Controls.

Changes

Cohort / File(s) Summary
Build Configuration
build.gradle.kts
Removed replayWatch JavaExec task registration.
Logging Infrastructure
src/main/kotlin/org/frc5183/robot/logging/AutoLogInputs.kt, src/main/kotlin/org/frc5183/robot/logging/struct/*
Removed AutoLogInputs base class and custom Struct implementations (EstimatedRobotPoseStruct, PhotonTrackedTargetStruct) for binary serialization of vision data.
Collector Subsystem IO Removal
src/main/kotlin/org/frc5183/robot/subsystems/collector/CollectorSubsystem.kt, src/main/kotlin/org/frc5183/robot/subsystems/collector/io/*
Removed CollectorIO interface and RealCollectorIO implementation; CollectorSubsystem now accepts SparkMax instances directly as public properties, with Logger-based periodic output.
Shooter Subsystem IO Removal
src/main/kotlin/org/frc5183/robot/subsystems/shooter/ShooterSubsystem.kt, src/main/kotlin/org/frc5183/robot/subsystems/shooter/io/*
Removed ShooterIO interface and RealShooterIO; ShooterSubsystem now uses three public SparkMax properties (shooter, intake, feeder) with direct motor control.
Turntable Subsystem IO Removal
src/main/kotlin/org/frc5183/robot/subsystems/turntable/TurntableSubsystem.kt, src/main/kotlin/org/frc5183/robot/subsystems/turntable/io/*
Removed TurntableIO interface and RealTurntableIO; TurntableSubsystem now accepts SparkMax and PhotonCamera as public properties.
Drive Subsystem Refactor
src/main/kotlin/org/frc5183/robot/subsystems/drive/SwerveDriveSubsystem.kt, src/main/kotlin/org/frc5183/robot/subsystems/drive/io/*
Removed SwerveDriveIO interface, RealSwerveDriveIO, SimulatedSwerveDriveIO, and SwerveDriveIOInputs; SwerveDriveSubsystem now directly depends on Swervelib SwerveDrive with integrated vision handling and odometry management.
Vision Subsystem Refactor
src/main/kotlin/org/frc5183/robot/subsystems/vision/VisionSubsystem.kt, src/main/kotlin/org/frc5183/robot/subsystems/vision/io/*
Removed VisionIO interface, RealVisionIO, and VisionIOInputs; VisionSubsystem now uses FixedCamera instances directly with separate front/back pose and target accessors.
Robot & Control Initialization
src/main/kotlin/org/frc5183/robot/Robot.kt, src/main/kotlin/org/frc5183/robot/constants/Controls.kt
Robot.kt simplified to single SwerveDrive initialization path; Controls.kt replaced TeleopDriveCommand with generic Command-based DRIVE_COMMAND.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • PR #12: Directly modifies SwerveDriveSubsystem and SwerveDriveIO implementations with overlapping refactoring of drive subsystem architecture.
  • PR #13: Modifies Robot.kt and Controls.kt command initialization patterns, affecting the same TeleopDriveCommand removal flow.
  • PR #14: Refactors swerve drive integration including RealSwerveDriveIO and drive subsystem IO patterns.

Suggested labels

Kind/Feature

Suggested reviewers

  • Trip-kun

Poem

🐰 IO layers fade to shadow's end,
Direct hardware now our trusted friend,
Collectors, shooters, turntables bright,
Speak without abstraction's veil tonight! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title clearly and concisely summarizes the main change: removing AdvantageKit IO abstraction layers from subsystems. It accurately reflects the primary objective of the changeset across multiple files.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch subsystems-remove-io
📝 Coding Plan
  • Generate coding plan for human review comments

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Tip

You can disable poems in the walkthrough.

Disable the reviews.poem setting to disable the poems in the walkthrough.

@coderabbitai coderabbitai bot added the Kind/Feature New functionality label Mar 17, 2026
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/main/kotlin/org/frc5183/robot/subsystems/drive/SwerveDriveSubsystem.kt (1)

54-58: ⚠️ Potential issue | 🔴 Critical

This callback calls a nonexistent overload.

Line 58 invokes drive(robotRelativeSpeeds), but SwerveDriveSubsystem has no drive(ChassisSpeeds) overload. The available drive methods are drive(Translation2d, Double, Boolean, Boolean) and drive(ChassisSpeeds, Array, Array). Use this::driveRobotOriented instead, which accepts a single ChassisSpeeds parameter and delegates to the wrapped SwerveDrive.

🛠️ Minimal fix
-            { robotRelativeSpeeds: ChassisSpeeds -> drive(robotRelativeSpeeds) },
+            this::driveRobotOriented,
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/kotlin/org/frc5183/robot/subsystems/drive/SwerveDriveSubsystem.kt`
around lines 54 - 58, The AutoBuilder.configure callback currently references
drive(robotRelativeSpeeds), which doesn't exist on SwerveDriveSubsystem; locate
the AutoBuilder.configure call and replace that callback with
this::driveRobotOriented (a single-parameter ChassisSpeeds-compatible method on
SwerveDriveSubsystem). Ensure you do not attempt to call the existing overloads
drive(Translation2d, Double, Boolean, Boolean) or drive(ChassisSpeeds, Array,
Array); instead wire the single-argument method driveRobotOriented so the
AutoBuilder will pass ChassisSpeeds correctly to the subsystem.
🧹 Nitpick comments (2)
src/main/kotlin/org/frc5183/robot/constants/Controls.kt (1)

8-8: Unused import: SwerveInputStream.

This import is not referenced anywhere in the file. Remove it to keep the code clean.

-import swervelib.SwerveInputStream
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/kotlin/org/frc5183/robot/constants/Controls.kt` at line 8, Remove
the unused import of SwerveInputStream from the top-level imports in
Controls.kt; locate the import line referencing SwerveInputStream and delete it
(or let your IDE optimize/remove unused imports) so the file no longer
references the unused symbol SwerveInputStream.
src/main/kotlin/org/frc5183/robot/Robot.kt (1)

45-54: Vision fusion is implemented but unreachable—verify if disabling it is intentional.

SwerveDriveSubsystem contains active vision pose fusion logic (lines 80–85) that will never execute because Robot.kt passes null for the vision dependency. VisionSubsystem exists and is fully functional with front/back camera support, but is never instantiated anywhere in the codebase. If PhotonVision-based localization is required, instantiate VisionSubsystem and pass it here. If vision is intentionally disabled for now, add a comment explaining why.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/kotlin/org/frc5183/robot/Robot.kt` around lines 45 - 54,
SwerveDriveSubsystem's vision fusion code is unreachable because Robot.kt
constructs SwerveDriveSubsystem with a null vision dependency; either
instantiate and pass the existing VisionSubsystem into SwerveDriveSubsystem
(create a VisionSubsystem with the configured front/back cameras and pass that
instance instead of null when constructing SwerveDriveSubsystem/SwerveDrive) so
PhotonVision-based localization runs, or if vision is intentionally disabled add
a clear inline comment where Robot.kt passes null explaining why vision is
omitted and when/how to re-enable it; update only the Robot.kt construction site
referencing SwerveDriveSubsystem and VisionSubsystem.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/main/kotlin/org/frc5183/robot/constants/Controls.kt`:
- Around line 17-21: The registerControls function references an old constant
name: replace the undefined TELEOP_DRIVE_COMMAND with the renamed DRIVE_COMMAND
in registerControls(drive: SwerveDriveSubsystem) so drive.defaultCommand =
DRIVE_COMMAND, and remove the now-unused TeleopDriveCommand import if it isn’t
used elsewhere in this file to clean up imports.

In `@src/main/kotlin/org/frc5183/robot/subsystems/drive/SwerveDriveSubsystem.kt`:
- Around line 32-35: SwerveDriveSubsystem.periodic() is re-adding identical
vision measurements each tick because frontCamera.estimatedRobotPose and
backCamera.estimatedRobotPose only change when new frames arrive; to fix it add
monotonic timestamp guards (e.g., lastFrontVisionTimestamp and
lastBackVisionTimestamp fields) and only call drive.addVisionMeasurement(...)
when the incoming pose.timestamp is greater than the stored last timestamp, then
update the stored timestamp; reference the symbols
SwerveDriveSubsystem.periodic(), frontCamera.estimatedRobotPose,
backCamera.estimatedRobotPose, and drive.addVisionMeasurement() when making the
change so stale measurements from FixedCamera.updateUnreadResults() are not
repeatedly added.

In
`@src/main/kotlin/org/frc5183/robot/subsystems/turntable/TurntableSubsystem.kt`:
- Around line 13-18: The targets getter currently calls camera.allUnreadResults
each time, consuming unread results multiple times per scheduler loop; change
TurntableSubsystem to snapshot unread results once per loop by adding a private
backing field (e.g., cachedTargets: Array<PhotonTrackedTarget>) and populate it
inside TurntableSubsystem.periodic() by reading camera.allUnreadResults once,
mapping and flattening that result into the cachedTargets, then have the public
targets property simply return cachedTargets so later consumers and the existing
logging use the same snapshot.

---

Outside diff comments:
In `@src/main/kotlin/org/frc5183/robot/subsystems/drive/SwerveDriveSubsystem.kt`:
- Around line 54-58: The AutoBuilder.configure callback currently references
drive(robotRelativeSpeeds), which doesn't exist on SwerveDriveSubsystem; locate
the AutoBuilder.configure call and replace that callback with
this::driveRobotOriented (a single-parameter ChassisSpeeds-compatible method on
SwerveDriveSubsystem). Ensure you do not attempt to call the existing overloads
drive(Translation2d, Double, Boolean, Boolean) or drive(ChassisSpeeds, Array,
Array); instead wire the single-argument method driveRobotOriented so the
AutoBuilder will pass ChassisSpeeds correctly to the subsystem.

---

Nitpick comments:
In `@src/main/kotlin/org/frc5183/robot/constants/Controls.kt`:
- Line 8: Remove the unused import of SwerveInputStream from the top-level
imports in Controls.kt; locate the import line referencing SwerveInputStream and
delete it (or let your IDE optimize/remove unused imports) so the file no longer
references the unused symbol SwerveInputStream.

In `@src/main/kotlin/org/frc5183/robot/Robot.kt`:
- Around line 45-54: SwerveDriveSubsystem's vision fusion code is unreachable
because Robot.kt constructs SwerveDriveSubsystem with a null vision dependency;
either instantiate and pass the existing VisionSubsystem into
SwerveDriveSubsystem (create a VisionSubsystem with the configured front/back
cameras and pass that instance instead of null when constructing
SwerveDriveSubsystem/SwerveDrive) so PhotonVision-based localization runs, or if
vision is intentionally disabled add a clear inline comment where Robot.kt
passes null explaining why vision is omitted and when/how to re-enable it;
update only the Robot.kt construction site referencing SwerveDriveSubsystem and
VisionSubsystem.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: df600429-25ab-4d99-8ae3-3f040e9f2ce2

📥 Commits

Reviewing files that changed from the base of the PR and between a44fda8 and f876504.

📒 Files selected for processing (27)
  • build.gradle.kts
  • src/main/kotlin/org/frc5183/robot/Robot.kt
  • src/main/kotlin/org/frc5183/robot/constants/Controls.kt
  • src/main/kotlin/org/frc5183/robot/logging/AutoLogInputs.kt
  • src/main/kotlin/org/frc5183/robot/logging/struct/EstimatedRobotPoseStruct.kt
  • src/main/kotlin/org/frc5183/robot/logging/struct/PhotonTrackedTargetStruct.kt
  • src/main/kotlin/org/frc5183/robot/subsystems/collector/CollectorSubsystem.kt
  • src/main/kotlin/org/frc5183/robot/subsystems/collector/io/CollectorIO.kt
  • src/main/kotlin/org/frc5183/robot/subsystems/collector/io/CollectorIOInputs.kt
  • src/main/kotlin/org/frc5183/robot/subsystems/collector/io/RealCollectorIO.kt
  • src/main/kotlin/org/frc5183/robot/subsystems/drive/SwerveDriveSubsystem.kt
  • src/main/kotlin/org/frc5183/robot/subsystems/drive/io/RealSwerveDriveIO.kt
  • src/main/kotlin/org/frc5183/robot/subsystems/drive/io/SimulatedSwerveDriveIO.kt
  • src/main/kotlin/org/frc5183/robot/subsystems/drive/io/SwerveDriveIO.kt
  • src/main/kotlin/org/frc5183/robot/subsystems/drive/io/SwerveDriveIOInputs.kt
  • src/main/kotlin/org/frc5183/robot/subsystems/shooter/ShooterSubsystem.kt
  • src/main/kotlin/org/frc5183/robot/subsystems/shooter/io/RealShooterIO.kt
  • src/main/kotlin/org/frc5183/robot/subsystems/shooter/io/ShooterIO.kt
  • src/main/kotlin/org/frc5183/robot/subsystems/shooter/io/ShooterIOInputs.kt
  • src/main/kotlin/org/frc5183/robot/subsystems/turntable/TurntableSubsystem.kt
  • src/main/kotlin/org/frc5183/robot/subsystems/turntable/io/RealTurntableIO.kt
  • src/main/kotlin/org/frc5183/robot/subsystems/turntable/io/TurntableIO.kt
  • src/main/kotlin/org/frc5183/robot/subsystems/turntable/io/TurntableIOInputs.kt
  • src/main/kotlin/org/frc5183/robot/subsystems/vision/VisionSubsystem.kt
  • src/main/kotlin/org/frc5183/robot/subsystems/vision/io/RealVisionIO.kt
  • src/main/kotlin/org/frc5183/robot/subsystems/vision/io/VisionIO.kt
  • src/main/kotlin/org/frc5183/robot/subsystems/vision/io/VisionIOInputs.kt
💤 Files with no reviewable changes (20)
  • src/main/kotlin/org/frc5183/robot/subsystems/vision/io/RealVisionIO.kt
  • src/main/kotlin/org/frc5183/robot/logging/struct/EstimatedRobotPoseStruct.kt
  • src/main/kotlin/org/frc5183/robot/subsystems/shooter/io/RealShooterIO.kt
  • src/main/kotlin/org/frc5183/robot/subsystems/collector/io/CollectorIO.kt
  • src/main/kotlin/org/frc5183/robot/subsystems/drive/io/RealSwerveDriveIO.kt
  • src/main/kotlin/org/frc5183/robot/subsystems/turntable/io/TurntableIO.kt
  • build.gradle.kts
  • src/main/kotlin/org/frc5183/robot/subsystems/shooter/io/ShooterIO.kt
  • src/main/kotlin/org/frc5183/robot/logging/AutoLogInputs.kt
  • src/main/kotlin/org/frc5183/robot/subsystems/drive/io/SwerveDriveIOInputs.kt
  • src/main/kotlin/org/frc5183/robot/subsystems/drive/io/SwerveDriveIO.kt
  • src/main/kotlin/org/frc5183/robot/subsystems/vision/io/VisionIOInputs.kt
  • src/main/kotlin/org/frc5183/robot/subsystems/vision/io/VisionIO.kt
  • src/main/kotlin/org/frc5183/robot/subsystems/collector/io/CollectorIOInputs.kt
  • src/main/kotlin/org/frc5183/robot/subsystems/turntable/io/TurntableIOInputs.kt
  • src/main/kotlin/org/frc5183/robot/logging/struct/PhotonTrackedTargetStruct.kt
  • src/main/kotlin/org/frc5183/robot/subsystems/shooter/io/ShooterIOInputs.kt
  • src/main/kotlin/org/frc5183/robot/subsystems/drive/io/SimulatedSwerveDriveIO.kt
  • src/main/kotlin/org/frc5183/robot/subsystems/collector/io/RealCollectorIO.kt
  • src/main/kotlin/org/frc5183/robot/subsystems/turntable/io/RealTurntableIO.kt

Comment on lines 32 to 35
class SwerveDriveSubsystem(
private val io: SwerveDriveIO,
private val vision: VisionSubsystem? = null,
val drive: SwerveDrive,
val vision: VisionSubsystem?,
) : SubsystemBase() {
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

find . -type f -name "SwerveDriveSubsystem.kt" | head -5

Repository: frc5183/cleobotra

Length of output: 137


🏁 Script executed:

find . -type f -name "FixedCamera.kt" | head -5

Repository: frc5183/cleobotra

Length of output: 129


🏁 Script executed:

cat -n ./src/main/kotlin/org/frc5183/robot/subsystems/drive/SwerveDriveSubsystem.kt

Repository: frc5183/cleobotra

Length of output: 5781


🏁 Script executed:

cat -n ./src/main/kotlin/org/frc5183/robot/subsystems/vision/FixedCamera.kt

Repository: frc5183/cleobotra

Length of output: 6666


🏁 Script executed:

find . -type f -name "VisionSubsystem.kt" | head -5

Repository: frc5183/cleobotra

Length of output: 133


🏁 Script executed:

cat -n ./src/main/kotlin/org/frc5183/robot/subsystems/vision/VisionSubsystem.kt

Repository: frc5183/cleobotra

Length of output: 1545


Prevent re-adding stale vision measurements to the drive estimator.

The SwerveDriveSubsystem.periodic() method forwards every non-null pose to addVisionMeasurement() on every robot tick. However, frontCamera.estimatedRobotPose and backCamera.estimatedRobotPose only update when new frames arrive (see FixedCamera.updateUnreadResults() which feeds only new results to updateEstimatedGlobalPose()). This causes the same measurement timestamp to be re-added repeatedly until the next frame arrives, artificially overweighting stale vision data in the swerve drive's pose estimator.

Add monotonically increasing timestamp guards to each camera before calling addVisionMeasurement:

Suggested guard
 class SwerveDriveSubsystem(
     val drive: SwerveDrive,
     val vision: VisionSubsystem?,
 ) : SubsystemBase() {
+    private var lastFrontVisionTimestamp = Double.NEGATIVE_INFINITY
+    private var lastBackVisionTimestamp = Double.NEGATIVE_INFINITY
+
     val robotPose: Pose2d
         get() = drive.pose
@@
     override fun periodic() {
         if (vision != null) {
-            vision.frontRobotPose?.let {
+            vision.frontRobotPose?.takeIf { it.timestampSeconds > lastFrontVisionTimestamp }?.let {
+                lastFrontVisionTimestamp = it.timestampSeconds
                 addVisionMeasurement(it.estimatedPose.toPose2d(), it.timestampSeconds, vision.frontCamera.currentStandardDeviations)
             }
 
-            vision.backRobotPose?.let {
+            vision.backRobotPose?.takeIf { it.timestampSeconds > lastBackVisionTimestamp }?.let {
+                lastBackVisionTimestamp = it.timestampSeconds
                 addVisionMeasurement(it.estimatedPose.toPose2d(), it.timestampSeconds, vision.backCamera.currentStandardDeviations)
             }
 
             drive.updateOdometry()
         }
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/kotlin/org/frc5183/robot/subsystems/drive/SwerveDriveSubsystem.kt`
around lines 32 - 35, SwerveDriveSubsystem.periodic() is re-adding identical
vision measurements each tick because frontCamera.estimatedRobotPose and
backCamera.estimatedRobotPose only change when new frames arrive; to fix it add
monotonic timestamp guards (e.g., lastFrontVisionTimestamp and
lastBackVisionTimestamp fields) and only call drive.addVisionMeasurement(...)
when the incoming pose.timestamp is greater than the stored last timestamp, then
update the stored timestamp; reference the symbols
SwerveDriveSubsystem.periodic(), frontCamera.estimatedRobotPose,
backCamera.estimatedRobotPose, and drive.addVisionMeasurement() when making the
change so stale measurements from FixedCamera.updateUnreadResults() are not
repeatedly added.

Comment on lines 13 to +18
val targets: Array<PhotonTrackedTarget>
get() = ioInputs.targets
get() =
camera.allUnreadResults
.map { it.targets }
.flatten()
.toTypedArray()
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

fd "TurntableSubsystem" --type f

Repository: frc5183/cleobotra

Length of output: 137


🏁 Script executed:

fd "FixedCamera" --type f

Repository: frc5183/cleobotra

Length of output: 127


🏁 Script executed:

git ls-files | grep -E "(Turntable|Vision)" | head -20

Repository: frc5183/cleobotra

Length of output: 421


🏁 Script executed:

cat -n src/main/kotlin/org/frc5183/robot/subsystems/turntable/TurntableSubsystem.kt

Repository: frc5183/cleobotra

Length of output: 1161


🏁 Script executed:

cat -n src/main/kotlin/org/frc5183/robot/subsystems/vision/FixedCamera.kt

Repository: frc5183/cleobotra

Length of output: 6666


🏁 Script executed:

rg "allUnreadResults" --type kotlin -A 2 -B 2

Repository: frc5183/cleobotra

Length of output: 1054


🌐 Web query:

PhotonVision PhotonCamera allUnreadResults destructive read semantics

💡 Result:

PhotonCamera.getAllUnreadResults() / GetAllUnreadResults() has destructive-read semantics:

  • It returns all PhotonPipelineResults received since the previous call to getAllUnreadResults(). [1]
  • Calling it clears the camera’s internal FIFO queue, so subsequent calls return different results (often an empty list if nothing new arrived). [1]
  • The FIFO depth is limited to 20 results; if you don’t call it often enough, older results can be dropped. [1]
  • PhotonVision’s javadocs explicitly warn to call it exactly once per robot loop. [1]

Related note: getLatestResult() is not destructive (it always returns the most recent NT result), but it’s deprecated in favor of getAllUnreadResults() because it can miss results or return duplicates. [1]


Cache unread camera results once per loop.

targets consumes camera.allUnreadResults on every access, and line 22 already reads it once per scheduler tick for logging. Any later consumer of targets in the same loop will therefore see an empty array. FixedCamera already snapshots unread results in periodic() (lines 74-93); TurntableSubsystem should do the same.

📌 One way to fix it
 class TurntableSubsystem(
     val motor: SparkMax,
     val camera: PhotonCamera,
 ) : SubsystemBase() {
+    private var cachedTargets: Array<PhotonTrackedTarget> = emptyArray()
+
     val targets: Array<PhotonTrackedTarget>
-        get() =
-            camera.allUnreadResults
-                .map { it.targets }
-                .flatten()
-                .toTypedArray()
+        get() = cachedTargets.copyOf()
 
     override fun periodic() {
+        cachedTargets =
+            camera.allUnreadResults
+                .flatMap { it.targets }
+                .toTypedArray()
+
         Logger.recordOutput("Turntable/Speed", motor.get())
         Logger.recordOutput("Turntable/Targets", targets.map { it.fiducialId }.toIntArray())
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/kotlin/org/frc5183/robot/subsystems/turntable/TurntableSubsystem.kt`
around lines 13 - 18, The targets getter currently calls camera.allUnreadResults
each time, consuming unread results multiple times per scheduler loop; change
TurntableSubsystem to snapshot unread results once per loop by adding a private
backing field (e.g., cachedTargets: Array<PhotonTrackedTarget>) and populate it
inside TurntableSubsystem.periodic() by reading camera.allUnreadResults once,
mapping and flattening that result into the cachedTargets, then have the public
targets property simply return cachedTargets so later consumers and the existing
logging use the same snapshot.

Copy link

@Trip-kun Trip-kun left a comment

Choose a reason for hiding this comment

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

Looks mostly good to me. See the rabbit's suggestions about missing symbols.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Kind/Feature New functionality

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants