Merge pull request #24 from Team4388/Debug-Autos

Debug autos
This commit is contained in:
McGrathMaggie
2025-02-06 17:26:07 -07:00
committed by GitHub
11 changed files with 377 additions and 108 deletions
@@ -8,8 +8,8 @@
}, },
"prevControl": null, "prevControl": null,
"nextControl": { "nextControl": {
"x": 6.5546611575005915, "x": 5.96969696969697,
"y": 2.13657272729177 "y": 1.128219696969696
}, },
"isLocked": false, "isLocked": false,
"linkedName": null "linkedName": null
@@ -20,8 +20,8 @@
"y": 2.6833333333333327 "y": 2.6833333333333327
}, },
"prevControl": { "prevControl": {
"x": 5.563570773660507, "x": 5.75625,
"y": 2.6306173444056773 "y": 2.256439393939394
}, },
"nextControl": null, "nextControl": null,
"isLocked": false, "isLocked": false,
@@ -42,7 +42,7 @@
}, },
"goalEndState": { "goalEndState": {
"velocity": 0, "velocity": 0,
"rotation": -62.35402463626126 "rotation": -60.52411099675423
}, },
"reversed": false, "reversed": false,
"folder": null, "folder": null,
+17 -13
View File
@@ -105,8 +105,8 @@ public final class Constants {
public static final double FORWARD_OFFSET = 90; // 0, 90, 180, 270 public static final double FORWARD_OFFSET = 90; // 0, 90, 180, 270
public static final boolean DRIFT_CORRECTION_ENABLED = true; public static final boolean DRIFT_CORRECTION_ENABLED = true;
public static final boolean INVERT_X = true; public static final boolean INVERT_X = false;
public static final boolean INVERT_Y = false; public static final boolean INVERT_Y = true;
public static final boolean INVERT_ROTATION = false; public static final boolean INVERT_ROTATION = false;
// public static final Trim POINTLESS_TRIM = new Trim("Pointless Trim", Double.MAX_VALUE, Double.MIN_VALUE, 0.1, 0); // public static final Trim POINTLESS_TRIM = new Trim("Pointless Trim", Double.MAX_VALUE, Double.MIN_VALUE, 0.1, 0);
@@ -227,21 +227,22 @@ public final class Constants {
.withKS(0).withKV(0.124); .withKS(0).withKV(0.124);
public static final Gains DRIFT_CORRECTION_GAINS = new Gains(2.5, 0, 0.1); public static final Gains DRIFT_CORRECTION_GAINS = new Gains(2.5, 0, 0.1);
public static final Gains RELATIVE_LOCKED_ANGLE_GAINS = new Gains(5, 0, 0.1); // TODO: TEST
} }
public static final class AutoConstants { public static final class AutoConstants {
public static final Gains XY_GAINS = new Gains(3,0.01,0); public static final Gains XY_GAINS = new Gains(3,0.01,0.0);
public static final Gains ROT_GAINS = new Gains(0.05,0,0.0); public static final Gains ROT_GAINS = new Gains(0.05,0,0.0);
public static final Trim X_OFFSET_TRIM = new Trim("X Offset Trim", Double.MAX_VALUE, -Double.MAX_VALUE, 0.05, 0); public static final Trim X_OFFSET_TRIM = new Trim("X Offset Trim", Double.MAX_VALUE, -Double.MAX_VALUE, 0.05, 0);
public static final int LIDAR_DETECT_DISTANCE = 100; // Min distance to detect pole public static final int LIDAR_DETECT_DISTANCE = 100; // Min distance to detect pole
public static final int LIDAR_DIO_CHANNEL = 0; public static final int LIDAR_DIO_CHANNEL = 2;
public static final int LIDAR_MICROS_TO_CM = 10; public static final int LIDAR_MICROS_TO_CM = 10;
public static final int SECONDS_TO_MICROS = 1000000; public static final int SECONDS_TO_MICROS = 1000000;
public static final double XY_TOLERANCE = 0.1; public static final double XY_TOLERANCE = 0.07; // Meters
public static final double ROT_TOLERANCE = 1; public static final double ROT_TOLERANCE = 1; // Degrees
// public static final Pose2d targetpos = new Pose2d(new Translation2d(0.3,0), new Rotation2d()); // public static final Pose2d targetpos = new Pose2d(new Translation2d(0.3,0), new Rotation2d());
// public static final Pose2d targetpos = // public static final Pose2d targetpos =
@@ -249,8 +250,8 @@ public final class Constants {
public static final class Configurations { public static final class Configurations {
public static final double OPEN_LOOP_RAMP_RATE = 0.2; // Todo: Test. think this will help. public static final double OPEN_LOOP_RAMP_RATE = 0.4; // Todo: Test. think this will help.
public static final double CLOSED_LOOP_RAMP_RATE = 0.2; // Todo: Test. think this will help. public static final double CLOSED_LOOP_RAMP_RATE = 0.4; // Todo: Test. think this will help.
public static final double NEUTRAL_DEADBAND = 0.04; public static final double NEUTRAL_DEADBAND = 0.04;
// POWER! (limiting) // POWER! (limiting)
@@ -282,7 +283,7 @@ public final class Constants {
// new ClosedLoopRampsConfigs() // new ClosedLoopRampsConfigs()
// .withDutyCycleClosedLoopRampPeriod(SwerveDriveConstants.Configurations.CLOSED_LOOP_RAMP_RATE) // .withDutyCycleClosedLoopRampPeriod(SwerveDriveConstants.Configurations.CLOSED_LOOP_RAMP_RATE)
); );
private static final double SLIP_CURRENT = 100; // TODO: Tune??? public static final double SLIP_CURRENT = 60; // TODO: Tune???
} }
// No mans land // No mans land
@@ -339,9 +340,11 @@ public final class Constants {
} }
public static final class VisionConstants { public static final class VisionConstants {
public static final String CAMERA_NAME = "Camera_Module_v1"; public static final String LEFT_CAMERA_NAME = "CAMERA_LEFT";
public static final String RIGHT_CAMERA_NAME = "CAMERA_RIGHT";
public static final Transform3d CAMERA_POS = new Transform3d(new Translation3d(-.3048, 0.2413, .2794), new Rotation3d(0,0.52333,Math.PI)); public static final Transform3d LEFT_CAMERA_POS = new Transform3d(new Translation3d(-.3048, 0.2413, .2794), new Rotation3d(0,0.52333,Math.PI));
public static final Transform3d RIGHT_CAMERA_POS = new Transform3d(new Translation3d(-.3048, 0.2413, .2794), new Rotation3d(0,0.52333,Math.PI));
public static final double MIN_ESTIMATION_DISTANCE = 1; // Meters public static final double MIN_ESTIMATION_DISTANCE = 1; // Meters
@@ -354,8 +357,9 @@ public final class Constants {
public static final class FieldConstants { public static final class FieldConstants {
public static final AprilTagFieldLayout kTagLayout = AprilTagFieldLayout.loadField(AprilTagFields.k2025Reefscape); public static final AprilTagFieldLayout kTagLayout = AprilTagFieldLayout.loadField(AprilTagFields.k2025Reefscape);
public static final double HORISONTAL_SCORING_POSITION_OFFSET = .2794 // public static final double HORISONTAL_SCORING_POSITION_OFFSET = Units.inchesToMeters(9.5);
; public static final double HORISONTAL_SCORING_POSITION_OFFSET = Units.inchesToMeters(6.5);
;;;;;;;;;;;;;;;;;;;;;;;;;;;;
// public static final double HORISONTAL_SCORING_POSITION_OFFSET = Units.inchesToMeters(6.5); // Positive is Right // public static final double HORISONTAL_SCORING_POSITION_OFFSET = Units.inchesToMeters(6.5); // Positive is Right
public static final double VERTICAL_SCORING_POSITION_OFFSET = Units.inchesToMeters(20); public static final double VERTICAL_SCORING_POSITION_OFFSET = Units.inchesToMeters(20);
@@ -36,7 +36,9 @@ import edu.wpi.first.wpilibj2.command.Commands;
// Autos // Autos
import frc4388.utility.controller.VirtualController; import frc4388.utility.controller.VirtualController;
import frc4388.robot.commands.GotoPositionCommand; import frc4388.robot.commands.GotoLastApril;
import frc4388.robot.commands.LidarAlign;
import frc4388.robot.commands.MoveForTimeCommand;
import frc4388.robot.commands.Swerve.neoJoystickPlayback; import frc4388.robot.commands.Swerve.neoJoystickPlayback;
import frc4388.robot.commands.Swerve.neoJoystickRecorder; import frc4388.robot.commands.Swerve.neoJoystickRecorder;
@@ -73,7 +75,7 @@ public class RobotContainer {
/* Subsystems */ /* Subsystems */
// private final LED m_robotLED = new LED(); // private final LED m_robotLED = new LED();
public final Vision m_vision = new Vision(m_robotMap.camera); public final Vision m_vision = new Vision(m_robotMap.leftCamera, m_robotMap.rightCamera);
public final Lidar m_lidar = new Lidar(); public final Lidar m_lidar = new Lidar();
public final Elevator m_robotElevator= new Elevator(m_robotMap.elevator, m_robotMap.endeffector, m_robotMap.basinLimitSwitch, m_robotMap.endefectorLimitSwitch); public final Elevator m_robotElevator= new Elevator(m_robotMap.elevator, m_robotMap.endeffector, m_robotMap.basinLimitSwitch, m_robotMap.endefectorLimitSwitch);
public final SwerveDrive m_robotSwerveDrive = new SwerveDrive(m_robotMap.swerveDrivetrain, m_vision); public final SwerveDrive m_robotSwerveDrive = new SwerveDrive(m_robotMap.swerveDrivetrain, m_vision);
@@ -105,7 +107,26 @@ public class RobotContainer {
() -> autoplaybackName.get(), // lastAutoName () -> autoplaybackName.get(), // lastAutoName
new VirtualController[]{getVirtualDriverController(), getVirtualOperatorController()}, new VirtualController[]{getVirtualDriverController(), getVirtualOperatorController()},
true, false); true, false);
private Command AutoGotoPosition = new GotoPositionCommand(m_robotSwerveDrive, m_vision); private Command AutoGotoPosition = new GotoLastApril(m_robotSwerveDrive, m_vision);
private Command AprilLidarAlign = new SequentialCommandGroup(
new GotoLastApril(m_robotSwerveDrive, m_vision),
new InstantCommand(() -> System.out.println("Soup")),
new WaitCommand(1),
new LidarAlign(m_robotSwerveDrive, m_lidar)
);
private Command AprilLidarLeft = new SequentialCommandGroup(
AutoGotoPosition.asProxy(),
new LidarAlign(m_robotSwerveDrive, m_lidar)
);
private Command AprilLidarRight = new SequentialCommandGroup(
AutoGotoPosition.asProxy(),
new InstantCommand(() -> System.out.println("Soup")),
new WaitCommand(1),
new LidarAlign(m_robotSwerveDrive, m_lidar)//,
// new MoveForTimeCommand(m_robotSwerveDrive,
// new Translation2d(0, 0.5), new Translation2d(), 1000, true)
);
private Command placeCoral = new SequentialCommandGroup( private Command placeCoral = new SequentialCommandGroup(
new InstantCommand(() -> m_robotSwerveDrive.stopModules()), new InstantCommand(() -> m_robotSwerveDrive.stopModules()),
@@ -131,7 +152,7 @@ public class RobotContainer {
public RobotContainer() { public RobotContainer() {
NamedCommands.registerCommand("AutoGotoPosition", AutoGotoPosition); NamedCommands.registerCommand("AutoGotoPosition", AutoGotoPosition);
NamedCommands.registerCommand("april-allign", AutoGotoPosition); NamedCommands.registerCommand("april-allign", AprilLidarAlign);
NamedCommands.registerCommand("place-coral", placeCoral); NamedCommands.registerCommand("place-coral", placeCoral);
NamedCommands.registerCommand("grab-coral", grabCoral); NamedCommands.registerCommand("grab-coral", grabCoral);
@@ -208,6 +229,15 @@ public class RobotContainer {
new JoystickButton(getDeadbandedDriverController(), XboxController.LEFT_BUMPER_BUTTON) // final new JoystickButton(getDeadbandedDriverController(), XboxController.LEFT_BUMPER_BUTTON) // final
.onTrue(new InstantCommand(() -> m_robotSwerveDrive.shiftDown())); .onTrue(new InstantCommand(() -> m_robotSwerveDrive.shiftDown()));
new JoystickButton(getDeadbandedDriverController(), XboxController.START_BUTTON) // final
.onTrue(new InstantCommand(() -> m_robotSwerveDrive.activateLuigiMode()));
new JoystickButton(getDeadbandedDriverController(), XboxController.BACK_BUTTON) // final
.onTrue(new InstantCommand(() -> m_robotSwerveDrive.deactivateLuigiMode()));
new JoystickButton(getDeadbandedDriverController(), XboxController.LEFT_BUMPER_BUTTON) // final
.onTrue(new InstantCommand(() -> m_robotSwerveDrive.shiftDown()));
new Trigger(() -> getDeadbandedDriverController().getPOV() == 270) new Trigger(() -> getDeadbandedDriverController().getPOV() == 270)
.onTrue(new InstantCommand(() -> m_robotSwerveDrive.shiftDownRot())); .onTrue(new InstantCommand(() -> m_robotSwerveDrive.shiftDownRot()));
@@ -217,10 +247,11 @@ public class RobotContainer {
// ? /* Operator Buttons */ // ? /* Operator Buttons */
new JoystickButton(getDeadbandedDriverController(), XboxController.Y_BUTTON) new JoystickButton(getDeadbandedDriverController(), XboxController.Y_BUTTON)
.onTrue(AutoGotoPosition); // .onTrue(AutoGotoPosition);
.onTrue(AprilLidarRight);
new JoystickButton(getDeadbandedDriverController(), XboxController.B_BUTTON) new JoystickButton(getDeadbandedDriverController(), XboxController.B_BUTTON)
.onTrue(new InstantCommand(() -> {}, m_robotSwerveDrive)); .onTrue(new InstantCommand(() -> {}, m_robotSwerveDrive, m_lidar));
DualJoystickButton(getDeadbandedOperatorController(), getVirtualOperatorController(), XboxController.A_BUTTON) DualJoystickButton(getDeadbandedOperatorController(), getVirtualOperatorController(), XboxController.A_BUTTON)
+2 -1
View File
@@ -35,7 +35,8 @@ public class RobotMap {
// private Pigeon2 m_pigeon2 = new Pigeon2(SwerveDriveConstants.IDs.DRIVE_PIGEON.id); // private Pigeon2 m_pigeon2 = new Pigeon2(SwerveDriveConstants.IDs.DRIVE_PIGEON.id);
// public RobotGyro gyro = new RobotGyro(m_pigeon2); // public RobotGyro gyro = new RobotGyro(m_pigeon2);
public PhotonCamera camera = new PhotonCamera(VisionConstants.CAMERA_NAME); public PhotonCamera leftCamera = new PhotonCamera(VisionConstants.LEFT_CAMERA_NAME);
public PhotonCamera rightCamera = new PhotonCamera(VisionConstants.RIGHT_CAMERA_NAME);
public RobotMap() { public RobotMap() {
configureDriveMotorControllers(); configureDriveMotorControllers();
@@ -15,7 +15,7 @@ import frc4388.utility.UtilityStructs.AutoRecordingControllerFrame;
import frc4388.utility.UtilityStructs.AutoRecordingFrame; import frc4388.utility.UtilityStructs.AutoRecordingFrame;
import frc4388.utility.controller.VirtualController; import frc4388.utility.controller.VirtualController;
public class GotoPositionCommand extends Command { public class GotoLastApril extends Command {
// private Translation2d translation2d= new Translation2d(14.579471999999997,0.24587199999999998); // private Translation2d translation2d= new Translation2d(14.579471999999997,0.24587199999999998);
@@ -34,12 +34,18 @@ public class GotoPositionCommand extends Command {
* @param SwerveDrive m_robotSwerveDrive * @param SwerveDrive m_robotSwerveDrive
*/ */
public GotoPositionCommand(SwerveDrive swerveDrive, Vision vision) { public GotoLastApril(SwerveDrive swerveDrive, Vision vision) {
this.swerveDrive = swerveDrive; this.swerveDrive = swerveDrive;
this.vision = vision; this.vision = vision;
// addRequirements(swerveDrive); // addRequirements(swerveDrive);
} }
public static double tagRelativeXError = -1;
private static void setTagRelativeXError(double val){
tagRelativeXError = val;
}
@Override @Override
public void initialize() { public void initialize() {
xPID.initialize(); xPID.initialize();
@@ -65,8 +71,8 @@ public class GotoPositionCommand extends Command {
double rotoutput = rotPID.update(roterr); double rotoutput = rotPID.update(roterr);
Translation2d leftStick = new Translation2d( Translation2d leftStick = new Translation2d(
Math.max(Math.min(youtput, 1), -1), Math.max(Math.min(-youtput, 1), -1),
Math.max(Math.min(xoutput, 1), -1) Math.max(Math.min(-xoutput, 1), -1)
// 0,0 // 0,0
); );
@@ -75,9 +81,10 @@ public class GotoPositionCommand extends Command {
0 0
); );
// SmartDashboard.putNumber("PID X Output", xoutput); setTagRelativeXError(
// SmartDashboard.putNumber("PID Y Output", youtput); new Translation2d(xerr, yerr).getAngle()
// // SmartDashboard.putNumber("PID Y Output", youtput); .rotateBy(targetpos.getRotation())
.getCos());
swerveDrive.driveWithInput(leftStick, rightStick, true); swerveDrive.driveWithInput(leftStick, rightStick, true);
} }
@@ -86,6 +93,10 @@ public class GotoPositionCommand extends Command {
public final boolean isFinished() { public final boolean isFinished() {
boolean finished = (Math.abs(xerr) < AutoConstants.XY_TOLERANCE && Math.abs(yerr) < AutoConstants.XY_TOLERANCE && Math.abs(roterr) < AutoConstants.ROT_TOLERANCE); boolean finished = (Math.abs(xerr) < AutoConstants.XY_TOLERANCE && Math.abs(yerr) < AutoConstants.XY_TOLERANCE && Math.abs(roterr) < AutoConstants.ROT_TOLERANCE);
// System.out.println(finished); // System.out.println(finished);
if(finished)
swerveDrive.softStop();
return finished; return finished;
// this statement is a boolean in and of itself // this statement is a boolean in and of itself
} }
@@ -0,0 +1,94 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package frc4388.robot.commands;
import edu.wpi.first.math.geometry.Rotation2d;
import edu.wpi.first.math.geometry.Translation2d;
import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard;
import edu.wpi.first.wpilibj2.command.Command;
import frc4388.robot.subsystems.Lidar;
import frc4388.robot.subsystems.SwerveDrive;
/* You should consider using the more terse Command factories API instead https://docs.wpilib.org/en/stable/docs/software/commandbased/organizing-command-based.html#defining-commands */
public class LidarAlign extends Command {
private SwerveDrive swerveDrive;
private Lidar lidar;
private int currentFinderTick;
// private int tickFoundPipe;
private boolean foundReef;
private boolean headedRight;
private double speed;
// private final boolean constructedHeadedRight;
/** Creates a new LidarAlign. */
public LidarAlign(SwerveDrive swerveDrive, Lidar lidar) {//, boolean headedRight) {
// Use addRequirements() here to declare subsystem dependencies.
this.swerveDrive = swerveDrive;
this.lidar = lidar;
addRequirements(swerveDrive, lidar);
}
// Called when the command is initially scheduled.
@Override
public void initialize() {
this.currentFinderTick = 0;
this.speed = 0.4; // TODO: find good speed for this
this.foundReef = false;
this.headedRight = !(GotoLastApril.tagRelativeXError < 0);
}
// Called every time the scheduler runs while the command is scheduled.
@Override
public void execute() {
if (lidar.withinDistance()) {
swerveDrive.softStop();
foundReef = true;
return;
}
if (currentFinderTick > 100) { //arbutrary threshhold for now.
headedRight = !headedRight;
currentFinderTick *= -1;
}
double currentHeading = (swerveDrive.getGyroAngle() * 180) / Math.PI;
double relAngle = (Math.round(currentHeading / 60.d) * 60); // Relative driving to the side of the reef
SmartDashboard.putNumber("Rel Angle", relAngle);
SmartDashboard.putNumber("heading", currentHeading);
if (!headedRight) {
swerveDrive.driveRelativeLockedAngle(new Translation2d(0, -speed), Rotation2d.fromDegrees(relAngle));
} else {
swerveDrive.driveRelativeLockedAngle(new Translation2d(0, speed), Rotation2d.fromDegrees(relAngle));
}
currentFinderTick++;
}
// Called once the command ends or is interrupted.
@Override
public void end(boolean interrupted) {
}
// Returns true when the command should end.
@Override
public boolean isFinished() {
if (foundReef && lidar.withinDistance()) { // spot on
swerveDrive.stopModules();
return true;
} else if (foundReef && !lidar.withinDistance()) { // over shot
speed = speed / 2;
headedRight = !headedRight;
currentFinderTick = 0;
foundReef = false;
return false;
} else {
return false;
}
}
}
@@ -0,0 +1,48 @@
package frc4388.robot.commands;
import java.time.Instant;
import edu.wpi.first.math.geometry.Translation2d;
import edu.wpi.first.wpilibj2.command.Command;
import frc4388.robot.subsystems.SwerveDrive;
// Command to repeat a joystick movement for a specific time.
public class MoveForTimeCommand extends Command {
private final SwerveDrive swerveDrive;
private final Translation2d leftStick;
private final Translation2d rightStick;
private final long duration;
private final boolean robotRelative;
private Instant startTime;
public MoveForTimeCommand(
SwerveDrive swerveDrive,
Translation2d leftStick,
Translation2d rightStick,
long millis,
boolean robotRelative) {
addRequirements(swerveDrive);
this.swerveDrive = swerveDrive;
this.leftStick = leftStick;
this.rightStick = rightStick;
this.duration = millis;
this.robotRelative = robotRelative;
}
@Override
public void initialize() {
startTime = Instant.now();
}
@Override
public void execute() {
swerveDrive.driveWithInput(leftStick, rightStick, !robotRelative);
}
@Override
public boolean isFinished() {
return Math.abs(startTime.toEpochMilli() - Instant.now().toEpochMilli()) > duration;
}
}
@@ -24,9 +24,14 @@ public class Elevator extends SubsystemBase {
public enum CoordinationState { public enum CoordinationState {
Waiting, // for coral into the though Waiting, // for coral into the though
Ready, // Has coral in enefector Ready, // Has coral in enefector
PrimedThree, // Arm and elevator Waiting to score in the level 3 position
ScoringThree, // Arm and elevator in the level three position ScoringThree, // Arm and elevator in the level three position
ScoringFour // Arm and elevator in the level four position PrimedFour, // Arm and elevator Waiting to score in the level 4 position
ScoringFour, // Arm and elevator in the level four position
BallRemoverL2Primed, // Arm and elevator ready to remove the ball in the level 2 reef.
BallRemoverL2Go, // Arm and elevator removing the ball in the level 2 reef.
BallRemoverL3Primed, // Arm and elevator ready to remove the ball in the level 3 reef.
BallRemoverL3Go, // Arm and elevator removing the ball in the level 3 reef.
} }
private CoordinationState currentState; private CoordinationState currentState;
@@ -8,10 +8,13 @@ import java.util.Optional;
import java.util.function.DoubleSupplier; import java.util.function.DoubleSupplier;
import com.ctre.phoenix6.Utils; import com.ctre.phoenix6.Utils;
import com.ctre.phoenix6.configs.TalonFXConfiguration;
import com.ctre.phoenix6.hardware.CANcoder; import com.ctre.phoenix6.hardware.CANcoder;
import com.ctre.phoenix6.hardware.TalonFX; import com.ctre.phoenix6.hardware.TalonFX;
import com.ctre.phoenix6.swerve.SwerveDrivetrain; import com.ctre.phoenix6.swerve.SwerveDrivetrain;
import com.ctre.phoenix6.swerve.SwerveModule;
import com.ctre.phoenix6.swerve.SwerveRequest; import com.ctre.phoenix6.swerve.SwerveRequest;
import com.ctre.phoenix6.swerve.SwerveRequest.ForwardPerspectiveValue;
import edu.wpi.first.math.geometry.Pose2d; import edu.wpi.first.math.geometry.Pose2d;
import edu.wpi.first.math.geometry.Rotation2d; import edu.wpi.first.math.geometry.Rotation2d;
@@ -28,6 +31,8 @@ import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard;
// import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard; // import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard;
import frc4388.robot.Constants.SwerveDriveConstants; import frc4388.robot.Constants.SwerveDriveConstants;
import frc4388.robot.Constants.VisionConstants; import frc4388.robot.Constants.VisionConstants;
import frc4388.robot.commands.GotoLastApril;
import frc4388.robot.commands.LidarAlign;
import frc4388.utility.Status; import frc4388.utility.Status;
import frc4388.utility.Subsystem; import frc4388.utility.Subsystem;
import frc4388.utility.Status.ReportLevel; import frc4388.utility.Status.ReportLevel;
@@ -149,6 +154,7 @@ public class SwerveDrive extends Subsystem {
.withVelocityX(leftStick.getX() * speedAdjust) .withVelocityX(leftStick.getX() * speedAdjust)
.withVelocityY(leftStick.getY() * speedAdjust) .withVelocityY(leftStick.getY() * speedAdjust)
.withRotationalRate(rightStick.getX() * rotSpeedAdjust)); .withRotationalRate(rightStick.getX() * rotSpeedAdjust));
// .withForwardPerspective(ForwardPerspectiveValue.OperatorPerspective));
SmartDashboard.putBoolean("drift correction", false); SmartDashboard.putBoolean("drift correction", false);
} else { } else {
var ctrl = new SwerveRequest.FieldCentricFacingAngle() var ctrl = new SwerveRequest.FieldCentricFacingAngle()
@@ -210,6 +216,41 @@ public class SwerveDrive extends Subsystem {
.withTargetDirection(rightStick.getAngle())); .withTargetDirection(rightStick.getAngle()));
} }
public void driveRelativeLockedAngle(Translation2d leftStick, Rotation2d heading) {
leftStick = leftStick.rotateBy(heading);
var ctrl = new SwerveRequest.FieldCentricFacingAngle()
.withVelocityX(leftStick.getX() * speedAdjust)
.withVelocityY(leftStick.getY() * speedAdjust)
.withTargetDirection(Rotation2d.fromDegrees(rotTarget));
ctrl.HeadingController.setPID(
SwerveDriveConstants.PIDConstants.RELATIVE_LOCKED_ANGLE_GAINS.kP,
SwerveDriveConstants.PIDConstants.RELATIVE_LOCKED_ANGLE_GAINS.kI,
SwerveDriveConstants.PIDConstants.RELATIVE_LOCKED_ANGLE_GAINS.kD
);
swerveDriveTrain.setControl(ctrl);
}
public void setLimits(double limitInAmps) {
for (SwerveModule<TalonFX, TalonFX, CANcoder> module : swerveDriveTrain.getModules()) {
var talonFXConfigurator = module.getDriveMotor().getConfigurator();
var talonFXConfigs = new TalonFXConfiguration();
talonFXConfigurator.refresh(talonFXConfigs);
talonFXConfigs.CurrentLimits.StatorCurrentLimit = limitInAmps;
talonFXConfigs.CurrentLimits.SupplyCurrentLimit = limitInAmps+10;
talonFXConfigurator.apply(talonFXConfigs);
}
}
public void activateLuigiMode() {
setLimits(20);
}
public void deactivateLuigiMode() {
setLimits(SwerveDriveConstants.Configurations.SLIP_CURRENT);
}
public boolean rotateToTarget(double angle) { public boolean rotateToTarget(double angle) {
swerveDriveTrain.setControl(new SwerveRequest.FieldCentricFacingAngle() swerveDriveTrain.setControl(new SwerveRequest.FieldCentricFacingAngle()
.withVelocityX(0) .withVelocityX(0)
@@ -241,13 +282,27 @@ public class SwerveDrive extends Subsystem {
} }
public double getGyroAngle() { public double getGyroAngle() {
return swerveDriveTrain.getRotation3d().getAngle(); return getPose2d().getRotation().getRadians();
}
public Pose2d getPose2d() {
return swerveDriveTrain.samplePoseAt(Vision.getTime()).orElse(initalPose2d);
} }
public void resetGyro() { public void resetGyro() {
swerveDriveTrain.tareEverything(); swerveDriveTrain.tareEverything();
} }
public void softStop() {
stopped = true;
swerveDriveTrain.setControl(new SwerveRequest.FieldCentric()
.withVelocityX(0)
.withVelocityY(0)
.withRotationalRate(0)
); // stop the modules without breaking
}
public void stopModules() { public void stopModules() {
stopped = true; stopped = true;
swerveDriveTrain.setControl(new SwerveRequest.SwerveDriveBrake()); swerveDriveTrain.setControl(new SwerveRequest.SwerveDriveBrake());
@@ -256,11 +311,12 @@ public class SwerveDrive extends Subsystem {
@Override @Override
public void periodic() { public void periodic() {
// This method will be called once per scheduler run\ // This method will be called once per scheduler run\
SmartDashboard.putNumber("Gyro", getGyroAngle()); SmartDashboard.putNumber("Gyro", (getGyroAngle() * 180) / Math.PI);
SmartDashboard.putNumber("RotTartget", rotTarget); SmartDashboard.putNumber("RotTartget", rotTarget);
double time = Vision.getTime(); double time = Vision.getTime();
vision.setLastOdomPose(swerveDriveTrain.samplePoseAt(time)); vision.setLastOdomPose(swerveDriveTrain.samplePoseAt(time));
if (vision.isTag()) { if (vision.isTag()) {
@@ -39,7 +39,11 @@ import frc4388.utility.Subsystem;
public class Vision extends Subsystem { public class Vision extends Subsystem {
private PhotonCamera camera; // private PhotonCamera leftCamera;
// private PhotonCamera rightCamera;
private PhotonCamera[] cameras;
private PhotonPoseEstimator[] estimators;
private boolean isTagDetected = false; private boolean isTagDetected = false;
private boolean isTagProcessed = false; private boolean isTagProcessed = false;
@@ -47,7 +51,6 @@ public class Vision extends Subsystem {
private Pose2d lastPhysOdomPose = new Pose2d(); private Pose2d lastPhysOdomPose = new Pose2d();
private Matrix<N3, N1> curStdDevs; private Matrix<N3, N1> curStdDevs;
private final PhotonPoseEstimator photonEstimator;
private Field2d field = new Field2d(); private Field2d field = new Field2d();
@@ -66,59 +69,87 @@ public class Vision extends Subsystem {
.withWidget(BuiltInWidgets.kBooleanBox) .withWidget(BuiltInWidgets.kBooleanBox)
.getEntry(); .getEntry();
GenericEntry sbCamConnected = subsystemLayout GenericEntry sbLeftCamConnected = subsystemLayout
.add("Camera Connnected", false) .add("Left Camera Connnected", false)
.withWidget(BuiltInWidgets.kBooleanBox) .withWidget(BuiltInWidgets.kBooleanBox)
.getEntry(); .getEntry();
public Vision(PhotonCamera camera){ GenericEntry sbRightCamConnected = subsystemLayout
this.camera = camera; .add("Right Camera Connnected", false)
.withWidget(BuiltInWidgets.kBooleanBox)
.getEntry();
public Vision(PhotonCamera leftCamera, PhotonCamera rightCamera){
SmartDashboard.putData(field); SmartDashboard.putData(field);
photonEstimator = new PhotonPoseEstimator(FieldConstants.kTagLayout, PoseStrategy.MULTI_TAG_PNP_ON_COPROCESSOR, VisionConstants.CAMERA_POS); this.cameras = new PhotonCamera[]{leftCamera, rightCamera};
photonEstimator.setMultiTagFallbackStrategy(PoseStrategy.LOWEST_AMBIGUITY);
PhotonPoseEstimator photonEstimatorLeft = new PhotonPoseEstimator(FieldConstants.kTagLayout, PoseStrategy.MULTI_TAG_PNP_ON_COPROCESSOR, VisionConstants.LEFT_CAMERA_POS);
PhotonPoseEstimator photonEstimatorRight = new PhotonPoseEstimator(FieldConstants.kTagLayout, PoseStrategy.MULTI_TAG_PNP_ON_COPROCESSOR, VisionConstants.RIGHT_CAMERA_POS);
photonEstimatorLeft.setMultiTagFallbackStrategy(PoseStrategy.LOWEST_AMBIGUITY);
photonEstimatorRight.setMultiTagFallbackStrategy(PoseStrategy.LOWEST_AMBIGUITY);
this.estimators = new PhotonPoseEstimator[]{photonEstimatorLeft, photonEstimatorRight};
} }
@Override @Override
public void periodic() { public void periodic() {
// var result = camera.getLatestResult(); update();
var results = camera.getAllUnreadResults();
if (results.size() == 0) return;
var result = results.get(results.size()-1);
isTagDetected = result.hasTargets();
isTagProcessed = false;
if(!isTagDetected){
// sbTagDetected.setBoolean(isTagDetected);
field.setRobotPose(getPose2d());
return;
}
var EstimatedRobotPose = getEstimatedGlobalPose(result);
// In case the pose estimator fails to estimate the pose, fallback to physical odometry.
if(EstimatedRobotPose.isEmpty()){
field.setRobotPose(getPose2d());
return;
}
isTagProcessed = true;
lastVisionPose = EstimatedRobotPose.get().estimatedPose.toPose2d();
// lastVisionPose.rotateBy(Rotation2d.k180deg);
// lastVisionPose = new Pose2d(
// lastVisionPose.getTranslation(),
// lastPhysOdomPose.getRotation()
// );
field.setRobotPose(getPose2d()); field.setRobotPose(getPose2d());
} }
private void update() {
isTagProcessed = false;
isTagDetected = false;
int cams = 0;
double X = 0;
double Y = 0;
double Yaw = 0;
for(int i = 0; i < cameras.length; i++){
PhotonCamera camera = cameras[i];
PhotonPoseEstimator estimator = estimators[i];
var results = camera.getAllUnreadResults();
// If there are no more updates from the camera
if (results.size() == 0)
continue;
var result = results.get(results.size()-1);
isTagDetected = isTagDetected | result.hasTargets();
// If there are no tags
if(!result.hasTargets())
continue;
Optional<EstimatedRobotPose> estimatedRobotPose = getEstimatedGlobalPose(result, estimator);
// If the tag was failed to be processed
if(estimatedRobotPose.isEmpty())
continue;
Pose2d pose = estimatedRobotPose.get().estimatedPose.toPose2d();
X += pose.getX();
Y += pose.getY();
Yaw += pose.getRotation().getDegrees();
cams++;
isTagProcessed = true;
}
if(isTagProcessed){
lastVisionPose = new Pose2d(X/cams, Y/cams, Rotation2d.fromDegrees(Yaw/cams));
}
}
/** /**
@@ -131,36 +162,24 @@ public class Vision extends Subsystem {
* @return An {@link EstimatedRobotPose} with an estimated pose, estimate timestamp, and targets * @return An {@link EstimatedRobotPose} with an estimated pose, estimate timestamp, and targets
* used for estimation. * used for estimation.
*/ */
public Optional<EstimatedRobotPose> getEstimatedGlobalPose(PhotonPipelineResult change) { public Optional<EstimatedRobotPose> getEstimatedGlobalPose(PhotonPipelineResult change, PhotonPoseEstimator estimator) {
Optional<EstimatedRobotPose> visionEst = Optional.empty(); Optional<EstimatedRobotPose> visionEst = Optional.empty();
// for (var change : camera.getAllUnreadResults()) {
var targets = change.getTargets(); var targets = change.getTargets();
for(int i = targets.size()-1; i >= 0; i--){ for(int i = targets.size()-1; i >= 0; i--){
Transform3d pos = targets.get(i).getBestCameraToTarget(); Transform3d pos = targets.get(i).getBestCameraToTarget();
double distance = Math.sqrt(Math.pow(pos.getX(),2) + Math.pow(pos.getY(),2) + Math.pow(pos.getZ(),2)); double distance = Math.sqrt(Math.pow(pos.getX(),2) + Math.pow(pos.getY(),2) + Math.pow(pos.getZ(),2));
if (distance > VisionConstants.MIN_ESTIMATION_DISTANCE) { if (distance > VisionConstants.MIN_ESTIMATION_DISTANCE) {
change.targets.remove(i); change.targets.remove(i);
}
} }
}
if(targets.size() <= 0) if(targets.size() <= 0)
return visionEst; // Will be empty return visionEst; // Will be empty
visionEst = photonEstimator.update(change); visionEst = estimator.update(change);
updateEstimationStdDevs(visionEst, change.getTargets()); updateEstimationStdDevs(visionEst, change.getTargets(), estimator);
// if (Robot.isSimulation()) {
// visionEst.ifPresentOrElse(
// est ->
// getSimDebugField()
// .getObject("VisionEstimation")
// .setPose(est.estimatedPose.toPose2d()),
// () -> {
// getSimDebugField().getObject("VisionEstimation").setPoses();
// });
// }
// }
return visionEst; return visionEst;
} }
@@ -173,7 +192,9 @@ public class Vision extends Subsystem {
* @param targets All targets in this camera frame * @param targets All targets in this camera frame
*/ */
private void updateEstimationStdDevs( private void updateEstimationStdDevs(
Optional<EstimatedRobotPose> estimatedPose, List<PhotonTrackedTarget> targets) { Optional<EstimatedRobotPose> estimatedPose,
List<PhotonTrackedTarget> targets,
PhotonPoseEstimator estimator) {
if (estimatedPose.isEmpty()) { if (estimatedPose.isEmpty()) {
// No pose input. Default to single-tag std devs // No pose input. Default to single-tag std devs
curStdDevs = VisionConstants.kSingleTagStdDevs; curStdDevs = VisionConstants.kSingleTagStdDevs;
@@ -186,7 +207,7 @@ public class Vision extends Subsystem {
// Precalculation - see how many tags we found, and calculate an average-distance metric // Precalculation - see how many tags we found, and calculate an average-distance metric
for (var tgt : targets) { for (var tgt : targets) {
var tagPose = photonEstimator.getFieldTags().getTagPose(tgt.getFiducialId()); var tagPose = estimator.getFieldTags().getTagPose(tgt.getFiducialId());
if (tagPose.isEmpty()) continue; if (tagPose.isEmpty()) continue;
double distance = tagPose double distance = tagPose
@@ -281,7 +302,8 @@ public class Vision extends Subsystem {
public void queryStatus() { public void queryStatus() {
sbTagDetected.setBoolean(isTagDetected); sbTagDetected.setBoolean(isTagDetected);
sbTagProcessed.setBoolean(isTagProcessed); sbTagProcessed.setBoolean(isTagProcessed);
sbCamConnected.setBoolean(camera.isConnected()); sbLeftCamConnected.setBoolean(cameras[0].isConnected());
sbRightCamConnected.setBoolean(cameras[1].isConnected());
// field.setRobotPose(getPose2d()); // field.setRobotPose(getPose2d());
} }
@@ -50,14 +50,11 @@ public class ReefPositionHelper {
for(int i = 1; i < locations.length; i++){ for(int i = 1; i < locations.length; i++){
double dist = distanceTo(locations[i],position); double dist = distanceTo(locations[i],position);
if(dist < minDistance){ if(dist < minDistance){
System.out.println(i);
minPos = locations[i]; minPos = locations[i];
minDistance = dist; minDistance = dist;
} }
} }
System.out.println(minPos);
return minPos; return minPos;
} }