-
Notifications
You must be signed in to change notification settings - Fork 1
Turret Camera #13
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Turret Camera #13
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This pull request introduces support for dynamic camera transforms, enabling cameras mounted on moving mechanisms (like turrets) to report their position correctly over time. The core change is the introduction of the DynamicCameraTransform class, which abstracts camera-to-robot transformations and supports both static and time-dependent camera positioning.
Changes:
- Added
DynamicCameraTransformclass to handle both static and time-dependent camera transformations - Refactored all AprilTag camera IO classes to accept
DynamicCameraTransforminstead ofTransform3d - Updated simulation camera to dynamically adjust camera position on each update cycle
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| DynamicCameraTransform.java | New class providing abstraction for static and dynamic camera transforms with time-based lookups |
| AprilTagPhotonCameraIO.java | Updated to use DynamicCameraTransform and retrieve time-based transforms for pose calculations |
| AprilTagSimulationCameraIO.java | Added updateInputs override to continuously update simulated camera position |
| AprilTagLimelightIO.java | Constructor signature updated to accept DynamicCameraTransform (not yet used due to incomplete implementation) |
| AprilTagCameraIO.java | Factory method updated to accept and pass DynamicCameraTransform |
| AprilTagCameraConstants.java | Updated enum to use DynamicCameraTransform in BiFunction signature |
| AprilTagCamera.java | Added constructor overload for DynamicCameraTransform and refactored to use time-based transforms |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
src/main/java/frc/trigon/robot/poseestimation/apriltagcamera/DynamicCameraTransform.java
Show resolved
Hide resolved
src/main/java/frc/trigon/robot/poseestimation/apriltagcamera/DynamicCameraTransform.java
Show resolved
Hide resolved
WalkthroughIntroduces DynamicCameraTransform to provide time-varying camera-to-robot transforms and replaces static Transform3d usage across AprilTag camera IO and pose-estimation code. AprilTagCamera, AprilTagCameraIO, AprilTagCameraConstants, and IO implementations now accept DynamicCameraTransform; pose conversions and related flows propagate result timestamps. Adds TurretCameraTransformCalculator (with sampling/forecasting) and integrates turret angle/velocity updates in Turret. CameraConstants adds RIGHT_TURRET_CAMERA and LEFT_TURRET_CAMERA using dynamic transforms, and RobotContainer now supplies those turret cameras to the robot pose estimator. 🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Tip 🧪 Unit Test Generation v2 is now available!We have significantly improved our unit test generation capabilities. To enable: Add this to your reviews:
finishing_touches:
unit_tests:
enabled: trueTry it out by using the Have feedback? Share your thoughts on our Discord thread! 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. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
src/main/java/frc/trigon/robot/poseestimation/apriltagcamera/io/AprilTagPhotonCameraIO.java (2)
16-35: Add a fail‑fast null guard fordynamicCameraTransform.This avoids deferred NPEs during pose estimation and makes misconfiguration obvious at construction time.
Proposed fix
import java.util.Arrays; import java.util.List; +import java.util.Objects; import java.util.Optional; ... public AprilTagPhotonCameraIO(String cameraName, DynamicCameraTransform dynamicCameraTransform) { photonCamera = new PhotonCamera(cameraName); - this.dynamicCameraTransform = dynamicCameraTransform; + this.dynamicCameraTransform = Objects.requireNonNull(dynamicCameraTransform, "dynamicCameraTransform"); }
142-167: Add null guard forsamplePoseAtTimestamp()result.
samplePoseAtTimestamp()returnsnullwhen the pose is outside the buffer window (early in match). Calling.getRotation()on null will crash. Similar code elsewhere guards against this (see ObjectDetectionCamera.java:89). Check the timestamp and fallback if the pose is unavailable, or handle the case where constrained solve-pnp cannot proceed.
src/main/java/frc/trigon/robot/poseestimation/apriltagcamera/DynamicCameraTransform.java
Show resolved
Hide resolved
|
So we doing SOTM this season? |
src/main/java/frc/trigon/robot/poseestimation/apriltagcamera/DynamicCameraTransform.java
Show resolved
Hide resolved
src/main/java/frc/trigon/robot/poseestimation/apriltagcamera/io/AprilTagPhotonCameraIO.java
Outdated
Show resolved
Hide resolved
I have no idea what Shirt On The Mop means. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
src/main/java/frc/trigon/robot/misc/TurretCameraCalculations.java
Outdated
Show resolved
Hide resolved
src/main/java/frc/trigon/robot/misc/TurretCameraCalculations.java
Outdated
Show resolved
Hide resolved
|
Needs testing |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 5
src/main/java/frc/trigon/robot/poseestimation/apriltagcamera/io/AprilTagPhotonCameraIO.java
Show resolved
Hide resolved
src/main/java/frc/trigon/robot/subsystems/turret/TurretCameraTransformCalculator.java
Show resolved
Hide resolved
src/main/java/frc/trigon/robot/subsystems/turret/TurretCameraTransformCalculator.java
Show resolved
Hide resolved
src/main/java/frc/trigon/robot/subsystems/turret/TurretCameraTransformCalculator.java
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
src/main/java/frc/trigon/robot/subsystems/turret/TurretCameraTransformCalculator.java
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
| private Rotation2d calculateTurretAngleAtTime(double timestampSeconds) { | ||
| if (isTimestampTooNew(timestampSeconds)) | ||
| return estimateFutureTurretAngle(timestampSeconds); | ||
|
|
||
| return sampleTurretAngleAtTime(timestampSeconds); | ||
| } | ||
|
|
||
| private boolean isTimestampTooNew(double timestampSeconds) { | ||
| final Map.Entry<Double, Rotation2d> latestBufferEntry = getLatestBufferEntry(); | ||
| if (latestBufferEntry == null) | ||
| return false; | ||
| final Double latestTimestamp = latestBufferEntry.getKey(); | ||
| return timestampSeconds > latestTimestamp; | ||
| } | ||
|
|
||
| private Rotation2d estimateFutureTurretAngle(double futureTimestampSeconds) { | ||
| final Map.Entry<Double, Rotation2d> latestBufferEntry = getLatestBufferEntry(); | ||
| if (latestBufferEntry == null) | ||
| return RobotContainer.TURRET.getCurrentSelfRelativeAngle(); | ||
| final Double latestTimestamp = latestBufferEntry.getKey(); | ||
| final Rotation2d latestAngle = latestBufferEntry.getValue(); | ||
|
|
||
| final double timeDeltaSeconds = futureTimestampSeconds - latestTimestamp; | ||
| final double predictedRotations = latestVelocityRotationsPerSecond * timeDeltaSeconds; | ||
| return latestAngle.plus(Rotation2d.fromRotations(predictedRotations)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# First, locate and examine the file in question
fd "TurretCameraTransformCalculator.java"Repository: Programming-TRIGON/RobotCode2026
Length of output: 161
🏁 Script executed:
# Search for downstream callers of the transform methods
rg -n "calculateRobotTo.*CameraAtTime|calculateRobotToCameraAtTime" --type javaRepository: Programming-TRIGON/RobotCode2026
Length of output: 1410
🏁 Script executed:
# Look for uses of DynamicCameraTransform and how null is handled
rg -n "DynamicCameraTransform" --type java -A 3 -B 1Repository: Programming-TRIGON/RobotCode2026
Length of output: 13370
🏁 Script executed:
# Search for sampleTurretAngleAtTime to see if it can return null
rg -n "sampleTurretAngleAtTime" --type java -A 5 -B 1Repository: Programming-TRIGON/RobotCode2026
Length of output: 1872
🏁 Script executed:
# Look at the buffer management and getLatestBufferEntry
rg -n "getLatestBufferEntry" --type java -A 3 -B 1Repository: Programming-TRIGON/RobotCode2026
Length of output: 2190
🏁 Script executed:
cat -n src/main/java/frc/trigon/robot/subsystems/turret/TurretCameraTransformCalculator.javaRepository: Programming-TRIGON/RobotCode2026
Length of output: 4940
🏁 Script executed:
# Check how downstream AprilTagCamera uses the transform
rg -n "getTransform\|robotCenterToCameraFunction" src/main/java/frc/trigon/robot/poseestimation/apriltagcamera/ --type java -A 3 -B 1Repository: Programming-TRIGON/RobotCode2026
Length of output: 58
🏁 Script executed:
# Search for where robotCenterToCameraFunction is invoked
rg -n "robotCenterToCameraFunction\.apply\|robotCenterToCameraFunction\.get\|robotCenterToCameraFunction\(" src/main/java/frc/trigon/robot/poseestimation/ --type java -A 2 -B 1Repository: Programming-TRIGON/RobotCode2026
Length of output: 58
🏁 Script executed:
# Look for where AprilTagCamera's getTransform method is used
rg -n "getTransform\(\|\.dynamicCameraTransform" src/main/java/frc/trigon/robot/ --type java -A 2 -B 1 | head -80Repository: Programming-TRIGON/RobotCode2026
Length of output: 58
🏁 Script executed:
# Find where the transform functions are called
rg -n "calculateRobotTo.*CameraAtTime\(" src/main/java/frc/trigon/robot/ --type java -A 5 -B 1Repository: Programming-TRIGON/RobotCode2026
Length of output: 2144
🏁 Script executed:
# Search in AprilTagCamera for getTransform or transform retrieval
cat -n src/main/java/frc/trigon/robot/poseestimation/apriltagcamera/AprilTagCamera.java | head -100Repository: Programming-TRIGON/RobotCode2026
Length of output: 5652
🏁 Script executed:
# Look for AprilTagCamera.update or process methods
rg -n "update\|process" src/main/java/frc/trigon/robot/poseestimation/apriltagcamera/AprilTagCamera.java --type java -A 10Repository: Programming-TRIGON/RobotCode2026
Length of output: 58
🏁 Script executed:
# Get more of AprilTagCamera file to see calculateRobotPose
cat -n src/main/java/frc/trigon/robot/poseestimation/apriltagcamera/AprilTagCamera.java | tail -100Repository: Programming-TRIGON/RobotCode2026
Length of output: 5868
🏁 Script executed:
# Search for calculateRobotPose to see full implementation
rg -n "calculateRobotPose" src/main/java/frc/trigon/robot/poseestimation/apriltagcamera/AprilTagCamera.java --type java -A 20Repository: Programming-TRIGON/RobotCode2026
Length of output: 1866
🏁 Script executed:
# Check DynamicCameraTransform.calculate2dRobotPose implementation
rg -n "calculate2dRobotPose" src/main/java/frc/trigon/robot/poseestimation/apriltagcamera/DynamicCameraTransform.java --type java -A 10 -B 1Repository: Programming-TRIGON/RobotCode2026
Length of output: 608
🏁 Script executed:
# Check get2dCameraToRobotCenter implementation
rg -n "get2dCameraToRobotCenter" src/main/java/frc/trigon/robot/poseestimation/apriltagcamera/DynamicCameraTransform.java --type java -A 10 -B 1Repository: Programming-TRIGON/RobotCode2026
Length of output: 1090
🏁 Script executed:
# Check get3dCameraToRobotCenter implementation
rg -n "get3dCameraToRobotCenter" src/main/java/frc/trigon/robot/poseestimation/apriltagcamera/DynamicCameraTransform.java --type java -A 10 -B 1Repository: Programming-TRIGON/RobotCode2026
Length of output: 1653
Handle empty buffer at startup to avoid null Transform3d propagating downstream.
With an empty buffer, isTimestampTooNew() returns false, so calculateTurretAngleAtTime() calls sampleTurretAngleAtTime(), which returns null. This null propagates through calculateRobotToCameraAtTime() to DynamicCameraTransform, where inverse() is called on a null Transform3d—causing an NPE when AprilTagCamera attempts pose estimation at startup. The fallback at line 74 is unreachable.
Treat an empty buffer as "too new" (return true from isTimestampTooNew()) so the fallback uses RobotContainer.TURRET.getCurrentSelfRelativeAngle(), or handle null Transform3d explicitly in the downstream chain.
TODO: Implement a TimeInterpolatingBuffer inside the turret subsystem