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
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
a269e59
feat: Add PhotonVision AprilTag subsystem and telemetry classes
SeanErn Nov 13, 2024
76beaa0
refactor: Update PhotonVision AprilTag documentation and references
SeanErn Nov 13, 2024
3c8540e
refactor: Rename variables for consistency in PhotonvisionAprilTagSub…
SeanErn Nov 13, 2024
42888d9
refactor: Rename photonvisionTab to aprilTagTab for clarity
SeanErn Nov 13, 2024
62be281
refactor: Update AprilTag variable names for consistency across project
SeanErn Nov 13, 2024
a8ebca4
feat: Add PhotonvisionAprilTagSubsystemConstants for AprilTag vision …
SeanErn Nov 13, 2024
9391bfe
refactor: Standardize AprilTag variable naming across project files
SeanErn Nov 13, 2024
253327d
AprilTag refactor
SeanErn Nov 13, 2024
c3ad55f
feat: Add PhotonVision object detection implementation with constants…
SeanErn Nov 13, 2024
ae8db7a
refactor: Rename constants class to match subsystem naming convention
SeanErn Nov 13, 2024
058cb9b
Actually make it work?
SeanErn Nov 14, 2024
ec29947
refactor: Implement camera-specific widget telemetry for object detec…
SeanErn Nov 14, 2024
6a3b5c8
refactor: Improve code formatting and readability in PhotonVisionObje…
SeanErn Nov 14, 2024
b4c1720
feat: Add rate-limited telemetry updates and round object detection d…
SeanErn Nov 14, 2024
6982cff
style: Reformat code for improved readability
SeanErn Nov 14, 2024
a4d628e
refactor: Remove rate limiting from object detection telemetry
SeanErn Nov 14, 2024
5ffef84
refactor: Split object detection telemetry pose into X, Y, Z entries
SeanErn Nov 14, 2024
566829e
refactor: Add truncate method and remove Z pose display for object de…
SeanErn Nov 14, 2024
b497099
refactor: Reorganize truncate method and adjust camera widget layout …
SeanErn Nov 14, 2024
6c6ea2b
feat: Add tracer lines from robot to detected objects on field telemetry
SeanErn Nov 14, 2024
f0e6951
refactor: Extract tracer line drawing into dedicated method for impro…
SeanErn Nov 14, 2024
8659c59
feat: Add per-camera enable toggle for object detection
SeanErn Nov 14, 2024
f11ce94
fix: Update telemetry entry to use add() instead of addBoolean()
SeanErn Nov 14, 2024
a9fd2f4
refactor: Simplify code formatting in PhotonVisionObjectDetectionTele…
SeanErn Nov 14, 2024
68efbee
fix: Clear objects from field when camera is disabled or object not d…
SeanErn Nov 14, 2024
0691805
refactor: Simplify object detection camera filtering logic
SeanErn Nov 14, 2024
97289e5
refactor: Remove objects from field when camera is disabled
SeanErn Nov 14, 2024
5c51cd2
refactor: Improve camera disabling logic in object detection subsystem
SeanErn Nov 14, 2024
adce577
refactor: Optimize PhotonVision object detection subsystem imports an…
SeanErn Nov 14, 2024
1ce5bad
feat: Add global stats, object detection settings, and teleop mode to…
SeanErn Nov 14, 2024
7b5415b
refactor: Improve code formatting and readability in PhotonVisionObje…
SeanErn Nov 14, 2024
a24c6ab
refactor: Update PhotonVision telemetry layout to match AprilTag style
SeanErn Nov 14, 2024
a99c5e6
refactor: Simplify object detection teleop condition check
SeanErn Nov 14, 2024
ac63b49
refactor: Convert object detection toggles to persistent dashboard sw…
SeanErn Nov 14, 2024
ff82780
style: Format code with consistent indentation and line breaks
SeanErn Nov 14, 2024
898f379
fix: Assign toggle entries to class fields to prevent NullPointerExce…
SeanErn Nov 14, 2024
77571cf
feat: Plot all detected objects on field map with individual tracer l…
SeanErn Nov 14, 2024
b3ac991
chore: Remove debug print statements from PhotonVision object detection
SeanErn Nov 14, 2024
955f569
feat: Add back object detection subsystem initialization message
SeanErn Nov 14, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions src/main/java/frc/alotobots/RobotContainer.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
import frc.alotobots.library.drivetrains.swerve.ctre.mk4il22023.TunerConstants;
import frc.alotobots.library.pneumatics.PneumaticsSubsystem;
import frc.alotobots.library.vision.limelight.LimelightSubsystem;
import frc.alotobots.library.vision.photonvision.PhotonvisionSubsystem;
import frc.alotobots.library.vision.photonvision.apriltag.PhotonvisionAprilTagSubsystem;
import frc.alotobots.library.vision.photonvision.objectdetection.PhotonVisionObjectDetectionSubsystem;

/**
* This class is where the bulk of the robot should be declared. Since Command-based is a
Expand All @@ -23,7 +24,8 @@ public class RobotContainer {
private final SwerveDriveSubsystem drivetrainSubsystem;
private final LimelightSubsystem limelightSubsystem;
private final BlingSubsystem blingSubsystem;
private final PhotonvisionSubsystem photonvisionSubsystem;
private final PhotonvisionAprilTagSubsystem photonvisionAprilTagSubsystem;
private final PhotonVisionObjectDetectionSubsystem photonvisionObjectDetectionSubsystem;
private final PneumaticsSubsystem pneumaticsSubsystem;

// Human-Machine Interface
Expand All @@ -42,7 +44,9 @@ public RobotContainer() {
drivetrainSubsystem = TunerConstants.DRIVE_TRAIN;
blingSubsystem = new BlingSubsystem();
limelightSubsystem = new LimelightSubsystem(blingSubsystem, drivetrainSubsystem);
photonvisionSubsystem = new PhotonvisionSubsystem();
photonvisionAprilTagSubsystem = new PhotonvisionAprilTagSubsystem();
photonvisionObjectDetectionSubsystem =
new PhotonVisionObjectDetectionSubsystem(drivetrainSubsystem);
pneumaticsSubsystem = new PneumaticsSubsystem();

// Initialize HMI
Expand Down Expand Up @@ -100,6 +104,6 @@ public Command getAutonomousCommand() {

/** Sets up the PhotonVision subsystem for the drivetrain. */
public void setupVision() {
drivetrainSubsystem.setPhotonVisionSubSys(photonvisionSubsystem);
drivetrainSubsystem.setPhotonVisionSubSys(photonvisionAprilTagSubsystem);
}
}
2 changes: 1 addition & 1 deletion src/main/java/frc/alotobots/game/HMIStation.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@
import edu.wpi.first.wpilibj2.command.button.POVButton;
import edu.wpi.first.wpilibj2.command.button.Trigger;
import frc.alotobots.Constants.Robot.Calibrations.DriveTrain;
import frc.alotobots.library.driverstation.JoystickUtilities;
import frc.alotobots.game.constants.HMIDeadbands;
import frc.alotobots.library.driverstation.JoystickUtilities;

/**
* The DriverStation class represents the available inputs to the robot, providing access to
Expand Down
22 changes: 11 additions & 11 deletions src/main/java/frc/alotobots/game/constants/HMIDeadbands.java
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
package frc.alotobots.game.constants;

public final class HMIDeadbands {
private HMIDeadbands() {} // Prevent instantiation
private HMIDeadbands() {} // Prevent instantiation

// Basic drive control deadbands
public static final double DRIVER_FWD_AXIS_DEADBAND = 0.1;
public static final double DRIVER_STR_AXIS_DEADBAND = 0.1;
public static final double DRIVER_ROT_AXIS_DEADBAND = 0.1;
public static final double TRIGGER_DEADBAND = 0.3;
// Basic drive control deadbands
public static final double DRIVER_FWD_AXIS_DEADBAND = 0.1;
public static final double DRIVER_STR_AXIS_DEADBAND = 0.1;
public static final double DRIVER_ROT_AXIS_DEADBAND = 0.1;
public static final double TRIGGER_DEADBAND = 0.3;

/* Example game-specific deadbands:
* public static final double PRIMARY_MECHANISM_AXIS_DEADBAND = 0.1;
* public static final double SECONDARY_MECHANISM_AXIS_DEADBAND = 0.15;
* public static final double TERTIARY_MECHANISM_AXIS_DEADBAND = 0.2;
*/
/* Example game-specific deadbands:
* public static final double PRIMARY_MECHANISM_AXIS_DEADBAND = 0.1;
* public static final double SECONDARY_MECHANISM_AXIS_DEADBAND = 0.15;
* public static final double TERTIARY_MECHANISM_AXIS_DEADBAND = 0.2;
*/
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package frc.alotobots.library.drivetrains.swerve.ctre;

import static frc.alotobots.library.vision.photonvision.PhotonvisionSubsystemConstants.ONLY_USE_POSE_ESTIMATION_IN_TELEOP;
import static frc.alotobots.library.vision.photonvision.PhotonvisionSubsystemConstants.USE_VISION_POSE_ESTIMATION;
import static frc.alotobots.library.vision.photonvision.apriltag.PhotonvisionAprilTagSubsystemConstants.ONLY_USE_POSE_ESTIMATION_IN_TELEOP;
import static frc.alotobots.library.vision.photonvision.apriltag.PhotonvisionAprilTagSubsystemConstants.USE_VISION_POSE_ESTIMATION;

import com.ctre.phoenix6.Utils;
import com.ctre.phoenix6.configs.Slot0Configs;
Expand All @@ -19,7 +19,7 @@
import edu.wpi.first.wpilibj2.command.Command;
import edu.wpi.first.wpilibj2.command.Subsystem;
import frc.alotobots.library.drivetrains.swerve.ctre.mk4il22023.TunerConstants;
import frc.alotobots.library.vision.photonvision.PhotonvisionSubsystem;
import frc.alotobots.library.vision.photonvision.apriltag.PhotonvisionAprilTagSubsystem;
import java.util.Optional;
import java.util.function.Supplier;
import lombok.Getter;
Expand All @@ -35,7 +35,7 @@ public class SwerveDriveSubsystem extends SwerveDrivetrain implements Subsystem
private final SwerveRequest.ApplyChassisSpeeds autoRequest =
new SwerveRequest.ApplyChassisSpeeds();

private PhotonvisionSubsystem subSysPhotonvision;
private PhotonvisionAprilTagSubsystem subSysPhotonvision;
private SwerveDriveTelemetry telemetry;
private SwerveDrivePathPlanner pathPlanner;

Expand Down Expand Up @@ -143,7 +143,7 @@ private void updateVisionPoseEstimate() {
*
* @param subSysPhotonvision The PhotonVision subsystem to use.
*/
public void setPhotonVisionSubSys(PhotonvisionSubsystem subSysPhotonvision) {
public void setPhotonVisionSubSys(PhotonvisionAprilTagSubsystem subSysPhotonvision) {
this.subSysPhotonvision = subSysPhotonvision;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package frc.alotobots.library.vision.photonvision;
package frc.alotobots.library.vision.photonvision.apriltag;

import static frc.alotobots.library.vision.photonvision.PhotonvisionSubsystemConstants.*;
import static frc.alotobots.library.vision.photonvision.apriltag.PhotonvisionAprilTagSubsystemConstants.*;

import edu.wpi.first.apriltag.AprilTagFieldLayout;
import edu.wpi.first.apriltag.AprilTagFields;
Expand All @@ -20,26 +20,27 @@
import org.photonvision.targeting.PhotonTrackedTarget;

/**
* A subsystem that manages multiple PhotonVision cameras and provides pose estimation
* functionality.
* A subsystem that manages multiple PhotonVision cameras specifically for AprilTag detection and
* provides pose estimation functionality using AprilTag fiducial markers.
*/
public class PhotonvisionSubsystem extends SubsystemBase {
private final AprilTagFieldLayout aprilTagFieldLayout;
private ArrayList<PhotonPoseEstimator> photonPoseEstimators;
private final PhotonvisionTelemetry telemetry;
private final boolean[] cameraEnabled;
public class PhotonvisionAprilTagSubsystem extends SubsystemBase {
private final AprilTagFieldLayout fieldLayout;
private ArrayList<PhotonPoseEstimator> poseEstimators;
private final PhotonvisionAprilTagTelemetry telemetry;
private final boolean[] camerasEnabled;

// Smoothing filter state
private Pose3d lastSmoothedPose;

/** Constructs a new PhotonvisionSubsystem. */
public PhotonvisionSubsystem() {
aprilTagFieldLayout = AprilTagFields.k2024Crescendo.loadAprilTagLayoutField();
photonPoseEstimators = new ArrayList<>();
cameraEnabled = new boolean[CAMERAS.length];
Arrays.fill(cameraEnabled, true);
/** Constructs a new PhotonvisionAprilTagSubsystem for AprilTag detection and pose estimation. */
public PhotonvisionAprilTagSubsystem() {
this.fieldLayout = AprilTagFields.k2024Crescendo.loadAprilTagLayoutField();
this.poseEstimators = new ArrayList<>();
this.camerasEnabled = new boolean[CAMERAS.length];
Arrays.fill(camerasEnabled, true);
initializePoseEstimators();
telemetry = new PhotonvisionTelemetry();
telemetry = new PhotonvisionAprilTagTelemetry();
System.out.println("PhotonVision AprilTag subsystem initialized");
}

/**
Expand All @@ -48,7 +49,7 @@ public PhotonvisionSubsystem() {
* camera offsets are not properly configured.
*/
private void initializePoseEstimators() {
photonPoseEstimators = new ArrayList<>();
poseEstimators = new ArrayList<>();

if (CAMERAS.length != CAMERA_OFFSETS.length) {
throw new RuntimeException(
Expand All @@ -60,17 +61,17 @@ private void initializePoseEstimators() {
if (CAMERAS[i] != null) {
PhotonPoseEstimator estimator =
new PhotonPoseEstimator(
aprilTagFieldLayout,
fieldLayout,
PhotonPoseEstimator.PoseStrategy.MULTI_TAG_PNP_ON_COPROCESSOR,
CAMERAS[i],
CAMERA_OFFSETS[i]);
estimator.setMultiTagFallbackStrategy(PhotonPoseEstimator.PoseStrategy.LOWEST_AMBIGUITY);
photonPoseEstimators.add(estimator);
poseEstimators.add(estimator);

cameraEnabled[i] = CAMERAS[i].isConnected();
camerasEnabled[i] = CAMERAS[i].isConnected();
} else {
photonPoseEstimators.add(null);
cameraEnabled[i] = false;
poseEstimators.add(null);
camerasEnabled[i] = false;
}
}
}
Expand Down Expand Up @@ -116,9 +117,9 @@ private List<PhotonTrackedTarget> getDetectedTags() {
*/
public Optional<Pair<Pose3d, Double>> getEstimatedVisionPose3d(Pose2d previousPose) {
ArrayList<EstimatedRobotPose> estimates = new ArrayList<>();
for (int i = 0; i < photonPoseEstimators.size(); i++) {
PhotonPoseEstimator estimator = photonPoseEstimators.get(i);
if (estimator != null && cameraEnabled[i] && CAMERAS[i].isConnected()) {
for (int i = 0; i < poseEstimators.size(); i++) {
PhotonPoseEstimator estimator = poseEstimators.get(i);
if (estimator != null && camerasEnabled[i] && CAMERAS[i].isConnected()) {
estimator.setLastPose(previousPose);
var estimate = estimator.update();
if (estimate.isPresent()) {
Expand All @@ -137,9 +138,9 @@ public Optional<Pair<Pose3d, Double>> getEstimatedVisionPose3d(Pose2d previousPo
*/
public Optional<Pair<Pose3d, Double>> getEstimatedVisionPose3d() {
ArrayList<EstimatedRobotPose> estimates = new ArrayList<>();
for (int i = 0; i < photonPoseEstimators.size(); i++) {
PhotonPoseEstimator estimator = photonPoseEstimators.get(i);
if (estimator != null && cameraEnabled[i] && CAMERAS[i].isConnected()) {
for (int i = 0; i < poseEstimators.size(); i++) {
PhotonPoseEstimator estimator = poseEstimators.get(i);
if (estimator != null && camerasEnabled[i] && CAMERAS[i].isConnected()) {
var estimate = estimator.update();
if (estimate.isPresent()) {
estimates.add(estimate.get());
Expand Down Expand Up @@ -243,34 +244,34 @@ private Optional<Pair<Pose3d, Double>> averageEstimates(ArrayList<EstimatedRobot
exponentialSmooth(
lastSmoothedPose.getX(),
averagePose.getX(),
PhotonvisionSubsystemConstants.POSITION_ALPHA);
PhotonvisionAprilTagSubsystemConstants.POSITION_ALPHA);
double smoothedY =
exponentialSmooth(
lastSmoothedPose.getY(),
averagePose.getY(),
PhotonvisionSubsystemConstants.POSITION_ALPHA);
PhotonvisionAprilTagSubsystemConstants.POSITION_ALPHA);
double smoothedZ =
exponentialSmooth(
lastSmoothedPose.getZ(),
averagePose.getZ(),
PhotonvisionSubsystemConstants.POSITION_ALPHA);
PhotonvisionAprilTagSubsystemConstants.POSITION_ALPHA);

// Smooth rotation
double smoothedRotX =
exponentialSmooth(
lastSmoothedPose.getRotation().getX(),
averagePose.getRotation().getX(),
PhotonvisionSubsystemConstants.ROTATION_ALPHA);
PhotonvisionAprilTagSubsystemConstants.ROTATION_ALPHA);
double smoothedRotY =
exponentialSmooth(
lastSmoothedPose.getRotation().getY(),
averagePose.getRotation().getY(),
PhotonvisionSubsystemConstants.ROTATION_ALPHA);
PhotonvisionAprilTagSubsystemConstants.ROTATION_ALPHA);
double smoothedRotZ =
exponentialSmooth(
lastSmoothedPose.getRotation().getZ(),
averagePose.getRotation().getZ(),
PhotonvisionSubsystemConstants.ROTATION_ALPHA);
PhotonvisionAprilTagSubsystemConstants.ROTATION_ALPHA);

lastSmoothedPose =
new Pose3d(
Expand Down Expand Up @@ -376,11 +377,11 @@ private double exponentialSmooth(double oldValue, double newValue, double alpha)
*/
public List<Pair<Integer, Pair<Pose3d, Double>>> getPerCameraEstimatedPoses() {
List<Pair<Integer, Pair<Pose3d, Double>>> perCameraPoses = new ArrayList<>();
for (int i = 0; i < photonPoseEstimators.size(); i++) {
PhotonPoseEstimator estimator = photonPoseEstimators.get(i);
for (int i = 0; i < poseEstimators.size(); i++) {
PhotonPoseEstimator estimator = poseEstimators.get(i);
PhotonCamera camera = CAMERAS[i];

if (estimator != null && cameraEnabled[i] && camera != null && camera.isConnected()) {
if (estimator != null && camerasEnabled[i] && camera != null && camera.isConnected()) {
// Get the latest result directly from the camera first
var result = camera.getLatestResult();
if (result.hasTargets()) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package frc.alotobots.library.vision.photonvision;
package frc.alotobots.library.vision.photonvision.apriltag;

import edu.wpi.first.apriltag.AprilTagFieldLayout;
import edu.wpi.first.apriltag.AprilTagFields;
Expand All @@ -15,9 +15,9 @@

@SuppressWarnings("resource")
@UtilityClass
public class PhotonvisionSubsystemConstants {
public class PhotonvisionAprilTagSubsystemConstants {

public static final AprilTagFieldLayout aprilTagFieldLayout =
public static final AprilTagFieldLayout fieldLayout =
AprilTagFields.k2024Crescendo.loadAprilTagLayoutField();

public static final double FIELD_LENGTH = 16.54175; // in meters
Expand Down
Loading
Loading