diff --git a/simgui-ds.json b/simgui-ds.json
index e3a2a39..512b0fe 100644
--- a/simgui-ds.json
+++ b/simgui-ds.json
@@ -1,4 +1,9 @@
{
+ "Keyboard 0 Settings": {
+ "window": {
+ "visible": true
+ }
+ },
"keyboardJoysticks": [
{
"axisConfig": [
@@ -7,17 +12,20 @@
"incKey": 68
},
{
- "decKey": 87,
- "incKey": 83
+ "decKey": 83,
+ "incKey": 87
},
{
- "decKey": 69,
- "decayRate": 0.0,
- "incKey": 82,
+ "decayRate": 0.009999999776482582,
"keyRate": 0.009999999776482582
+ },
+ {},
+ {
+ "decKey": 81,
+ "incKey": 69
}
],
- "axisCount": 3,
+ "axisCount": 5,
"buttonCount": 4,
"buttonKeys": [
90,
@@ -91,7 +99,7 @@
],
"robotJoysticks": [
{
- "guid": "030000004c050000cc09000011810000"
+ "guid": "Keyboard0"
}
]
}
diff --git a/src/main/deploy/pathplanner/autos/Shoot 8. Hub.auto b/src/main/deploy/pathplanner/autos/Shoot 8. Hub.auto
index a7380ff..216b0a1 100644
--- a/src/main/deploy/pathplanner/autos/Shoot 8. Hub.auto
+++ b/src/main/deploy/pathplanner/autos/Shoot 8. Hub.auto
@@ -9,6 +9,25 @@
"data": {
"pathName": "S. Hub. shoot 8. E-Hub"
}
+ },
+ {
+ "type": "deadline",
+ "data": {
+ "commands": [
+ {
+ "type": "wait",
+ "data": {
+ "waitTime": 10.0
+ }
+ },
+ {
+ "type": "named",
+ "data": {
+ "name": "ChassisAlignShoot"
+ }
+ }
+ ]
+ }
}
]
}
diff --git a/src/main/deploy/pathplanner/paths/S. Hub. shoot 8. E-Hub.path b/src/main/deploy/pathplanner/paths/S. Hub. shoot 8. E-Hub.path
index 8793d07..87aa838 100644
--- a/src/main/deploy/pathplanner/paths/S. Hub. shoot 8. E-Hub.path
+++ b/src/main/deploy/pathplanner/paths/S. Hub. shoot 8. E-Hub.path
@@ -32,12 +32,12 @@
},
{
"anchor": {
- "x": 3.473,
- "y": 4.013
+ "x": 2.9483700538099855,
+ "y": 4.00221686746988
},
"prevControl": {
- "x": 3.1233132530120478,
- "y": 4.034855421686746
+ "x": 2.5986833068220334,
+ "y": 4.024072289156626
},
"nextControl": null,
"isLocked": false,
diff --git a/src/main/java/frc/robot/Constants.java b/src/main/java/frc/robot/Constants.java
index 62a15ef..4fdb60e 100644
--- a/src/main/java/frc/robot/Constants.java
+++ b/src/main/java/frc/robot/Constants.java
@@ -1,124 +1,167 @@
// 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 frc.robot;
-import edu.wpi.first.units.Units;
-import edu.wpi.first.units.measure.Angle;
-
import com.ctre.phoenix6.signals.InvertedValue;
+import edu.wpi.first.apriltag.AprilTagFieldLayout;
+import edu.wpi.first.apriltag.AprilTagFields;
+import edu.wpi.first.math.geometry.Pose3d;
+import edu.wpi.first.math.geometry.Rotation2d;
+import edu.wpi.first.math.geometry.Transform2d;
+import edu.wpi.first.math.geometry.Transform3d;
+import edu.wpi.first.units.measure.Angle;
+
/**
- * The Constants class provides a convenient place for teams to hold robot-wide numerical or boolean
- * constants. This class should not be used for any other purpose. All constants should be declared
- * globally (i.e. public static). Do not put anything functional in this class.
+ * The Constants class provides a convenient place for teams to hold robot-wide
+ * numerical or boolean constants. This class should not be used for any other
+ * purpose. All constants should be declared globally (i.e. public static). Do
+ * not put anything functional in this class.
*
- *
It is advised to statically import this class (or one of its inner classes) wherever the
- * constants are needed, to reduce verbosity.
+ *
+ * It is advised to statically import this class (or one of its inner classes)
+ * wherever the constants are needed, to reduce verbosity.
*/
public final class Constants {
- public static class OperatorConstants {
- public static final int kDriverControllerPort = 0;
- }
- public static class CameraConstanst {
+ public static class OperatorConstants {
- public static class IDFilters {
- public static final int[] RED_HUB_SHOOTING_IDS = new int[]{ 8, 9, 10, 11 };
- public static final int[] BLUE_HUB_SHOOTING_IDS = new int[]{ 27, 26, 25, 24 };
+ public static final int kDriverControllerPort = 0;
}
- public static final String BACK_CAMERA_NAME = "limelight-back";
- public static final int BACK_LOCALIZATION_PIPELINE_NUMBER = 0;
- public static final int BACK_HUB_TRACKING_2D_PIPELINE_NUMBER = 1;
- public static final int BACK_HUB_TRACKING_3D_PIPELINE_NUMBER = 2;
+ public static class CameraConstanst {
- public static final String FRONT_CAMERA_NAME = "limelight-front";
- public static final int FRONT_LOCALIZATION_PIPELINE_NUMBER = 0;
-
- }
+ public static class IDFilters {
- public static class AdvantageKitConstants{
- public enum RobotType{
- SIM,
- REAL,
- REPLAY
+ public static final int[] RED_HUB_SHOOTING_IDS = new int[]{8, 9, 10, 11};
+ public static final int[] BLUE_HUB_SHOOTING_IDS = new int[]{27, 26, 25, 24};
+ }
+
+ public static final String BACK_CAMERA_NAME = "limelight-back";
+ public static final int BACK_LOCALIZATION_PIPELINE_NUMBER = 0;
+ public static final int BACK_HUB_TRACKING_2D_PIPELINE_NUMBER = 1;
+ public static final int BACK_HUB_TRACKING_3D_PIPELINE_NUMBER = 2;
+
+ public static final String FRONT_CAMERA_NAME = "limelight-front";
+ public static final int FRONT_LOCALIZATION_PIPELINE_NUMBER = 0;
+ public static final double[] BLUE_ZONE_COOR = new double[]{1};
+ public static final double[] RED_ZONE_COOR = new double[]{1};
+ public static final double[] NEUTRAL_ZONE_COOR = new double[]{1};
}
- public static final RobotType CURRENT_MODE = RobotType.REAL;
- }
- // Swerve offsets as of 3/2/26
- public static class SwerveDriveOffsets {
- public static final float FRONT_LEFT_MOTOR_OFFSET = -0.336426f;
- public static final float FRONT_RIGHT_MOTOR_OFFSET = 0.108887f;
- public static final float BACK_LEFT_MOTOR_OFFSET = -0.492432f;
- public static final float BACK_RIGHT_MOTOR_OFFSET = 0.470215f;
- }
- /*
+
+ public static class AdvantageKitConstants {
+
+ public enum RobotType {
+ SIM,
+ REAL,
+ REPLAY
+ }
+ public static final RobotType CURRENT_MODE = RobotType.REAL;
+ }
+ // Swerve offsets as of 3/2/26
+
+ public static class SwerveDriveOffsets {
+
+ public static final float FRONT_LEFT_MOTOR_OFFSET = -0.336426f;
+ public static final float FRONT_RIGHT_MOTOR_OFFSET = 0.108887f;
+ public static final float BACK_LEFT_MOTOR_OFFSET = -0.492432f;
+ public static final float BACK_RIGHT_MOTOR_OFFSET = 0.470215f;
+ }
+
+ /*
* Numbers starting with 1 (E.g. 11, 12, 13) are in the Front Left of the robot
* Numbers starting with 2 (E.g. 21, 22, 23) are in the Front Right of the robot
* Numbers starting with 3 (E.g. 31, 32, 33) are in the Back Left of the robot
* Numbers starting with 4 (E.g. 41, 42, 43) are in the Back Right of the robot
* Laters numbers will be added for more subsystems
* Single diget numbers (E.g. 1, 2, 3) are extra, non-motor, pieces that require IDs, such as the Pigeon
- */
- public static class SwerveDriveIDs {
- public static final int FRONT_LEFT_STEER_ID = 11;
- public static final int FRONT_LEFT_DRIVE_ID = 12;
- public static final int FRONT_LEFT_ENCODER_ID = 13;
- public static final int FRONT_RIGHT_STEER_ID = 21;
- public static final int FRONT_RIGHT_DRIVE_ID = 22;
- public static final int FRONT_RIGHT_ENCODER_ID = 23;
- public static final int BACK_LEFT_STEER_ID = 31;
- public static final int BACK_LEFT_DRIVE_ID = 32;
- public static final int BACK_LEFT_ENCODER_ID = 33;
- public static final int BACK_RIGHT_STEER_ID = 41;
- public static final int BACK_RIGHT_DRIVE_ID = 42;
- public static final int BACK_RIGHT_ENCODER_ID = 43;
- }
- //Bird
- public static class ExtraIDEntities {
- public static final int PIGEON_ID = 1;
- }
-
- public static class IntakeConstants {
- public static final int DEPLOY_MOTOR_ID = 17;
- public static final boolean DEPLOY_MOTOR_INVERTED = true; // TODO: Test this
+ */
+ public static class SwerveDriveIDs {
- public static final int INTAKE_MOTOR_ID = 2;
- public static final InvertedValue INTAKE_MOTOR_DIRECTION = InvertedValue.Clockwise_Positive; // TODO: Test this
- }
+ public static final int FRONT_LEFT_STEER_ID = 11;
+ public static final int FRONT_LEFT_DRIVE_ID = 12;
+ public static final int FRONT_LEFT_ENCODER_ID = 13;
+ public static final int FRONT_RIGHT_STEER_ID = 21;
+ public static final int FRONT_RIGHT_DRIVE_ID = 22;
+ public static final int FRONT_RIGHT_ENCODER_ID = 23;
+ public static final int BACK_LEFT_STEER_ID = 31;
+ public static final int BACK_LEFT_DRIVE_ID = 32;
+ public static final int BACK_LEFT_ENCODER_ID = 33;
+ public static final int BACK_RIGHT_STEER_ID = 41;
+ public static final int BACK_RIGHT_DRIVE_ID = 42;
+ public static final int BACK_RIGHT_ENCODER_ID = 43;
+ }
- public static class ShooterConstants {
- public static final int LAUNCHER_MOTOR_ID = 3;
- public static final boolean LAUNCHER_MOTOR_INVERTED = false;
+ public static class RobotChassisLimits {
+ // Max velocity in meters per second
- public static final int TURRET_MOTOR_ID = 4;
- public static final InvertedValue TURRET_MOTOR_DIRECTION = InvertedValue.CounterClockwise_Positive;
- public static final int TURRET_LIMIT_CHANNEL = 9;
- public static final Angle LIMIT_AXIMUTH_POS = edu.wpi.first.units.Units.Degrees.of(165);
- public static final Angle LIMIT_AXIMUTH_NEG = edu.wpi.first.units.Units.Degrees.of(5);
- public static final double HOMING_SPEED = .35;
- public static final double TURRET_GEAR_RATIO = 1;
+ public static final double MAX_ROBOT_LINEAR_VELOCITY = 3;
+ // In meters per second squared
+ public static final double MAX_ROBOT_LINEAR_VELOCITY_ACCEL = 2;
- public static final int HOOD_SERVO_CHANNEL = 0;
- public static final boolean HOOD_SERVO_INVERTED = false; // TODO: Test this
- public static final int HOOD_ENCODER_ID = 4;
- public static final Angle TARGET_ELEVATION_DIF = edu.wpi.first.units.Units.Degrees.of(1);
- public static final Angle LIMIT_ELEVATION_POS = edu.wpi.first.units.Units.Degrees.of(90);
- public static final Angle LIMIT_ELEVATION_NEG = edu.wpi.first.units.Units.Degrees.of(0);
- public static final double DEFLECTOR_STORED_ANGLE = 0;
- public static final double DEFLECTOR_SET_ANGLE1 = 100;
- public static final double DEFLECTOR_SET_ANGLE2 = 200;
- public static final double DEFLECTOR_SET_ANGLE3 = 300;
- public static final double DEFLECTOR_SERVO_RATIO = 1.0;
- }
-
- public static class HopperConstants {
- public static final int KICKER_MOTOR_ID = 9;
- public static final InvertedValue KICKER_MOTOR_DIRECTION = InvertedValue.CounterClockwise_Positive;
+ // In radians per second
+ public static final double MAX_ROBOT_ANGULAR_VELOCITY = Math.PI;
+ // In radians per second squared
+ public static final double MAX_ROBOT_ANGULAR_VELOCITY_ACCEL = Math.PI;
+ }
- public static final int SPINDEXER_MOTOR_ID = 8;
- public static final InvertedValue SPINDEXER_MOTOR_DIRECTION = InvertedValue.CounterClockwise_Positive;
- }
+ //Bird
+ public static class ExtraIDEntities {
+
+ public static final int PIGEON_ID = 1;
+ }
+
+ public static class IntakeConstants {
+
+ public static final int DEPLOY_MOTOR_ID = 17;
+ public static final boolean DEPLOY_MOTOR_INVERTED = true; // TODO: Test this
+
+ public static final int INTAKE_MOTOR_ID = 2;
+ public static final InvertedValue INTAKE_MOTOR_DIRECTION = InvertedValue.Clockwise_Positive; // TODO: Test this
+ }
+
+ public static class ShooterConstants {
+
+ public static final int LAUNCHER_MOTOR_ID = 3;
+ public static final boolean LAUNCHER_MOTOR_INVERTED = false;
+
+ public static final int TURRET_MOTOR_ID = 4;
+ public static final InvertedValue TURRET_MOTOR_DIRECTION = InvertedValue.CounterClockwise_Positive;
+ public static final int TURRET_LIMIT_CHANNEL = 9;
+ public static final Angle LIMIT_AXIMUTH_POS = edu.wpi.first.units.Units.Degrees.of(165);
+ public static final Angle LIMIT_AXIMUTH_NEG = edu.wpi.first.units.Units.Degrees.of(5);
+ public static final double HOMING_SPEED = .35;
+ public static final double TURRET_GEAR_RATIO = 6;
+
+ public static final int HOOD_SERVO_CHANNEL = 0;
+ public static final boolean HOOD_SERVO_INVERTED = false; // TODO: Test this
+ public static final int HOOD_ENCODER_ID = 4;
+ public static final Angle TARGET_ELEVATION_DIF = edu.wpi.first.units.Units.Degrees.of(1);
+ public static final Angle LIMIT_ELEVATION_POS = edu.wpi.first.units.Units.Degrees.of(90);
+ public static final Angle LIMIT_ELEVATION_NEG = edu.wpi.first.units.Units.Degrees.of(0);
+ public static final double DEFLECTOR_STORED_ANGLE = 0;
+ public static final double DEFLECTOR_SET_ANGLE1 = 100;
+ public static final double DEFLECTOR_SET_ANGLE2 = 200;
+ public static final double DEFLECTOR_SET_ANGLE3 = 200; // Return to 300 once hood is fixed
+ public static final double DEFLECTOR_SERVO_RATIO = 1.0;
+ }
+
+ public static class HopperConstants {
+
+ public static final int KICKER_MOTOR_ID = 9;
+ public static final InvertedValue KICKER_MOTOR_DIRECTION = InvertedValue.Clockwise_Positive;
+
+ public static final int SPINDEXER_MOTOR_ID = 8;
+ public static final InvertedValue SPINDEXER_MOTOR_DIRECTION = InvertedValue.CounterClockwise_Positive;
+ }
+
+ public static class FieldPoses {
+
+ private static AprilTagFieldLayout fieldTags = AprilTagFieldLayout.loadField(AprilTagFields.k2026RebuiltWelded);
+
+ public static Pose3d BLUE_HUB_POSE = fieldTags.getTagPose(26).get().transformBy(new Transform3d(new Transform2d(-0.5207, 0, Rotation2d.kZero)));
+ public static Pose3d RED_HUB_POSE = fieldTags.getTagPose(10).get().transformBy(new Transform3d(new Transform2d(-0.5207, 0, Rotation2d.kZero)));
+
+ }
}
diff --git a/src/main/java/frc/robot/RobotContainer.java b/src/main/java/frc/robot/RobotContainer.java
index 397d7ad..f441446 100644
--- a/src/main/java/frc/robot/RobotContainer.java
+++ b/src/main/java/frc/robot/RobotContainer.java
@@ -1,78 +1,101 @@
// 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 frc.robot;
+import com.pathplanner.lib.auto.NamedCommands;
+
import edu.wpi.first.wpilibj2.command.Command;
+import edu.wpi.first.wpilibj2.command.Commands;
import edu.wpi.first.wpilibj2.command.button.CommandXboxController;
import edu.wpi.first.wpilibj2.command.button.Trigger;
import frc.robot.Constants.OperatorConstants;
import frc.robot.commands.AutoShootCommandChassisTurret;
-import frc.robot.commands.ManualHopperCommand;
-import frc.robot.commands.ManualIntake;
-import frc.robot.commands.ManualShootCommand;
+import frc.robot.commands.AutoShootCommandChassisTurretPathPlanner;
+import frc.robot.commands.RelayCommand;
import frc.robot.commands.SetDeflectorCommand;
+import frc.robot.commands.ZoneCheck;
import frc.robot.subsystems.DriveSubsystem;
import frc.robot.subsystems.HopperSubsystem;
import frc.robot.subsystems.IntakeSubsystem;
import frc.robot.subsystems.TurretSubsystem;
/**
- * This class is where the bulk of the robot should be declared. Since Command-based is a
- * "declarative" paradigm, very little robot logic should actually be handled in the {@link Robot}
- * periodic methods (other than the scheduler calls). Instead, the structure of the robot (including
- * subsystems, commands, and trigger mappings) should be declared here.
+ * This class is where the bulk of the robot should be declared. Since
+ * Command-based is a "declarative" paradigm, very little robot logic should
+ * actually be handled in the {@link Robot} periodic methods (other than the
+ * scheduler calls). Instead, the structure of the robot (including subsystems,
+ * commands, and trigger mappings) should be declared here.
*/
public class RobotContainer {
- // The robot's subsystems and commands are defined here...
- // Replace with CommandPS4Controller or CommandJoystick if needed
- private final CommandXboxController m_driverController =
- new CommandXboxController(OperatorConstants.kDriverControllerPort);
+ // The robot's subsystems and commands are defined here...
+ // Replace with CommandPS4Controller or CommandJoystick if needed
- // private final CommandPS4Controller m_driverController = new CommandPS4Controller(OperatorConstants.kDriverControllerPort);
+ private final CommandXboxController m_driverController
+ = new CommandXboxController(OperatorConstants.kDriverControllerPort);
- public final DriveSubsystem driveSubsystem = new DriveSubsystem(m_driverController);
+ // private final CommandPS4Controller m_driverController = new CommandPS4Controller(OperatorConstants.kDriverControllerPort);
+ public final DriveSubsystem driveSubsystem = new DriveSubsystem(m_driverController);
- public final IntakeSubsystem intakeSubsystem = new IntakeSubsystem();
+ public final IntakeSubsystem intakeSubsystem = new IntakeSubsystem();
- public final TurretSubsystem turretSubsystem = new TurretSubsystem();
+ public final TurretSubsystem turretSubsystem = new TurretSubsystem();
- public final HopperSubsystem hopperSubsystem = new HopperSubsystem();
-
- /** The container for the robot. Contains subsystems, OI devices, and commands. */
- public RobotContainer() {
- // Configure the trigger bindings
- configureBindings();
- }
+ public final HopperSubsystem hopperSubsystem = new HopperSubsystem();
- /**
- * Use this method to define your trigger->command mappings. Triggers can be created via the
- * {@link Trigger#Trigger(java.util.function.BooleanSupplier)} constructor with an arbitrary
- * predicate, or via the named factories in {@link
- * edu.wpi.first.wpilibj2.command.button.CommandGenericHID}'s subclasses for {@link
- * CommandXboxController Xbox}/{@link edu.wpi.first.wpilibj2.command.button.CommandPS4Controller
- * PS4} controllers or {@link edu.wpi.first.wpilibj2.command.button.CommandJoystick Flight
- * joysticks}.
- */
+ /**
+ * The container for the robot. Contains subsystems, OI devices, and
+ * commands.
+ */
+ public RobotContainer() {
- private void configureBindings() {
- turretSubsystem.startHoming();
- m_driverController.povDown().onTrue(new SetDeflectorCommand(turretSubsystem, Constants.ShooterConstants.DEFLECTOR_STORED_ANGLE));
- m_driverController.povLeft().onTrue(new SetDeflectorCommand(turretSubsystem, Constants.ShooterConstants.DEFLECTOR_SET_ANGLE1));
- m_driverController.povRight().onTrue(new SetDeflectorCommand(turretSubsystem, Constants.ShooterConstants.DEFLECTOR_SET_ANGLE3));
- m_driverController.povUp().onTrue(new SetDeflectorCommand(turretSubsystem, Constants.ShooterConstants.DEFLECTOR_SET_ANGLE2));
+ // turretSubsystem.setDefaultCommand(new AutoTurretCommand(turretSubsystem, driveSubsystem));
+ // turretSubsystem.homeTurret();
+ // Configure the trigger bindings
+ configureBindings();
- m_driverController.a().whileTrue(new AutoShootCommandChassisTurret(driveSubsystem, hopperSubsystem, turretSubsystem));
- }
+ NamedCommands.registerCommand("ChassisAlignShoot", new AutoShootCommandChassisTurret(driveSubsystem, hopperSubsystem, turretSubsystem));
- /**
- * Use this to pass the autonomous command to the main {@link Robot} class.
- *
- * @return the command to run in autonomous
- */
- public Command getAutonomousCommand() {
- // An example command will be run in autonomous
- return driveSubsystem.getAutoCommand();
- }
+ }
+
+ /**
+ * Use this method to define your trigger->command mappings. Triggers can be
+ * created via the
+ * {@link Trigger#Trigger(java.util.function.BooleanSupplier)} constructor
+ * with an arbitrary predicate, or via the named factories in {@link
+ * edu.wpi.first.wpilibj2.command.button.CommandGenericHID}'s subclasses for {@link
+ * CommandXboxController Xbox}/{@link edu.wpi.first.wpilibj2.command.button.CommandPS4Controller
+ * PS4} controllers or {@link edu.wpi.first.wpilibj2.command.button.CommandJoystick Flight
+ * joysticks}.
+ *
+ */
+ private void configureBindings() {
+ m_driverController.povDown().onTrue(new SetDeflectorCommand(turretSubsystem, Constants.ShooterConstants.DEFLECTOR_STORED_ANGLE));
+ m_driverController.povLeft().onTrue(new SetDeflectorCommand(turretSubsystem, Constants.ShooterConstants.DEFLECTOR_SET_ANGLE1));
+ m_driverController.povRight().onTrue(new SetDeflectorCommand(turretSubsystem, Constants.ShooterConstants.DEFLECTOR_SET_ANGLE3));
+ m_driverController.povUp().onTrue(new SetDeflectorCommand(turretSubsystem, Constants.ShooterConstants.DEFLECTOR_SET_ANGLE2));
+
+ m_driverController.back().whileTrue(new AutoShootCommandChassisTurretPathPlanner(driveSubsystem, hopperSubsystem, turretSubsystem));
+ //m_driverController.a().whileTrue(new AutoShootCommandChassisTurretPathPlanner(driveSubsystem, hopperSubsystem, turretSubsystem));
+ // m_driverController:wa.a().whileTrue(new AutoShootCommandChassisTurret(driveSubsystem, hopperSubsystem, turretSubsystem));
+
+ m_driverController.leftBumper().onTrue(Commands.runOnce(() -> turretSubsystem.homeTurret(), turretSubsystem));
+ m_driverController.rightBumper().onTrue(intakeSubsystem.intake());
+ m_driverController.y().whileTrue(new RelayCommand(hopperSubsystem, turretSubsystem, intakeSubsystem));
+ m_driverController.start().whileTrue(intakeSubsystem.resetDeploy());
+ m_driverController.x().toggleOnTrue(new AutoShootCommandChassisTurret(driveSubsystem, hopperSubsystem, turretSubsystem));
+ m_driverController.b().toggleOnTrue(new ZoneCheck());
+ }
+
+ /**
+ * Use this to pass the autonomous command to the main {@link Robot} class.
+ *
+ * @return the command to run in autonomous
+ */
+ public Command getAutonomousCommand() {
+ // An example command will be run in autonomous
+ return Commands.parallel(intakeSubsystem.deploy(), Commands.run(() -> {
+ turretSubsystem.homeTurret();
+ }, turretSubsystem), driveSubsystem.getAutoCommand());
+ }
}
diff --git a/src/main/java/frc/robot/Utils.java b/src/main/java/frc/robot/Utils.java
new file mode 100644
index 0000000..64bd85f
--- /dev/null
+++ b/src/main/java/frc/robot/Utils.java
@@ -0,0 +1,25 @@
+package frc.robot;
+
+public class Utils {
+
+ /**
+ * Calculates the needed angle of the turret for a distance from the HUB.
+ * @param distanceToTag
+ * @return number of rotations of the turret, robot relative
+ */
+ public static double calculateTurretAngleFromCameraTagDistance(double distanceToTag){
+
+ // Calculate turret Angle
+ double cameraDistanceToTarget = distanceToTag + .6;
+ double cameraToShootDistance = 0.26035;
+ // a^2 + b^2 = c^2
+ double shooterDistanceToTarget = Math
+ .sqrt(Math.pow(cameraDistanceToTarget, 2) + Math.pow(cameraToShootDistance, 2));
+ double angleAtShooter = Math.acos(cameraToShootDistance / shooterDistanceToTarget);
+ double robotTurretAngle = (Math.PI / 2) - angleAtShooter;
+ double robotTurretRotations = (robotTurretAngle / Math.PI);
+
+ return robotTurretRotations;
+ }
+
+}
diff --git a/src/main/java/frc/robot/commands/AnyTarget.java b/src/main/java/frc/robot/commands/AnyTarget.java
new file mode 100644
index 0000000..9604e33
--- /dev/null
+++ b/src/main/java/frc/robot/commands/AnyTarget.java
@@ -0,0 +1,144 @@
+package frc.robot.commands;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.fairportrobotics.frc.robolib.vision.limelight.LimelightHelpers;
+import org.littletonrobotics.junction.Logger;
+
+import edu.wpi.first.apriltag.AprilTagFieldLayout;
+import edu.wpi.first.apriltag.AprilTagFields;
+import edu.wpi.first.math.controller.PIDController;
+import edu.wpi.first.math.geometry.Pose3d;
+import edu.wpi.first.math.geometry.Rotation2d;
+import edu.wpi.first.math.geometry.Translation2d;
+import edu.wpi.first.wpilibj.DriverStation;
+import edu.wpi.first.wpilibj.DriverStation.Alliance;
+import edu.wpi.first.wpilibj2.command.Command;
+import frc.robot.Constants;
+import frc.robot.Utils;
+import frc.robot.subsystems.DriveSubsystem;
+import frc.robot.subsystems.HopperSubsystem;
+import frc.robot.subsystems.TurretSubsystem;
+
+public class AnyTarget extends Command {
+
+ // For Chassis Control
+ private DriveSubsystem driveSubsystem;
+
+ private HopperSubsystem hopperSubsystem;
+ private TurretSubsystem turretSubsystem;
+
+ private PIDController cameraAutoCenterController;
+ private PIDController deadreckoningAutoCenterController;
+
+ private int[] tagFilters;
+
+ private AprilTagFieldLayout fieldTags = AprilTagFieldLayout.loadField(AprilTagFields.k2026RebuiltWelded);
+
+ private Pose3d closestTag;
+
+ private final double chassisRotateSpeed = Math.PI * 0.1;
+
+ public AnyTarget(DriveSubsystem driveSubsystem, HopperSubsystem hopperSubsystem, TurretSubsystem turretSubsystem) {
+ this.driveSubsystem = driveSubsystem;
+ this.hopperSubsystem = hopperSubsystem;
+ this.turretSubsystem = turretSubsystem;
+
+ this.addRequirements(driveSubsystem, hopperSubsystem, turretSubsystem);
+
+ cameraAutoCenterController = new PIDController(0.15, 0.0, 0.0);
+ cameraAutoCenterController.setTolerance(0.2); // Units degrees
+ cameraAutoCenterController.setSetpoint(0);
+
+ deadreckoningAutoCenterController = new PIDController(Math.PI * 0.1, 0, 0.0);
+ deadreckoningAutoCenterController.setTolerance(0.2); // Units is rotations
+ deadreckoningAutoCenterController.enableContinuousInput(-Math.PI, Math.PI);
+ }
+
+ @Override
+ public void initialize() {
+ DriverStation.getAlliance().ifPresent((aliance) -> {
+ if (aliance == Alliance.Blue) {
+ tagFilters = Constants.CameraConstanst.IDFilters.BLUE_HUB_SHOOTING_IDS;
+ } else {
+ tagFilters = Constants.CameraConstanst.IDFilters.RED_HUB_SHOOTING_IDS;
+ }
+ });
+
+ turretSubsystem.setLauncher(6000);
+ turretSubsystem.setTargetElevation(Constants.ShooterConstants.DEFLECTOR_STORED_ANGLE);
+ hopperSubsystem.spindexerOn();
+ cameraAutoCenterController.calculate(-100);
+
+ // Change to HUB tracking pipeline
+ LimelightHelpers.setPipelineIndex(Constants.CameraConstanst.BACK_CAMERA_NAME, Constants.CameraConstanst.BACK_HUB_TRACKING_3D_PIPELINE_NUMBER);
+ LimelightHelpers.SetFiducialIDFiltersOverride(Constants.CameraConstanst.BACK_CAMERA_NAME, tagFilters);
+
+ Pose3d botPose = driveSubsystem.getBotPose();
+ // Find closest target to us
+ List tagPoses = Arrays.stream(tagFilters).mapToObj(tagId -> fieldTags.getTagPose(tagId).get()).toList();
+ closestTag = botPose.nearest(tagPoses);
+ Logger.recordOutput("AutoAlign-ClosestAprilTagPose", closestTag);
+
+ Translation2d delta = botPose.getTranslation().toTranslation2d().minus(closestTag.getTranslation().toTranslation2d());
+ Logger.recordOutput("AutoAlign-ClosestAprilTagTransform", delta);
+
+ deadreckoningAutoCenterController.setSetpoint(delta.getAngle().plus(Rotation2d.kZero).getRadians());
+ }
+
+ @Override
+ public void execute() {
+ // Need to compute shoot speed and angle
+
+ Logger.recordOutput("AutoAlign-CenteringError", cameraAutoCenterController.getError());
+
+ // No april tag in camera view. Rotate towards our theoretical closest tag
+ if (!LimelightHelpers.getTV(Constants.CameraConstanst.BACK_CAMERA_NAME)) {
+ Logger.recordOutput("AutoAlignState-Tracking", "Deadreckoning");
+
+ Pose3d botPose = driveSubsystem.getBotPose();
+ //driveSubsystem.rotateChassis(-deadreckoningAutoCenterController.calculate(botPose.getRotation().toRotation2d().getRadians()));
+ } else // We have an april tag, center it to the camera frame
+ {
+ Logger.recordOutput("AutoAlignState-Tracking", "Camera");
+ // [tx, ty, tz, pitch, yaw, roll]
+ double[] targetsPose = LimelightHelpers.getTargetPose_CameraSpace(Constants.CameraConstanst.BACK_CAMERA_NAME);
+ if (targetsPose.length >= 1) {
+ Logger.recordOutput("AutoAlign-Target Distance", targetsPose[2]);
+
+ // Calculate turret Angle
+ double turretAngle = Utils.calculateTurretAngleFromCameraTagDistance(targetsPose[2]) * Constants.ShooterConstants.TURRET_GEAR_RATIO;
+ turretSubsystem.setTurretMotorRotation(-turretAngle);
+
+ driveSubsystem.rotateChassis(-cameraAutoCenterController.calculate(targetsPose[0])); // This may need to be negated
+ }
+ }
+
+ // If robot is centered on HUB and shooter is up to speed. Run the kicker
+ if (turretSubsystem.isLauncherUpToSpeed() && cameraAutoCenterController.atSetpoint()) {
+ Logger.recordOutput("AutoAlignState-Shoot", "FIRE!");
+ hopperSubsystem.feedKicker();
+ } else {
+ Logger.recordOutput("AutoAlignState-Shoot", "Waiting");
+ }
+ }
+
+ @Override
+ public boolean isFinished() {
+ return false;
+ }
+
+ @Override
+ public void end(boolean interrupted) {
+ turretSubsystem.setLauncher(0);
+
+ hopperSubsystem.stopKicker();
+ hopperSubsystem.spindexerOff();
+
+ driveSubsystem.stopDrive();
+
+ LimelightHelpers.setPipelineIndex(Constants.CameraConstanst.BACK_CAMERA_NAME, Constants.CameraConstanst.BACK_LOCALIZATION_PIPELINE_NUMBER);
+ }
+
+}
diff --git a/src/main/java/frc/robot/commands/AutoShootCommandChassisTurret.java b/src/main/java/frc/robot/commands/AutoShootCommandChassisTurret.java
index fc9a56b..0b6d64d 100644
--- a/src/main/java/frc/robot/commands/AutoShootCommandChassisTurret.java
+++ b/src/main/java/frc/robot/commands/AutoShootCommandChassisTurret.java
@@ -23,6 +23,7 @@ import edu.wpi.first.wpilibj.DriverStation;
import edu.wpi.first.wpilibj.DriverStation.Alliance;
import edu.wpi.first.wpilibj2.command.Command;
import frc.robot.Constants;
+import frc.robot.Utils;
import frc.robot.subsystems.DriveSubsystem;
import frc.robot.subsystems.HopperSubsystem;
import frc.robot.subsystems.TurretSubsystem;
@@ -40,7 +41,7 @@ public class AutoShootCommandChassisTurret extends Command{
private int[] tagFilters;
- private AprilTagFieldLayout fieldTags = AprilTagFieldLayout.loadField(AprilTagFields.k2026RebuiltAndymark);
+ private AprilTagFieldLayout fieldTags = AprilTagFieldLayout.loadField(AprilTagFields.k2026RebuiltWelded);
private Pose3d closestTag;
@@ -54,8 +55,8 @@ public class AutoShootCommandChassisTurret extends Command{
this.addRequirements(driveSubsystem, hopperSubsystem, turretSubsystem);
- cameraAutoCenterController = new PIDController(0.1, 0, 0.0);
- cameraAutoCenterController.setTolerance(0.2); // Units is meters
+ cameraAutoCenterController = new PIDController(0.15, 0.0, 0.0);
+ cameraAutoCenterController.setTolerance(0.2); // Units degrees
cameraAutoCenterController.setSetpoint(0);
@@ -74,12 +75,13 @@ public class AutoShootCommandChassisTurret extends Command{
}
});
- turretSubsystem.setLauncher(2500);
+ turretSubsystem.setLauncher(6000);
+ turretSubsystem.setTargetElevation(Constants.ShooterConstants.DEFLECTOR_STORED_ANGLE);
hopperSubsystem.spindexerOn();
cameraAutoCenterController.calculate(-100);
// Change to HUB tracking pipeline
- LimelightHelpers.setPipelineIndex(Constants.CameraConstanst.BACK_CAMERA_NAME, Constants.CameraConstanst.BACK_HUB_TRACKING_2D_PIPELINE_NUMBER);
+ LimelightHelpers.setPipelineIndex(Constants.CameraConstanst.BACK_CAMERA_NAME, Constants.CameraConstanst.BACK_HUB_TRACKING_3D_PIPELINE_NUMBER);
LimelightHelpers.SetFiducialIDFiltersOverride(Constants.CameraConstanst.BACK_CAMERA_NAME, tagFilters);
Pose3d botPose = driveSubsystem.getBotPose();
@@ -91,7 +93,7 @@ public class AutoShootCommandChassisTurret extends Command{
Translation2d delta = botPose.getTranslation().toTranslation2d().minus(closestTag.getTranslation().toTranslation2d());
Logger.recordOutput("AutoAlign-ClosestAprilTagTransform", delta);
- deadreckoningAutoCenterController.setSetpoint(delta.getAngle().getRadians());
+ deadreckoningAutoCenterController.setSetpoint(delta.getAngle().plus(Rotation2d.kZero).getRadians());
}
@Override
@@ -102,25 +104,33 @@ public class AutoShootCommandChassisTurret extends Command{
// No april tag in camera view. Rotate towards our theoretical closest tag
if(!LimelightHelpers.getTV(Constants.CameraConstanst.BACK_CAMERA_NAME)){
- Logger.recordOutput("AutoAlignState", "Look for tag");
+ Logger.recordOutput("AutoAlignState-Tracking", "Deadreckoning");
Pose3d botPose = driveSubsystem.getBotPose();
- driveSubsystem.rotateChassis(deadreckoningAutoCenterController.calculate(botPose.getRotation().toRotation2d().getRadians())); // May need to flip this
+ //driveSubsystem.rotateChassis(-deadreckoningAutoCenterController.calculate(botPose.getRotation().toRotation2d().getRadians()));
}
else // We have an april tag, center it to the camera frame
{
- Logger.recordOutput("AutoAlignState", "Center on tag");
+ Logger.recordOutput("AutoAlignState-Tracking", "Camera");
// [tx, ty, tz, pitch, yaw, roll]
double[] targetsPose = LimelightHelpers.getTargetPose_CameraSpace(Constants.CameraConstanst.BACK_CAMERA_NAME);
if(targetsPose.length >= 1){
+ Logger.recordOutput("AutoAlign-Target Distance", targetsPose[2]);
+
+ // Calculate turret Angle
+ double turretAngle = Utils.calculateTurretAngleFromCameraTagDistance(targetsPose[2]) * Constants.ShooterConstants.TURRET_GEAR_RATIO;
+ turretSubsystem.setTurretMotorRotation(-turretAngle);
+
driveSubsystem.rotateChassis(-cameraAutoCenterController.calculate(targetsPose[0])); // This may need to be negated
}
}
// If robot is centered on HUB and shooter is up to speed. Run the kicker
if(turretSubsystem.isLauncherUpToSpeed() && cameraAutoCenterController.atSetpoint()){
- Logger.recordOutput("AutoAlignState", "FIRE!");
+ Logger.recordOutput("AutoAlignState-Shoot", "FIRE!");
hopperSubsystem.feedKicker();
+ }else{
+ Logger.recordOutput("AutoAlignState-Shoot", "Waiting");
}
}
diff --git a/src/main/java/frc/robot/commands/AutoShootCommandChassisTurretPathPlanner.java b/src/main/java/frc/robot/commands/AutoShootCommandChassisTurretPathPlanner.java
new file mode 100644
index 0000000..683a056
--- /dev/null
+++ b/src/main/java/frc/robot/commands/AutoShootCommandChassisTurretPathPlanner.java
@@ -0,0 +1,130 @@
+package frc.robot.commands;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.fairportrobotics.frc.robolib.vision.limelight.LimelightHelpers;
+import org.littletonrobotics.junction.Logger;
+
+import com.pathplanner.lib.auto.AutoBuilder;
+import com.pathplanner.lib.path.PathConstraints;
+import edu.wpi.first.apriltag.AprilTagFieldLayout;
+import edu.wpi.first.apriltag.AprilTagFields;
+import edu.wpi.first.math.geometry.Pose2d;
+import edu.wpi.first.math.geometry.Pose3d;
+import edu.wpi.first.math.geometry.Translation2d;
+import edu.wpi.first.wpilibj.DriverStation;
+import edu.wpi.first.wpilibj.DriverStation.Alliance;
+import edu.wpi.first.wpilibj2.command.Command;
+import edu.wpi.first.wpilibj2.command.CommandScheduler;
+import frc.robot.Constants;
+import frc.robot.subsystems.DriveSubsystem;
+import frc.robot.subsystems.HopperSubsystem;
+import frc.robot.subsystems.TurretSubsystem;
+
+public class AutoShootCommandChassisTurretPathPlanner extends Command {
+
+ // For Chassis Control
+ private DriveSubsystem driveSubsystem;
+
+ private HopperSubsystem hopperSubsystem;
+ private TurretSubsystem turretSubsystem;
+
+ private int[] tagFilters;
+
+ private AprilTagFieldLayout fieldTags = AprilTagFieldLayout.loadField(AprilTagFields.k2026RebuiltWelded);
+
+ private Pose3d closestTag;
+ private Pose2d targetPPPose;
+
+ private Command pathFollowCommand;
+
+ public AutoShootCommandChassisTurretPathPlanner(DriveSubsystem driveSubsystem, HopperSubsystem hopperSubsystem,
+ TurretSubsystem turretSubsystem) {
+ this.driveSubsystem = driveSubsystem;
+ this.hopperSubsystem = hopperSubsystem;
+ this.turretSubsystem = turretSubsystem;
+
+ this.addRequirements(driveSubsystem, hopperSubsystem, turretSubsystem);
+
+ }
+
+ @Override
+ public void initialize() {
+
+ DriverStation.getAlliance().ifPresent((aliance) -> {
+ Pose3d targetHub;
+ if (aliance == Alliance.Blue) {
+ tagFilters = Constants.CameraConstanst.IDFilters.BLUE_HUB_SHOOTING_IDS;
+ targetHub = Constants.FieldPoses.BLUE_HUB_POSE;
+ } else {
+ tagFilters = Constants.CameraConstanst.IDFilters.RED_HUB_SHOOTING_IDS;
+ targetHub = Constants.FieldPoses.RED_HUB_POSE;
+ }
+
+ Pose3d botPose = driveSubsystem.getBotPose();
+ // Find closest target to us
+ List tagPoses = Arrays.stream(tagFilters).mapToObj(tagId -> fieldTags.getTagPose(tagId).get())
+ .toList();
+ closestTag = botPose.nearest(tagPoses);
+ Logger.recordOutput("AutoAlignPP-ClosestAprilTagPose", closestTag);
+
+ Translation2d delta = botPose.getTranslation().toTranslation2d()
+ .minus(closestTag.getTranslation().toTranslation2d());
+ Logger.recordOutput("AutoAlignPP-ClosestAprilTagTransform", delta);
+
+ // Add 180 because we want the back of the robot to face the HUB
+ // deadreckoningAutoCenterController.setSetpoint(delta.getAngle().plus(Rotation2d.k180deg).getRadians());
+
+ // Translate back 1 meter from HUB
+ Translation2d newTrans = targetHub.getTranslation().toTranslation2d()
+ .plus(new Translation2d(1.5, delta.getAngle()));
+ targetPPPose = new Pose2d(newTrans, delta.getAngle());
+ Logger.recordOutput("AutoAlignPP-PPTargetPose", targetPPPose);
+
+ pathFollowCommand = AutoBuilder.pathfindToPose(targetPPPose,
+ new PathConstraints(Constants.RobotChassisLimits.MAX_ROBOT_LINEAR_VELOCITY,
+ Constants.RobotChassisLimits.MAX_ROBOT_LINEAR_VELOCITY_ACCEL,
+ Constants.RobotChassisLimits.MAX_ROBOT_ANGULAR_VELOCITY,
+ Constants.RobotChassisLimits.MAX_ROBOT_LINEAR_VELOCITY_ACCEL));
+
+ CommandScheduler.getInstance().schedule(pathFollowCommand);
+ });
+
+ turretSubsystem.setLauncher(5500);
+ hopperSubsystem.spindexerOn();
+
+ }
+
+ @Override
+ public void execute() {
+
+ // If robot is centered on HUB and shooter is up to speed. Run the kicker
+ if (turretSubsystem.isLauncherUpToSpeed() && pathFollowCommand.isFinished()) {
+ Logger.recordOutput("AutoAlignState-Shoot", "FIRE!");
+ hopperSubsystem.feedKicker();
+ } else {
+ Logger.recordOutput("AutoAlignState-Shoot", "Waiting");
+ }
+ }
+
+ @Override
+ public boolean isFinished() {
+ return false;
+ }
+
+ @Override
+ public void end(boolean interrupted) {
+ CommandScheduler.getInstance().cancel(pathFollowCommand);
+ turretSubsystem.setLauncher(0);
+
+ hopperSubsystem.stopKicker();
+ hopperSubsystem.spindexerOff();
+
+ driveSubsystem.stopDrive();
+
+ LimelightHelpers.setPipelineIndex(Constants.CameraConstanst.BACK_CAMERA_NAME,
+ Constants.CameraConstanst.BACK_LOCALIZATION_PIPELINE_NUMBER);
+ }
+
+}
diff --git a/src/main/java/frc/robot/commands/AutoTurretCommand.java b/src/main/java/frc/robot/commands/AutoTurretCommand.java
new file mode 100644
index 0000000..f4498b0
--- /dev/null
+++ b/src/main/java/frc/robot/commands/AutoTurretCommand.java
@@ -0,0 +1,88 @@
+package frc.robot.commands;
+
+import org.littletonrobotics.junction.Logger;
+
+import edu.wpi.first.apriltag.AprilTagFieldLayout;
+import edu.wpi.first.apriltag.AprilTagFields;
+import edu.wpi.first.math.geometry.Pose3d;
+import edu.wpi.first.math.geometry.Rotation2d;
+import edu.wpi.first.math.geometry.Rotation3d;
+import edu.wpi.first.math.geometry.Transform2d;
+import edu.wpi.first.math.geometry.Transform3d;
+import edu.wpi.first.math.geometry.Translation2d;
+import edu.wpi.first.math.geometry.Translation3d;
+import edu.wpi.first.units.Units;
+import edu.wpi.first.units.measure.Angle;
+import edu.wpi.first.wpilibj.DriverStation;
+import edu.wpi.first.wpilibj.DriverStation.Alliance;
+import edu.wpi.first.wpilibj2.command.Command;
+import frc.robot.Constants;
+import frc.robot.subsystems.DriveSubsystem;
+import frc.robot.subsystems.TurretSubsystem;
+
+public class AutoTurretCommand extends Command {
+
+ private final Translation2d CENTER_TURRET_TO_ROBOT = new Translation2d(-0.1335024, -0.1824736);
+
+ private TurretSubsystem turretSubsystem;
+ private DriveSubsystem driveSubsystem;
+
+ private int[] shootingTagFilters;
+
+ private Pose3d closestTag;
+ private Pose3d scoringHubPose;
+
+ public AutoTurretCommand(TurretSubsystem turretSubsystem, DriveSubsystem driveSubsystem) {
+ this.turretSubsystem = turretSubsystem;
+ this.driveSubsystem = driveSubsystem;
+
+ addRequirements(turretSubsystem); // Not adding drive as we don't wan't the drive command to be de-scheduled
+ }
+
+ @Override
+ public void initialize() {
+ // Perform auto-home
+ turretSubsystem.homeTurret();
+
+ DriverStation.getAlliance().ifPresent((aliance) -> {
+ if (aliance == Alliance.Blue) {
+ shootingTagFilters = Constants.CameraConstanst.IDFilters.BLUE_HUB_SHOOTING_IDS;
+ scoringHubPose = Constants.FieldPoses.BLUE_HUB_POSE;
+ } else {
+ shootingTagFilters = Constants.CameraConstanst.IDFilters.RED_HUB_SHOOTING_IDS;
+ scoringHubPose = Constants.FieldPoses.RED_HUB_POSE;
+ }
+ Logger.recordOutput("AutoTurret-ScoringTarget", scoringHubPose);
+ });
+
+ }
+
+ @Override
+ public void execute() {
+
+ Pose3d botPose = driveSubsystem.getBotPose();
+ Pose3d turretPose = botPose.plus(new Transform3d(new Translation3d(CENTER_TURRET_TO_ROBOT),
+ new Rotation3d(Rotation2d.fromRotations(turretSubsystem.getTurretAngleRobotRelative()))));
+ Logger.recordOutput("AutoTurret-TurretPose", turretPose);
+
+ Translation2d targetTranslation = scoringHubPose.getTranslation().toTranslation2d().minus(turretPose.getTranslation().toTranslation2d());
+ Logger.recordOutput("AutoTurret-Translation", targetTranslation);
+
+
+ if(turretSubsystem.isTurretReady()){
+ // turretSubsystem.setTurretFieldRelative(botPose.getRotation().toRotation2d().minus(targetTranslation.getAngle()).plus(Rotation2d.k180deg).getMeasure());
+ // turretSubsystem.setTurretRotation(Angle.ofRelativeUnits(-180, Units.Degrees));
+ }
+
+ }
+
+ @Override
+ public boolean isFinished() {
+ return false;
+ }
+
+ @Override
+ public void end(boolean interrupted) {
+ }
+
+}
diff --git a/src/main/java/frc/robot/commands/ManualIntake.java b/src/main/java/frc/robot/commands/ExampleCommand.java
similarity index 69%
rename from src/main/java/frc/robot/commands/ManualIntake.java
rename to src/main/java/frc/robot/commands/ExampleCommand.java
index 39c9aa4..7481d3c 100644
--- a/src/main/java/frc/robot/commands/ManualIntake.java
+++ b/src/main/java/frc/robot/commands/ExampleCommand.java
@@ -4,25 +4,21 @@
package frc.robot.commands;
-import frc.robot.subsystems.IntakeSubsystem;
-
-import edu.wpi.first.wpilibj.XboxController;
+import frc.robot.subsystems.ExampleSubsystem;
import edu.wpi.first.wpilibj2.command.Command;
/** An example command that uses an example subsystem. */
-public class ManualIntake extends Command {
+public class ExampleCommand extends Command {
@SuppressWarnings({"PMD.UnusedPrivateField", "PMD.SingularField"})
- private final IntakeSubsystem m_subsystem;
- private final XboxController m_XboxController;
+ private final ExampleSubsystem m_subsystem;
/**
* Creates a new ExampleCommand.
*
* @param subsystem The subsystem used by this command.
*/
- public ManualIntake(IntakeSubsystem subsystem, XboxController xboxController) {
+ public ExampleCommand(ExampleSubsystem subsystem) {
m_subsystem = subsystem;
- m_XboxController = xboxController;
// Use addRequirements() here to declare subsystem dependencies.
addRequirements(subsystem);
}
@@ -33,12 +29,7 @@ public class ManualIntake extends Command {
// Called every time the scheduler runs while the command is scheduled.
@Override
- public void execute() {
- if(m_XboxController.getYButton()==true)
- {
- m_subsystem.extend();
- }
- }
+ public void execute() {}
// Called once the command ends or is interrupted.
@Override
diff --git a/src/main/java/frc/robot/commands/ManualHopperCommand.java b/src/main/java/frc/robot/commands/ManualHopperCommand.java
deleted file mode 100644
index 1c552f7..0000000
--- a/src/main/java/frc/robot/commands/ManualHopperCommand.java
+++ /dev/null
@@ -1,58 +0,0 @@
-// 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 frc.robot.commands;
-
-import frc.robot.subsystems.HopperSubsystem;
-import edu.wpi.first.wpilibj.XboxController;
-import edu.wpi.first.wpilibj2.command.Command;
-
-/** An example command that uses an example subsystem. */
-public class ManualHopperCommand extends Command {
- private final HopperSubsystem m_subsystem;
- private final XboxController m_xboxController;
-
- public ManualHopperCommand(HopperSubsystem subsystem, XboxController xboxController) {
- m_subsystem = subsystem;
- m_xboxController = xboxController;
- addRequirements(subsystem);
- }
-
- // Called when the command is initially scheduled.
- @Override
- public void initialize() {
- m_subsystem.spindexerOn();
- }
-
- // Called every time the scheduler runs while the command is scheduled.
- @Override
- public void execute() {
- if(m_xboxController.getLeftTriggerAxis()>.5 && m_xboxController.getRightTriggerAxis()>.2)
- {
- m_subsystem.feedKicker();
- }
- else
- {
- m_subsystem.stopKicker();
- }
- if(m_xboxController.getRightBumper())
- {
- m_subsystem.spindexerOn();
- }
- if(m_xboxController.getLeftBumper())
- {
- m_subsystem.spindexerOff();
- }
- }
-
- // 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() {
- return false;
- }
-}
diff --git a/src/main/java/frc/robot/commands/ManualShootCommand.java b/src/main/java/frc/robot/commands/ManualShootCommand.java
deleted file mode 100644
index dbe750c..0000000
--- a/src/main/java/frc/robot/commands/ManualShootCommand.java
+++ /dev/null
@@ -1,48 +0,0 @@
-// 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 frc.robot.commands;
-
-import frc.robot.subsystems.TurretSubsystem;
-import edu.wpi.first.wpilibj.XboxController;
-import edu.wpi.first.wpilibj.GenericHID.RumbleType;
-import edu.wpi.first.wpilibj2.command.Command;
-
-/** An example command that uses an example subsystem. */
-public class ManualShootCommand extends Command {
- private final TurretSubsystem m_subsystem;
- private final XboxController m_controller;
-
- public ManualShootCommand(TurretSubsystem subsystem, XboxController controller) {
- m_subsystem = subsystem;
- m_controller = controller;
- // Use addRequirements() here to declare subsystem dependencies.
- addRequirements(subsystem);
- }
-
- // Called every time the scheduler runs while the command is scheduled.
- @Override
- public void execute() {
- if(m_controller.getRightTriggerAxis()>.5 && m_controller.getLeftTriggerAxis()==0)
- {
- m_subsystem.startRotate(-.5);
- m_controller.setRumble(RumbleType.kRightRumble, 1);
- }
- else if(m_controller.getLeftTriggerAxis()>.5 && m_controller.getRightTriggerAxis()==0)
- {
- m_subsystem.startRotate(.5);
- m_controller.setRumble(RumbleType.kLeftRumble, 1);
- }
- else
- {
- m_subsystem.startRotate(0);
- m_controller.setRumble(RumbleType.kBothRumble, 0);
- }
- }
-
- @Override
- public boolean isFinished() {
- return false;
- }
-}
diff --git a/src/main/java/frc/robot/commands/RelayCommand.java b/src/main/java/frc/robot/commands/RelayCommand.java
new file mode 100644
index 0000000..33648e4
--- /dev/null
+++ b/src/main/java/frc/robot/commands/RelayCommand.java
@@ -0,0 +1,63 @@
+package frc.robot.commands;
+
+import edu.wpi.first.units.Units;
+import edu.wpi.first.units.measure.Angle;
+import edu.wpi.first.wpilibj2.command.Command;
+import edu.wpi.first.wpilibj2.command.CommandScheduler;
+import edu.wpi.first.wpilibj2.command.Commands;
+import frc.robot.Constants;
+import frc.robot.subsystems.HopperSubsystem;
+import frc.robot.subsystems.IntakeSubsystem;
+import frc.robot.subsystems.TurretSubsystem;
+
+public class RelayCommand extends Command{
+
+ private HopperSubsystem hopperSubsystem;
+ private TurretSubsystem turretSubsystem;
+ private IntakeSubsystem intakeSubsystem;
+
+ private Command waitCommand = Commands.waitSeconds(1.5);
+
+ public RelayCommand(HopperSubsystem hopperSubsystem, TurretSubsystem turretSubsystem, IntakeSubsystem intakeSubsystem){
+ this.hopperSubsystem = hopperSubsystem;
+ this.turretSubsystem = turretSubsystem;
+ this.intakeSubsystem = intakeSubsystem;
+
+ addRequirements(hopperSubsystem, turretSubsystem, intakeSubsystem);
+ }
+
+ @Override
+ public void initialize() {
+ turretSubsystem.setTargetElevation(Constants.ShooterConstants.DEFLECTOR_SET_ANGLE3);
+ turretSubsystem.setLauncher(6000);
+ hopperSubsystem.spindexerOn();
+ CommandScheduler.getInstance().schedule(waitCommand);
+ turretSubsystem.setTurretMotorRotation(1); // Return to 0 after MIAMI VALLEY
+ }
+
+ @Override
+ public void execute() {
+ if(turretSubsystem.isLauncherUpToSpeed() && waitCommand.isFinished()){
+ hopperSubsystem.feedKicker();
+ }else{
+ hopperSubsystem.stopKicker();
+ }
+ }
+
+ @Override
+ public boolean isFinished() {
+ return false;
+ }
+
+ @Override
+ public void end(boolean interrupted) {
+ waitCommand.cancel();
+ hopperSubsystem.spindexerOff();
+ hopperSubsystem.stopKicker();
+
+ turretSubsystem.setLauncher(0);
+ turretSubsystem.setTargetElevation(Constants.ShooterConstants.DEFLECTOR_STORED_ANGLE);
+ turretSubsystem.setTurretMotorRotation(-0.34); // Return to 0 after MIAMI VALLEY
+ }
+
+}
diff --git a/src/main/java/frc/robot/commands/ZoneCheck.java b/src/main/java/frc/robot/commands/ZoneCheck.java
new file mode 100644
index 0000000..62f5359
--- /dev/null
+++ b/src/main/java/frc/robot/commands/ZoneCheck.java
@@ -0,0 +1,79 @@
+package frc.robot.commands;
+
+import org.fairportrobotics.frc.robolib.vision.limelight.LimelightHelpers;
+
+import edu.wpi.first.apriltag.AprilTagFieldLayout;
+import edu.wpi.first.apriltag.AprilTagFields;
+import edu.wpi.first.wpilibj.DriverStation;
+import edu.wpi.first.wpilibj.DriverStation.Alliance;
+import edu.wpi.first.wpilibj2.command.Command;
+import frc.robot.Constants;
+
+public class ZoneCheck extends Command {
+
+ private AprilTagFieldLayout fieldTags = AprilTagFieldLayout.loadField(AprilTagFields.k2026RebuiltWelded);
+ private Zone zone;
+
+ public enum Zone {
+ Blue,
+ Red,
+ Neutral;
+ }
+
+ public ZoneCheck() {
+ getBotPose();
+ }
+
+ @Override
+ public void initialize() {
+ DriverStation.getAlliance().ifPresent((aliance) -> {
+ if (aliance == Alliance.Blue) {
+ switch (zone) {
+ case Blue:
+ System.out.println("Im Home");
+ case Neutral:
+ System.out.println("Uhhhhhhhh not red");
+ ;
+ default:
+ System.out.println("BOOOOO, BOOOO RED");
+ ;
+ }
+ } else {
+ switch (zone) {
+ case Blue:
+ System.out.println("Screw Blue");
+ ;
+ case Neutral:
+ System.out.println("Uhhhhhhhh not red");
+ ;
+ default:
+ System.out.println("Im Home");
+ }
+ }
+ });
+ }
+
+ @Override
+ public void execute() {
+
+ }
+
+ @Override
+ public boolean isFinished() {
+ return false;
+ }
+
+ private double[] getBotPose() {
+ return LimelightHelpers.getBotPose_wpiBlue(Constants.CameraConstanst.BACK_CAMERA_NAME);
+ }
+
+ private void getZone() {
+ if (getBotPose()[0] >= Constants.CameraConstanst.RED_ZONE_COOR[0]) {
+ zone = Zone.Red;
+ } else if (getBotPose()[0] >= Constants.CameraConstanst.NEUTRAL_ZONE_COOR[0]) {
+ zone = Zone.Neutral;
+ } else {
+ zone = Zone.Blue;
+ }
+ }
+}
diff --git a/src/main/java/frc/robot/subsystems/DriveSubsystem.java b/src/main/java/frc/robot/subsystems/DriveSubsystem.java
index 485a5f0..85b5c8e 100644
--- a/src/main/java/frc/robot/subsystems/DriveSubsystem.java
+++ b/src/main/java/frc/robot/subsystems/DriveSubsystem.java
@@ -10,6 +10,8 @@ import org.fairportrobotics.frc.robolib.vision.limelight.LimelightHelpers;
import org.littletonrobotics.junction.Logger;
import com.pathplanner.lib.auto.AutoBuilder;
+import com.pathplanner.lib.auto.NamedCommands;
+import com.pathplanner.lib.commands.PathPlannerAuto;
import com.pathplanner.lib.config.PIDConstants;
import com.pathplanner.lib.config.RobotConfig;
import com.pathplanner.lib.controllers.PPHolonomicDriveController;
@@ -50,8 +52,8 @@ public class DriveSubsystem extends TestableSubsystem {
driveSystem = swerveBuilder
.withCanbusName("Drive")
.withPigeonId(Constants.ExtraIDEntities.PIGEON_ID)
- .withMaxLinearVelocity(3.0)
- .withMaxAngularVelocity(Math.PI)
+ .withMaxLinearVelocity(Constants.RobotChassisLimits.MAX_ROBOT_LINEAR_VELOCITY)
+ .withMaxAngularVelocity(Constants.RobotChassisLimits.MAX_ROBOT_ANGULAR_VELOCITY)
.withSwerveModule(
swerveBuilder.new SwerveModuleBuilder()
.withDriveMotorId(Constants.SwerveDriveIDs.FRONT_LEFT_DRIVE_ID)
@@ -133,9 +135,8 @@ public class DriveSubsystem extends TestableSubsystem {
.build())
.build();
-
// Set vision measurement confidence values
- driveSystem.getPoseEstimator().setVisionMeasurementStdDevs(VecBuilder.fill(0.7, 0.7, 0.7, 9999999));
+ driveSystem.getPoseEstimator().setVisionMeasurementStdDevs(VecBuilder.fill(0.7, 0.7, 0.7, 999999));
this.setDefaultCommand(Commands.run(new Runnable() {
@@ -163,8 +164,8 @@ public class DriveSubsystem extends TestableSubsystem {
driveSystem::getRobotRelativeSpeeds,
(speeds, feedforwards) -> driveSystem.setChassisSpeed(speeds, new Translation2d()),
new PPHolonomicDriveController(
- new PIDConstants(5.0, 0, 0),
- new PIDConstants(5.0, 0, 0)),
+ new PIDConstants(1.5, 0, 0),
+ new PIDConstants(Math.PI / 2, 0, 0)),
config,
() -> {
var alliance = DriverStation.getAlliance();
@@ -193,12 +194,12 @@ public class DriveSubsystem extends TestableSubsystem {
Logger.recordOutput("RobotPose", driveSystem.getRobotPose3d());
LimelightHelpers.PoseEstimate frontCameraPose = LimelightHelpers.getBotPoseEstimate_wpiBlue(Constants.CameraConstanst.FRONT_CAMERA_NAME);
- if(frontCameraPose.tagCount >= 1){
+ if (frontCameraPose.tagCount >= 1) {
driveSystem.getPoseEstimator().addVisionMeasurement(new Pose3d(frontCameraPose.pose), frontCameraPose.timestampSeconds);
Logger.recordOutput("FrontPoseEstimate", frontCameraPose.pose);
}
LimelightHelpers.PoseEstimate backCameraPose = LimelightHelpers.getBotPoseEstimate_wpiBlue(Constants.CameraConstanst.BACK_CAMERA_NAME);
- if(backCameraPose.tagCount >= 1){
+ if (backCameraPose.tagCount >= 1) {
driveSystem.getPoseEstimator().addVisionMeasurement(new Pose3d(backCameraPose.pose), backCameraPose.timestampSeconds);
Logger.recordOutput("BackPoseEstimate", backCameraPose.pose);
}
@@ -210,15 +211,15 @@ public class DriveSubsystem extends TestableSubsystem {
driveSystem.simulationPeriodic();
}
- public Command getAutoCommand(){
+ public Command getAutoCommand() {
return autoChooser.getSelected();
}
- public void stopDrive(){
- driveSystem.setChassisSpeed(ChassisSpeeds.fromRobotRelativeSpeeds(0,0,0, driveSystem.getGyro().getRotation2d()), Translation2d.kZero);
+ public void stopDrive() {
+ driveSystem.setChassisSpeed(ChassisSpeeds.fromRobotRelativeSpeeds(0, 0, 0, driveSystem.getGyro().getRotation2d()), Translation2d.kZero);
}
- public void rotateChassis(double rotSpeed){
+ public void rotateChassis(double rotSpeed) {
driveSystem.setChassisSpeed(ChassisSpeeds.fromRobotRelativeSpeeds(0, 0, rotSpeed, driveSystem.getGyro().getRotation2d()), Translation2d.kZero);
}
diff --git a/src/main/java/frc/robot/subsystems/HopperSubsystem.java b/src/main/java/frc/robot/subsystems/HopperSubsystem.java
index a8bae7d..e8e4e53 100644
--- a/src/main/java/frc/robot/subsystems/HopperSubsystem.java
+++ b/src/main/java/frc/robot/subsystems/HopperSubsystem.java
@@ -6,36 +6,84 @@ package frc.robot.subsystems;
import org.fairportrobotics.frc.posty.TestableSubsystem;
import org.fairportrobotics.frc.posty.test.PostTest;
+import org.littletonrobotics.junction.Logger;
+import com.ctre.phoenix6.StatusSignal;
+import com.ctre.phoenix6.configs.ClosedLoopGeneralConfigs;
import com.ctre.phoenix6.configs.MotorOutputConfigs;
+import com.ctre.phoenix6.configs.Slot0Configs;
+import com.ctre.phoenix6.configs.TalonFXConfiguration;
+import com.ctre.phoenix6.controls.VelocityVoltage;
import com.ctre.phoenix6.hardware.TalonFX;
+import edu.wpi.first.units.AngularVelocityUnit;
+import edu.wpi.first.units.Units;
+import edu.wpi.first.units.measure.AngularVelocity;
+
import static org.fairportrobotics.frc.posty.assertions.Assertions.*;
import frc.robot.Constants;
public class HopperSubsystem extends TestableSubsystem {
private TalonFX spindexerMotor;
+
+
private TalonFX kickerMotor;
+ private VelocityVoltage kickerControl = new VelocityVoltage(0);
+ private StatusSignal kickerVelocity;
+
/** Creates a new HopperSubsystem. */
public HopperSubsystem() {
spindexerMotor = new TalonFX(Constants.HopperConstants.SPINDEXER_MOTOR_ID);
- spindexerMotor.getConfigurator().apply(new MotorOutputConfigs().withInverted(Constants.HopperConstants.SPINDEXER_MOTOR_DIRECTION));
+ spindexerMotor.getConfigurator().apply(
+ new TalonFXConfiguration()
+ .withMotorOutput(
+ new MotorOutputConfigs()
+ .withInverted(Constants.HopperConstants.SPINDEXER_MOTOR_DIRECTION))
+ .withSlot0(
+ new Slot0Configs()
+ .withKP(0)
+ .withKI(0)
+ .withKD(0)
+ .withKS(0)));
kickerMotor = new TalonFX(Constants.HopperConstants.KICKER_MOTOR_ID);
- kickerMotor.getConfigurator().apply(new MotorOutputConfigs().withInverted(Constants.HopperConstants.KICKER_MOTOR_DIRECTION));
+ kickerMotor.getConfigurator().apply(
+ new TalonFXConfiguration()
+ .withMotorOutput(
+ new MotorOutputConfigs()
+ .withInverted(Constants.HopperConstants.KICKER_MOTOR_DIRECTION)
+ )
+ .withSlot0(new Slot0Configs()
+ .withKP(0)
+ .withKI(0)
+ .withKD(0)
+ .withKS(0)
+ ));
+ kickerVelocity = kickerMotor.getVelocity();
}
- public void feedKicker() {kickerMotor.set(0.5);}
+ public void feedKicker() {
+ kickerMotor.setControl(kickerControl.withVelocity(1000));
+ // kickerMotor.set(0.75);
+ }
- public void reverseKicker() {kickerMotor.set(-0.5);}
+ public void reverseKicker() {
+ kickerMotor.setControl(kickerControl.withVelocity(-500));
+ // kickerMotor.set(-0.5);
+ }
public void stopKicker() {kickerMotor.stopMotor();}
- public void spindexerOn() { spindexerMotor.set(0.5);}
+ public void spindexerOn() { spindexerMotor.set(0.75);}
public void spindexerOff() { spindexerMotor.stopMotor();}
+ @Override
+ public void periodic() {
+ Logger.recordOutput("HopperSubsystem-KickerSpeed(Rotations/sec)", kickerVelocity.refresh().getValue().in(Units.RotationsPerSecond));
+ }
+
@PostTest(enabled = true)
public void hopperSystem_CANDevicesConnected(){
assertThat(kickerMotor.isConnected()).as("Kicker motor not connected!").isTrue();
diff --git a/src/main/java/frc/robot/subsystems/IntakeSubsystem.java b/src/main/java/frc/robot/subsystems/IntakeSubsystem.java
index a200006..7d0e930 100644
--- a/src/main/java/frc/robot/subsystems/IntakeSubsystem.java
+++ b/src/main/java/frc/robot/subsystems/IntakeSubsystem.java
@@ -17,6 +17,7 @@ import static org.fairportrobotics.frc.posty.assertions.Assertions.*;
import static org.fairportrobotics.frc.robolib.motors.Utils.*;
import edu.wpi.first.wpilibj2.command.Command;
+import edu.wpi.first.wpilibj2.command.Commands;
public class IntakeSubsystem extends TestableSubsystem {
/** Creates a new ExampleSubsystem. */
@@ -35,9 +36,21 @@ public class IntakeSubsystem extends TestableSubsystem {
deployMotor.setInverted(Constants.IntakeConstants.DEPLOY_MOTOR_INVERTED);
}
- public void extend()
+ public Command deploy()
{
- deployMotor.set(1);
+ return Commands.sequence(
+ Commands.deadline(
+ Commands.waitSeconds(2),
+ this.runOnce(
+ () -> {deployMotor.set(1);} // Bump this speed up if intake doesn't deploy
+ )
+ ),
+ this.runOnce(() -> deployMotor.stopMotor())
+ );
+ }
+
+ public Command resetDeploy(){
+ return this.runEnd(() -> deployMotor.set(-1), () -> deployMotor.stopMotor());
}
public void setSpeed(double speed)
@@ -45,19 +58,14 @@ public class IntakeSubsystem extends TestableSubsystem {
intakeMotor.set(speed);
}
- public Command startSpeedCommand()
+ public Command intake()
{
- return this.runOnce(() -> setSpeed(-.5));
+ return this.runOnce(() -> {if(intakeMotor.get()==0){setSpeed(-.5);}else{intakeMotor.stopMotor();}});
}
- public Command killSpeedCommand()
+ public Command reverseIntake()
{
- return this.runOnce(() -> setSpeed(0));
- }
-
- public Command revSpeedCommand()
- {
- return this.runOnce(() -> setSpeed(.5));
+ return this.runEnd(() -> setSpeed(.5), () -> { intakeMotor.stopMotor();});
}
@PostTest(enabled = true)
diff --git a/src/main/java/frc/robot/subsystems/TurretSubsystem.java b/src/main/java/frc/robot/subsystems/TurretSubsystem.java
index 87af396..3391db5 100644
--- a/src/main/java/frc/robot/subsystems/TurretSubsystem.java
+++ b/src/main/java/frc/robot/subsystems/TurretSubsystem.java
@@ -11,15 +11,22 @@ import org.littletonrobotics.junction.Logger;
import static org.fairportrobotics.frc.posty.assertions.Assertions.*;
import com.ctre.phoenix6.controls.PositionVoltage;
+import com.ctre.phoenix6.StatusSignal;
import com.ctre.phoenix6.configs.CurrentLimitsConfigs;
+import com.ctre.phoenix6.configs.FeedbackConfigs;
import com.ctre.phoenix6.configs.MotorOutputConfigs;
import com.ctre.phoenix6.configs.Slot0Configs;
+import com.ctre.phoenix6.configs.SoftwareLimitSwitchConfigs;
import com.ctre.phoenix6.configs.TalonFXConfiguration;
import com.ctre.phoenix6.hardware.TalonFX;
+import com.ctre.phoenix6.signals.ForwardLimitValue;
import com.ctre.phoenix6.signals.InvertedValue;
+import com.ctre.phoenix6.signals.ReverseLimitValue;
+import com.ctre.phoenix6.sim.TalonFXSimState;
import com.revrobotics.PersistMode;
import com.revrobotics.ResetMode;
import com.revrobotics.spark.ClosedLoopSlot;
+import com.revrobotics.spark.FeedbackSensor;
import com.revrobotics.spark.SparkClosedLoopController;
import com.revrobotics.spark.SparkMax;
import com.revrobotics.spark.SparkBase.ControlType;
@@ -27,29 +34,36 @@ import com.revrobotics.spark.SparkLowLevel.MotorType;
import com.revrobotics.spark.config.SparkMaxConfig;
import frc.robot.Constants;
+import edu.wpi.first.units.AngleUnit;
+import edu.wpi.first.units.Units;
import edu.wpi.first.units.measure.Angle;
import edu.wpi.first.wpilibj.DigitalInput;
import edu.wpi.first.wpilibj.Servo;
import edu.wpi.first.wpilibj2.command.Command;
+import edu.wpi.first.wpilibj2.command.Commands;
public class TurretSubsystem extends TestableSubsystem {
public enum TurretState {
INIT,
HOMING,
- MANUAL;
+ READY;
}
private final boolean LOGGING = true;
- private TurretState currentState;
+ private TurretState turretState;
private DigitalInput turretLimitSwitch;
private TalonFX turretMotor;
+ private PositionVoltage turretControlMode = new PositionVoltage(0);
+ private TalonFXSimState turretSim;
+ private StatusSignal turretMotorPosition;
+ private StatusSignal turretMotorForwardLimit;
+ private StatusSignal turretMotorReverseLimit;
private SparkMax launcherMotor;
private SparkClosedLoopController launcherControler;
+ private double turretOffsetInRotations = 0;
+
private Servo hood;
- private Angle limitPos;
- private Angle limitNeg;
- private boolean turretGoingPos;
public TurretSubsystem() {
@@ -60,9 +74,10 @@ public class TurretSubsystem extends TestableSubsystem {
new TalonFXConfiguration()
.withSlot0(
new Slot0Configs()
- .withKP(1.0)
+ .withKP(6)
.withKI(0)
- .withKD(0)
+ .withKD(0.3)
+ .withKS(0)
)
.withMotorOutput(
new MotorOutputConfigs()
@@ -70,35 +85,53 @@ public class TurretSubsystem extends TestableSubsystem {
)
.withCurrentLimits(
new CurrentLimitsConfigs()
+ .withStatorCurrentLimit(50)
+ )
+ .withSoftwareLimitSwitch(new SoftwareLimitSwitchConfigs().withForwardSoftLimitEnable(false).withReverseSoftLimitEnable(false))
+ .withFeedback(
+ new FeedbackConfigs()
+ .withFeedbackRotorOffset(0)
)
);
+ turretMotorPosition = turretMotor.getPosition();
+ turretMotorForwardLimit = turretMotor.getForwardLimit();
+ turretMotorReverseLimit = turretMotor.getReverseLimit();
+
+ turretSim = turretMotor.getSimState();
// Launcher configuration
launcherMotor = new SparkMax(Constants.ShooterConstants.LAUNCHER_MOTOR_ID, MotorType.kBrushless);
SparkMaxConfig config = new SparkMaxConfig().apply((SparkMaxConfig) SparkMaxConfig.Presets.REV_NEO);
config.inverted(Constants.ShooterConstants.LAUNCHER_MOTOR_INVERTED);
- config.closedLoop.p(1).i(0).d(0.1);
- config.closedLoop.allowedClosedLoopError(10, ClosedLoopSlot.kSlot0);
+ config.voltageCompensation(10);
+ config.closedLoop.p(0.0001).i(0).d(0.0); // I = 0.0000001
+ config.closedLoop.feedForward.kS(0.2).kV(0.002).kA(0.00);
+ // config.closedLoop.allowedClosedLoopError(10, ClosedLoopSlot.kSlot0);
+ config.closedLoop.feedbackSensor(FeedbackSensor.kPrimaryEncoder);
+ config.closedLoop.positionWrappingEnabled(false);
+ // config.closedLoopRampRate(0.5);
+ // config.smartCurrentLimit(5, 50);
launcherMotor.configure(config, ResetMode.kResetSafeParameters, PersistMode.kPersistParameters);
launcherControler = launcherMotor.getClosedLoopController();
// Hood configuration
hood = new Servo(Constants.ShooterConstants.HOOD_SERVO_CHANNEL);
- currentState = TurretState.INIT;
- limitNeg = Constants.ShooterConstants.LIMIT_AXIMUTH_NEG;
- limitPos = Constants.ShooterConstants.LIMIT_AXIMUTH_POS;
- turretGoingPos = false;
+ turretState = TurretState.INIT;
}
- public void setLauncher(double speed) {launcherControler.setSetpoint(speed, ControlType.kVelocity);}
+ public void setLauncher(double speed) {
+ if(speed == 0)
+ {
+ launcherMotor.stopMotor();
+ return;
+ }
+ launcherControler.setSetpoint(speed, ControlType.kVelocity, ClosedLoopSlot.kSlot0);
+ }
public boolean isLauncherUpToSpeed() {
- return launcherControler.isAtSetpoint();
- }
-
- public void turretControl(double position)
- {
- turretMotor.setControl(new PositionVoltage(position));
+ // Valid if velcity is within 10% of setpoint.
+ // May need to lower this
+ return Math.abs(launcherControler.getSetpoint() - launcherMotor.getEncoder().getVelocity()) >= launcherControler.getSetpoint() * 0.03;
}
public void setTargetElevation(double elev)
@@ -113,97 +146,118 @@ public class TurretSubsystem extends TestableSubsystem {
return this.runOnce(() -> setLauncher(-.5));
}
- public void startHoming()
+ public Command setShooter(int speedRPM){
+ return Commands.runEnd(() -> {
+ setLauncher(speedRPM);
+ }, () -> {
+ launcherMotor.stopMotor();
+ }, this);
+ }
+
+ public void homeTurret()
{
+ if(turretState != TurretState.INIT){
+ return; // Early return, we don't want to home if we already have
+ }
turretMotor.set(Constants.ShooterConstants.HOMING_SPEED);
- currentState = TurretState.HOMING;
+ turretState = TurretState.HOMING;
}
- public void startRotate(double speed)
+ public boolean isTurretReady(){
+ return turretState == TurretState.READY;
+ }
+
+ public void turretRotateDir(double speed)
{
- turretGoingPos=speed>0;
-
- if(!passedLimit())
- {
- turretMotor.set(speed);
- }
- else
- {
- turretMotor.set(0);
- }
+ turretMotor.set(speed);
}
- public boolean passedLimit(){
- return (getTurretAngle().gt(limitPos) && turretGoingPos) || (getTurretAngle().lt(limitNeg) && !turretGoingPos);
- }
-
- public Angle getTurretAngle()
+ public double getTurretAngleRobotRelative()
{
- return turretMotor.getPosition().refresh().getValue().times(Constants.ShooterConstants.TURRET_GEAR_RATIO);
+ return getTurretMotorPosition() / Constants.ShooterConstants.TURRET_GEAR_RATIO;
+ }
+
+ private double getTurretMotorPosition(){
+ return turretMotorPosition.refresh().getValueAsDouble() - turretOffsetInRotations;
}
@Override
public void periodic() {
- // This method will be called once per scheduler run
- switch (currentState) {
- case HOMING:
- periodicHoming();
- break;
- case MANUAL:
- periodicManual();
- break;
- default:
- break;
+ if(turretState == TurretState.HOMING)
+ {
+ turretMotor.set(0.05);
+
+ if(turretLimitSwitch.get())
+ { // Turret has tripped the switch
+ turretMotor.stopMotor();
+ turretOffsetInRotations = (turretMotorPosition.refresh().getValueAsDouble() - 1.323);
+ turretState = TurretState.READY;
+ // Angle forwardLimit = Angle.ofRelativeUnits(-90, Units.Degrees).times(Constants.ShooterConstants.TURRET_GEAR_RATIO).plus(turretOffset);
+ // Angle reverseLimit = Angle.ofRelativeUnits(90, Units.Degrees).times(Constants.ShooterConstants.TURRET_GEAR_RATIO).minus(turretOffset);
+ // Logger.recordOutput("TurretSubsystem-TurretForwardLimit", forwardLimit);
+ // Logger.recordOutput("TurretSubsystem-TurretReverseLimit", reverseLimit);
+ turretMotor.getConfigurator().apply(
+ new SoftwareLimitSwitchConfigs()
+ // .withForwardSoftLimitEnable(true)
+ // .withForwardSoftLimitThreshold(forwardLimit)
+ // .withReverseSoftLimitEnable(true)
+ // .withReverseSoftLimitThreshold(reverseLimit)
+ );
+ // setTurretRobotRelative(Angle.ofRelativeUnits(0, Units.Degrees));
+ setTurretMotorRotation(-0.34); // Return to 0 after MIAMI VALLEY
+ }
}
if(LOGGING)
{
- Logger.recordOutput("Launcher Speed (RPM)", launcherMotor.getEncoder().getVelocity());
+ Logger.recordOutput("TurretSubsystem-TurretLimitSwitch", turretLimitSwitch.get());
+ Logger.recordOutput("TurretSubsystem-Launcher Speed (RPM)", launcherMotor.getEncoder().getVelocity());
+ Logger.recordOutput("TurretSubsystem-TurretState", turretState);
+ Logger.recordOutput("TurretSubsystem-TurretPosition", getTurretAngleRobotRelative());
+ Logger.recordOutput("TurretSubsystem-TurretMotorPositionWithOffset", getTurretMotorPosition());
+ Logger.recordOutput("TurretSubsystem-TurretMotorPositionRaw", turretMotorPosition.refresh().getValue().in(Units.Degrees));
+ Logger.recordOutput("TurretSubsystem-TurretRequestedPosRaw", turretControlMode.getPositionMeasure().in(Units.Degrees));
+ Logger.recordOutput("TurretSubsystem-TurretRequestedPos", getRequestedPosTurretRelative());
+ Logger.recordOutput("TurretSubsystem-TurretOffset", turretOffsetInRotations);
+ Logger.recordOutput("TurretSubsystem-TurretForwardLimitHit", turretMotorForwardLimit.refresh().getValue());
+ Logger.recordOutput("TurretSubsystem-TurretReverseLimitHit", turretMotorReverseLimit.refresh().getValue());
}
}
- private void periodicHoming()
+ public void setTurretFieldRelative(double pos)
{
- if(turretLimitSwitch.get())
+ if(turretState != TurretState.READY)
{
- currentState = TurretState.MANUAL;
- turretMotor.set(0);
- turretMotor.setPosition(0);
- goTo(limitPos);
+ // Not ready to set angle
+ return;
}
}
- private void goTo(Angle pos)
+ public void setTurretRobotRelative(double pos)
{
- if(pos.gt(limitNeg) && pos.lt(limitPos))
+ if(turretState != TurretState.READY)
{
- while(getTurretAngle()!=pos)
- {
- if(getTurretAngle().gt(pos))
- {
- turretMotor.set(.5);
- }
- else
- {
- turretMotor.set(-.5);
- }
- }
+ // Not ready to set angle
+ return;
}
+
+ setTurretMotorRotation(pos * Constants.ShooterConstants.TURRET_GEAR_RATIO);
}
- private void periodicManual()
- {
- if(passedLimit())
- {
- turretMotor.set(0);
- }
+ public void setTurretMotorRotation(double pos){
+ turretMotor.setControl(turretControlMode.withPosition((pos + turretOffsetInRotations)));
+ turretSim.setRawRotorPosition(pos + turretOffsetInRotations);
+ }
+
+ private double getRequestedPosTurretRelative() {
+ return (turretControlMode.getPositionMeasure().in(Units.Rotations) - turretOffsetInRotations) / Constants.ShooterConstants.TURRET_GEAR_RATIO;
}
@PostTest()
public void TurretSubsystem_CANDevicesConnected(){
- assertThat(launcherMotor.getDeviceId()).as("Launcher motor not connected!").isGreaterThan(0);
+ assertThat(launcherMotor.getFaults().can).as("Launcher motor not connected!").isFalse();
assertThat(turretMotor.isConnected()).as("Turret motor not connected!").isTrue();
}