Skip to content
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

Add Object Detection Support #13

Open
wants to merge 39 commits into
base: master
Choose a base branch
from
Open

Add Object Detection Support #13

wants to merge 39 commits into from

Conversation

SeanErn
Copy link
Member

@SeanErn SeanErn commented Nov 14, 2024

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced two new vision subsystems: PhotonvisionAprilTagSubsystem and PhotonVisionObjectDetectionSubsystem for enhanced object detection capabilities.
    • Added support for detecting objects through multiple cameras with improved telemetry visualization.
    • New classes DetectedObject and GameElement to represent detected objects and game elements, respectively.
  • Bug Fixes

    • Improved handling of joystick inputs by activating previously commented-out utilities.
  • Documentation

    • Enhanced readability and consistency in various classes and constants related to vision processing.

These updates aim to improve the overall functionality and user experience in vision-based tasks within the robotics framework.

Copy link

coderabbitai bot commented Nov 14, 2024

📝 Walkthrough

Walkthrough

The pull request introduces substantial modifications to the vision subsystem of the robotics framework. It replaces the existing PhotonvisionSubsystem with two new subsystems: PhotonvisionAprilTagSubsystem and PhotonVisionObjectDetectionSubsystem. The RobotContainer class is updated to integrate these new subsystems, enhancing the robot's vision capabilities. Additionally, several new classes related to object detection and telemetry are introduced, while existing classes undergo renaming and restructuring to align with the new functionality. Overall, the changes focus on improving the handling of vision tasks in the robotics system.

Changes

File Change Summary
src/main/java/frc/alotobots/RobotContainer.java Replaced PhotonvisionSubsystem with PhotonvisionAprilTagSubsystem and PhotonVisionObjectDetectionSubsystem. Updated method calls and variable declarations accordingly.
src/main/java/frc/alotobots/game/HMIStation.java Activated the import for JoystickUtilities, indicating its usage for joystick input processing.
src/main/java/frc/alotobots/game/constants/HMIDeadbands.java Reformatted constants for consistency; no functional changes.
src/main/java/frc/alotobots/library/drivetrains/swerve/ctre/SwerveDriveSubsystem.java Updated imports and variable types from PhotonvisionSubsystem to PhotonvisionAprilTagSubsystem.
src/main/java/frc/alotobots/library/vision/photonvision/apriltag/PhotonvisionAprilTagSubsystem.java Renamed and refactored PhotonvisionSubsystem to focus on AprilTag detection with updated fields and methods.
src/main/java/frc/alotobots/library/vision/photonvision/apriltag/PhotonvisionAprilTagSubsystemConstants.java Renamed constants class to reflect AprilTag focus; updated constant names.
src/main/java/frc/alotobots/library/vision/photonvision/apriltag/PhotonvisionAprilTagTelemetry.java Refactored telemetry class to manage AprilTag detection data; updated methods and references.
src/main/java/frc/alotobots/library/vision/photonvision/objectdetection/DetectedObject.java Introduced a new class for detected objects with attributes and methods for handling object data.
src/main/java/frc/alotobots/library/vision/photonvision/objectdetection/GameElement.java Added a new class representing game elements with dimensions and identifiers.
src/main/java/frc/alotobots/library/vision/photonvision/objectdetection/PhotonVisionObjectDetectionSubsystem.java Introduced a new subsystem for managing object detection with multiple cameras.
src/main/java/frc/alotobots/library/vision/photonvision/objectdetection/PhotonVisionObjectDetectionSubsystemConstants.java Added a utility class for object detection constants, including camera configurations and game elements.
src/main/java/frc/alotobots/library/vision/photonvision/objectdetection/PhotonVisionObjectDetectionTelemetry.java Introduced a telemetry class for visualizing object detection data on Shuffleboard.

Possibly related PRs

  • Add Tracers in Photonvision tab from robot to tag #5: The changes in the PhotonvisionSubsystem class enhance its functionality related to pose estimation and target detection, which is directly related to the modifications made in the main PR that introduces the PhotonvisionAprilTagSubsystem.
  • Add Multicam Support for AprilTags #11: This PR adds significant enhancements to the PhotonvisionSubsystem, including the introduction of a camera-enabled tracking system for pose estimations, which aligns with the changes made in the main PR regarding the new vision subsystems.

📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 7209bc5 and 955f569.

📒 Files selected for processing (12)
  • src/main/java/frc/alotobots/RobotContainer.java (4 hunks)
  • src/main/java/frc/alotobots/game/HMIStation.java (1 hunks)
  • src/main/java/frc/alotobots/game/constants/HMIDeadbands.java (1 hunks)
  • src/main/java/frc/alotobots/library/drivetrains/swerve/ctre/SwerveDriveSubsystem.java (4 hunks)
  • src/main/java/frc/alotobots/library/vision/photonvision/apriltag/PhotonvisionAprilTagSubsystem.java (8 hunks)
  • src/main/java/frc/alotobots/library/vision/photonvision/apriltag/PhotonvisionAprilTagSubsystemConstants.java (2 hunks)
  • src/main/java/frc/alotobots/library/vision/photonvision/apriltag/PhotonvisionAprilTagTelemetry.java (9 hunks)
  • src/main/java/frc/alotobots/library/vision/photonvision/objectdetection/DetectedObject.java (1 hunks)
  • src/main/java/frc/alotobots/library/vision/photonvision/objectdetection/GameElement.java (1 hunks)
  • src/main/java/frc/alotobots/library/vision/photonvision/objectdetection/PhotonVisionObjectDetectionSubsystem.java (1 hunks)
  • src/main/java/frc/alotobots/library/vision/photonvision/objectdetection/PhotonVisionObjectDetectionSubsystemConstants.java (1 hunks)
  • src/main/java/frc/alotobots/library/vision/photonvision/objectdetection/PhotonVisionObjectDetectionTelemetry.java (1 hunks)
✅ Files skipped from review due to trivial changes (2)
  • src/main/java/frc/alotobots/game/constants/HMIDeadbands.java
  • src/main/java/frc/alotobots/library/vision/photonvision/objectdetection/PhotonVisionObjectDetectionSubsystemConstants.java
🔇 Additional comments (11)
src/main/java/frc/alotobots/library/vision/photonvision/apriltag/PhotonvisionAprilTagSubsystemConstants.java (3)

20-22: LGTM! Field layout configuration is appropriate

The use of k2024Crescendo field layout is correct for the current season.


Line range hint 24-43: Verify camera positioning and document configuration decisions

The camera configuration shows:

  1. Only 2 of 4 possible cameras are active (FL and FM)
  2. Specific offset values that need verification
  3. Commented-out cameras (BL and BR) without explanation

Please:

  1. Verify that the Transform3d values match the physical robot configuration
  2. Document why the back cameras are commented out

Consider adding a comment explaining the camera selection strategy and future plans for the commented-out cameras.


Line range hint 1-18: Verify resource management for PhotonCamera instances

The @SuppressWarnings("resource") suggests that PhotonCamera resources aren't being explicitly closed. While this might be intentional for long-lived camera instances, we should verify the lifecycle management approach.

✅ Verification successful

@SuppressWarnings("resource") annotation is appropriate

The @SuppressWarnings("resource") annotation is justified in this context because:

  • PhotonCamera instances are long-lived system resources that exist throughout the robot's operation lifecycle
  • They are managed as constant fields in utility classes and subsystems
  • WPILib's SubsystemBase handles cleanup during robot shutdown
  • The implementation follows the standard pattern used in WPILib vision processing

The code follows the established patterns for vision subsystems in FRC, where cameras are initialized once and remain active until robot shutdown.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for PhotonCamera cleanup patterns in the codebase
rg -A 5 "close\(\)|shutdown\(\)" | grep -C 5 "PhotonCamera"

# Check if there are any existing patterns for managing PhotonCamera lifecycle
ast-grep --pattern 'try ($camera = new PhotonCamera($_)) { $$$ }'

Length of output: 127


Script:

#!/bin/bash
# Let's try a broader search for PhotonCamera usage patterns
rg -l "PhotonCamera"

# Check PhotonCamera instantiation patterns
ast-grep --pattern 'new PhotonCamera($$$)'

# Look for any dispose/close patterns in subsystem classes
rg -A 5 "extends SubsystemBase" | grep -C 10 "PhotonCamera"

# Search for any lifecycle management in test files
fd -e java -E "build" | xargs rg "PhotonCamera.*close|PhotonCamera.*dispose"

Length of output: 3184

src/main/java/frc/alotobots/RobotContainer.java (3)

12-13: LGTM! Imports are well-organized.

The new imports follow the logical package structure for vision components.


107-107: Verify object detection subsystem configuration.

While the AprilTag subsystem is properly configured with the drivetrain, there's no setup for the object detection subsystem. Please verify if:

  1. The object detection subsystem requires similar configuration
  2. The configuration is handled elsewhere
  3. This is intentional based on the design

Let's check for any other configuration points:

#!/bin/bash
# Search for object detection subsystem configuration
echo "Checking for object detection configuration:"
rg "photonvisionObjectDetectionSubsystem\." --type java -A 3

# Check if there are similar setup methods in other files
echo "Checking for other setup methods:"
ast-grep --pattern 'setupVision($$$) {
  $$$
}'

47-49: Review dependency pattern between vision subsystems.

There's an architectural inconsistency in how the vision subsystems are initialized:

  • photonvisionAprilTagSubsystem is created without dependencies
  • photonvisionObjectDetectionSubsystem requires the drivetrain subsystem

This difference in initialization patterns might indicate:

  1. A potential missing dependency in the AprilTag subsystem
  2. An unnecessary dependency in the object detection subsystem

Let's verify the dependency requirements:

✅ Verification successful

Let me try another verification approach to understand the dependency patterns better.


Let me check the implementation of the DetectedObject class to understand why the drivetrain dependency is needed.


Based on the DetectedObject implementation, I can now provide a final response about the architectural pattern:

Drivetrain dependency is correctly used in vision subsystems

The dependency injection pattern is actually consistent with the system's requirements:

  • PhotonvisionObjectDetectionSubsystem needs the drivetrain to calculate field-relative poses and distances for detected objects
  • PhotonvisionAprilTagSubsystem handles its own pose calculations independently using the AprilTag field layout

Key evidence from the code:

  • DetectedObject uses drivetrain to:
    • Transform camera-space detections into field-space coordinates
    • Calculate accurate distances and angles to detected objects
    • Provide field-relative positioning for game elements and robots
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check how these subsystems are used in the codebase

# Check AprilTag subsystem usage patterns
echo "Checking AprilTag subsystem usage:"
ast-grep --pattern 'new PhotonvisionAprilTagSubsystem($$$)'

# Check ObjectDetection subsystem usage patterns
echo "Checking ObjectDetection subsystem usage:"
ast-grep --pattern 'new PhotonVisionObjectDetectionSubsystem($$$)'

# Check method calls that might explain the dependency
echo "Checking drivetrain-related method calls:"
rg -l "drivetrain" --type java | xargs ast-grep --pattern 'photonvisionObjectDetectionSubsystem.$$$'

Length of output: 604


Script:

#!/bin/bash
# Check implementation of both subsystems
echo "=== PhotonvisionAprilTagSubsystem Implementation ==="
fd "PhotonvisionAprilTagSubsystem.java" --type f --exec cat {}

echo -e "\n=== PhotonVisionObjectDetectionSubsystem Implementation ==="
fd "PhotonVisionObjectDetectionSubsystem.java" --type f --exec cat {}

# Check where drivetrain is used in object detection
echo -e "\n=== Drivetrain Usage in Object Detection ==="
rg "drivetrain" -B2 -A2 --type java

Length of output: 38297


Script:

#!/bin/bash
# Check DetectedObject implementation to understand drivetrain usage
echo "=== DetectedObject Implementation ==="
fd "DetectedObject.java" --type f --exec cat {}

# Check if there are any methods in ObjectDetection subsystem that use drivetrain
echo -e "\n=== Methods using drivetrain in ObjectDetection ==="
rg -p "drivetrain" PhotonVisionObjectDetectionSubsystem.java

Length of output: 11287

src/main/java/frc/alotobots/library/vision/photonvision/objectdetection/DetectedObject.java (1)

14-14: Verify thread safety of static drive field.

The static drive field could lead to race conditions if accessed concurrently.

✅ Verification successful

Let me gather more context about the usage patterns of DetectedObject class.


Based on the analysis of the code, I can now generate the final response:

Static drive field is thread-safe in this context

The static drive field in DetectedObject is safely used because:

  • It's only initialized once during robot startup in a controlled manner by either PhotonVisionObjectDetectionSubsystem or LimelightSubsystem
  • All access is read-only through the @Getter annotation
  • The field is only accessed during periodic updates in vision subsystems which run on the main robot loop
  • No concurrent modifications or async operations are performed on this field
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for potential concurrent access to the static drive field

# Search for concurrent access patterns
rg -l "ExecutorService|Runnable|Thread|CompletableFuture|parallel|async" | while read -r file; do
  echo "=== $file ==="
  rg "DetectedObject\.(?:get)?drive" "$file" -A 5 -B 5
done

# Search for multiple initialization points
ast-grep --pattern 'DetectedObject.setDrive($_)'

Length of output: 1069


Script:

#!/bin/bash
# Check how DetectedObject is used and accessed
rg "DetectedObject" -A 5 -B 5

# Check for any periodic/scheduled tasks that might access drive field
rg "periodic|schedule|interval|timer" -l | while read -r file; do
  echo "=== $file ==="
  rg "DetectedObject|drive" "$file" -A 5 -B 5
done

# Look for the full DetectedObject class implementation
ast-grep --pattern 'class DetectedObject {
  $$$
}'

Length of output: 59204

src/main/java/frc/alotobots/library/drivetrains/swerve/ctre/SwerveDriveSubsystem.java (2)

Line range hint 1-256: Verify scope of object detection support

While the PR title is "Add Object Detection Support", this class has been modified to work specifically with AprilTags but shows no integration with general object detection functionality. Please clarify:

  1. Is object detection support implemented in separate classes?
  2. Should this class also integrate with the new object detection subsystem?
  3. If not, should the PR title be updated to better reflect the AprilTag-specific changes?
#!/bin/bash
# Search for files that might contain the object detection implementation
echo "Files potentially related to object detection:"
fd -e java -e kt | rg -l "ObjectDetection|Detection|Vision"

# Search for references to the new subsystems mentioned in the AI summary
echo "\nReferences to new vision subsystems:"
rg "PhotonVisionObjectDetectionSubsystem|PhotonvisionAprilTagSubsystem"

3-4: Verify integration of object detection functionality

While the changes transition to AprilTag-based vision, the imports and usage suggest this class only handles AprilTag detection. Given that the PR's objective is to "Add Object Detection Support", we should verify if object detection functionality needs to be integrated here as well.

Also applies to: 22-22

src/main/java/frc/alotobots/game/HMIStation.java (1)

15-15: Verify the JoystickUtilities import dependency.

The code was previously using JoystickUtilities without an explicit import. Let's verify this doesn't break any existing functionality.

src/main/java/frc/alotobots/library/vision/photonvision/objectdetection/PhotonVisionObjectDetectionSubsystem.java (1)

56-72: ⚠️ Potential issue

Ensure CAMERAS and CAMERA_OFFSETS arrays are synchronized

Accessing CAMERA_OFFSETS[i] assumes that the CAMERA_OFFSETS array has the same length and order as the cameras array. If these arrays are not aligned, it could lead to IndexOutOfBoundsException or incorrect offset applications.

Run the following script to confirm that both arrays have the same length:

✅ Verification successful

Arrays are properly synchronized - no issues found

The CAMERAS and CAMERA_OFFSETS arrays in PhotonVisionObjectDetectionSubsystemConstants.java are correctly synchronized. Both arrays have exactly one element each:

  • CAMERAS: One camera named "FM_ObjectDetection"
  • CAMERA_OFFSETS: One corresponding transform for the front middle camera

The arrays are properly aligned in both length and order, eliminating any risk of IndexOutOfBoundsException.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify that CAMERAS and CAMERA_OFFSETS arrays have the same length.

# Expected: Both arrays should be declared and have the same length.

# Using ast-grep to extract the array lengths.
ast-grep --pattern $'public static final PhotonCamera[] CAMERAS = new PhotonCamera[$_];' PhotonVisionObjectDetectionSubsystemConstants.java
ast-grep --pattern $'public static final Transform3d[] CAMERA_OFFSETS = new Transform3d[$_];' PhotonVisionObjectDetectionSubsystemConstants.java

Length of output: 482


Script:

#!/bin/bash
# First, let's find the correct path to the constants file
fd PhotonVisionObjectDetectionSubsystemConstants.java

# Then, let's search for array declarations and initializations
rg -A 5 "CAMERAS|CAMERA_OFFSETS" --type java

Length of output: 18684


Script:

#!/bin/bash
# Let's get the full content of the constants file to see the array declarations and their sizes
cat src/main/java/frc/alotobots/library/vision/photonvision/objectdetection/PhotonVisionObjectDetectionSubsystemConstants.java

Length of output: 1269


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

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.

Caution

Inline review comments failed to post. This is likely due to GitHub's limits when posting large numbers of comments.

Actionable comments posted: 8

🧹 Outside diff range and nitpick comments (26)
src/main/java/frc/alotobots/library/vision/photonvision/objectdetection/GameElement.java (4)

5-9: Consider adding input validation for the fields

Since these fields represent physical measurements and identifiers:

  • Length, width, and height should be positive numbers
  • Name should not be null or empty
  • ClassId might need range validation based on PhotonVision's specifications
 private String name;
 private double length;
 private double width;
 private double height;
 private int classId;
+
+private void validateInputs(String name, double length, double width, double height, int classId) {
+    if (name == null || name.trim().isEmpty()) {
+        throw new IllegalArgumentException("Name cannot be null or empty");
+    }
+    if (length <= 0 || width <= 0 || height <= 0) {
+        throw new IllegalArgumentException("Dimensions must be positive");
+    }
+    // Add classId validation if there are known constraints from PhotonVision
+}

11-19: Enhance constructor documentation

The documentation should:

  • Include @throws tags if input validation is added
  • Consider making the units more prominent in parameter documentation
 /**
  * Represents a game element (measurements are in meters)
  *
- * @param name The name of the object
- * @param length The length of the object
- * @param width The width of the object
- * @param height The height of the object (floor to top)
+ * @param name The name of the object
+ * @param length The length of the object in meters
+ * @param width The width of the object in meters
+ * @param height The height of the object in meters (floor to top)
  * @param classId The class ID reported by PhotonVision
+ * @throws IllegalArgumentException if any dimension is not positive or name is empty
  */

20-26: Add input validation to constructor

The constructor should validate inputs before assignment.

 public GameElement(String name, double length, double width, double height, int classId) {
+    validateInputs(name, length, width, height, classId);
     this.name = name;
     this.length = length;
     this.width = width;
     this.height = height;
     this.classId = classId;
 }

28-46: LGTM! Consider making the class immutable

The getter implementations are clean and follow best practices. Since this class represents physical game elements with fixed properties, consider making it immutable by:

  1. Making all fields final
  2. Ensuring deep immutability if you add any object fields in the future
-  private String name;
-  private double length;
-  private double width;
-  private double height;
-  private int classId;
+  private final String name;
+  private final double length;
+  private final double width;
+  private final double height;
+  private final int classId;
src/main/java/frc/alotobots/library/vision/photonvision/apriltag/PhotonvisionAprilTagSubsystemConstants.java (3)

Line range hint 45-46: Document vision pose estimation control flags

The boolean flags control critical vision functionality but lack documentation explaining:

  • Impact of enabling/disabling vision pose estimation
  • Reasons for potentially limiting pose estimation to teleop

Add documentation explaining the purpose and implications of these flags:

+  /** Controls whether vision-based pose estimation is used at all */
   public static final boolean USE_VISION_POSE_ESTIMATION = true;
+  /** When true, vision pose estimation only runs during teleop, potentially saving processing power during auto */
   public static final boolean ONLY_USE_POSE_ESTIMATION_IN_TELEOP = false;

Line range hint 48-59: Review vision standard deviation values and update process

Several concerns with the current configuration:

  1. The comment "NEEDS TO BE COPIED FROM PHOTONVISION ON COMPETITION DAY" suggests a manual process that could be error-prone
  2. The heading standard deviation (1000) effectively disables vision-based heading correction

Consider:

  1. Automating the process of obtaining these values
  2. Documenting why the heading correction is disabled
  3. Adding validation to ensure values are updated before competition

Would you like help creating a utility to automatically fetch these values from PhotonVision?


Line range hint 61-71: Document constant tuning methodology

The pose estimation and smoothing constants lack documentation explaining:

  • How these values were determined
  • What effects adjusting these values has on performance
  • When these values should be adjusted

Consider adding detailed comments explaining:

  1. The tuning process for these constants
  2. The impact of different values
  3. Guidelines for when and how to adjust them
src/main/java/frc/alotobots/RobotContainer.java (1)

27-28: Consider adding Javadoc for new subsystem variables.

While the variable declarations are well-structured, adding Javadoc comments would improve code documentation and maintainability.

+  /** Subsystem handling AprilTag detection and processing */
   private final PhotonvisionAprilTagSubsystem photonvisionAprilTagSubsystem;
+  /** Subsystem managing object detection capabilities */
   private final PhotonVisionObjectDetectionSubsystem photonvisionObjectDetectionSubsystem;
src/main/java/frc/alotobots/library/vision/photonvision/objectdetection/DetectedObject.java (2)

102-121: Improve error handling consistency and documentation.

The getDistance and getAngle methods have inconsistent null checking and could benefit from better error handling:

  1. getDistance checks for null target and robotToCamera, but getAngle only checks drive
  2. Both methods silently return 0 on error, which could mask issues
  3. Javadoc doesn't document error cases

Consider these improvements:

  /**
   * Gets the distance from the center of the robot to the object.
   *
   * @return The distance in meters.
+  * @throws IllegalStateException if drive is not set or required fields are null
   */
  public double getDistance() {
-   if (target == null || robotToCamera == null) {
-     return 0;
+   if (drive == null || target == null || robotToCamera == null) {
+     throw new IllegalStateException("Required fields not initialized");
    }
    return PhotonUtils.getDistanceToPose(drive.getPose(), pose.toPose2d());
  }

  /**
   * Gets the field-relative angle from the robot to the object. (Rotational)
   *
   * @return The angle in radians.
+  * @throws IllegalStateException if drive is not set
   */
  public double getAngle() {
-   if (drive != null) {
-     return Math.atan2(
-         pose.getY() - drive.getState().Pose.getY(),
-         pose.getX() - drive.getState().Pose.getX());
+   if (drive == null) {
+     throw new IllegalStateException("Drive not initialized");
    }
-   return 0;
+   return Math.atan2(
+       pose.getY() - drive.getState().Pose.getY(),
+       pose.getX() - drive.getState().Pose.getX());
  }

123-126: Enhance toString output with more useful information.

The current implementation could be more helpful for debugging by including additional information about the target and transformations.

Consider enhancing the output:

  @Override
  public String toString() {
-   return String.format("Target at (%.2f, %.2f, %.2f)", pose.getX(), pose.getY(), pose.getZ());
+   return String.format("Target[id=%d] at (%.2f, %.2f, %.2f), distance=%.2f, angle=%.2f°",
+       target != null ? target.getFiducialId() : -1,
+       pose.getX(), pose.getY(), pose.getZ(),
+       getDistance(),
+       Units.radiansToDegrees(getAngle()));
  }
src/main/java/frc/alotobots/library/drivetrains/swerve/ctre/SwerveDriveSubsystem.java (2)

38-38: Consider a more specific variable name

The variable name subSysPhotonvision is now less accurate since it specifically handles AprilTag functionality. Consider renaming it to subSysAprilTag or aprilTagSubsystem to better reflect its specific purpose.

-  private PhotonvisionAprilTagSubsystem subSysPhotonvision;
+  private PhotonvisionAprilTagSubsystem aprilTagSubsystem;

146-148: Update method name and documentation

The method name and documentation should be updated to reflect that it specifically sets an AprilTag subsystem:

  1. The method name could be more specific
  2. The Javadoc comment refers to "PhotonVision subsystem" which is outdated
-  /**
-   * Sets the SubSys_PhotonVision object to use for vision-based pose estimation.
-   *
-   * @param subSysPhotonvision The PhotonVision subsystem to use.
-   */
-  public void setPhotonVisionSubSys(PhotonvisionAprilTagSubsystem subSysPhotonvision) {
-    this.subSysPhotonvision = subSysPhotonvision;
+  /**
+   * Sets the AprilTag subsystem to use for vision-based pose estimation.
+   *
+   * @param aprilTagSubsystem The AprilTag subsystem to use.
+   */
+  public void setAprilTagSubsystem(PhotonvisionAprilTagSubsystem aprilTagSubsystem) {
+    this.aprilTagSubsystem = aprilTagSubsystem;
src/main/java/frc/alotobots/game/HMIStation.java (3)

Line range hint 41-47: Consider implementing the suggested button naming improvements.

The TODO comment suggests renaming buttons based on function rather than number. This would improve code readability and maintainability. For example:

- public final JoystickButton driverButton1 = new JoystickButton(driverController, 1);
- public final JoystickButton driverButton2 = new JoystickButton(driverController, 2);
- public final JoystickButton driverButton3 = new JoystickButton(driverController, 3);
+ public final JoystickButton primaryActionButton = new JoystickButton(driverController, 1);
+ public final JoystickButton secondaryActionButton = new JoystickButton(driverController, 2);
+ public final JoystickButton tertiaryActionButton = new JoystickButton(driverController, 3);

Line range hint 173-179: Clean up commented-out auxiliary button declarations.

These commented-out button declarations should either be implemented or removed to maintain clean code.

- // public final JoystickButton auxButton3 = new JoystickButton(auxdriverController, 3);
- // public final JoystickButton auxButton4 = new JoystickButton(auxdriverController, 4);
- // public final JoystickButton auxButton5 = new JoystickButton(auxdriverController, 5);
- // public final JoystickButton auxButton6 = new JoystickButton(auxdriverController, 6);
- // Button Box

Line range hint 227-229: Consider enhancing alliance position handling.

The alliancePosition() method retrieves but doesn't use the alliance color. Consider enhancing this to support the new vision system's potential alliance-specific behaviors.

This could be particularly relevant for object detection where alliance color might influence target identification or tracking behavior.

src/main/java/frc/alotobots/library/vision/photonvision/apriltag/PhotonvisionAprilTagSubsystem.java (3)

Line range hint 52-74: Enhance initialization logging and validation

While the initialization logic is solid, it would benefit from more detailed logging and validation.

Consider adding more detailed logging and validation:

 private void initializePoseEstimators() {
     poseEstimators = new ArrayList<>();
 
     if (CAMERAS.length != CAMERA_OFFSETS.length) {
-        throw new RuntimeException(
-            "PhotonCamera object is missing offset! Did you add an offset in Photonvision_Constants?");
+        throw new IllegalStateException(
+            String.format("Camera count (%d) does not match offset count (%d). Check PhotonVision_Constants.",
+                CAMERAS.length, CAMERA_OFFSETS.length));
     }
 
     for (int i = 0; i < CAMERAS.length; i++) {
         if (CAMERAS[i] != null) {
+            System.out.printf("Initializing camera %d (%s)...%n", i, CAMERAS[i].getName());
             PhotonPoseEstimator estimator =
                 new PhotonPoseEstimator(
                     fieldLayout,
                     PhotonPoseEstimator.PoseStrategy.MULTI_TAG_PNP_ON_COPROCESSOR,
                     CAMERAS[i],
                     CAMERA_OFFSETS[i]);
             estimator.setMultiTagFallbackStrategy(PhotonPoseEstimator.PoseStrategy.LOWEST_AMBIGUITY);
             poseEstimators.add(estimator);
 
             camerasEnabled[i] = CAMERAS[i].isConnected();
+            System.out.printf("Camera %d initialized. Connected: %b%n", i, camerasEnabled[i]);
         } else {
+            System.out.printf("Warning: Camera %d is null, skipping initialization%n", i);
             poseEstimators.add(null);
             camerasEnabled[i] = false;
         }
     }
 }

Line range hint 77-119: Add error handling and timestamp validation for tag detection

The tag detection logic should handle potential camera failures and validate result timestamps.

Consider adding error handling and timestamp validation:

 private List<PhotonTrackedTarget> getDetectedTags() {
     List<PhotonTrackedTarget> allDetectedTags = new ArrayList<>();
-    for (PhotonCamera camera : CAMERAS) {
-        var result = camera.getLatestResult();
-        if (result.hasTargets()) {
-            allDetectedTags.addAll(result.getTargets());
+    for (int i = 0; i < CAMERAS.length; i++) {
+        PhotonCamera camera = CAMERAS[i];
+        if (camera == null || !camerasEnabled[i]) {
+            continue;
+        }
+        try {
+            var result = camera.getLatestResult();
+            // Validate result timestamp (e.g., not too old)
+            double latency = result.getLatencyMillis() / 1000.0;
+            if (latency > MAX_ACCEPTABLE_LATENCY) {
+                System.out.printf("Warning: High latency (%.2fs) from camera %d%n", latency, i);
+                continue;
+            }
+            if (result.hasTargets()) {
+                allDetectedTags.addAll(result.getTargets());
+            }
+        } catch (Exception e) {
+            System.err.printf("Error getting results from camera %d: %s%n", i, e.getMessage());
         }
     }
     return allDetectedTags;
 }

Line range hint 380-399: Optimize camera pose estimation and add null checks

The per-camera pose estimation could be optimized by checking camera connection status first and adding proper null checks.

Consider this optimization:

 public List<Pair<Integer, Pair<Pose3d, Double>>> getPerCameraEstimatedPoses() {
     List<Pair<Integer, Pair<Pose3d, Double>>> perCameraPoses = new ArrayList<>();
     for (int i = 0; i < poseEstimators.size(); i++) {
+        // Check camera validity first to avoid unnecessary operations
+        PhotonCamera camera = CAMERAS[i];
+        if (camera == null || !camerasEnabled[i] || !camera.isConnected()) {
+            continue;
+        }
+
         PhotonPoseEstimator estimator = poseEstimators.get(i);
-        PhotonCamera camera = CAMERAS[i];
+        if (estimator == null) {
+            continue;
+        }
 
-        if (estimator != null && camerasEnabled[i] && camera != null && camera.isConnected()) {
-            // Get the latest result directly from the camera first
+        try {
             var result = camera.getLatestResult();
             if (result.hasTargets()) {
-                // Only update the estimator if we actually have targets
                 var estimate = estimator.update();
                 if (estimate.isPresent()) {
                     EstimatedRobotPose pose = estimate.get();
                     perCameraPoses.add(
                         new Pair<>(i, new Pair<>(pose.estimatedPose, pose.timestampSeconds)));
                 }
             }
+        } catch (Exception e) {
+            System.err.printf("Error estimating pose for camera %d: %s%n", i, e.getMessage());
         }
     }
     return perCameraPoses;
 }
src/main/java/frc/alotobots/library/vision/photonvision/objectdetection/PhotonVisionObjectDetectionSubsystem.java (3)

33-35: Return an unmodifiable list to prevent external modification

Currently, getDetectedObjects() returns a new ArrayList, which creates a copy but doesn't prevent external code from modifying the DetectedObject instances within. To ensure encapsulation and prevent unintended modifications, consider returning an unmodifiable view.

You can modify the method as follows:

-public List<DetectedObject> getDetectedObjects() {
-  return new ArrayList<>(detectedObjects);
+public List<DetectedObject> getDetectedObjects() {
+  return Collections.unmodifiableList(detectedObjects);
 }

Don't forget to import java.util.Collections.


77-77: Consider logging when no targets are found

Currently, if a camera doesn't have targets, there's no feedback. For debugging and monitoring purposes, consider logging when no targets are detected by an enabled camera.

Example:

} else {
  // Optionally log that no targets were found for this camera
  logger.fine("No targets found for camera: " + camera.getName());
}

Ensure the appropriate logging level is used to avoid cluttering logs.


68-75: Extract target processing into a separate method for clarity

To improve readability and maintainability, consider extracting the target processing logic inside the loop into a separate method.

Example:

private void processTargets(PhotonTrackedTarget target, int cameraIndex) {
  DetectedObject object = DetectedObject.fromPhotonTarget(
      target, PhotonVisionObjectDetectionSubsystemConstants.CAMERA_OFFSETS[cameraIndex]);
  detectedObjects.add(object);
}

Update the loop:

 for (PhotonTrackedTarget target : result.getTargets()) {
-  // Create DetectedObject using camera transform for each target
-  DetectedObject object =
-      DetectedObject.fromPhotonTarget(
-          target, PhotonVisionObjectDetectionSubsystemConstants.CAMERA_OFFSETS[i]);

-  detectedObjects.add(object);
+  processTargets(target, i);
 }
src/main/java/frc/alotobots/library/vision/photonvision/apriltag/PhotonvisionAprilTagTelemetry.java (5)

90-94: Consolidate duplicate Javadoc comments in initializeField method

The initializeField method contains duplicate Javadoc comments. Merging them will improve readability and avoid redundancy.

Apply this diff to combine the comments:

 /**
- * Initializes the field widget in Shuffleboard.
- */
-/**
  * Initializes the field widget in Shuffleboard. Creates and configures a Field2d widget to
  * display robot position and AprilTag locations.
  */

99-104: Merge duplicate Javadoc comments in initializeCameraWidgets method

There are duplicate Javadoc comments in the initializeCameraWidgets method. Consolidating them will enhance clarity.

Apply this diff to merge the comments:

 /**
  * Initializes camera-specific widgets in Shuffleboard.
- */
-/**
  * Initializes camera-specific widgets in Shuffleboard. Creates a widget for each camera in the
  * CAMERAS array, displaying its pose and status information.
  */
+ * Creates a widget for each camera in the
+ * CAMERAS array, displaying its pose and status information.
  */

Line range hint 125-132: Eliminate duplicate Javadoc comments in updateCameraWidgets method

The updateCameraWidgets method has two Javadoc comments that can be combined for better readability.

Apply this diff to consolidate the comments:

 /**
  * Updates the camera-specific widgets with the latest data.
  *
  * @param cameras The array of PhotonCameras to get data from
- */
-/**
  * Updates the camera-specific widgets with the latest data from each camera. Displays connection
  * status, target detection results, and pose information.
  *
  * @param cameras Array of PhotonCameras to get data from
  */
+ * Displays connection status, target detection results, and pose information.
  */

241-243: Correct reference to 'photonvisionTab' in the Javadoc comment

The comment incorrectly refers to photonvisionTab. It should be updated to aprilTagTab to reflect the refactoring.

Apply this diff to correct the comment:

 /**
- * photonvisionTab Draws tracer lines from each camera's detected pose to its detected AprilTags.
+ * Draws tracer lines from each camera's detected pose to its detected AprilTags.
  *
  * @param cameraPoses List of camera poses and their indices
  */

Line range hint 244-273: Consider refactoring drawTracerLines method for improved readability

The drawTracerLines method contains nested loops and complex logic. Refactoring it into smaller helper methods could enhance readability and maintainability.

For example, you could extract the logic for creating trajectories and drawing tag boxes into separate methods.

🛑 Comments failed to post (8)
src/main/java/frc/alotobots/library/vision/photonvision/objectdetection/DetectedObject.java (2)

52-95: ⚠️ Potential issue

Add input validation and improve error handling in factory method.

The fromPhotonTarget method has several areas that could be improved:

  1. No validation of input parameters
  2. Hardcoded array index GAME_ELEMENTS[0] is fragile
  3. Complex transformation logic could use more detailed comments

Consider these improvements:

  public static DetectedObject fromPhotonTarget(
      PhotonTrackedTarget target, Transform3d robotToCamera) {
+   if (target == null || robotToCamera == null) {
+     throw new IllegalArgumentException("Target and robotToCamera must not be null");
+   }
+   
+   // Validate game element exists
+   if (GAME_ELEMENTS.length == 0) {
+     throw new IllegalStateException("No game elements configured");
+   }

    // Calculate distance using the first game element's height
    double targetToCameraDistance =
        PhotonUtils.calculateDistanceToTargetMeters(
            robotToCamera.getZ(),
            GAME_ELEMENTS[0].getHeight(),
            robotToCamera.getRotation().getY(),
            Units.degreesToRadians(target.getPitch()));

    // Rest of the method...

Committable suggestion skipped: line range outside the PR's diff.


14-14: 🛠️ Refactor suggestion

Consider removing static state for better testability and maintainability.

The static drive field creates a global state that can make the code harder to test and maintain. Consider injecting the drive subsystem through the constructor instead.

Here's a suggested refactoring approach:

- @Getter private static SwerveDriveSubsystem drive;
+ @Getter private final SwerveDriveSubsystem drive;

- public DetectedObject(Pose3d pose, PhotonTrackedTarget target, Transform3d robotToCamera) {
+ public DetectedObject(Pose3d pose, PhotonTrackedTarget target, Transform3d robotToCamera, SwerveDriveSubsystem drive) {
    this.pose = pose;
    this.target = target;
    this.robotToCamera = robotToCamera;
+   this.drive = drive;
  }

Committable suggestion skipped: line range outside the PR's diff.

src/main/java/frc/alotobots/library/vision/photonvision/apriltag/PhotonvisionAprilTagSubsystem.java (2)

247-274: 🛠️ Refactor suggestion

Validate smoothing parameters and add bounds checking

The smoothing logic should validate alpha parameters and ensure they're within valid bounds (0-1).

Add parameter validation:

 private double exponentialSmooth(double oldValue, double newValue, double alpha) {
+    if (alpha < 0.0 || alpha > 1.0) {
+        System.err.printf("Warning: Invalid smoothing alpha (%.2f), clamping to [0,1]%n", alpha);
+        alpha = Math.max(0.0, Math.min(1.0, alpha));
+    }
     return alpha * newValue + (1.0 - alpha) * oldValue;
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

private double exponentialSmooth(double oldValue, double newValue, double alpha) {
    if (alpha < 0.0 || alpha > 1.0) {
        System.err.printf("Warning: Invalid smoothing alpha (%.2f), clamping to [0,1]%n", alpha);
        alpha = Math.max(0.0, Math.min(1.0, alpha));
    }
    return alpha * newValue + (1.0 - alpha) * oldValue;
}

36-43: 🛠️ Refactor suggestion

Add error handling for field layout initialization

The constructor should handle potential failures when loading the AprilTag field layout, as this is a critical component for pose estimation.

Consider wrapping the field layout initialization with try-catch:

 public PhotonvisionAprilTagSubsystem() {
-    this.fieldLayout = AprilTagFields.k2024Crescendo.loadAprilTagLayoutField();
+    try {
+        this.fieldLayout = AprilTagFields.k2024Crescendo.loadAprilTagLayoutField();
+    } catch (Exception e) {
+        throw new RuntimeException("Failed to load AprilTag field layout", e);
+    }
     this.poseEstimators = new ArrayList<>();
     this.camerasEnabled = new boolean[CAMERAS.length];
     Arrays.fill(camerasEnabled, true);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

  public PhotonvisionAprilTagSubsystem() {
    try {
        this.fieldLayout = AprilTagFields.k2024Crescendo.loadAprilTagLayoutField();
    } catch (Exception e) {
        throw new RuntimeException("Failed to load AprilTag field layout", e);
    }
    this.poseEstimators = new ArrayList<>();
    this.camerasEnabled = new boolean[CAMERAS.length];
    Arrays.fill(camerasEnabled, true);
    initializePoseEstimators();
    telemetry = new PhotonvisionAprilTagTelemetry();
    System.out.println("PhotonVision AprilTag subsystem initialized");
src/main/java/frc/alotobots/library/vision/photonvision/objectdetection/PhotonVisionObjectDetectionSubsystem.java (2)

64-66: ⚠️ Potential issue

Handle potential null results from camera.getLatestResult()

camera.getLatestResult() might return null if no result is available. Accessing methods on a null result will cause a NullPointerException. Add a null check before using the result.

Apply this change to handle null results:

 var result = camera.getLatestResult();
+if (result != null && result.hasTargets()) {
-  if (result.hasTargets()) {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

        var result = camera.getLatestResult();

        if (result != null && result.hasTargets()) {

23-23: 🛠️ Refactor suggestion

Consider using a logging framework instead of System.out.println

Using a logging framework (e.g., java.util.logging, Log4j, or SLF4J) provides better control over log levels and output destinations, which is more suitable for production code.

Apply this change to use a logger:

- System.out.println("PhotonVisionObjectDetection Subsystem Initialized");
+ private static final Logger logger = Logger.getLogger(PhotonVisionObjectDetectionSubsystem.class.getName());
+ logger.info("PhotonVisionObjectDetection Subsystem Initialized");

Don't forget to import the appropriate logging classes.

Committable suggestion skipped: line range outside the PR's diff.

src/main/java/frc/alotobots/library/vision/photonvision/objectdetection/PhotonVisionObjectDetectionTelemetry.java (2)

140-145: ⚠️ Potential issue

Fix potential index misalignment between cameraWidgets and CAMERAS

In the constructor, cameraWidgets is populated only when a camera is not null. This can cause misalignment between the indices of CAMERAS and cameraWidgets, leading to potential IndexOutOfBoundsException or incorrect widget updates in the updateObjects method.

Apply this diff to ensure that cameraWidgets aligns with the CAMERAS array by adding a placeholder when a camera is null:

// Initialize camera widgets - position them below the field
for (int i = 0; i < PhotonVisionObjectDetectionSubsystemConstants.CAMERAS.length; i++) {
  PhotonCamera camera = PhotonVisionObjectDetectionSubsystemConstants.CAMERAS[i];
- if (camera != null) {
-   cameraWidgets.add(new CameraWidget(tab, camera.getName(), i * 2));
- }
+ CameraWidget widget = (camera != null)
+     ? new CameraWidget(tab, camera.getName(), i * 2)
+     : null;
+ cameraWidgets.add(widget);
}

This ensures that cameraWidgets has the same size as CAMERAS, maintaining index alignment.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

    for (int i = 0; i < PhotonVisionObjectDetectionSubsystemConstants.CAMERAS.length; i++) {
      PhotonCamera camera = PhotonVisionObjectDetectionSubsystemConstants.CAMERAS[i];
      CameraWidget widget = (camera != null)
          ? new CameraWidget(tab, camera.getName(), i * 2)
          : null;
      cameraWidgets.add(widget);
    }

185-212: ⚠️ Potential issue

Add null checks for CameraWidget instances in updateObjects

After ensuring index alignment, you need to handle potential null entries in cameraWidgets when a camera is null. Without this check, attempting to access a null widget will result in a NullPointerException.

Apply this diff to add a null check before using the CameraWidget:

for (int i = 0; i < PhotonVisionObjectDetectionSubsystemConstants.CAMERAS.length; i++) {
  PhotonCamera camera = PhotonVisionObjectDetectionSubsystemConstants.CAMERAS[i];
- if (camera != null && i < cameraWidgets.size()) {
+ if (camera != null && i < cameraWidgets.size() && cameraWidgets.get(i) != null) {
    CameraWidget widget = cameraWidgets.get(i);
+   if (widget != null) {
      // Update connection status
      widget.connectionStatus.setBoolean(camera.isConnected());

      // Existing code...
+   }
  }
}

This ensures that you only interact with non-null CameraWidget instances.

Committable suggestion skipped: line range outside the PR's diff.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant