diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml deleted file mode 100644 index ff7cce9..0000000 --- a/.github/workflows/main.yml +++ /dev/null @@ -1,30 +0,0 @@ -# This is a basic workflow to build robot code. -name: CI -# Controls when the action will run. Triggers the workflow on push or pull request -# events but only for the main branch. -on: - push: - branches: [ main ] - pull_request: - branches: [ main ] -# A workflow run is made up of one or more jobs that can run sequentially or in parallel -jobs: - # This workflow contains a single job called "build" - build: - # The type of runner that the job will run on - runs-on: ubuntu-22.04 - # This grabs the WPILib docker container - container: wpilib/roborio-cross-ubuntu:2025-22.04 - # Steps represent a sequence of tasks that will be executed as part of the job - steps: - # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - - uses: actions/checkout@v4 - # Declares the repository safe and not under dubious ownership. - - name: Add repository to git safe directories - run: git config --global --add safe.directory $GITHUB_WORKSPACE - # Grant execute permission for gradlew - - name: Grant execute permission for gradlew - run: chmod +x gradlew - # Runs a single command using the runners shell - - name: Compile and run tests on robot code - run: ./gradlew build diff --git a/README.md b/README.md deleted file mode 100644 index d83f9f7..0000000 --- a/README.md +++ /dev/null @@ -1 +0,0 @@ -[![CI](https://github.com/FRC5188/RebuiltCode/actions/workflows/main.yml/badge.svg)](https://github.com/FRC5188/RebuiltCode/actions/workflows/main.yml) diff --git a/build.gradle b/build.gradle index 648c456..675725f 100644 --- a/build.gradle +++ b/build.gradle @@ -1,4 +1,3 @@ - plugins { id "java" id "edu.wpi.first.GradleRIO" version "2026.1.1" @@ -11,14 +10,6 @@ java { targetCompatibility = JavaVersion.VERSION_17 } -sourceSets { - main { - java { - exclude 'frc/robot/subsystems/w8_examples/**' - } - } -} - def ROBOT_MAIN_CLASS = "frc.robot.Main" // Define my targets (RoboRIO) and artifacts (deployable files) @@ -133,7 +124,7 @@ spotless { java { target fileTree('.') { include '**/*.java' - exclude '**/build/**', '**/build-*/**', '**/bin/**', '**/frc/robot/subsystems/w8_examples/**' + exclude '**/build/**', '**/build-*/**', '**/bin/**' } toggleOffOn() googleJavaFormat() @@ -144,7 +135,7 @@ spotless { groovyGradle { target fileTree('.') { include '**/*.gradle' - exclude '**/build/**', '**/build-*/**', '**/frc/robot/subsystems/w8_examples/**' + exclude '**/build/**', '**/build-*/**' } greclipse() indentWithSpaces(4) diff --git a/src/main/java/frc/robot/Constants.java b/src/main/java/frc/robot/Constants.java index 2e4003d..dc018b7 100644 --- a/src/main/java/frc/robot/Constants.java +++ b/src/main/java/frc/robot/Constants.java @@ -13,8 +13,6 @@ package frc.robot; -import static edu.wpi.first.units.Units.Inches; -import static edu.wpi.first.units.Units.Volts; import static edu.wpi.first.units.Units.Inches; import static edu.wpi.first.units.Units.Meters; import static edu.wpi.first.units.Units.Rotations; @@ -27,13 +25,12 @@ import edu.wpi.first.math.geometry.Translation2d; import edu.wpi.first.math.geometry.Translation3d; import edu.wpi.first.units.AngularAccelerationUnit; -import edu.wpi.first.units.AngularVelocityUnit; import edu.wpi.first.units.measure.Angle; import edu.wpi.first.units.measure.AngularAcceleration; import edu.wpi.first.units.measure.AngularVelocity; import edu.wpi.first.units.measure.Distance; +import edu.wpi.first.units.measure.LinearVelocity; import edu.wpi.first.units.measure.Velocity; -import edu.wpi.first.units.measure.Voltage; import edu.wpi.first.wpilibj.RobotBase; import frc.lib.W8.mechanisms.linear.LinearMechanism.LinearMechCharacteristics; import frc.lib.W8.mechanisms.rotary.RotaryMechanism.RotaryMechCharacteristics; @@ -88,13 +85,7 @@ public class HopperConstants { public static final Distance MIN_DISTANCE = Inches.of(0.0); public static final Distance MAX_DISTANCE = Inches.of(15.0); public static final Distance STARTING_DISTANCE = Inches.of(0.0); - - // CHANGE TO PROPER RPMS !!!! - public static final double SLOW_SPEED_RPM = 0.0; - public static final double FAST_SPEED_RPM = 0.0; - public static final double REVERSE_SPEED_RPM = 0.0; - public static final Voltage VOLTAGE = Volts.of(12.0); - public static final Distance DRUM_RADIUS = Inches.of(2.0); + private static final Distance DRUM_RADIUS = Inches.of(2.0); public static final DistanceAngleConverter CONVERTER = new DistanceAngleConverter(DRUM_RADIUS); public static final AngularVelocity ANGULAR_VELOCITY = RotationsPerSecond.of(1); public static final AngularAcceleration ANGULAR_ACCELERATION = RotationsPerSecondPerSecond.of(1); @@ -109,7 +100,7 @@ public class Ports { } public final class ShooterConstants { - // Constants for the Shooter + // Constants for the Shooter public static final Angle ANGLE_TOLERANCE = Rotations.of(0.01); public static final AngularVelocity ANGLE_VELOCITY_TOLERANCE = RotationsPerSecond.of(0.01); public static final AngularVelocity CRUISE_VELOCITY = RotationsPerSecond.of(204); @@ -122,15 +113,10 @@ public final class ShooterConstants { public static final Angle MAX_ANGLE = Rotations.of(10.0); public static final Angle STARTING_ANGLE = Rotations.of(0.0); public static final Distance WHEEL_RADIUS = Meters.of(0.5); - public static final RotaryMechCharacteristics CONSTANTS = - new RotaryMechCharacteristics(OFFSET, WHEEL_RADIUS, MIN_ANGLE, MAX_ANGLE, STARTING_ANGLE); - public static final double IDLE_SPEED_RPM = (1.0); - public static final double HUB_SPEED_RPM = (1.0); - public static final double TOWER_SPEED_RPM = (1.0); - public static final double DEFAULT_SPEED_RPM = (1.0); public static final double FLYWHEEL_VELOCITY_TOLERANCE = 1.0; + public static final RotaryMechCharacteristics CONSTANTS = new RotaryMechCharacteristics(OFFSET, WHEEL_RADIUS, MIN_ANGLE, MAX_ANGLE, STARTING_ANGLE); } - + public static final int CANDLE_ID = 50; public class IntakeConstants { @@ -161,12 +147,7 @@ public class ClimberConstants { public static final Distance STARTING_DISTANCE = Inches.of(0.0); public static final Distance DRUM_RADIUS = Inches.of(2.0); public static final DistanceAngleConverter CONVERTER = new DistanceAngleConverter(DRUM_RADIUS); - public static final LinearMechCharacteristics CHARACTERISTICS = - new LinearMechCharacteristics( - new Translation3d(0.0, 0.0, 0.0), - MIN_DISTANCE, - MAX_DISTANCE, - STARTING_DISTANCE, - CONVERTER); + public static final LinearMechCharacteristics CHARACTERISTICS = new LinearMechCharacteristics(new Translation3d(0.0, 0.0, 0.0), MIN_DISTANCE, MAX_DISTANCE, STARTING_DISTANCE, CONVERTER); + public static final double CLIMBER_SPEED = 1.0; } } diff --git a/src/main/java/frc/robot/subsystems/LEDs/LEDs.java b/src/main/java/frc/robot/subsystems/LEDs/LEDs.java index 77517da..aba0e14 100644 --- a/src/main/java/frc/robot/subsystems/LEDs/LEDs.java +++ b/src/main/java/frc/robot/subsystems/LEDs/LEDs.java @@ -10,7 +10,6 @@ public LEDs(LightsIO io) { _io = io; } - @Override - public void periodic() {} - + @Override + public void periodic() {} } diff --git a/src/main/java/frc/robot/subsystems/Vision/Vision.java b/src/main/java/frc/robot/subsystems/Vision/Vision.java deleted file mode 100644 index ba4b9dc..0000000 --- a/src/main/java/frc/robot/subsystems/Vision/Vision.java +++ /dev/null @@ -1,18 +0,0 @@ -package frc.robot.subsystems.Vision; - -import edu.wpi.first.wpilibj2.command.SubsystemBase; -import frc.robot.Constants; -import frc.lib.W8.io.vision.VisionIO; - -public class Vision extends SubsystemBase { - private final VisionIO _io; - - public Vision(VisionIO io) { - _io = io; - } - - @Override - public void periodic() { - - } -} diff --git a/src/main/java/frc/robot/subsystems/climber/Climber.java b/src/main/java/frc/robot/subsystems/climber/Climber.java index 7be04be..2591a93 100644 --- a/src/main/java/frc/robot/subsystems/climber/Climber.java +++ b/src/main/java/frc/robot/subsystems/climber/Climber.java @@ -1,7 +1,11 @@ package frc.robot.subsystems.climber; +import edu.wpi.first.units.Units; +import edu.wpi.first.units.measure.LinearVelocity; +import edu.wpi.first.units.measure.Velocity; import edu.wpi.first.wpilibj2.command.SubsystemBase; import frc.lib.W8.mechanisms.linear.LinearMechanism; +import frc.robot.Constants.ClimberConstants; public class Climber extends SubsystemBase { private LinearMechanism _io; @@ -10,6 +14,18 @@ public Climber(LinearMechanism io) { io = _io; } + public enum State { + IDLE(Units.MetersPerSecond.of(0.0)), + ASCENDING(Units.MetersPerSecond.of(ClimberConstants.CLIMBER_SPEED)), + DESCENDING(Units.MetersPerSecond.of(-ClimberConstants.CLIMBER_SPEED)); + + private final LinearVelocity stateVelocity; + + private State(LinearVelocity stateVelocity) { + this.stateVelocity = stateVelocity; + } + } + @Override public void periodic() {} } diff --git a/src/main/java/frc/robot/subsystems/hopper/Hopper.java b/src/main/java/frc/robot/subsystems/hopper/Hopper.java index e86d633..95f1b8e 100644 --- a/src/main/java/frc/robot/subsystems/hopper/Hopper.java +++ b/src/main/java/frc/robot/subsystems/hopper/Hopper.java @@ -9,37 +9,20 @@ import frc.robot.Constants; import frc.robot.Constants.HopperConstants; -import static edu.wpi.first.units.Units.*; - -import edu.wpi.first.units.measure.*; -import frc.robot.Constants.HopperConstants.*; - public class Hopper extends SubsystemBase { - private FlywheelMechanism _io; - - public enum State - { - OFF (RevolutionsPerSecond.of(0.0)), - FORWARD_SLOW (RevolutionsPerSecond.of(HopperConstants.SLOW_SPEED_RPM/60)), - FORWARD_FAST (RevolutionsPerSecond.of(HopperConstants.FAST_SPEED_RPM/60)), - REVERSE (RevolutionsPerSecond.of(HopperConstants.REVERSE_SPEED_RPM/60)); - - private final AngularVelocity _stateVelocity; - private State(AngularVelocity stateVelocity) { - _stateVelocity = stateVelocity; - } - } +private FlywheelMechanism _io; - public Hopper(FlywheelMechanism io) { - _io = io; - } +public Hopper(FlywheelMechanism io) { +_io = io; +} - public void setGoal(double position) { - Distance positionInches = Inches.of(position); - _io.runPosition(HopperConstants.CONVERTER.toAngle(positionInches), HopperConstants.ANGULAR_VELOCITY, HopperConstants.ANGULAR_ACCELERATION, null, PIDSlot.SLOT_0); - } +public void setGoal(double position) { + Distance positionInches = Inches.of(position); + _io.runPosition(HopperConstants.CONVERTER.toAngle(positionInches), HopperConstants.ANGULAR_VELOCITY, HopperConstants.ANGULAR_ACCELERATION, null, PIDSlot.SLOT_0); +} @Override public void periodic() {} -} + +} \ No newline at end of file diff --git a/src/main/java/frc/robot/subsystems/shooter/Shooter.java b/src/main/java/frc/robot/subsystems/shooter/Shooter.java index bcb6880..ba3067c 100644 --- a/src/main/java/frc/robot/subsystems/shooter/Shooter.java +++ b/src/main/java/frc/robot/subsystems/shooter/Shooter.java @@ -8,17 +8,6 @@ import edu.wpi.first.wpilibj2.command.SubsystemBase; import frc.lib.W8.io.motor.MotorIO.PIDSlot; import frc.lib.W8.mechanisms.flywheel.FlywheelMechanism; -import frc.robot.Constants.ShooterConstants; - -import static edu.wpi.first.units.Units.Inches; -import static edu.wpi.first.units.Units.Meters; -import static edu.wpi.first.units.Units.Rotations; -import static edu.wpi.first.units.Units.RotationsPerSecond; -import static edu.wpi.first.units.Units.RotationsPerSecondPerSecond; -import static edu.wpi.first.units.Units.Second; -import edu.wpi.first.units.Units; -import edu.wpi.first.units.measure.AngularAcceleration; -import edu.wpi.first.units.measure.AngularVelocity; import frc.robot.Constants.FeederConstants; import frc.robot.Constants.ShooterConstants; @@ -47,20 +36,6 @@ public void setFlywheelVelocity(double velocity) { _flywheel.runVelocity(angVelo, ShooterConstants.ACCELERATION, PIDSlot.SLOT_0); } - public enum State { - OFF(Units.RevolutionsPerSecond.of(0.0)), - IDLE(Units.RevolutionsPerSecond.of(ShooterConstants.IDLE_SPEED_RPM/60)), - SHOOT_FROM_HUB(Units.RevolutionsPerSecond.of(ShooterConstants.HUB_SPEED_RPM/60)), - SHOOT_FROM_TOWER(Units.RevolutionsPerSecond.of(ShooterConstants.TOWER_SPEED_RPM/60)), - SHOOT(Units.RevolutionsPerSecond.of(ShooterConstants.DEFAULT_SPEED_RPM/60)), - SHOOT_ON_MOVE(Units.RevolutionsPerSecond.of(ShooterConstants.DEFAULT_SPEED_RPM/60)); - - private final AngularVelocity stateVelocity; - State(AngularVelocity stateVelocity) { - this.stateVelocity = stateVelocity; - } - } - // Checks if the flywheel is at speed and returns a boolean public boolean flyAtVelocity() { return Math.abs(desiredVelo - _flywheel.getVelocity().in(RotationsPerSecond)) diff --git a/src/main/java/frc/robot/subsystems/w8_examples/beambreak1/BeamBreak1.java b/src/main/java/frc/robot/subsystems/w8_examples/beambreak1/BeamBreak1.java deleted file mode 100644 index 6bd1458..0000000 --- a/src/main/java/frc/robot/subsystems/w8_examples/beambreak1/BeamBreak1.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2025 Windham Windup - * - * This program is free software: you can redistribute it and/or modify it under the terms of the - * GNU General Public License as published by the Free Software Foundation, either version 3 of the - * License, or any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without - * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program. If - * not, see . - */ - -package frc.robot.subsystems.beambreak1; - -import edu.wpi.first.wpilibj2.command.SubsystemBase; -import edu.wpi.first.wpilibj2.command.button.Trigger; -import frc.lib.devices.BeamBreak; -import frc.lib.io.beambreak.BeamBreakIO; - -public class BeamBreak1 extends SubsystemBase { - - private final BeamBreak beamBreak; - - public final Trigger broken; - - public BeamBreak1(BeamBreakIO io) - { - beamBreak = new BeamBreak(io); - - broken = new Trigger(beamBreak::isBroken); - } - - @Override - public void periodic() - { - beamBreak.periodic(); - } -} diff --git a/src/main/java/frc/robot/subsystems/w8_examples/beambreak1/BeamBreak1Constants.java b/src/main/java/frc/robot/subsystems/w8_examples/beambreak1/BeamBreak1Constants.java deleted file mode 100644 index 135a77c..0000000 --- a/src/main/java/frc/robot/subsystems/w8_examples/beambreak1/BeamBreak1Constants.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (C) 2025 Windham Windup - * - * This program is free software: you can redistribute it and/or modify it under the terms of the - * GNU General Public License as published by the Free Software Foundation, either version 3 of the - * License, or any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without - * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program. If - * not, see . - */ - -package frc.robot.subsystems.beambreak1; - -import frc.lib.io.beambreak.BeamBreakIO; -import frc.lib.io.beambreak.BeamBreakIODIO; -import frc.lib.io.beambreak.BeamBreakIOSim; -import frc.robot.Constants; -import frc.robot.Ports; - -public class BeamBreak1Constants { - - public final static String NAME = "Beam Break #1"; - - // private final static RangingMode RANGING_MODE = RangingMode.SHORT; - // private final static RegionOfInterest ROI = new RegionOfInterest(8, 8, 4, 4); - // private final static TimingBudget TIMING_BUDGET = TimingBudget.TIMING_BUDGET_20MS; - - - // public static BeamBreakIOLaserCAN getReal() - // { - // return new BeamBreakIOLaserCAN(Ports.laserCAN1, NAME, Millimeters.of(100), RANGING_MODE, - // ROI, TIMING_BUDGET); - - // } - - public static BeamBreak1 get() - { - switch (Constants.currentMode) { - case REAL: - return new BeamBreak1(new BeamBreakIODIO(Ports.diobeambreak, NAME)); - case SIM: - return new BeamBreak1(new BeamBreakIOSim(NAME)); - case REPLAY: - return new BeamBreak1(new BeamBreakIO() {}); - default: - throw new IllegalStateException("Unrecognized Robot Mode"); - } - } -} diff --git a/src/main/java/frc/robot/subsystems/w8_examples/drive/Drive.java b/src/main/java/frc/robot/subsystems/w8_examples/drive/Drive.java deleted file mode 100644 index 5001b96..0000000 --- a/src/main/java/frc/robot/subsystems/w8_examples/drive/Drive.java +++ /dev/null @@ -1,426 +0,0 @@ -/* - * Copyright (C) 2025 Windham Windup - * - * This program is free software: you can redistribute it and/or modify it under the terms of the - * GNU General Public License as published by the Free Software Foundation, either version 3 of the - * License, or any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without - * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program. If - * not, see . - */ - -package frc.robot.subsystems.drive; - -import static edu.wpi.first.units.Units.*; - -import com.ctre.phoenix6.CANBus; -import com.pathplanner.lib.auto.AutoBuilder; -import com.pathplanner.lib.config.ModuleConfig; -import com.pathplanner.lib.config.PIDConstants; -import com.pathplanner.lib.config.RobotConfig; -import com.pathplanner.lib.controllers.PPHolonomicDriveController; -import com.pathplanner.lib.pathfinding.Pathfinding; -import com.pathplanner.lib.util.PathPlannerLogging; -import edu.wpi.first.hal.FRCNetComm.tInstances; -import edu.wpi.first.hal.FRCNetComm.tResourceType; -import edu.wpi.first.hal.HAL; -import edu.wpi.first.math.Matrix; -import edu.wpi.first.math.estimator.SwerveDrivePoseEstimator; -import edu.wpi.first.math.geometry.Pose2d; -import edu.wpi.first.math.geometry.Rotation2d; -import edu.wpi.first.math.geometry.Translation2d; -import edu.wpi.first.math.geometry.Twist2d; -import edu.wpi.first.math.kinematics.ChassisSpeeds; -import edu.wpi.first.math.kinematics.SwerveDriveKinematics; -import edu.wpi.first.math.kinematics.SwerveModulePosition; -import edu.wpi.first.math.kinematics.SwerveModuleState; -import edu.wpi.first.math.numbers.N1; -import edu.wpi.first.math.numbers.N3; -import edu.wpi.first.math.system.plant.DCMotor; -import edu.wpi.first.units.measure.Time; -import edu.wpi.first.wpilibj.Alert; -import edu.wpi.first.wpilibj.Alert.AlertType; -import edu.wpi.first.wpilibj.DriverStation; -import edu.wpi.first.wpilibj.DriverStation.Alliance; -import edu.wpi.first.wpilibj.Timer; -import edu.wpi.first.wpilibj2.command.Command; -import edu.wpi.first.wpilibj2.command.SubsystemBase; -import edu.wpi.first.wpilibj2.command.sysid.SysIdRoutine; -import frc.lib.util.LoggerHelper; -import frc.lib.util.Timestamped; -import frc.robot.Constants; -import frc.robot.Constants.Mode; -import frc.robot.RobotState; -import frc.robot.util.LocalADStarAK; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; -import org.littletonrobotics.junction.AutoLogOutput; -import org.littletonrobotics.junction.Logger; - -public class Drive extends SubsystemBase { - // TunerConstants doesn't include these constants, so they are declared locally - static final double ODOMETRY_FREQUENCY = - new CANBus(DriveConstants.drivetrainConstants.CANBusName).isNetworkFD() - ? 250.0 - : 100.0; - public static final double DRIVE_BASE_RADIUS = Math.max( - Math.max( - Math.hypot(DriveConstants.FrontLeft.LocationX, DriveConstants.FrontLeft.LocationY), - Math.hypot(DriveConstants.FrontRight.LocationX, DriveConstants.FrontRight.LocationY)), - Math.max( - Math.hypot(DriveConstants.BackLeft.LocationX, DriveConstants.BackLeft.LocationY), - Math.hypot(DriveConstants.BackRight.LocationX, DriveConstants.BackRight.LocationY))); - - // PathPlanner config constants - private static final double ROBOT_MASS_KG = 74.088; - private static final double ROBOT_MOI = 6.883; - private static final double WHEEL_COF = 1.2; - private static final RobotConfig PP_CONFIG = new RobotConfig( - ROBOT_MASS_KG, - ROBOT_MOI, - new ModuleConfig( - DriveConstants.FrontLeft.WheelRadius, - DriveConstants.kSpeedAt12Volts.in(MetersPerSecond), - WHEEL_COF, - DCMotor.getKrakenX60Foc(1) - .withReduction(DriveConstants.FrontLeft.DriveMotorGearRatio), - DriveConstants.FrontLeft.SlipCurrent, - 1), - getModuleTranslations()); - - static final Lock odometryLock = new ReentrantLock(); - private final GyroIO gyroIO; - private final GyroIOInputsAutoLogged gyroInputs = new GyroIOInputsAutoLogged(); - private final Module[] modules = new Module[4]; // FL, FR, BL, BR - private final SysIdRoutine sysId; - private final Alert gyroDisconnectedAlert = - new Alert("Disconnected gyro, using kinematics as fallback.", - AlertType.kError); - - private SwerveDriveKinematics kinematics = new SwerveDriveKinematics(getModuleTranslations()); - private Rotation2d rawGyroRotation = new Rotation2d(); - private SwerveModulePosition[] lastModulePositions = // For delta tracking - new SwerveModulePosition[] { - new SwerveModulePosition(), - new SwerveModulePosition(), - new SwerveModulePosition(), - new SwerveModulePosition() - }; - private SwerveDrivePoseEstimator poseEstimator = - new SwerveDrivePoseEstimator(kinematics, rawGyroRotation, - lastModulePositions, new Pose2d()); - - public Drive( - GyroIO gyroIO, - ModuleIO flModuleIO, - ModuleIO frModuleIO, - ModuleIO blModuleIO, - ModuleIO brModuleIO) - { - this.gyroIO = gyroIO; - modules[0] = new Module(flModuleIO, 0, DriveConstants.FrontLeft); - modules[1] = new Module(frModuleIO, 1, DriveConstants.FrontRight); - modules[2] = new Module(blModuleIO, 2, DriveConstants.BackLeft); - modules[3] = new Module(brModuleIO, 3, DriveConstants.BackRight); - - // Usage reporting for swerve template - HAL.report(tResourceType.kResourceType_RobotDrive, - tInstances.kRobotDriveSwerve_AdvantageKit); - - // Start odometry thread - PhoenixOdometryThread.getInstance().start(); - - // Configure AutoBuilder for PathPlanner - if (!AutoBuilder.isConfigured()) { - AutoBuilder.configure( - this::getPose, - this::setPose, - this::getChassisSpeeds, - this::runVelocity, - new PPHolonomicDriveController( - new PIDConstants(5.0, 0.0, 0.0), new PIDConstants(5.0, 0.0, 0.0)), - PP_CONFIG, - () -> DriverStation.getAlliance().orElse(Alliance.Blue) == Alliance.Red, - this); - Pathfinding.setPathfinder(new LocalADStarAK()); - PathPlannerLogging.setLogActivePathCallback( - (activePath) -> { - Logger.recordOutput( - "Odometry/Trajectory", activePath.toArray(new Pose2d[activePath.size()])); - }); - PathPlannerLogging.setLogTargetPoseCallback( - (targetPose) -> { - Logger.recordOutput("Odometry/TrajectorySetpoint", targetPose); - }); - } - - // Configure SysId - sysId = new SysIdRoutine( - new SysIdRoutine.Config( - null, - null, - null, - (state) -> Logger.recordOutput("Drive/SysIdState", state.toString())), - new SysIdRoutine.Mechanism( - (voltage) -> runCharacterization(voltage.in(Volts)), null, this)); - } - - @Override - @SuppressWarnings("LockNotBeforeTry") - public void periodic() - { - LoggerHelper.recordCurrentCommand("Drive", this); - odometryLock.lock(); // Prevents odometry updates while reading data - gyroIO.updateInputs(gyroInputs); - Logger.processInputs("Drive/Gyro", gyroInputs); - for (var module : modules) { - module.periodic(); - } - odometryLock.unlock(); - - // Stop moving when disabled - if (DriverStation.isDisabled()) { - for (var module : modules) { - module.stop(); - } - } - - // Log empty setpoint states when disabled - if (DriverStation.isDisabled()) { - Logger.recordOutput("SwerveStates/Setpoints", new SwerveModuleState[] {}); - Logger.recordOutput("SwerveStates/SetpointsOptimized", new SwerveModuleState[] {}); - } - - // Update odometry - double[] sampleTimestamps = modules[0].getOdometryTimestamps(); // All signals are sampled - // together - int sampleCount = sampleTimestamps.length; - for (int i = 0; i < sampleCount; i++) { - // Read wheel positions and deltas from each module - SwerveModulePosition[] modulePositions = new SwerveModulePosition[4]; - SwerveModulePosition[] moduleDeltas = new SwerveModulePosition[4]; - for (int moduleIndex = 0; moduleIndex < 4; moduleIndex++) { - modulePositions[moduleIndex] = modules[moduleIndex].getOdometryPositions()[i]; - moduleDeltas[moduleIndex] = new SwerveModulePosition( - modulePositions[moduleIndex].distanceMeters - - lastModulePositions[moduleIndex].distanceMeters, - modulePositions[moduleIndex].angle); - lastModulePositions[moduleIndex] = modulePositions[moduleIndex]; - } - - // Update gyro angle - if (gyroInputs.connected) { - // Use the real gyro angle - rawGyroRotation = gyroInputs.odometryYawPositions[i]; - } else { - // Use the angle delta from the kinematics and module deltas - Twist2d twist = kinematics.toTwist2d(moduleDeltas); - rawGyroRotation = rawGyroRotation.plus(new Rotation2d(twist.dtheta)); - } - - // Apply update - poseEstimator.updateWithTime(sampleTimestamps[i], rawGyroRotation, modulePositions); - } - - // Update gyro alert - gyroDisconnectedAlert.set(!gyroInputs.connected && Constants.currentMode != Mode.SIM); - - // Update global pose - RobotState.getInstance().setPose(poseEstimator.getEstimatedPosition()); - - // Update RobotState velocity - RobotState.getInstance().setVelocity(getChassisSpeeds()); - - Logger.recordOutput("Drive/Speed", new Translation2d(getChassisSpeeds().vxMetersPerSecond, - getChassisSpeeds().vyMetersPerSecond).getNorm() * -1); - } - - /** - * Runs the drive at the desired velocity. - * - * @param speeds Speeds in meters/sec - */ - public void runVelocity(ChassisSpeeds speeds) - { - // Calculate module setpoints - ChassisSpeeds discreteSpeeds = ChassisSpeeds.discretize(speeds, 0.02); - SwerveModuleState[] setpointStates = kinematics.toSwerveModuleStates(discreteSpeeds); - SwerveDriveKinematics.desaturateWheelSpeeds(setpointStates, DriveConstants.kSpeedAt12Volts); - - // Log unoptimized setpoints and setpoint speeds - Logger.recordOutput("SwerveStates/Setpoints", setpointStates); - Logger.recordOutput("SwerveChassisSpeeds/Setpoints", discreteSpeeds); - - // Send setpoints to modules - for (int i = 0; i < 4; i++) { - modules[i].runSetpoint(setpointStates[i]); - } - - // Log optimized setpoints (runSetpoint mutates each state) - Logger.recordOutput("SwerveStates/SetpointsOptimized", setpointStates); - } - - /** Runs the drive in a straight line with the specified drive output. */ - public void runCharacterization(double output) - { - for (int i = 0; i < 4; i++) { - modules[i].runCharacterization(output); - } - } - - /** Stops the drive. */ - public void stop() - { - runVelocity(new ChassisSpeeds()); - } - - /** - * Stops the drive and turns the modules to an X arrangement to resist movement. The modules - * will return to their normal orientations the next time a nonzero velocity is requested. - */ - public void stopWithX() - { - Rotation2d[] headings = new Rotation2d[4]; - for (int i = 0; i < 4; i++) { - headings[i] = getModuleTranslations()[i].getAngle(); - } - kinematics.resetHeadings(headings); - stop(); - } - - /** Returns a command to run a quasistatic test in the specified direction. */ - public Command sysIdQuasistatic(SysIdRoutine.Direction direction) - { - return run(() -> runCharacterization(0.0)) - .withTimeout(1.0) - .andThen(sysId.quasistatic(direction)) - .withName("SysId Quasistatic " + direction.toString()); - } - - /** Returns a command to run a dynamic test in the specified direction. */ - public Command sysIdDynamic(SysIdRoutine.Direction direction) - { - return run(() -> runCharacterization(0.0)).withTimeout(1.0) - .andThen(sysId.dynamic(direction)) - .withName("SysId Dynamic " + direction.toString()); - } - - /** - * Returns the module states (turn angles and drive velocities) for all of the modules. - */ - @AutoLogOutput(key = "SwerveStates/Measured") - private SwerveModuleState[] getModuleStates() - { - SwerveModuleState[] states = new SwerveModuleState[4]; - for (int i = 0; i < 4; i++) { - states[i] = modules[i].getState(); - } - return states; - } - - /** - * Returns the module positions (turn angles and drive positions) for all of the modules. - */ - protected SwerveModulePosition[] getModulePositions() - { - SwerveModulePosition[] states = new SwerveModulePosition[4]; - for (int i = 0; i < 4; i++) { - states[i] = modules[i].getPosition(); - } - return states; - } - - /** Returns the measured chassis speeds of the robot. */ - @AutoLogOutput(key = "SwerveChassisSpeeds/Measured") - public ChassisSpeeds getChassisSpeeds() - { - return kinematics.toChassisSpeeds(getModuleStates()); - } - - /** Returns the position of each module in radians. */ - public double[] getWheelRadiusCharacterizationPositions() - { - double[] values = new double[4]; - for (int i = 0; i < 4; i++) { - values[i] = modules[i].getWheelRadiusCharacterizationPosition(); - } - return values; - } - - /** - * Returns the average velocity of the modules in rotations/sec (Phoenix native units). - */ - public double getFFCharacterizationVelocity() - { - double output = 0.0; - for (int i = 0; i < 4; i++) { - output += modules[i].getFFCharacterizationVelocity() / 4.0; - } - return output; - } - - /** Returns the current odometry pose. */ - @AutoLogOutput(key = "Odometry/Robot") - public Pose2d getPose() - { - return poseEstimator.getEstimatedPosition(); - } - - /** Returns the current odometry rotation. */ - public Rotation2d getRotation() - { - return getPose().getRotation(); - } - - public Timestamped getTimestampedHeading() - { - return new Timestamped(Seconds.of(Timer.getTimestamp()), getRotation()); - } - - /** Resets the current odometry pose. */ - public void setPose(Pose2d pose) - { - poseEstimator.resetPosition(rawGyroRotation, getModulePositions(), pose); - } - - /** Adds a new timestamped vision measurement. */ - public void addVisionMeasurement( - Pose2d visionRobotPoseMeters, - Time timestamp, - Matrix visionMeasurementStdDevs) - { - poseEstimator.addVisionMeasurement( - visionRobotPoseMeters, timestamp.in(Seconds), visionMeasurementStdDevs); - } - - /** Returns the maximum linear speed in meters per sec. */ - public double getMaxLinearSpeedMetersPerSec() - { - return DriveConstants.kSpeedAt12Volts.in(MetersPerSecond); - } - - /** Returns the maximum angular speed in radians per sec. */ - public double getMaxAngularSpeedRadPerSec() - { - return getMaxLinearSpeedMetersPerSec() / DRIVE_BASE_RADIUS; - } - - /** Returns an array of module translations. */ - public static Translation2d[] getModuleTranslations() - { - return new Translation2d[] { - new Translation2d(DriveConstants.FrontLeft.LocationX, - DriveConstants.FrontLeft.LocationY), - new Translation2d(DriveConstants.FrontRight.LocationX, - DriveConstants.FrontRight.LocationY), - new Translation2d(DriveConstants.BackLeft.LocationX, - DriveConstants.BackLeft.LocationY), - new Translation2d(DriveConstants.BackRight.LocationX, - DriveConstants.BackRight.LocationY) - }; - } -} diff --git a/src/main/java/frc/robot/subsystems/w8_examples/drive/DriveConstants.java b/src/main/java/frc/robot/subsystems/w8_examples/drive/DriveConstants.java deleted file mode 100644 index e2fc79d..0000000 --- a/src/main/java/frc/robot/subsystems/w8_examples/drive/DriveConstants.java +++ /dev/null @@ -1,353 +0,0 @@ -package frc.robot.subsystems.drive; - -import static edu.wpi.first.units.Units.*; - -import com.ctre.phoenix6.CANBus; -import com.ctre.phoenix6.configs.*; -import com.ctre.phoenix6.hardware.*; -import com.ctre.phoenix6.signals.*; -import com.ctre.phoenix6.swerve.*; -import com.ctre.phoenix6.swerve.SwerveModuleConstants.*; -import edu.wpi.first.math.Matrix; -import edu.wpi.first.math.numbers.N1; -import edu.wpi.first.math.numbers.N3; -import edu.wpi.first.units.measure.*; -import frc.robot.Constants; - -// Generated by the Tuner X Swerve Project Generator -// https://v6.docs.ctr-electronics.com/en/stable/docs/tuner/tuner-swerve/index.html -public class DriveConstants { - // Both sets of gains need to be tuned to your individual robot. - - // The steer motor uses any SwerveModule.SteerRequestType control request with - // the - // output type specified by SwerveModuleConstants.SteerMotorClosedLoopOutput - private static final Slot0Configs steerGains = new Slot0Configs() - .withKP(100) - .withKI(0) - .withKD(0.5) - .withKS(0.1) - .withKV(1.91) - .withKA(0) - .withStaticFeedforwardSign(StaticFeedforwardSignValue.UseClosedLoopSign); - // When using closed-loop control, the drive motor uses the control - // output type specified by SwerveModuleConstants.DriveMotorClosedLoopOutput - private static final Slot0Configs driveGains = - new Slot0Configs().withKP(0.1).withKI(0).withKD(0).withKS(0) - .withKV(0.124); - - // The closed-loop output type to use for the steer motors; - // This affects the PID/FF gains for the steer motors - private static final ClosedLoopOutputType kSteerClosedLoopOutput = ClosedLoopOutputType.Voltage; - // The closed-loop output type to use for the drive motors; - // This affects the PID/FF gains for the drive motors - private static final ClosedLoopOutputType kDriveClosedLoopOutput = - ClosedLoopOutputType.TorqueCurrentFOC; - - // The type of motor used for the drive motor - private static final DriveMotorArrangement kDriveMotorType = - DriveMotorArrangement.TalonFX_Integrated; - // The type of motor used for the drive motor - private static final SteerMotorArrangement kSteerMotorType = - SteerMotorArrangement.TalonFX_Integrated; - - // The remote sensor feedback type to use for the steer motors; - // When not Pro-licensed, FusedCANcoder/SyncCANcoder automatically fall back to - // RemoteCANcoder - private static final SteerFeedbackType kSteerFeedbackType = SteerFeedbackType.FusedCANcoder; - - // The stator current at which the wheels start to slip; - // This needs to be tuned to your individual robot - private static final Current kSlipCurrent = Amps.of(120.0); - - // Initial configs for the drive and steer motors and the azimuth encoder; these - // cannot be null. - // Some configs will be overwritten; check the `with*InitialConfigs()` API - // documentation. - private static final TalonFXConfiguration driveInitialConfigs = new TalonFXConfiguration(); - private static final TalonFXConfiguration steerInitialConfigs = new TalonFXConfiguration() - .withCurrentLimits( - new CurrentLimitsConfigs() - // Swerve azimuth does not require much torque output, so we can set a - // relatively - // low - // stator current limit to help avoid brownouts without impacting performance. - .withStatorCurrentLimit(Amps.of(60)) - .withStatorCurrentLimitEnable(true)); - private static final CANcoderConfiguration encoderInitialConfigs = new CANcoderConfiguration(); - // Configs for the Pigeon 2; leave this null to skip applying Pigeon 2 configs - private static final Pigeon2Configuration pigeonConfigs = null; - - // CAN bus that the devices are located on; - // All swerve devices must share the same CAN bus - public static final CANBus kCANBus = new CANBus("canivore", "./logs/example.hoot"); - - // Theoretical free speed (m/s) at 12 V applied output; - // This needs to be tuned to your individual robot - public static final LinearVelocity kSpeedAt12Volts = MetersPerSecond.of(4.69); - - // Every 1 rotation of the azimuth results in kCoupleRatio drive motor turns; - // This may need to be tuned to your individual robot - private static final double kCoupleRatio = 3.8181818181818183; - - private static final double kDriveGearRatio = 7.363636363636365; - private static final double kSteerGearRatio = 15.42857142857143; - private static final Distance kWheelRadius = Inches.of(2.167); - - private static final boolean kInvertLeftSide = false; - private static final boolean kInvertRightSide = true; - - private static final int kPigeonId = 1; - - // These are only used for simulation - private static final MomentOfInertia kSteerInertia = KilogramSquareMeters.of(0.004); - private static final MomentOfInertia kDriveInertia = KilogramSquareMeters.of(0.025); - // Simulated voltage necessary to overcome friction - private static final Voltage kSteerFrictionVoltage = Volts.of(0.2); - private static final Voltage kDriveFrictionVoltage = Volts.of(0.2); - - public static final SwerveDrivetrainConstants drivetrainConstants = - new SwerveDrivetrainConstants() - .withCANBusName(kCANBus.getName()) - .withPigeon2Id(kPigeonId) - .withPigeon2Configs(pigeonConfigs); - - private static final SwerveModuleConstantsFactory ConstantCreator = - new SwerveModuleConstantsFactory() - .withDriveMotorGearRatio(kDriveGearRatio) - .withSteerMotorGearRatio(kSteerGearRatio) - .withCouplingGearRatio(kCoupleRatio) - .withWheelRadius(kWheelRadius) - .withSteerMotorGains(steerGains) - .withDriveMotorGains(driveGains) - .withSteerMotorClosedLoopOutput(kSteerClosedLoopOutput) - .withDriveMotorClosedLoopOutput(kDriveClosedLoopOutput) - .withSlipCurrent(kSlipCurrent) - .withSpeedAt12Volts(kSpeedAt12Volts) - .withDriveMotorType(kDriveMotorType) - .withSteerMotorType(kSteerMotorType) - .withFeedbackSource(kSteerFeedbackType) - .withDriveMotorInitialConfigs(driveInitialConfigs) - .withSteerMotorInitialConfigs(steerInitialConfigs) - .withEncoderInitialConfigs(encoderInitialConfigs) - .withSteerInertia(kSteerInertia) - .withDriveInertia(kDriveInertia) - .withSteerFrictionVoltage(kSteerFrictionVoltage) - .withDriveFrictionVoltage(kDriveFrictionVoltage); - - // Front Left - private static final int kFrontLeftDriveMotorId = 3; - private static final int kFrontLeftSteerMotorId = 2; - private static final int kFrontLeftEncoderId = 1; - private static final Angle kFrontLeftEncoderOffset = Rotations.of(0.15234375); - private static final boolean kFrontLeftSteerMotorInverted = true; - private static final boolean kFrontLeftEncoderInverted = false; - - private static final Distance kFrontLeftXPos = Inches.of(10); - private static final Distance kFrontLeftYPos = Inches.of(10); - - // Front Right - private static final int kFrontRightDriveMotorId = 1; - private static final int kFrontRightSteerMotorId = 0; - private static final int kFrontRightEncoderId = 0; - private static final Angle kFrontRightEncoderOffset = Rotations.of(-0.4873046875); - private static final boolean kFrontRightSteerMotorInverted = true; - private static final boolean kFrontRightEncoderInverted = false; - - private static final Distance kFrontRightXPos = Inches.of(10); - private static final Distance kFrontRightYPos = Inches.of(-10); - - // Back Left - private static final int kBackLeftDriveMotorId = 7; - private static final int kBackLeftSteerMotorId = 6; - private static final int kBackLeftEncoderId = 3; - private static final Angle kBackLeftEncoderOffset = Rotations.of(-0.219482421875); - private static final boolean kBackLeftSteerMotorInverted = true; - private static final boolean kBackLeftEncoderInverted = false; - - private static final Distance kBackLeftXPos = Inches.of(-10); - private static final Distance kBackLeftYPos = Inches.of(10); - - // Back Right - private static final int kBackRightDriveMotorId = 5; - private static final int kBackRightSteerMotorId = 4; - private static final int kBackRightEncoderId = 2; - private static final Angle kBackRightEncoderOffset = Rotations.of(0.17236328125); - private static final boolean kBackRightSteerMotorInverted = true; - private static final boolean kBackRightEncoderInverted = false; - - private static final Distance kBackRightXPos = Inches.of(-10); - private static final Distance kBackRightYPos = Inches.of(-10); - - public static final SwerveModuleConstants FrontLeft = - ConstantCreator - .createModuleConstants( - kFrontLeftSteerMotorId, - kFrontLeftDriveMotorId, - kFrontLeftEncoderId, - kFrontLeftEncoderOffset, - kFrontLeftXPos, - kFrontLeftYPos, - kInvertLeftSide, - kFrontLeftSteerMotorInverted, - kFrontLeftEncoderInverted); - public static final SwerveModuleConstants FrontRight = - ConstantCreator - .createModuleConstants( - kFrontRightSteerMotorId, - kFrontRightDriveMotorId, - kFrontRightEncoderId, - kFrontRightEncoderOffset, - kFrontRightXPos, - kFrontRightYPos, - kInvertRightSide, - kFrontRightSteerMotorInverted, - kFrontRightEncoderInverted); - public static final SwerveModuleConstants BackLeft = - ConstantCreator - .createModuleConstants( - kBackLeftSteerMotorId, - kBackLeftDriveMotorId, - kBackLeftEncoderId, - kBackLeftEncoderOffset, - kBackLeftXPos, - kBackLeftYPos, - kInvertLeftSide, - kBackLeftSteerMotorInverted, - kBackLeftEncoderInverted); - public static final SwerveModuleConstants BackRight = - ConstantCreator - .createModuleConstants( - kBackRightSteerMotorId, - kBackRightDriveMotorId, - kBackRightEncoderId, - kBackRightEncoderOffset, - kBackRightXPos, - kBackRightYPos, - kInvertRightSide, - kBackRightSteerMotorInverted, - kBackRightEncoderInverted); - - /** - * Creates a CommandSwerveDrivetrain instance. This should only be called once in your robot - * program,. - */ - // public static CommandSwerveDrivetrain createDrivetrain() { - // return new CommandSwerveDrivetrain( - // DrivetrainConstants, FrontLeft, FrontRight, BackLeft, BackRight); - // } - - /** - * Swerve Drive class utilizing CTR Electronics' Phoenix 6 API with the selected device types. - */ - public static class TunerSwerveDrivetrain extends SwerveDrivetrain { - /** - * Constructs a CTRE SwerveDrivetrain using the specified constants. - * - *

- * This constructs the underlying hardware devices, so users should not construct the - * devices themselves. If they need the devices, they can access them through getters in the - * classes. - * - * @param drivetrainConstants Drivetrain-wide constants for the swerve drive - * @param modules Constants for each specific module - */ - public TunerSwerveDrivetrain( - SwerveDrivetrainConstants drivetrainConstants, - SwerveModuleConstants... modules) - { - super(TalonFX::new, TalonFX::new, CANcoder::new, drivetrainConstants, modules); - } - - /** - * Constructs a CTRE SwerveDrivetrain using the specified constants. - * - *

- * This constructs the underlying hardware devices, so users should not construct the - * devices themselves. If they need the devices, they can access them through getters in the - * classes. - * - * @param drivetrainConstants Drivetrain-wide constants for the swerve drive - * @param odometryUpdateFrequency The frequency to run the odometry loop. If unspecified or - * set to 0 Hz, this is 250 Hz on CAN FD, and 100 Hz on CAN 2.0. - * @param modules Constants for each specific module - */ - public TunerSwerveDrivetrain( - SwerveDrivetrainConstants drivetrainConstants, - double odometryUpdateFrequency, - SwerveModuleConstants... modules) - { - super( - TalonFX::new, - TalonFX::new, - CANcoder::new, - drivetrainConstants, - odometryUpdateFrequency, - modules); - } - - /** - * Constructs a CTRE SwerveDrivetrain using the specified constants. - * - *

- * This constructs the underlying hardware devices, so users should not construct the - * devices themselves. If they need the devices, they can access them through getters in the - * classes. - * - * @param drivetrainConstants Drivetrain-wide constants for the swerve drive - * @param odometryUpdateFrequency The frequency to run the odometry loop. If unspecified or - * set to 0 Hz, this is 250 Hz on CAN FD, and 100 Hz on CAN 2.0. - * @param odometryStandardDeviation The standard deviation for odometry calculation in the - * form [x, y, theta]ᵀ, with units in meters and radians - * @param visionStandardDeviation The standard deviation for vision calculation in the form - * [x, y, theta]ᵀ, with units in meters and radians - * @param modules Constants for each specific module - */ - public TunerSwerveDrivetrain( - SwerveDrivetrainConstants drivetrainConstants, - double odometryUpdateFrequency, - Matrix odometryStandardDeviation, - Matrix visionStandardDeviation, - SwerveModuleConstants... modules) - { - super( - TalonFX::new, - TalonFX::new, - CANcoder::new, - drivetrainConstants, - odometryUpdateFrequency, - odometryStandardDeviation, - visionStandardDeviation, - modules); - } - } - - public static Drive get() - { - switch (Constants.currentMode) { - case REAL: - return new Drive( - new GyroIOPigeon2(), - new ModuleIOTalonFX(DriveConstants.FrontLeft), - new ModuleIOTalonFX(DriveConstants.FrontRight), - new ModuleIOTalonFX(DriveConstants.BackLeft), - new ModuleIOTalonFX(DriveConstants.BackRight)); - case SIM: - return new Drive( - new GyroIO() {}, - new ModuleIOSim(DriveConstants.FrontLeft), - new ModuleIOSim(DriveConstants.FrontRight), - new ModuleIOSim(DriveConstants.BackLeft), - new ModuleIOSim(DriveConstants.BackRight)); - case REPLAY: - return new Drive( - new GyroIO() {}, - new ModuleIO() {}, - new ModuleIO() {}, - new ModuleIO() {}, - new ModuleIO() {}); - default: - throw new IllegalStateException("Unrecognized Robot Mode"); - } - } -} diff --git a/src/main/java/frc/robot/subsystems/w8_examples/drive/GyroIO.java b/src/main/java/frc/robot/subsystems/w8_examples/drive/GyroIO.java deleted file mode 100644 index 8a0a1c5..0000000 --- a/src/main/java/frc/robot/subsystems/w8_examples/drive/GyroIO.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2025 Windham Windup - * - * This program is free software: you can redistribute it and/or modify it under the terms of the - * GNU General Public License as published by the Free Software Foundation, either version 3 of the - * License, or any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without - * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program. If - * not, see . - */ - -package frc.robot.subsystems.drive; - -import edu.wpi.first.math.geometry.Rotation2d; -import org.littletonrobotics.junction.AutoLog; - -public interface GyroIO { - @AutoLog - public static class GyroIOInputs { - public boolean connected = false; - public Rotation2d yawPosition = new Rotation2d(); - public double yawVelocityRadPerSec = 0.0; - public double[] odometryYawTimestamps = new double[] {}; - public Rotation2d[] odometryYawPositions = new Rotation2d[] {}; - } - - public default void updateInputs(GyroIOInputs inputs) - {} -} diff --git a/src/main/java/frc/robot/subsystems/w8_examples/drive/GyroIOPigeon2.java b/src/main/java/frc/robot/subsystems/w8_examples/drive/GyroIOPigeon2.java deleted file mode 100644 index 768b803..0000000 --- a/src/main/java/frc/robot/subsystems/w8_examples/drive/GyroIOPigeon2.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) 2025 Windham Windup - * - * This program is free software: you can redistribute it and/or modify it under the terms of the - * GNU General Public License as published by the Free Software Foundation, either version 3 of the - * License, or any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without - * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program. If - * not, see . - */ - -package frc.robot.subsystems.drive; - -import com.ctre.phoenix6.BaseStatusSignal; -import com.ctre.phoenix6.StatusCode; -import com.ctre.phoenix6.StatusSignal; -import com.ctre.phoenix6.configs.Pigeon2Configuration; -import com.ctre.phoenix6.hardware.Pigeon2; -import edu.wpi.first.math.geometry.Rotation2d; -import edu.wpi.first.math.util.Units; -import edu.wpi.first.units.measure.Angle; -import edu.wpi.first.units.measure.AngularVelocity; - -import java.util.Queue; - -/** IO implementation for Pigeon 2. */ -public class GyroIOPigeon2 implements GyroIO { - private final Pigeon2 pigeon = new Pigeon2( - DriveConstants.drivetrainConstants.Pigeon2Id, - DriveConstants.drivetrainConstants.CANBusName); - private final StatusSignal yaw = pigeon.getYaw(); - private final Queue yawPositionQueue; - private final Queue yawTimestampQueue; - private final StatusSignal yawVelocity = pigeon.getAngularVelocityZWorld(); - - public GyroIOPigeon2() - { - pigeon.getConfigurator().apply(new Pigeon2Configuration()); - pigeon.getConfigurator().setYaw(0.0); - yaw.setUpdateFrequency(Drive.ODOMETRY_FREQUENCY); - yawVelocity.setUpdateFrequency(50.0); - pigeon.optimizeBusUtilization(); - yawTimestampQueue = PhoenixOdometryThread.getInstance().makeTimestampQueue(); - yawPositionQueue = PhoenixOdometryThread.getInstance().registerSignal(pigeon.getYaw()); - } - - @Override - public void updateInputs(GyroIOInputs inputs) - { - inputs.connected = BaseStatusSignal.refreshAll(yaw, yawVelocity).equals(StatusCode.OK); - inputs.yawPosition = Rotation2d.fromDegrees(yaw.getValueAsDouble()); - inputs.yawVelocityRadPerSec = Units.degreesToRadians(yawVelocity.getValueAsDouble()); - - inputs.odometryYawTimestamps = - yawTimestampQueue.stream().mapToDouble((Double value) -> value).toArray(); - inputs.odometryYawPositions = yawPositionQueue.stream() - .map((Double value) -> Rotation2d.fromDegrees(value)) - .toArray(Rotation2d[]::new); - yawTimestampQueue.clear(); - yawPositionQueue.clear(); - } -} diff --git a/src/main/java/frc/robot/subsystems/w8_examples/drive/Module.java b/src/main/java/frc/robot/subsystems/w8_examples/drive/Module.java deleted file mode 100644 index ab1961c..0000000 --- a/src/main/java/frc/robot/subsystems/w8_examples/drive/Module.java +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Copyright (C) 2025 Windham Windup - * - * This program is free software: you can redistribute it and/or modify it under the terms of the - * GNU General Public License as published by the Free Software Foundation, either version 3 of the - * License, or any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without - * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program. If - * not, see . - */ - -package frc.robot.subsystems.drive; - -import com.ctre.phoenix6.configs.CANcoderConfiguration; -import com.ctre.phoenix6.configs.TalonFXConfiguration; -import com.ctre.phoenix6.swerve.SwerveModuleConstants; -import edu.wpi.first.math.geometry.Rotation2d; -import edu.wpi.first.math.kinematics.SwerveModulePosition; -import edu.wpi.first.math.kinematics.SwerveModuleState; -import edu.wpi.first.math.util.Units; -import edu.wpi.first.wpilibj.Alert; -import edu.wpi.first.wpilibj.Alert.AlertType; -import org.littletonrobotics.junction.Logger; - -public class Module { - private final ModuleIO io; - private final ModuleIOInputsAutoLogged inputs = new ModuleIOInputsAutoLogged(); - private final int index; - private final SwerveModuleConstants constants; - - private final Alert driveDisconnectedAlert; - private final Alert turnDisconnectedAlert; - private final Alert turnEncoderDisconnectedAlert; - private SwerveModulePosition[] odometryPositions = new SwerveModulePosition[] {}; - - public Module( - ModuleIO io, - int index, - SwerveModuleConstants constants) - { - this.io = io; - this.index = index; - this.constants = constants; - driveDisconnectedAlert = new Alert( - "Disconnected drive motor on module " + Integer.toString(index) + ".", - AlertType.kError); - turnDisconnectedAlert = new Alert( - "Disconnected turn motor on module " + Integer.toString(index) + ".", AlertType.kError); - turnEncoderDisconnectedAlert = new Alert( - "Disconnected turn encoder on module " + Integer.toString(index) + ".", - AlertType.kError); - } - - public void periodic() - { - io.updateInputs(inputs); - Logger.processInputs("Drive/Module" + Integer.toString(index), inputs); - - // Calculate positions for odometry - int sampleCount = inputs.odometryTimestamps.length; // All signals are sampled together - odometryPositions = new SwerveModulePosition[sampleCount]; - for (int i = 0; i < sampleCount; i++) { - double positionMeters = inputs.odometryDrivePositionsRad[i] * constants.WheelRadius; - Rotation2d angle = inputs.odometryTurnPositions[i]; - odometryPositions[i] = new SwerveModulePosition(positionMeters, angle); - } - - // Update alerts - driveDisconnectedAlert.set(!inputs.driveConnected); - turnDisconnectedAlert.set(!inputs.turnConnected); - turnEncoderDisconnectedAlert.set(!inputs.turnEncoderConnected); - } - - /** - * Runs the module with the specified setpoint state. Mutates the state to optimize it. - */ - public void runSetpoint(SwerveModuleState state) - { - // Optimize velocity setpoint - state.optimize(getAngle()); - state.cosineScale(inputs.turnPosition); - - // Apply setpoints - io.setDriveVelocity(state.speedMetersPerSecond / constants.WheelRadius); - io.setTurnPosition(state.angle); - } - - /** - * Runs the module with the specified output while controlling to zero degrees. - */ - public void runCharacterization(double output) - { - io.setDriveOpenLoop(output); - io.setTurnPosition(new Rotation2d()); - } - - /** Disables all outputs to motors. */ - public void stop() - { - io.setDriveOpenLoop(0.0); - io.setTurnOpenLoop(0.0); - } - - /** Returns the current turn angle of the module. */ - public Rotation2d getAngle() - { - return inputs.turnPosition; - } - - /** Returns the current drive position of the module in meters. */ - public double getPositionMeters() - { - return inputs.drivePositionRad * constants.WheelRadius; - } - - /** Returns the current drive velocity of the module in meters per second. */ - public double getVelocityMetersPerSec() - { - return inputs.driveVelocityRadPerSec * constants.WheelRadius; - } - - /** Returns the module position (turn angle and drive position). */ - public SwerveModulePosition getPosition() - { - return new SwerveModulePosition(getPositionMeters(), getAngle()); - } - - /** Returns the module state (turn angle and drive velocity). */ - public SwerveModuleState getState() - { - return new SwerveModuleState(getVelocityMetersPerSec(), getAngle()); - } - - /** Returns the module positions received this cycle. */ - public SwerveModulePosition[] getOdometryPositions() - { - return odometryPositions; - } - - /** Returns the timestamps of the samples received this cycle. */ - public double[] getOdometryTimestamps() - { - return inputs.odometryTimestamps; - } - - /** Returns the module position in radians. */ - public double getWheelRadiusCharacterizationPosition() - { - return inputs.drivePositionRad; - } - - /** Returns the module velocity in rotations/sec (Phoenix native units). */ - public double getFFCharacterizationVelocity() - { - return Units.radiansToRotations(inputs.driveVelocityRadPerSec); - } -} diff --git a/src/main/java/frc/robot/subsystems/w8_examples/drive/ModuleIO.java b/src/main/java/frc/robot/subsystems/w8_examples/drive/ModuleIO.java deleted file mode 100644 index 1f72846..0000000 --- a/src/main/java/frc/robot/subsystems/w8_examples/drive/ModuleIO.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (C) 2025 Windham Windup - * - * This program is free software: you can redistribute it and/or modify it under the terms of the - * GNU General Public License as published by the Free Software Foundation, either version 3 of the - * License, or any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without - * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program. If - * not, see . - */ - -package frc.robot.subsystems.drive; - -import edu.wpi.first.math.geometry.Rotation2d; -import org.littletonrobotics.junction.AutoLog; - -public interface ModuleIO { - @AutoLog - public static class ModuleIOInputs { - public boolean driveConnected = false; - public double drivePositionRad = 0.0; - public double driveVelocityRadPerSec = 0.0; - public double driveAppliedVolts = 0.0; - public double driveCurrentAmps = 0.0; - - public boolean turnConnected = false; - public boolean turnEncoderConnected = false; - public Rotation2d turnAbsolutePosition = new Rotation2d(); - public Rotation2d turnPosition = new Rotation2d(); - public double turnVelocityRadPerSec = 0.0; - public double turnAppliedVolts = 0.0; - public double turnCurrentAmps = 0.0; - - public double[] odometryTimestamps = new double[] {}; - public double[] odometryDrivePositionsRad = new double[] {}; - public Rotation2d[] odometryTurnPositions = new Rotation2d[] {}; - } - - /** Updates the set of loggable inputs. */ - public default void updateInputs(ModuleIOInputs inputs) - {} - - /** Run the drive motor at the specified open loop value. */ - public default void setDriveOpenLoop(double output) - {} - - /** Run the turn motor at the specified open loop value. */ - public default void setTurnOpenLoop(double output) - {} - - /** Run the drive motor at the specified velocity. */ - public default void setDriveVelocity(double velocityRadPerSec) - {} - - /** Run the turn motor to the specified rotation. */ - public default void setTurnPosition(Rotation2d rotation) - {} -} diff --git a/src/main/java/frc/robot/subsystems/w8_examples/drive/ModuleIOSim.java b/src/main/java/frc/robot/subsystems/w8_examples/drive/ModuleIOSim.java deleted file mode 100644 index 8eddad1..0000000 --- a/src/main/java/frc/robot/subsystems/w8_examples/drive/ModuleIOSim.java +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright (C) 2025 Windham Windup - * - * This program is free software: you can redistribute it and/or modify it under the terms of the - * GNU General Public License as published by the Free Software Foundation, either version 3 of the - * License, or any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without - * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program. If - * not, see . - */ - -package frc.robot.subsystems.drive; - -import com.ctre.phoenix6.configs.CANcoderConfiguration; -import com.ctre.phoenix6.configs.TalonFXConfiguration; -import com.ctre.phoenix6.swerve.SwerveModuleConstants; -import edu.wpi.first.math.MathUtil; -import edu.wpi.first.math.controller.PIDController; -import edu.wpi.first.math.geometry.Rotation2d; -import edu.wpi.first.math.system.plant.DCMotor; -import edu.wpi.first.math.system.plant.LinearSystemId; -import edu.wpi.first.math.util.Units; -import edu.wpi.first.wpilibj.Timer; -import edu.wpi.first.wpilibj.simulation.DCMotorSim; - -/** - * Physics sim implementation of module IO. The sim models are configured using a set of module - * constants from Phoenix. Simulation is always based on voltage control. - */ -public class ModuleIOSim implements ModuleIO { - // TunerConstants doesn't support separate sim constants, so they are declared - // locally - private static final double DRIVE_KP = 0.05; - private static final double DRIVE_KD = 0.0; - private static final double DRIVE_KS = 0.0; - private static final double DRIVE_KV_ROT = 0.91035; // Same units as TunerConstants: (volt * - // secs) / rotation - private static final double DRIVE_KV = 1.0 / Units.rotationsToRadians(1.0 / DRIVE_KV_ROT); - private static final double TURN_KP = 8.0; - private static final double TURN_KD = 0.0; - private static final DCMotor DRIVE_GEARBOX = DCMotor.getKrakenX60Foc(1); - private static final DCMotor TURN_GEARBOX = DCMotor.getKrakenX60Foc(1); - - private final DCMotorSim driveSim; - private final DCMotorSim turnSim; - - private boolean driveClosedLoop = false; - private boolean turnClosedLoop = false; - private PIDController driveController = new PIDController(DRIVE_KP, 0, DRIVE_KD); - private PIDController turnController = new PIDController(TURN_KP, 0, TURN_KD); - private double driveFFVolts = 0.0; - private double driveAppliedVolts = 0.0; - private double turnAppliedVolts = 0.0; - - public ModuleIOSim( - SwerveModuleConstants constants) - { - // Create drive and turn sim models - driveSim = new DCMotorSim( - LinearSystemId.createDCMotorSystem( - DRIVE_GEARBOX, constants.DriveInertia, constants.DriveMotorGearRatio), - DRIVE_GEARBOX); - turnSim = new DCMotorSim( - LinearSystemId.createDCMotorSystem( - TURN_GEARBOX, constants.SteerInertia, constants.SteerMotorGearRatio), - TURN_GEARBOX); - - // Enable wrapping for turn PID - turnController.enableContinuousInput(-Math.PI, Math.PI); - } - - @Override - public void updateInputs(ModuleIOInputs inputs) - { - // Run closed-loop control - if (driveClosedLoop) { - driveAppliedVolts = - driveFFVolts + driveController.calculate(driveSim.getAngularVelocityRadPerSec()); - } else { - driveController.reset(); - } - if (turnClosedLoop) { - turnAppliedVolts = turnController.calculate(turnSim.getAngularPositionRad()); - } else { - turnController.reset(); - } - - // Update simulation state - driveSim.setInputVoltage(MathUtil.clamp(driveAppliedVolts, -12.0, 12.0)); - turnSim.setInputVoltage(MathUtil.clamp(turnAppliedVolts, -12.0, 12.0)); - driveSim.update(0.02); - turnSim.update(0.02); - - // Update drive inputs - inputs.driveConnected = true; - inputs.drivePositionRad = driveSim.getAngularPositionRad(); - inputs.driveVelocityRadPerSec = driveSim.getAngularVelocityRadPerSec(); - inputs.driveAppliedVolts = driveAppliedVolts; - inputs.driveCurrentAmps = Math.abs(driveSim.getCurrentDrawAmps()); - - // Update turn inputs - inputs.turnConnected = true; - inputs.turnEncoderConnected = true; - inputs.turnAbsolutePosition = new Rotation2d(turnSim.getAngularPositionRad()); - inputs.turnPosition = new Rotation2d(turnSim.getAngularPositionRad()); - inputs.turnVelocityRadPerSec = turnSim.getAngularVelocityRadPerSec(); - inputs.turnAppliedVolts = turnAppliedVolts; - inputs.turnCurrentAmps = Math.abs(turnSim.getCurrentDrawAmps()); - - // Update odometry inputs (50Hz because high-frequency odometry in sim doesn't - // matter) - inputs.odometryTimestamps = new double[] {Timer.getFPGATimestamp()}; - inputs.odometryDrivePositionsRad = new double[] {inputs.drivePositionRad}; - inputs.odometryTurnPositions = new Rotation2d[] {inputs.turnPosition}; - } - - @Override - public void setDriveOpenLoop(double output) - { - driveClosedLoop = false; - driveAppliedVolts = output; - } - - @Override - public void setTurnOpenLoop(double output) - { - turnClosedLoop = false; - turnAppliedVolts = output; - } - - @Override - public void setDriveVelocity(double velocityRadPerSec) - { - driveClosedLoop = true; - driveFFVolts = DRIVE_KS * Math.signum(velocityRadPerSec) + DRIVE_KV * velocityRadPerSec; - driveController.setSetpoint(velocityRadPerSec); - } - - @Override - public void setTurnPosition(Rotation2d rotation) - { - turnClosedLoop = true; - turnController.setSetpoint(rotation.getRadians()); - } -} diff --git a/src/main/java/frc/robot/subsystems/w8_examples/drive/ModuleIOTalonFX.java b/src/main/java/frc/robot/subsystems/w8_examples/drive/ModuleIOTalonFX.java deleted file mode 100644 index 143eebd..0000000 --- a/src/main/java/frc/robot/subsystems/w8_examples/drive/ModuleIOTalonFX.java +++ /dev/null @@ -1,278 +0,0 @@ -/* - * Copyright (C) 2025 Windham Windup - * - * This program is free software: you can redistribute it and/or modify it under the terms of the - * GNU General Public License as published by the Free Software Foundation, either version 3 of the - * License, or any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without - * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program. If - * not, see . - */ - -package frc.robot.subsystems.drive; - -import com.ctre.phoenix6.BaseStatusSignal; -import com.ctre.phoenix6.StatusSignal; -import com.ctre.phoenix6.configs.CANcoderConfiguration; -import com.ctre.phoenix6.configs.TalonFXConfiguration; -import com.ctre.phoenix6.controls.PositionTorqueCurrentFOC; -import com.ctre.phoenix6.controls.PositionVoltage; -import com.ctre.phoenix6.controls.TorqueCurrentFOC; -import com.ctre.phoenix6.controls.VelocityTorqueCurrentFOC; -import com.ctre.phoenix6.controls.VelocityVoltage; -import com.ctre.phoenix6.controls.VoltageOut; -import com.ctre.phoenix6.hardware.CANcoder; -import com.ctre.phoenix6.hardware.ParentDevice; -import com.ctre.phoenix6.hardware.TalonFX; -import com.ctre.phoenix6.signals.FeedbackSensorSourceValue; -import com.ctre.phoenix6.signals.InvertedValue; -import com.ctre.phoenix6.signals.NeutralModeValue; -import com.ctre.phoenix6.signals.SensorDirectionValue; -import com.ctre.phoenix6.swerve.SwerveModuleConstants; -import edu.wpi.first.math.filter.Debouncer; -import edu.wpi.first.math.geometry.Rotation2d; -import edu.wpi.first.math.util.Units; -import edu.wpi.first.units.measure.Angle; -import edu.wpi.first.units.measure.AngularVelocity; -import edu.wpi.first.units.measure.Current; -import edu.wpi.first.units.measure.Voltage; -import frc.lib.util.CANUpdateThread; -import java.util.Queue; - -/** - * Module IO implementation for Talon FX drive motor controller, Talon FX turn motor controller, and - * CANcoder. Configured using a set of module constants from Phoenix. - * - *

- * Device configuration and other behaviors not exposed by TunerConstants can be customized here. - */ -public class ModuleIOTalonFX implements ModuleIO { - private final SwerveModuleConstants constants; - - // Hardware objects - private final TalonFX driveTalon; - private final TalonFX turnTalon; - private final CANcoder cancoder; - - // Voltage control requests - private final VoltageOut voltageRequest = new VoltageOut(0); - private final PositionVoltage positionVoltageRequest = new PositionVoltage(0.0); - private final VelocityVoltage velocityVoltageRequest = new VelocityVoltage(0.0); - - // Torque-current control requests - private final TorqueCurrentFOC torqueCurrentRequest = new TorqueCurrentFOC(0); - private final PositionTorqueCurrentFOC positionTorqueCurrentRequest = - new PositionTorqueCurrentFOC(0.0); - private final VelocityTorqueCurrentFOC velocityTorqueCurrentRequest = - new VelocityTorqueCurrentFOC(0.0); - - // Timestamp inputs from Phoenix thread - private final Queue timestampQueue; - - // Inputs from drive motor - private final StatusSignal drivePosition; - private final Queue drivePositionQueue; - private final StatusSignal driveVelocity; - private final StatusSignal driveAppliedVolts; - private final StatusSignal driveCurrent; - - // Inputs from turn motor - private final StatusSignal turnAbsolutePosition; - private final StatusSignal turnPosition; - private final Queue turnPositionQueue; - private final StatusSignal turnVelocity; - private final StatusSignal turnAppliedVolts; - private final StatusSignal turnCurrent; - - // Connection debouncers - private final Debouncer driveConnectedDebounce = new Debouncer(0.5); - private final Debouncer turnConnectedDebounce = new Debouncer(0.5); - private final Debouncer turnEncoderConnectedDebounce = new Debouncer(0.5); - - // Configuration Thread - CANUpdateThread updateThread = new CANUpdateThread(); - - public ModuleIOTalonFX( - SwerveModuleConstants constants) - { - this.constants = constants; - driveTalon = - new TalonFX(constants.DriveMotorId, DriveConstants.drivetrainConstants.CANBusName); - turnTalon = - new TalonFX(constants.SteerMotorId, DriveConstants.drivetrainConstants.CANBusName); - cancoder = new CANcoder(constants.EncoderId, DriveConstants.drivetrainConstants.CANBusName); - - // Configure drive motor - var driveConfig = constants.DriveMotorInitialConfigs; - driveConfig.MotorOutput.NeutralMode = NeutralModeValue.Brake; - driveConfig.Slot0 = constants.DriveMotorGains; - driveConfig.Feedback.SensorToMechanismRatio = constants.DriveMotorGearRatio; - driveConfig.TorqueCurrent.PeakForwardTorqueCurrent = constants.SlipCurrent; - driveConfig.TorqueCurrent.PeakReverseTorqueCurrent = -constants.SlipCurrent; - driveConfig.CurrentLimits.StatorCurrentLimit = constants.SlipCurrent; - driveConfig.CurrentLimits.StatorCurrentLimitEnable = true; - driveConfig.MotorOutput.Inverted = constants.DriveMotorInverted - ? InvertedValue.Clockwise_Positive - : InvertedValue.CounterClockwise_Positive; - updateThread - .CTRECheckErrorAndRetry(() -> driveTalon.getConfigurator().apply(driveConfig, 0.25)); - updateThread - .CTRECheckErrorAndRetry(() -> driveTalon.setPosition(0.0, 0.25)); - - // Configure turn motor - var turnConfig = new TalonFXConfiguration(); - turnConfig.MotorOutput.NeutralMode = NeutralModeValue.Brake; - turnConfig.Slot0 = constants.SteerMotorGains; - turnConfig.Feedback.FeedbackRemoteSensorID = constants.EncoderId; - turnConfig.Feedback.FeedbackSensorSource = switch (constants.FeedbackSource) { - case RemoteCANcoder -> FeedbackSensorSourceValue.RemoteCANcoder; - case FusedCANcoder -> FeedbackSensorSourceValue.FusedCANcoder; - case SyncCANcoder -> FeedbackSensorSourceValue.SyncCANcoder; - default -> throw new RuntimeException( - "You are using an unsupported swerve configuration, which this template does not support without manual customization. The 2025 release of Phoenix supports some swerve configurations which were not available during 2025 beta testing, preventing any development and support from the AdvantageKit developers."); - }; - turnConfig.Feedback.RotorToSensorRatio = constants.SteerMotorGearRatio; - turnConfig.MotionMagic.MotionMagicCruiseVelocity = 100.0 / constants.SteerMotorGearRatio; - turnConfig.MotionMagic.MotionMagicAcceleration = - turnConfig.MotionMagic.MotionMagicCruiseVelocity / 0.100; - turnConfig.MotionMagic.MotionMagicExpo_kV = 0.12 * constants.SteerMotorGearRatio; - turnConfig.MotionMagic.MotionMagicExpo_kA = 0.1; - turnConfig.ClosedLoopGeneral.ContinuousWrap = true; - turnConfig.MotorOutput.Inverted = constants.SteerMotorInverted - ? InvertedValue.Clockwise_Positive - : InvertedValue.CounterClockwise_Positive; - updateThread - .CTRECheckErrorAndRetry(() -> turnTalon.getConfigurator().apply(turnConfig, 0.25)); - - // Configure CANCoder - CANcoderConfiguration cancoderConfig = constants.EncoderInitialConfigs; - cancoderConfig.MagnetSensor.MagnetOffset = constants.EncoderOffset; - cancoderConfig.MagnetSensor.SensorDirection = constants.EncoderInverted - ? SensorDirectionValue.Clockwise_Positive - : SensorDirectionValue.CounterClockwise_Positive; - cancoder.getConfigurator().apply(cancoderConfig); - - // Create timestamp queue - timestampQueue = PhoenixOdometryThread.getInstance().makeTimestampQueue(); - - // Create drive status signals - drivePosition = driveTalon.getPosition(); - drivePositionQueue = - PhoenixOdometryThread.getInstance().registerSignal(driveTalon.getPosition()); - driveVelocity = driveTalon.getVelocity(); - driveAppliedVolts = driveTalon.getMotorVoltage(); - driveCurrent = driveTalon.getStatorCurrent(); - - // Create turn status signals - turnAbsolutePosition = cancoder.getAbsolutePosition(); - turnPosition = turnTalon.getPosition(); - turnPositionQueue = - PhoenixOdometryThread.getInstance().registerSignal(turnTalon.getPosition()); - turnVelocity = turnTalon.getVelocity(); - turnAppliedVolts = turnTalon.getMotorVoltage(); - turnCurrent = turnTalon.getStatorCurrent(); - - // Configure periodic frames - BaseStatusSignal.setUpdateFrequencyForAll( - Drive.ODOMETRY_FREQUENCY, drivePosition, turnPosition); - BaseStatusSignal.setUpdateFrequencyForAll( - 50.0, - driveVelocity, - driveAppliedVolts, - driveCurrent, - turnAbsolutePosition, - turnVelocity, - turnAppliedVolts, - turnCurrent); - ParentDevice.optimizeBusUtilizationForAll(driveTalon, turnTalon); - } - - @Override - public void updateInputs(ModuleIOInputs inputs) - { - // Refresh all signals - var driveStatus = BaseStatusSignal.refreshAll(drivePosition, driveVelocity, - driveAppliedVolts, driveCurrent); - var turnStatus = - BaseStatusSignal.refreshAll(turnPosition, turnVelocity, turnAppliedVolts, turnCurrent); - var turnEncoderStatus = BaseStatusSignal.refreshAll(turnAbsolutePosition); - - // Update drive inputs - inputs.driveConnected = driveConnectedDebounce.calculate(driveStatus.isOK()); - inputs.drivePositionRad = Units.rotationsToRadians(drivePosition.getValueAsDouble()); - inputs.driveVelocityRadPerSec = Units.rotationsToRadians(driveVelocity.getValueAsDouble()); - inputs.driveAppliedVolts = driveAppliedVolts.getValueAsDouble(); - inputs.driveCurrentAmps = driveCurrent.getValueAsDouble(); - - // Update turn inputs - inputs.turnConnected = turnConnectedDebounce.calculate(turnStatus.isOK()); - inputs.turnEncoderConnected = - turnEncoderConnectedDebounce.calculate(turnEncoderStatus.isOK()); - inputs.turnAbsolutePosition = - Rotation2d.fromRotations(turnAbsolutePosition.getValueAsDouble()); - inputs.turnPosition = Rotation2d.fromRotations(turnPosition.getValueAsDouble()); - inputs.turnVelocityRadPerSec = Units.rotationsToRadians(turnVelocity.getValueAsDouble()); - inputs.turnAppliedVolts = turnAppliedVolts.getValueAsDouble(); - inputs.turnCurrentAmps = turnCurrent.getValueAsDouble(); - - // Update odometry inputs - inputs.odometryTimestamps = - timestampQueue.stream().mapToDouble((Double value) -> value).toArray(); - inputs.odometryDrivePositionsRad = drivePositionQueue.stream() - .mapToDouble((Double value) -> Units.rotationsToRadians(value)) - .toArray(); - inputs.odometryTurnPositions = turnPositionQueue.stream() - .map((Double value) -> Rotation2d.fromRotations(value)) - .toArray(Rotation2d[]::new); - timestampQueue.clear(); - drivePositionQueue.clear(); - turnPositionQueue.clear(); - } - - @Override - public void setDriveOpenLoop(double output) - { - driveTalon.setControl( - switch (constants.DriveMotorClosedLoopOutput) { - case Voltage -> voltageRequest.withOutput(output); - case TorqueCurrentFOC -> torqueCurrentRequest.withOutput(output); - }); - } - - @Override - public void setTurnOpenLoop(double output) - { - turnTalon.setControl( - switch (constants.SteerMotorClosedLoopOutput) { - case Voltage -> voltageRequest.withOutput(output); - case TorqueCurrentFOC -> torqueCurrentRequest.withOutput(output); - }); - } - - @Override - public void setDriveVelocity(double velocityRadPerSec) - { - double velocityRotPerSec = Units.radiansToRotations(velocityRadPerSec); - driveTalon.setControl( - switch (constants.DriveMotorClosedLoopOutput) { - case Voltage -> velocityVoltageRequest.withVelocity(velocityRotPerSec); - case TorqueCurrentFOC -> velocityTorqueCurrentRequest - .withVelocity(velocityRotPerSec); - }); - } - - @Override - public void setTurnPosition(Rotation2d rotation) - { - turnTalon.setControl( - switch (constants.SteerMotorClosedLoopOutput) { - case Voltage -> positionVoltageRequest.withPosition(rotation.getRotations()); - case TorqueCurrentFOC -> positionTorqueCurrentRequest.withPosition( - rotation.getRotations()); - }); - } -} diff --git a/src/main/java/frc/robot/subsystems/w8_examples/drive/PhoenixOdometryThread.java b/src/main/java/frc/robot/subsystems/w8_examples/drive/PhoenixOdometryThread.java deleted file mode 100644 index af5dc81..0000000 --- a/src/main/java/frc/robot/subsystems/w8_examples/drive/PhoenixOdometryThread.java +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright (C) 2025 Windham Windup - * - * This program is free software: you can redistribute it and/or modify it under the terms of the - * GNU General Public License as published by the Free Software Foundation, either version 3 of the - * License, or any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without - * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program. If - * not, see . - */ - -package frc.robot.subsystems.drive; - -import com.ctre.phoenix6.BaseStatusSignal; -import com.ctre.phoenix6.CANBus; -import com.ctre.phoenix6.StatusSignal; -import edu.wpi.first.units.measure.Angle; -import edu.wpi.first.wpilibj.RobotController; - -import java.util.ArrayList; -import java.util.List; -import java.util.Queue; -import java.util.concurrent.ArrayBlockingQueue; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; -import java.util.function.DoubleSupplier; - -/** - * Provides an interface for asynchronously reading high-frequency measurements to a set of queues. - * - *

- * This version is intended for Phoenix 6 devices on both the RIO and CANivore buses. When using a - * CANivore, the thread uses the "waitForAll" blocking method to enable more consistent sampling. - * This also allows Phoenix Pro users to benefit from lower latency between devices using CANivore - * time synchronization. - */ -public class PhoenixOdometryThread extends Thread { - private final Lock signalsLock = new ReentrantLock(); // Prevents conflicts when registering - // signals - private BaseStatusSignal[] phoenixSignals = new BaseStatusSignal[0]; - private final List genericSignals = new ArrayList<>(); - private final List> phoenixQueues = new ArrayList<>(); - private final List> genericQueues = new ArrayList<>(); - private final List> timestampQueues = new ArrayList<>(); - - private static boolean isCANFD = - new CANBus(DriveConstants.drivetrainConstants.CANBusName).isNetworkFD(); - private static PhoenixOdometryThread instance = null; - - public static PhoenixOdometryThread getInstance() - { - if (instance == null) { - instance = new PhoenixOdometryThread(); - } - return instance; - } - - private PhoenixOdometryThread() - { - setName("PhoenixOdometryThread"); - setDaemon(true); - } - - @Override - public synchronized void start() - { - if (timestampQueues.size() > 0) { - super.start(); - } - } - - /** Registers a Phoenix signal to be read from the thread. */ - public Queue registerSignal(StatusSignal signal) - { - Queue queue = new ArrayBlockingQueue<>(20); - signalsLock.lock(); - Drive.odometryLock.lock(); - try { - BaseStatusSignal[] newSignals = new BaseStatusSignal[phoenixSignals.length + 1]; - System.arraycopy(phoenixSignals, 0, newSignals, 0, phoenixSignals.length); - newSignals[phoenixSignals.length] = signal; - phoenixSignals = newSignals; - phoenixQueues.add(queue); - } finally { - signalsLock.unlock(); - Drive.odometryLock.unlock(); - } - return queue; - } - - /** Registers a generic signal to be read from the thread. */ - public Queue registerSignal(DoubleSupplier signal) - { - Queue queue = new ArrayBlockingQueue<>(20); - signalsLock.lock(); - Drive.odometryLock.lock(); - try { - genericSignals.add(signal); - genericQueues.add(queue); - } finally { - signalsLock.unlock(); - Drive.odometryLock.unlock(); - } - return queue; - } - - /** Returns a new queue that returns timestamp values for each sample. */ - public Queue makeTimestampQueue() - { - Queue queue = new ArrayBlockingQueue<>(20); - Drive.odometryLock.lock(); - try { - timestampQueues.add(queue); - } finally { - Drive.odometryLock.unlock(); - } - return queue; - } - - @Override - @SuppressWarnings("CatchAndPrintStackTrace") - public void run() - { - while (true) { - // Wait for updates from all signals - signalsLock.lock(); - try { - if (isCANFD && phoenixSignals.length > 0) { - BaseStatusSignal.waitForAll(2.0 / Drive.ODOMETRY_FREQUENCY, phoenixSignals); - } else { - // "waitForAll" does not support blocking on multiple signals with a bus - // that is not CAN FD, regardless of Pro licensing. No reasoning for this - // behavior is provided by the documentation. - Thread.sleep((long) (1000.0 / Drive.ODOMETRY_FREQUENCY)); - if (phoenixSignals.length > 0) - BaseStatusSignal.refreshAll(phoenixSignals); - } - } catch (InterruptedException e) { - e.printStackTrace(); - } finally { - signalsLock.unlock(); - } - - // Save new data to queues - Drive.odometryLock.lock(); - try { - // Sample timestamp is current FPGA time minus average CAN latency - // Default timestamps from Phoenix are NOT compatible with - // FPGA timestamps, this solution is imperfect but close - double timestamp = RobotController.getFPGATime() / 1e6; - double totalLatency = 0.0; - for (BaseStatusSignal signal : phoenixSignals) { - totalLatency += signal.getTimestamp().getLatency(); - } - if (phoenixSignals.length > 0) { - timestamp -= totalLatency / phoenixSignals.length; - } - - // Add new samples to queues - for (int i = 0; i < phoenixSignals.length; i++) { - phoenixQueues.get(i).offer(phoenixSignals[i].getValueAsDouble()); - } - for (int i = 0; i < genericSignals.size(); i++) { - genericQueues.get(i).offer(genericSignals.get(i).getAsDouble()); - } - for (int i = 0; i < timestampQueues.size(); i++) { - timestampQueues.get(i).offer(timestamp); - } - } finally { - Drive.odometryLock.unlock(); - } - } - } -} diff --git a/src/main/java/frc/robot/subsystems/w8_examples/flywheel/Flywheel.java b/src/main/java/frc/robot/subsystems/w8_examples/flywheel/Flywheel.java deleted file mode 100644 index 6306949..0000000 --- a/src/main/java/frc/robot/subsystems/w8_examples/flywheel/Flywheel.java +++ /dev/null @@ -1,63 +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.subsystems.flywheel; - -import static edu.wpi.first.units.Units.Amps; -import edu.wpi.first.units.measure.AngularVelocity; -import edu.wpi.first.units.measure.Current; -import edu.wpi.first.wpilibj2.command.Command; -import edu.wpi.first.wpilibj2.command.SubsystemBase; -import frc.lib.io.motor.MotorIO.PIDSlot; -import frc.lib.mechanisms.flywheel.FlywheelMechanism; -import frc.lib.util.LoggerHelper; - -/** Add your docs here. */ -public class Flywheel extends SubsystemBase { // Don't extend if contained in superstructure - private final FlywheelMechanism io; - - public Flywheel(FlywheelMechanism io) - { - this.io = io; - } - - @Override - public void periodic() - { - LoggerHelper.recordCurrentCommand(FlywheelConstants.NAME, this); - io.periodic(); - } - - public Command shoot() - { - return this.runOnce(() -> io.runVelocity(FlywheelConstants.MAX_VELOCITY, - FlywheelConstants.MAX_ACCELERATION, PIDSlot.SLOT_0)).withName("Shoot"); - } - - public Command stop() - { - return this.runOnce(() -> io.runCoast()).withName("Stop"); - } - - // For unit testing - protected Command shootAmps() - { - return this.runOnce(() -> io.runCurrent(Amps.of(30))).withName("Shoot Amps"); - } - - public Current getTorqueCurrent() - { - return io.getTorqueCurrent(); - } - - public AngularVelocity getVelocity() - { - return io.getVelocity(); - } - - public void close() - { - io.close(); - } -} diff --git a/src/main/java/frc/robot/subsystems/w8_examples/flywheel/FlywheelConstants.java b/src/main/java/frc/robot/subsystems/w8_examples/flywheel/FlywheelConstants.java deleted file mode 100644 index 3bb8437..0000000 --- a/src/main/java/frc/robot/subsystems/w8_examples/flywheel/FlywheelConstants.java +++ /dev/null @@ -1,96 +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.subsystems.flywheel; - -import static edu.wpi.first.units.Units.KilogramSquareMeters; -import static edu.wpi.first.units.Units.Second; -import com.ctre.phoenix6.configs.Slot0Configs; -import com.ctre.phoenix6.configs.TalonFXConfiguration; -import com.ctre.phoenix6.signals.InvertedValue; -import com.ctre.phoenix6.signals.NeutralModeValue; -import edu.wpi.first.math.system.plant.DCMotor; -import edu.wpi.first.units.Units; -import edu.wpi.first.units.measure.AngularAcceleration; -import edu.wpi.first.units.measure.AngularVelocity; -import edu.wpi.first.units.measure.MomentOfInertia; -import frc.lib.io.motor.MotorIOTalonFX; -import frc.lib.io.motor.MotorIOTalonFXSim; -import frc.lib.mechanisms.flywheel.FlywheelMechanism; -import frc.lib.mechanisms.flywheel.FlywheelMechanismReal; -import frc.lib.mechanisms.flywheel.FlywheelMechanismSim; -import frc.robot.Constants; -import frc.robot.Ports; -import frc.robot.Robot; - -/** Add your docs here. */ -public class FlywheelConstants { - - public static String NAME = "Flywheel"; - - public static final AngularVelocity MAX_VELOCITY = - Units.RadiansPerSecond.of(2 * Math.PI); - public static final AngularAcceleration MAX_ACCELERATION = MAX_VELOCITY.per(Second); - - private static final double GEARING = (2.0 / 1.0); - - public static final AngularVelocity TOLERANCE = MAX_VELOCITY.times(0.1); - - private static final DCMotor DCMOTOR = DCMotor.getKrakenX60(1); - public static final MomentOfInertia MOI = KilogramSquareMeters.of(1.0); - - // Velocity PID - private static Slot0Configs SLOT0CONFIG = new Slot0Configs() - .withKP(1000.0) - .withKI(0.0) - .withKD(0.0); - - public static TalonFXConfiguration getFXConfig() - { - TalonFXConfiguration config = new TalonFXConfiguration(); - - config.CurrentLimits.SupplyCurrentLimitEnable = Robot.isReal(); - config.CurrentLimits.SupplyCurrentLimit = 40.0; - config.CurrentLimits.SupplyCurrentLowerLimit = 40.0; - config.CurrentLimits.SupplyCurrentLowerTime = 0.1; - - config.CurrentLimits.StatorCurrentLimitEnable = Robot.isReal(); - config.CurrentLimits.StatorCurrentLimit = 80.0; - - config.Voltage.PeakForwardVoltage = 12.0; - config.Voltage.PeakReverseVoltage = -12.0; - - config.MotorOutput.NeutralMode = NeutralModeValue.Brake; - config.MotorOutput.Inverted = InvertedValue.CounterClockwise_Positive; - - config.SoftwareLimitSwitch.ForwardSoftLimitEnable = false; - - config.SoftwareLimitSwitch.ReverseSoftLimitEnable = false; - - config.Feedback.RotorToSensorRatio = 1.0; - - config.Feedback.SensorToMechanismRatio = GEARING; - - config.Slot0 = SLOT0CONFIG; - - return config; - } - - public static Flywheel get() - { - switch (Constants.currentMode) { - case REAL: - return new Flywheel(new FlywheelMechanismReal( - new MotorIOTalonFX(NAME, getFXConfig(), Ports.flywheel))); - case SIM: - return new Flywheel(new FlywheelMechanismSim( - new MotorIOTalonFXSim(NAME, getFXConfig(), Ports.flywheel), - DCMOTOR, MOI, TOLERANCE)); - case REPLAY: - return new Flywheel(new FlywheelMechanism() {}); - default: - throw new IllegalStateException("Unrecognized Robot Mode"); - } - } -} diff --git a/src/main/java/frc/robot/subsystems/w8_examples/lasercan1/LaserCAN1.java b/src/main/java/frc/robot/subsystems/w8_examples/lasercan1/LaserCAN1.java deleted file mode 100644 index 4366aee..0000000 --- a/src/main/java/frc/robot/subsystems/w8_examples/lasercan1/LaserCAN1.java +++ /dev/null @@ -1,64 +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.subsystems.lasercan1; - -import static edu.wpi.first.units.Units.Inches; -import static edu.wpi.first.units.Units.Millimeters; -import org.littletonrobotics.junction.Logger; -import edu.wpi.first.math.geometry.Pose3d; -import edu.wpi.first.math.geometry.Rotation3d; -import edu.wpi.first.math.geometry.Transform3d; -import edu.wpi.first.units.measure.Distance; -import edu.wpi.first.wpilibj2.command.SubsystemBase; -import edu.wpi.first.wpilibj2.command.button.Trigger; -import frc.lib.devices.DistanceSensor; -import frc.lib.io.distancesensor.DistanceSensorIO; -import frc.robot.RobotState; - -public class LaserCAN1 extends SubsystemBase { - private final DistanceSensor distanceSensor; - private final RobotState robotState; - - public final Trigger inside = - new Trigger(() -> betweenDistance(Millimeters.of(5), Millimeters.of(10))); - - public LaserCAN1(DistanceSensorIO io) - { - distanceSensor = new DistanceSensor(io); - robotState = RobotState.getInstance(); - } - - @Override - public void periodic() - { - distanceSensor.periodic(); - Logger.recordOutput(LaserCAN1Constants.NAME + "Sensor Reading Pose", - new Pose3d(robotState.getPose()).plus(LaserCAN1Constants.LASERCAN_TRANSFORM.plus( - new Transform3d( - getDistance(), - Inches.of(0), - Inches.of(0), - new Rotation3d())))); - } - - public Distance getDistance() - { - if (distanceSensor.getDistance().isEmpty()) { - return Inches.of(-1.0); - } else { - return distanceSensor.getDistance().get(); - } - } - - public boolean betweenDistance(Distance min, Distance max) - { - if (distanceSensor.getDistance().isEmpty()) { - return false; - } - - Distance distance = distanceSensor.getDistance().get(); - return distance.gt(min) && distance.lt(max); - } -} diff --git a/src/main/java/frc/robot/subsystems/w8_examples/lasercan1/LaserCAN1Constants.java b/src/main/java/frc/robot/subsystems/w8_examples/lasercan1/LaserCAN1Constants.java deleted file mode 100644 index e5ae78d..0000000 --- a/src/main/java/frc/robot/subsystems/w8_examples/lasercan1/LaserCAN1Constants.java +++ /dev/null @@ -1,69 +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.subsystems.lasercan1; - -import static edu.wpi.first.units.Units.Inches; -import static edu.wpi.first.units.Units.Radians; -import au.grapplerobotics.interfaces.LaserCanInterface.RangingMode; -import au.grapplerobotics.interfaces.LaserCanInterface.RegionOfInterest; -import au.grapplerobotics.interfaces.LaserCanInterface.TimingBudget; -import edu.wpi.first.math.geometry.Rotation3d; -import edu.wpi.first.math.geometry.Transform3d; -import edu.wpi.first.math.geometry.Translation3d; -import frc.lib.io.distancesensor.DistanceSensorIO; -import frc.lib.io.distancesensor.DistanceSensorIOLaserCAN; -import frc.lib.io.distancesensor.DistanceSensorIOSim; -import frc.robot.Constants; -import frc.robot.Ports; - -/** Add your docs here. */ -public class LaserCAN1Constants { - - public final static String NAME = "LaserCAN #1"; - private final static RangingMode RANGING_MODE = RangingMode.SHORT; - private final static RegionOfInterest ROI = new RegionOfInterest(8, 8, 4, 4); - private final static TimingBudget TIMING_BUDGET = TimingBudget.TIMING_BUDGET_20MS; - public final static Transform3d LASERCAN_TRANSFORM = new Transform3d( - new Translation3d( - Inches.of(12), - Inches.of(0.0), - Inches.of(12)), - new Rotation3d( - Radians.of(0.0), - Radians.of(0.0), - Radians.of(0.0))); - - public static DistanceSensorIOLaserCAN getReal() - { - return new DistanceSensorIOLaserCAN(Ports.laserCAN1, NAME, RANGING_MODE, ROI, - TIMING_BUDGET); - } - - public static DistanceSensorIOSim getSim() - { - return new DistanceSensorIOSim(NAME); - } - - public static DistanceSensorIO getReplay() - { - return new DistanceSensorIO() {}; - } - - public static LaserCAN1 get() - { - switch (Constants.currentMode) { - case REAL: - return new LaserCAN1( - new DistanceSensorIOLaserCAN(Ports.laserCAN1, NAME, RANGING_MODE, ROI, - TIMING_BUDGET)); - case SIM: - return new LaserCAN1(new DistanceSensorIOSim(NAME)); - case REPLAY: - return new LaserCAN1(new DistanceSensorIO() {}); - default: - throw new IllegalStateException("Unrecognized Robot Mode"); - } - } -} diff --git a/src/main/java/frc/robot/subsystems/w8_examples/leds/LEDs.java b/src/main/java/frc/robot/subsystems/w8_examples/leds/LEDs.java deleted file mode 100644 index fb27709..0000000 --- a/src/main/java/frc/robot/subsystems/w8_examples/leds/LEDs.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (C) 2025 Windham Windup - * - * This program is free software: you can redistribute it and/or modify it under the terms of the - * GNU General Public License as published by the Free Software Foundation, either version 3 of the - * License, or any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without - * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program. If - * not, see . - */ - -package frc.robot.subsystems.leds; - -import edu.wpi.first.wpilibj2.command.Command; -import edu.wpi.first.wpilibj2.command.SubsystemBase; -import frc.lib.devices.Lights; -import frc.lib.io.lights.LightsIO; -import frc.lib.util.LoggerHelper; - -public class LEDs extends SubsystemBase { - private final Lights lights; - - public LEDs(LightsIO io) - { - lights = new Lights(io); - } - - @Override - public void periodic() - { - LoggerHelper.recordCurrentCommand(LEDsConstants.NAME, this); - } - - public Command runDisabledAnimation() - { - return this.startEnd( - () -> lights.setAnimations(LEDsConstants.disabledAnimation), - () -> lights.setAnimations(LEDsConstants.offAnimation)) - .withName("Disabled Animation"); - } - - public Command runAutoAnimation() - { - return this.startEnd( - () -> lights.setAnimations(LEDsConstants.autoAnimation), - () -> lights.setAnimations(LEDsConstants.offAnimation)) - .withName("Auto Animation"); - } -} diff --git a/src/main/java/frc/robot/subsystems/w8_examples/leds/LEDsConstants.java b/src/main/java/frc/robot/subsystems/w8_examples/leds/LEDsConstants.java deleted file mode 100644 index ec999a9..0000000 --- a/src/main/java/frc/robot/subsystems/w8_examples/leds/LEDsConstants.java +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright (C) 2025 Windham Windup - * - * This program is free software: you can redistribute it and/or modify it under the terms of the - * GNU General Public License as published by the Free Software Foundation, either version 3 of the - * License, or any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without - * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program. If - * not, see . - */ - -package frc.robot.subsystems.leds; - -import java.util.List; -import com.ctre.phoenix6.configs.CANdleConfiguration; -import com.ctre.phoenix6.configs.CANdleFeaturesConfigs; -import com.ctre.phoenix6.configs.LEDConfigs; -import com.ctre.phoenix6.controls.ControlRequest; -import com.ctre.phoenix6.controls.EmptyAnimation; -import com.ctre.phoenix6.controls.FireAnimation; -import com.ctre.phoenix6.controls.RainbowAnimation; -import com.ctre.phoenix6.controls.StrobeAnimation; -import com.ctre.phoenix6.signals.AnimationDirectionValue; -import com.ctre.phoenix6.signals.Enable5VRailValue; -import com.ctre.phoenix6.signals.LossOfSignalBehaviorValue; -import com.ctre.phoenix6.signals.RGBWColor; -import com.ctre.phoenix6.signals.StatusLedWhenActiveValue; -import com.ctre.phoenix6.signals.StripTypeValue; -import com.ctre.phoenix6.signals.VBatOutputModeValue; - -import edu.wpi.first.wpilibj.util.Color; -import frc.lib.io.lights.LightsIO; -import frc.lib.io.lights.LightsIOCandle; -import frc.lib.io.lights.LightsIOSim; -import frc.robot.Constants; -import frc.robot.Ports; - -public class LEDsConstants { - public static final String NAME = "MainLEDs"; - - public static final LEDSegment CANDLE_LEDS = new LEDSegment(0, 7, 0); - public static final LEDSegment FRONT_STRIP = new LEDSegment(8, 10, 1); - - public static final CANdleConfiguration CANDLE_CONFIG = new CANdleConfiguration() - .withCANdleFeatures(new CANdleFeaturesConfigs() - .withEnable5VRail(Enable5VRailValue.Enabled) - .withVBatOutputMode(VBatOutputModeValue.On) - .withStatusLedWhenActive(StatusLedWhenActiveValue.Disabled)) - .withLED(new LEDConfigs() - .withBrightnessScalar(1.0) - .withStripType(StripTypeValue.RGB) - .withLossOfSignalBehavior(LossOfSignalBehaviorValue.DisableLEDs)); - - public static final LightsIOCandle getLightsIOReal() - { - return new LightsIOCandle(NAME, Ports.lights, CANDLE_CONFIG); - } - - public static final LightsIOSim getLightsIOSim() - { - return new LightsIOSim(NAME); - } - - public static final LightsIO getLightsIOReplay() - { - return new LightsIO() {}; - } - - public static LEDs get() - { - switch (Constants.currentMode) { - case REAL: - return new LEDs(new LightsIOCandle(NAME, Ports.lights, CANDLE_CONFIG)); - case SIM: - return new LEDs(new LightsIOSim(NAME)); - case REPLAY: - return new LEDs(new LightsIO() {}); - default: - throw new IllegalStateException("Unrecognized Robot Mode"); - } - } - - public record LEDSegment(int startIndex, int endIndex, int animationSlot) { - }; - - // Animations - - // Off - public static final ControlRequest candleOff = new EmptyAnimation(CANDLE_LEDS.animationSlot); - - public static final ControlRequest frontOff = new EmptyAnimation(FRONT_STRIP.animationSlot);; - - public static final List offAnimation = List.of(candleOff, frontOff); - - // Disabled - public static final ControlRequest candleDisabled = - new RainbowAnimation(CANDLE_LEDS.startIndex, CANDLE_LEDS.endIndex) - .withSlot(CANDLE_LEDS.animationSlot) - .withFrameRate(10) - .withBrightness(0.7) - .withDirection(AnimationDirectionValue.Forward); - - public static final ControlRequest frontDisabled = - new RainbowAnimation(FRONT_STRIP.startIndex, FRONT_STRIP.endIndex) - .withSlot(FRONT_STRIP.animationSlot) - .withFrameRate(10) - .withBrightness(0.7) - .withDirection(AnimationDirectionValue.Forward); - - public static final List disabledAnimation = - List.of(candleDisabled, frontDisabled); - - // Auto - public static final ControlRequest candleAuto = - new FireAnimation(CANDLE_LEDS.startIndex, CANDLE_LEDS.endIndex) - .withSlot(CANDLE_LEDS.animationSlot) - .withFrameRate(10) - .withBrightness(0.7) - .withDirection(AnimationDirectionValue.Forward) - .withCooling(0.1) - .withSparking(1.0); - - public static final ControlRequest frontAuto = - new FireAnimation(FRONT_STRIP.startIndex, FRONT_STRIP.endIndex) - .withSlot(FRONT_STRIP.animationSlot) - .withFrameRate(10) - .withBrightness(0.7) - .withDirection(AnimationDirectionValue.Forward) - .withCooling(0.1) - .withSparking(1.0); - - public static final List autoAnimation = List.of(candleAuto, frontAuto); - - // Flashing - public static final ControlRequest candleFlash = - new StrobeAnimation(CANDLE_LEDS.startIndex, CANDLE_LEDS.endIndex) - .withSlot(CANDLE_LEDS.animationSlot) - .withFrameRate(10) - .withColor(new RGBWColor(Color.kRed)); - -} diff --git a/src/main/java/frc/robot/subsystems/w8_examples/linear/Linear.java b/src/main/java/frc/robot/subsystems/w8_examples/linear/Linear.java deleted file mode 100644 index 7233d58..0000000 --- a/src/main/java/frc/robot/subsystems/w8_examples/linear/Linear.java +++ /dev/null @@ -1,125 +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.subsystems.linear; - -import static edu.wpi.first.units.Units.Amps; -import static edu.wpi.first.units.Units.Inches; -import static edu.wpi.first.units.Units.Seconds; -import static edu.wpi.first.units.Units.Volts; -import edu.wpi.first.math.filter.Debouncer; -import edu.wpi.first.math.filter.Debouncer.DebounceType; -import edu.wpi.first.units.measure.Angle; -import edu.wpi.first.units.measure.AngularVelocity; -import edu.wpi.first.units.measure.Distance; -import edu.wpi.first.units.measure.LinearVelocity; -import edu.wpi.first.wpilibj2.command.Command; -import edu.wpi.first.wpilibj2.command.Commands; -import edu.wpi.first.wpilibj2.command.SubsystemBase; -import edu.wpi.first.wpilibj2.command.button.Trigger; -import frc.lib.io.motor.MotorIO.PIDSlot; -import frc.lib.mechanisms.linear.LinearMechanism; -import frc.lib.util.LoggedTunableNumber; -import frc.lib.util.LoggerHelper; -import frc.robot.RobotState; -import lombok.Getter; -import lombok.RequiredArgsConstructor; - -/** Add your docs here. */ -public class Linear extends SubsystemBase { - private final LinearMechanism io; - private Trigger homedTrigger; - private Debouncer homeDebouncer = new Debouncer(0.1, DebounceType.kRising); - - private static final LoggedTunableNumber STOW_SETPOINT = - new LoggedTunableNumber("Stow Height", 0.0); - private static final LoggedTunableNumber RASIED_SETPOINT = - new LoggedTunableNumber("Raised Height", 30.0); - - @RequiredArgsConstructor - @SuppressWarnings("Immutable") - @Getter - public enum Setpoint { - HOME(Inches.of(0.0)), - STOW(Inches.of(STOW_SETPOINT.get())), - RAISED(Inches.of(RASIED_SETPOINT.get())); - - private final Distance setpoint; - - public Angle getAngle() - { - return LinearConstants.CONVERTER.toAngle(setpoint); - } - } - - private final RobotState robotstate = RobotState.getInstance(); - - public Linear(LinearMechanism io) - { - this.io = io; - homedTrigger = - new Trigger(() -> homeDebouncer.calculate(io.getSupplyCurrent().gte(Amps.of(10)))); - } - - @Override - public void periodic() - { - LoggerHelper.recordCurrentCommand(LinearConstants.NAME, this); - io.periodic(); - robotstate.setLinearPose(io.getPoseSupplier().get()); - } - - public Command setGoal(Setpoint setpoint) - { - return this - .runOnce(() -> io.runPosition(setpoint.getAngle(), LinearConstants.CRUISE_VELOCITY, - LinearConstants.ACCELERATION, LinearConstants.JERK, PIDSlot.SLOT_0)) - .withName("Go To " + setpoint.toString() + " Setpoint"); - } - - public boolean nearGoal(Distance goalPosition) - { - return io.nearGoal(goalPosition, LinearConstants.TOLERANCE); - } - - public Command waitUntilGoalCommand(Distance position) - { - return Commands.waitUntil(() -> { - return nearGoal(position); - }); - } - - public Command setGoalCommandWithWait(Setpoint setpoint) - { - return waitUntilGoalCommand(setpoint.getSetpoint()) - .deadlineFor(setGoal(setpoint)) - .withName("Go To " + setpoint.toString() + " Setpoint with wait"); - } - - public Command homeCommand() - { - return Commands.sequence( - runOnce(() -> io.runVoltage(Volts.of(-2))), - Commands.waitUntil(homedTrigger), - runOnce(() -> io.setEncoderPosition(Setpoint.HOME.getAngle())), - setGoal(Setpoint.STOW)) - .withName("Homing"); - } - - public AngularVelocity getVelocity() - { - return io.getVelocity(); - } - - public LinearVelocity getLinearVelocity() - { - return LinearConstants.CONVERTER.toDistance(io.getVelocity().times(Seconds.of(1))) - .div(Seconds.of(1)); - } - - public void close() - { - io.close(); - } -} diff --git a/src/main/java/frc/robot/subsystems/w8_examples/linear/LinearConstants.java b/src/main/java/frc/robot/subsystems/w8_examples/linear/LinearConstants.java deleted file mode 100644 index 2dc1716..0000000 --- a/src/main/java/frc/robot/subsystems/w8_examples/linear/LinearConstants.java +++ /dev/null @@ -1,128 +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.subsystems.linear; - -import static edu.wpi.first.units.Units.Degrees; -import static edu.wpi.first.units.Units.Inches; -import static edu.wpi.first.units.Units.Kilograms; -import static edu.wpi.first.units.Units.Rotations; -import static edu.wpi.first.units.Units.Second; -import com.ctre.phoenix6.configs.Slot0Configs; -import com.ctre.phoenix6.configs.TalonFXConfiguration; -import com.ctre.phoenix6.signals.InvertedValue; -import com.ctre.phoenix6.signals.NeutralModeValue; -import edu.wpi.first.math.geometry.Rotation3d; -import edu.wpi.first.math.geometry.Translation3d; -import edu.wpi.first.math.system.plant.DCMotor; -import edu.wpi.first.units.AngularAccelerationUnit; -import edu.wpi.first.units.Units; -import edu.wpi.first.units.measure.AngularAcceleration; -import edu.wpi.first.units.measure.AngularVelocity; -import edu.wpi.first.units.measure.Distance; -import edu.wpi.first.units.measure.Mass; -import edu.wpi.first.units.measure.Velocity; -import frc.lib.io.motor.MotorIOTalonFX; -import frc.lib.io.motor.MotorIOTalonFXSim; -import frc.lib.mechanisms.linear.*; -import frc.lib.mechanisms.linear.LinearMechanism.LinearMechCharacteristics; -import frc.lib.util.MechanismUtil.DistanceAngleConverter; -import frc.robot.Constants; -import frc.robot.Ports; -import frc.robot.Robot; - -/** Add your docs here. */ -public class LinearConstants { - public static String NAME = "Linear"; - - public static final Distance TOLERANCE = Inches.of(2.0); - - public static final AngularVelocity CRUISE_VELOCITY = - Units.RadiansPerSecond.of(2 * Math.PI).times(10.0); - public static final AngularAcceleration ACCELERATION = - CRUISE_VELOCITY.div(0.1).per(Units.Second); - public static final Velocity JERK = ACCELERATION.per(Second); - - private static final double GEARING = (2.0 / 1.0); - private static final Distance MIN_DISTANCE = Inches.of(0.0); - private static final Distance MAX_DISTANCE = Inches.of(36.0); - private static final Distance STARTING_DISTANCE = Inches.of(0.0); - - private static final Distance DRUM_RADIUS = Inches.of(1.0); - private static final Mass CARRIAGE_MASS = Kilograms.of(.01); - private static final DCMotor DCMOTOR = DCMotor.getKrakenX60(1); - - public static final DistanceAngleConverter CONVERTER = new DistanceAngleConverter(DRUM_RADIUS); - - // Orientation for the linear mechanism. - // Uses WPILib's counter-clockwise positive convention around Y-axis: - // A pitch of -90 degrees represents a vertical mechanism extending upward (like an elevator). - // Pitch of 0 degrees would be horizontal extending forward. - // Roll and yaw can be used for mechanisms that extend in other directions. - private static final Rotation3d ORIENTATION = - new Rotation3d(0.0, Degrees.of(-90.0).in(Units.Radians), 0.0); - - private static final LinearMechCharacteristics CHARACTERISTICS = - new LinearMechCharacteristics(new Translation3d(0.0, 0.0, 0.0), MIN_DISTANCE, MAX_DISTANCE, - STARTING_DISTANCE, CONVERTER, ORIENTATION); - - // Positional PID - public static Slot0Configs SLOT0CONFIG = new Slot0Configs() - .withKP(50.0) - .withKI(0.0) - .withKD(0.0); - - public static TalonFXConfiguration getFXConfig() - { - TalonFXConfiguration config = new TalonFXConfiguration(); - - config.CurrentLimits.SupplyCurrentLimitEnable = Robot.isReal(); - config.CurrentLimits.SupplyCurrentLimit = 40.0; - config.CurrentLimits.SupplyCurrentLowerLimit = 40.0; - config.CurrentLimits.SupplyCurrentLowerTime = 0.1; - - config.CurrentLimits.StatorCurrentLimitEnable = Robot.isReal(); - config.CurrentLimits.StatorCurrentLimit = 80.0; - - config.Voltage.PeakForwardVoltage = 12.0; - config.Voltage.PeakReverseVoltage = -12.0; - - config.MotorOutput.NeutralMode = NeutralModeValue.Brake; - config.MotorOutput.Inverted = InvertedValue.CounterClockwise_Positive; - - config.SoftwareLimitSwitch.ForwardSoftLimitEnable = true; - config.SoftwareLimitSwitch.ForwardSoftLimitThreshold = - CONVERTER.toAngle(MAX_DISTANCE).in(Rotations); - - config.SoftwareLimitSwitch.ReverseSoftLimitEnable = true; - config.SoftwareLimitSwitch.ReverseSoftLimitThreshold = - CONVERTER.toAngle(MIN_DISTANCE).in(Rotations); - - - config.Feedback.RotorToSensorRatio = 1.0; - - config.Feedback.SensorToMechanismRatio = GEARING; - - config.Slot0 = SLOT0CONFIG; - - return config; - } - - public static Linear get() - { - switch (Constants.currentMode) { - case REAL: - return new Linear(new LinearMechanismReal( - new MotorIOTalonFX(NAME, getFXConfig(), Ports.linear), CHARACTERISTICS)); - case SIM: - return new Linear(new LinearMechanismSim( - new MotorIOTalonFXSim(NAME, getFXConfig(), Ports.linear), - DCMOTOR, CARRIAGE_MASS, CHARACTERISTICS, true)); - case REPLAY: - return new Linear(new LinearMechanism(NAME, CHARACTERISTICS) {}); - default: - throw new IllegalStateException("Unrecognized Robot Mode"); - } - } -} diff --git a/src/main/java/frc/robot/subsystems/w8_examples/objectDetector/ObjectDetector.java b/src/main/java/frc/robot/subsystems/w8_examples/objectDetector/ObjectDetector.java deleted file mode 100644 index b05114e..0000000 --- a/src/main/java/frc/robot/subsystems/w8_examples/objectDetector/ObjectDetector.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (C) 2025 Windham Windup - * - * This program is free software: you can redistribute it and/or modify it under the terms of the - * GNU General Public License as published by the Free Software Foundation, either version 3 of the - * License, or any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without - * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program. If - * not, see . - */ - -package frc.robot.subsystems.objectDetector; - -import frc.lib.devices.ObjectDetection; -import frc.lib.io.objectdetection.ObjectDetectionIO; -import frc.robot.subsystems.drive.Drive; -import org.littletonrobotics.junction.Logger; -import edu.wpi.first.math.geometry.Translation2d; -import edu.wpi.first.wpilibj2.command.SubsystemBase; -import java.util.ArrayList; - -public class ObjectDetector extends SubsystemBase { - private final ObjectDetection objectDetection; - private final Drive drive; - private double range, heading, distance; - private Translation2d targetLocation; - private ArrayList lastNDetections = new ArrayList<>(10); - - // Pass in any object detection IO implementation (e.g. PhotonVision) that implements - // objectDetectionIO interface [real or sim] - public ObjectDetector(ObjectDetectionIO io, Drive drive) - { - objectDetection = new ObjectDetection(io); - this.drive = drive; - - } - - @Override - public void periodic() - { - objectDetection.periodic(); - - if (objectDetection.getTargetObservations().length > 0) { - range = objectDetection.rangeToTarget_Pitch(objectDetection.getTargetObservations()[0], - ObjectDetectorConstants.CAMERA0_TRANSFORM, - ObjectDetectorConstants.algaeHeightMeters / 2, - 1, 0); - heading = - objectDetection.headingToTarget_Yaw(objectDetection.getTargetObservations()[0], - ObjectDetectorConstants.CAMERA0_TRANSFORM, - range, 1, 0); - distance = objectDetection.distanceToTarget2d(range, heading); - targetLocation = - objectDetection.estimateTargetToField(range, heading, drive.getPose()); - objectDetection.getLastNDetections(10, lastNDetections, 0.4572, - targetLocation); - - Logger.recordOutput("Detection/" + "Calculated Range", range); - Logger.recordOutput("Detection/" + "Calculated Heading", heading); - Logger.recordOutput("Detection/" + "Calculated Distance", distance); - Logger.recordOutput("Detection/" + "Latest Detection's Calculated Coordinates", - targetLocation); - Logger.recordOutput("Detection/" + "Newest Detection", - lastNDetections.get(lastNDetections.size() - 1)); - Logger.recordOutput("Detection/" + "Oldest Detection", lastNDetections.get(0)); - Logger.recordOutput("Detection/" + "Detection List Size", lastNDetections.size()); - - Logger.recordOutput("Detection/" + "Sim Target #0 True Range", - ObjectDetectorConstants.SIM_TARGETS[0].getPose().toPose2d().getTranslation() - .minus(drive.getPose().getTranslation()).getX()); - Logger.recordOutput("Detection/" + "Sim Target #0 True Heading", - ObjectDetectorConstants.SIM_TARGETS[0].getPose().toPose2d().getTranslation() - .minus(drive.getPose().getTranslation()).getY()); - Logger.recordOutput("Detection/" + "Sim Target #0 True Distance", - ObjectDetectorConstants.SIM_TARGETS[0].getPose().toPose2d().getTranslation() - .getDistance(drive.getPose().getTranslation())); - } - } -} diff --git a/src/main/java/frc/robot/subsystems/w8_examples/objectDetector/ObjectDetectorConstants.java b/src/main/java/frc/robot/subsystems/w8_examples/objectDetector/ObjectDetectorConstants.java deleted file mode 100644 index b6e0f9f..0000000 --- a/src/main/java/frc/robot/subsystems/w8_examples/objectDetector/ObjectDetectorConstants.java +++ /dev/null @@ -1,93 +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.subsystems.objectDetector; - -import java.util.function.Supplier; -import org.photonvision.estimation.TargetModel; -import org.photonvision.simulation.VisionTargetSim; -import edu.wpi.first.math.geometry.Pose3d; -import edu.wpi.first.math.geometry.Rotation3d; -import edu.wpi.first.math.geometry.Transform3d; -import edu.wpi.first.units.measure.Angle; -import edu.wpi.first.units.Units; -import edu.wpi.first.wpilibj.Timer; -import frc.lib.io.objectdetection.ObjectDetectionIO; -import frc.lib.io.objectdetection.ObjectDetectionIOPhotonVision; -import frc.lib.io.objectdetection.ObjectDetectionIOSim; -import frc.robot.Constants; -import frc.robot.subsystems.drive.Drive; - -/* - * Subsystem constants (e.g. names, transforms) for the various object detector cameras on the - * robot. Used to create object detector subsystems within RobotContainer. - */ -public class ObjectDetectorConstants { - // Camera constants - // Transform sign convention: +X -> towards other alliance's station, +Y -> towards center of - // field from starting starboard edge, +theta -> right-hand rule. units: meters & degrees. - // Object detection camera # 0 - public final static String CAMERA0_NAME = "Detection Camera #0"; - public final static Angle CAMERA0_ROLL = Units.Degrees.of(0.0); - public final static Angle CAMERA0_PITCH = Units.Degrees.of(25.0); - public final static Angle CAMERA0_YAW = Units.Degrees.of(0.0); - public final static double CAMERA0_X = 0.30; - public final static double CAMERA0_Y = -0.30; - public final static double CAMERA0_Z = 1.0; - public static Transform3d CAMERA0_TRANSFORM = - new Transform3d(CAMERA0_X, CAMERA0_Y, CAMERA0_Z, - new Rotation3d(CAMERA0_ROLL, CAMERA0_PITCH, CAMERA0_YAW)); - // Object detection camera # 1 - // ... - - // Sim constants - // 2025 Simulated Algae Targets - public final static String SIM_NAME = "Algae"; - public final static double algaeHeightMeters = 0.41; - // Initialize fixed array of sim targets - public static VisionTargetSim[] SIM_TARGETS = new VisionTargetSim[] { - new VisionTargetSim(new Pose3d(3, 2, algaeHeightMeters / 2, new Rotation3d()), - new TargetModel(algaeHeightMeters)), - new VisionTargetSim(new Pose3d(7, 6, algaeHeightMeters / 2, new Rotation3d()), - new TargetModel(algaeHeightMeters)), - new VisionTargetSim((new Pose3d(12, 7, algaeHeightMeters / 2, new Rotation3d())), - new TargetModel(algaeHeightMeters)), - null, - }; - // Dynamic supplier for moving sim targets - public static Supplier visionTargetSimSupplier = - () -> SIM_TARGETS = new VisionTargetSim[] { - new VisionTargetSim(new Pose3d(3, 2, algaeHeightMeters / 2, new Rotation3d()), - new TargetModel(algaeHeightMeters)), - new VisionTargetSim(new Pose3d(7, 6, algaeHeightMeters / 2, new Rotation3d()), - new TargetModel(algaeHeightMeters)), - new VisionTargetSim((new Pose3d(12, 7, algaeHeightMeters / 2, new Rotation3d())), - new TargetModel(algaeHeightMeters)), - new VisionTargetSim( - (new Pose3d(16, 3.5 * Math.sin(0.25 * Math.PI * Timer.getFPGATimestamp()) + 4.1, - algaeHeightMeters / 2, new Rotation3d())), - new TargetModel(algaeHeightMeters)), - }; - // 2026 Targets - // ... - - // Robot runtime mode for use in roboRIO & AKit - public static ObjectDetector get(Drive drive) - { - switch (Constants.currentMode) { - case REAL: - // Real IO, inputs = PhotonVision implementation of ObjectDetectionIO - return new ObjectDetector(new ObjectDetectionIOPhotonVision(CAMERA0_NAME), drive); - case SIM: - // Sim IO, inputs = sim implementation of ObjectionDetectionIO - return new ObjectDetector(new ObjectDetectionIOSim(CAMERA0_NAME, CAMERA0_TRANSFORM, - () -> drive.getPose(), SIM_NAME, visionTargetSimSupplier), drive); - case REPLAY: - // Replayed robot, use logged data for IO - return new ObjectDetector(new ObjectDetectionIO() {}, drive); - default: - throw new IllegalStateException("Unrecognized Robot Mode"); - } - } -} diff --git a/src/main/java/frc/robot/subsystems/w8_examples/revRotary/RevRotary.java b/src/main/java/frc/robot/subsystems/w8_examples/revRotary/RevRotary.java deleted file mode 100644 index 8e198a9..0000000 --- a/src/main/java/frc/robot/subsystems/w8_examples/revRotary/RevRotary.java +++ /dev/null @@ -1,96 +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.subsystems.revRotary; - -import static edu.wpi.first.units.Units.Degrees; -import edu.wpi.first.units.measure.Angle; -import edu.wpi.first.units.measure.AngularVelocity; -import edu.wpi.first.wpilibj2.command.Command; -import edu.wpi.first.wpilibj2.command.Commands; -import edu.wpi.first.wpilibj2.command.SubsystemBase; -import frc.lib.io.motor.MotorIO.PIDSlot; -import frc.lib.mechanisms.rotary.RotaryMechanism; -import frc.lib.util.LoggedTunableNumber; -import frc.lib.util.LoggerHelper; -import lombok.Getter; -import lombok.RequiredArgsConstructor; - -public class RevRotary extends SubsystemBase { - - private final RotaryMechanism io; - - private static final LoggedTunableNumber STOW_SETPOINT = - new LoggedTunableNumber("REV STOW", 0.0); - private static final LoggedTunableNumber RAISED_SETPOINT = - new LoggedTunableNumber("REV RAISED", 90); - - @RequiredArgsConstructor - @Getter - public enum Setpoint { - STOW(STOW_SETPOINT), - RAISED(RAISED_SETPOINT); - - private final LoggedTunableNumber tunableNumber; - - public Angle getSetpoint() - { - return Degrees.of(tunableNumber.get()); - } - } - - - public RevRotary(RotaryMechanism io) - { - this.io = io; - - setSetpoint(RevRotaryConstants.DEFAULT_SETPOINT).ignoringDisable(true).schedule(); - } - - @Override - public void periodic() - { - LoggerHelper.recordCurrentCommand(RevRotaryConstants.NAME, this); - io.periodic(); - // robotstate.setRotaryPose(io.getPoseSupplier().get()); - } - - public Command setSetpoint(Setpoint setpoint) - { - return this.runOnce( - () -> io.runPosition(setpoint.getSetpoint(), - PIDSlot.SLOT_0)) - .withName("Go To " + setpoint.toString() + " Setpoint"); - }; - - public boolean nearGoal(Angle targetPosition) - { - return io.nearGoal(targetPosition, RevRotaryConstants.TOLERANCE); - } - - public Command waitUntilGoalCommand(Angle position) - { - return Commands.waitUntil(() -> { - return nearGoal(position); - }); - } - - public Command setGoalCommandWithWait(Setpoint setpoint) - { - return waitUntilGoalCommand(setpoint.getSetpoint()) - .deadlineFor(setSetpoint(setpoint)) - .withName("Go To " + setpoint.toString() + " Setpoint with wait"); - } - - public AngularVelocity getVelocity() - { - return io.getVelocity(); - } - - public void close() - { - io.close(); - } - -} diff --git a/src/main/java/frc/robot/subsystems/w8_examples/revRotary/RevRotaryConstants.java b/src/main/java/frc/robot/subsystems/w8_examples/revRotary/RevRotaryConstants.java deleted file mode 100644 index d0ba8fb..0000000 --- a/src/main/java/frc/robot/subsystems/w8_examples/revRotary/RevRotaryConstants.java +++ /dev/null @@ -1,196 +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.subsystems.revRotary; - -import static edu.wpi.first.units.Units.Degrees; -import static edu.wpi.first.units.Units.KilogramSquareMeters; -import static edu.wpi.first.units.Units.Kilograms; -import static edu.wpi.first.units.Units.Rotations; -import static edu.wpi.first.units.Units.Second; -import java.util.Optional; -import static edu.wpi.first.units.Units.Meters; -import frc.robot.Constants; -import edu.wpi.first.math.geometry.Translation3d; -import edu.wpi.first.math.system.plant.DCMotor; -import edu.wpi.first.units.AngularAccelerationUnit; -import edu.wpi.first.units.Units; -import edu.wpi.first.units.measure.Angle; -import edu.wpi.first.units.measure.AngularAcceleration; -import edu.wpi.first.units.measure.AngularVelocity; -import edu.wpi.first.units.measure.Distance; -import edu.wpi.first.units.measure.Mass; -import edu.wpi.first.units.measure.MomentOfInertia; -import edu.wpi.first.units.measure.Velocity; -import edu.wpi.first.wpilibj.simulation.SingleJointedArmSim; -import frc.lib.io.motor.MotorIO; -import frc.lib.io.motor.MotorIORev; -import frc.lib.io.motor.MotorIORevSim; -import frc.lib.io.motor.MotorIOSim; -import frc.lib.mechanisms.rotary.*; -import frc.lib.mechanisms.rotary.RotaryMechanism.RotaryAxis; -import frc.lib.mechanisms.rotary.RotaryMechanism.RotaryMechCharacteristics; -import frc.robot.Ports; -import com.revrobotics.spark.ClosedLoopSlot; -import com.revrobotics.spark.config.ClosedLoopConfig; -import com.revrobotics.spark.config.SparkBaseConfig; -import com.revrobotics.spark.config.SparkFlexConfig; -import com.revrobotics.spark.config.SparkBaseConfig.IdleMode; - - -/** Add your docs here. */ -public class RevRotaryConstants { - public static String NAME = "REVRotary"; - - public static final Angle TOLERANCE = Degrees.of(2.0); - - public static final AngularVelocity CRUISE_VELOCITY = - Units.RadiansPerSecond.of(1); - public static final AngularAcceleration ACCELERATION = - CRUISE_VELOCITY.div(0.1).per(Units.Second); - public static final Velocity JERK = ACCELERATION.per(Second); - - private static final double ROTOR_TO_SENSOR = (2.0 / 1.0); - private static final double SENSOR_TO_MECHANISM = (2.0 / 1.0); - private static final double GEAR_RATIO = ROTOR_TO_SENSOR * SENSOR_TO_MECHANISM; - - public static final Translation3d OFFSET = Translation3d.kZero; - - public static final Angle MIN_ANGLE = Degrees.of(0.0); - public static final Angle MAX_ANGLE = Rotations.of(.5); - public static final Angle STARTING_ANGLE = Rotations.of(0.0); - public static final Distance ARM_LENGTH = Meters.of(1.0); - - public static final RotaryMechCharacteristics CONSTANTS = - new RotaryMechCharacteristics(OFFSET, ARM_LENGTH, MIN_ANGLE, MAX_ANGLE, STARTING_ANGLE, - RotaryAxis.PITCH); - - public static final Mass ARM_MASS = Kilograms.of(.01); - public static final DCMotor DCMOTOR = DCMotor.getKrakenX60(1); - public static final MomentOfInertia MOI = KilogramSquareMeters - .of(SingleJointedArmSim.estimateMOI(ARM_LENGTH.in(Meters), ARM_MASS.in(Kilograms))); - - private static final Angle ENCODER_OFFSET = Rotations.of(0.0); - - public static final RevRotary.Setpoint DEFAULT_SETPOINT = - RevRotary.Setpoint.STOW; - - - - // Positional PID - private static ClosedLoopConfig SLOT0CONFIG = new ClosedLoopConfig() - .pid(30.0, 0, 5.0, ClosedLoopSlot.kSlot0); // Added D gain to match TalonFX config - - /** - * Creates and returns the SparkFlex/SparkMax motor controller configuration for the rotary mechanism. - * - *

- * This configuration includes: - *

    - *
  • Voltage compensation for consistent power output
  • - *
  • Idle (brake) mode to hold position when not moving
  • - *
  • Motor inversion setting
  • - *
  • Encoder position and velocity conversion factors for proper feedback scaling
  • - *
  • PID gains applied to the selected closed-loop slot
  • - * - *
- * - * @return A configured {@link SparkBaseConfig} object ready to apply to a REV Robotics SparkFlex or SparkMax motor controller - */ - public static SparkBaseConfig getREVConfig() - { - SparkFlexConfig config = new SparkFlexConfig(); - - config.voltageCompensation(12.0); - config.idleMode(IdleMode.kBrake); - config.inverted(false); - - // Add gear ratio configuration for position/velocity conversion - config.encoder.positionConversionFactor(1.0 / GEAR_RATIO); - config.encoder.velocityConversionFactor(1.0 / GEAR_RATIO / 60.0); // RPM to RPS - - // Add soft limits to match TalonFX behavior - - config.apply(SLOT0CONFIG); - - return config; - } - - /** - * Creates the real robot implementation of the rotary mechanism. - * - *

- * This method instantiates the actual hardware objects (TalonFX motors and CANcoder) that will - * be used when running on a real robot. - * - * @return A RotaryMechanismReal object configured with real hardware - */ - public static RevRotary getReal() - { - MotorIO io = new MotorIORev(NAME, Ports.revRotarySubsytemMotorMain, true, getREVConfig()); - - return new RevRotary(new RotaryMechanismReal(io, CONSTANTS, Optional.empty())); - } - - /** - * Creates the simulation implementation of the rotary mechanism. - * - *

- * This method creates a physics-based simulation of the mechanism using WPILib's simulation - * classes. It models the motor, moment of inertia, and other physical properties to provide - * realistic behavior in simulation. - * - * @return A RotaryMechanismSim object configured for physics simulation - */ - public static RevRotary getSim() - { - MotorIOSim io = new MotorIORevSim( - NAME, - Ports.revRotarySubsytemMotorMain, - true, - DCMOTOR, - getREVConfig()); - - return new RevRotary(new RotaryMechanismSim( - io, - DCMOTOR, - MOI, - false, - CONSTANTS, - Optional.empty())); - } - - /** - * Creates the log replay implementation of the rotary mechanism. - * - *

- * This is used with AdvantageKit's log replay feature, which allows you to replay logged data - * and debug robot code without having the actual robot or running simulation. - * - * @return A RotaryMechanism object for log replay - */ - public static RevRotary getReplay() - { - return new RevRotary(new RotaryMechanism(NAME, CONSTANTS) {}); - } - - /** - * Method to get the appropriate RotaryMechanism based on the current robot mode. - * - * @return RotaryMechanism instance for the current mode (real, sim, or replay) - */ - public static RevRotary get() - { - switch (Constants.currentMode) { - case REAL: - return getReal(); - case SIM: - return getSim(); - case REPLAY: - return getReplay(); - default: - throw new IllegalStateException("Unrecognized Robot Mode"); - } - } -} diff --git a/src/main/java/frc/robot/subsystems/w8_examples/rotary/Rotary.java b/src/main/java/frc/robot/subsystems/w8_examples/rotary/Rotary.java deleted file mode 100644 index b497ffc..0000000 --- a/src/main/java/frc/robot/subsystems/w8_examples/rotary/Rotary.java +++ /dev/null @@ -1,132 +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.subsystems.rotary; - -import static edu.wpi.first.units.Units.Amps; -import static edu.wpi.first.units.Units.Degrees; -import static edu.wpi.first.units.Units.Volts; -import edu.wpi.first.math.filter.Debouncer; -import edu.wpi.first.math.filter.Debouncer.DebounceType; -import edu.wpi.first.units.measure.Angle; -import edu.wpi.first.units.measure.AngularVelocity; -import edu.wpi.first.wpilibj2.command.Command; -import edu.wpi.first.wpilibj2.command.Commands; -import edu.wpi.first.wpilibj2.command.SubsystemBase; -import edu.wpi.first.wpilibj2.command.button.Trigger; -import frc.lib.io.motor.MotorIO.PIDSlot; -import frc.lib.mechanisms.rotary.RotaryMechanism; -import frc.lib.util.LoggedTunableNumber; -import frc.lib.util.LoggerHelper; -import frc.robot.RobotState; -import lombok.Getter; -import lombok.RequiredArgsConstructor; - -public class Rotary extends SubsystemBase { - - private final RotaryMechanism io; - private static LoggedTunableNumber STOW_SETPOINT = - new LoggedTunableNumber("Rotary STOW", 0.0); - private static LoggedTunableNumber RAISED_SETPOINT = - new LoggedTunableNumber("Rotary RAISED", -90); - - @RequiredArgsConstructor - @Getter - public enum Setpoint { - HOME(null), - STOW(STOW_SETPOINT), - RAISED(RAISED_SETPOINT); - - private final LoggedTunableNumber tunableNumber; - - public Angle getSetpoint() - { - if (tunableNumber == null) { - return Degrees.of(0.0); - } - return Degrees.of(tunableNumber.get()); - } - } - - private Debouncer homeDebouncer = new Debouncer(0.1, DebounceType.kRising); - private Trigger homedTrigger; - - private final RobotState robotstate; - private Setpoint setpoint = Setpoint.STOW; - - public Rotary(RotaryMechanism io) - { - this.io = io; - this.robotstate = RobotState.getInstance(); - setSetpoint(RotaryConstants.DEFAULT_SETPOINT) - .ignoringDisable(true) - .schedule(); - homedTrigger = - new Trigger(() -> homeDebouncer.calculate(io.getSupplyCurrent().gte(Amps.of(10)))); - - } - - @Override - public void periodic() - { - LoggerHelper.recordCurrentCommand(RotaryConstants.NAME, this); - io.periodic(); - robotstate.setRotaryPose(io.getPoseSupplier().get()); - - } - - public Command setSetpoint(Setpoint setpoint) - { - return this.runOnce( - () -> io.runPosition(setpoint.getSetpoint(), RotaryConstants.CRUISE_VELOCITY, - RotaryConstants.ACCELERATION, RotaryConstants.JERK, - PIDSlot.SLOT_0)) - .withName("Go To " + setpoint.toString() + " Setpoint"); - }; - - public boolean nearGoal(Angle targetPosition) - { - return io.nearGoal(targetPosition, RotaryConstants.TOLERANCE); - } - - public Command waitUntilGoalCommand(Angle position) - { - return Commands.waitUntil(() -> { - return nearGoal(position); - }); - } - - public Command setGoalCommandWithWait(Setpoint setpoint) - { - return waitUntilGoalCommand(setpoint.getSetpoint()) - .deadlineFor(setSetpoint(setpoint)) - .withName("Go To " + setpoint.toString() + " Setpoint with wait"); - } - - public Command setStateCommand(Setpoint setpoint) - { - return this.runOnce(() -> this.setpoint = setpoint) - .withName("Elevator Set State: " + setpoint.name()); - } - - public Command homeCommand() - { - return Commands.sequence(runOnce(() -> io.runVoltage(Volts.of(-2))), - Commands.waitUntil(homedTrigger), - runOnce(() -> io.setEncoderPosition(Setpoint.HOME.getSetpoint())), - this.setStateCommand(Setpoint.STOW)) - .withName("Homing"); - - } - - public AngularVelocity getVelocity() - { - return io.getVelocity(); - } - - public void close() - { - io.close(); - } -} diff --git a/src/main/java/frc/robot/subsystems/w8_examples/rotary/RotaryConstants.java b/src/main/java/frc/robot/subsystems/w8_examples/rotary/RotaryConstants.java deleted file mode 100644 index 344c0b3..0000000 --- a/src/main/java/frc/robot/subsystems/w8_examples/rotary/RotaryConstants.java +++ /dev/null @@ -1,181 +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.subsystems.rotary; - -import static edu.wpi.first.units.Units.Degrees; -import static edu.wpi.first.units.Units.KilogramSquareMeters; -import static edu.wpi.first.units.Units.Kilograms; -import static edu.wpi.first.units.Units.Rotations; -import static edu.wpi.first.units.Units.Second; -import java.util.Optional; -import static edu.wpi.first.units.Units.Meters; -import com.ctre.phoenix6.configs.*; -import com.ctre.phoenix6.signals.FeedbackSensorSourceValue; -import com.ctre.phoenix6.signals.InvertedValue; -import com.ctre.phoenix6.signals.NeutralModeValue; -import edu.wpi.first.math.geometry.Translation3d; -import edu.wpi.first.math.system.plant.DCMotor; -import edu.wpi.first.units.AngularAccelerationUnit; -import edu.wpi.first.units.Units; -import edu.wpi.first.units.measure.Angle; -import edu.wpi.first.units.measure.AngularAcceleration; -import edu.wpi.first.units.measure.AngularVelocity; -import edu.wpi.first.units.measure.Distance; -import edu.wpi.first.units.measure.Mass; -import edu.wpi.first.units.measure.MomentOfInertia; -import edu.wpi.first.units.measure.Velocity; -import edu.wpi.first.wpilibj.simulation.SingleJointedArmSim; -import frc.lib.io.absoluteencoder.AbsoluteEncoderIOCANCoderSim; -import frc.lib.io.motor.MotorIOTalonFX; -import frc.lib.io.motor.MotorIOTalonFX.TalonFXFollower; -import frc.lib.io.motor.MotorIOTalonFXSim; -import frc.lib.mechanisms.rotary.*; -import frc.lib.mechanisms.rotary.RotaryMechanism.RotaryAxis; -import frc.lib.mechanisms.rotary.RotaryMechanism.RotaryMechCharacteristics; -import frc.robot.Constants; -import frc.robot.Ports; - - -public class RotaryConstants { - public static String NAME = "Rotary"; - - public static final Angle TOLERANCE = Degrees.of(2.0); - - public static final AngularVelocity CRUISE_VELOCITY = - Units.RadiansPerSecond.of(1); - public static final AngularAcceleration ACCELERATION = - CRUISE_VELOCITY.div(0.1).per(Units.Second); - public static final Velocity JERK = ACCELERATION.per(Second); - - private static final double ROTOR_TO_SENSOR = (2.0 / 1.0); - private static final double SENSOR_TO_MECHANISM = (2.0 / 1.0); - - public static final Translation3d OFFSET = Translation3d.kZero; - - public static final Angle MIN_ANGLE = Degrees.of(-130.0); - public static final Angle MAX_ANGLE = Rotations.of(.5); - public static final Angle STARTING_ANGLE = Rotations.of(0.0); - public static final Distance ARM_LENGTH = Meters.of(1.0); - - public static final RotaryMechCharacteristics CONSTANTS = - new RotaryMechCharacteristics( - OFFSET, - ARM_LENGTH, - MIN_ANGLE, - MAX_ANGLE, - STARTING_ANGLE, - RotaryAxis.PITCH); - - public static final Mass ARM_MASS = Kilograms.of(.01); - public static final DCMotor DCMOTOR = DCMotor.getKrakenX60(1); - public static final MomentOfInertia MOI = KilogramSquareMeters - .of(SingleJointedArmSim.estimateMOI(ARM_LENGTH.in(Meters), ARM_MASS.in(Kilograms))); - - private static final Angle ENCODER_OFFSET = Rotations.of(0.0); - - public static final Rotary.Setpoint DEFAULT_SETPOINT = Rotary.Setpoint.STOW; - - // Positional PID - private static Slot0Configs SLOT0CONFIG = new Slot0Configs() - .withKP(30.0) - .withKI(0.0) - .withKD(5.0); - - /** - * Creates and returns the TalonFX motor controller configuration for the rotary mechanism. - * - *

- * This configuration includes: - *

    - *
  • Current limits to prevent motor damage and brownouts
  • - *
  • Voltage limits for power output
  • - *
  • Brake mode to hold position when not moving
  • - *
  • Software limit switches to prevent mechanism damage
  • - *
  • Gear ratios for proper position/velocity feedback
  • - *
  • Remote CANcoder feedback for absolute positioning
  • - *
  • PID gains for control
  • - *
- * - * @return A configured TalonFXConfiguration object ready to apply to a motor controller - */ - public static TalonFXConfiguration getFXConfig() - { - TalonFXConfiguration config = new TalonFXConfiguration(); - - config.CurrentLimits.SupplyCurrentLimitEnable = false; - config.CurrentLimits.SupplyCurrentLimit = 40.0; - config.CurrentLimits.SupplyCurrentLowerLimit = 40.0; - config.CurrentLimits.SupplyCurrentLowerTime = 0.1; - - config.CurrentLimits.StatorCurrentLimitEnable = false; - config.CurrentLimits.StatorCurrentLimit = 80.0; - - config.Voltage.PeakForwardVoltage = 12.0; - config.Voltage.PeakReverseVoltage = -12.0; - - config.MotorOutput.NeutralMode = NeutralModeValue.Brake; - config.MotorOutput.Inverted = InvertedValue.CounterClockwise_Positive; - - config.SoftwareLimitSwitch.ForwardSoftLimitEnable = false; - config.SoftwareLimitSwitch.ForwardSoftLimitThreshold = MAX_ANGLE.in(Units.Rotations); - - config.SoftwareLimitSwitch.ReverseSoftLimitEnable = false; - config.SoftwareLimitSwitch.ReverseSoftLimitThreshold = MIN_ANGLE.in(Units.Rotations); - - config.Feedback.RotorToSensorRatio = ROTOR_TO_SENSOR; - config.Feedback.SensorToMechanismRatio = SENSOR_TO_MECHANISM; - - config.Feedback.FeedbackRemoteSensorID = Ports.RotarySubsystemEncoder.id(); - config.Feedback.FeedbackSensorSource = FeedbackSensorSourceValue.RemoteCANcoder; - - config.Slot0 = SLOT0CONFIG; - - return config; - } - - /** - * Creates and returns the CANcoder absolute encoder configuration. - * - *

- * The CANcoder provides absolute position feedback, meaning it knows the true position of the - * mechanism even after power cycling. The magnet offset calibrates the encoder's zero position. - * - * @param sim Whether this configuration is for simulation (true) or real robot (false). In - * simulation, the offset is set to 0.0 since it's not needed. - * @return A configured CANcoderConfiguration object - */ - public static CANcoderConfiguration getCANcoderConfig(boolean sim) - { - CANcoderConfiguration config = new CANcoderConfiguration(); - - config.MagnetSensor.MagnetOffset = sim ? 0.0 : ENCODER_OFFSET.in(Rotations); - - return config; - } - - public static Rotary get() - { - switch (Constants.currentMode) { - case REAL: - return new Rotary(new RotaryMechanismReal( - new MotorIOTalonFX(NAME, getFXConfig(), Ports.RotarySubsystemMotorMain, - new TalonFXFollower(Ports.RotarySubsystemMotorFollower, false)), - CONSTANTS, - Optional.of(new AbsoluteEncoderIOCANCoderSim(Ports.RotarySubsystemEncoder, - NAME + "Encoder", getCANcoderConfig(false))))); - case SIM: - return new Rotary(new RotaryMechanismSim( - new MotorIOTalonFXSim(NAME, getFXConfig(), Ports.RotarySubsystemMotorMain, - new TalonFXFollower(Ports.RotarySubsystemMotorFollower, false)), - DCMOTOR, MOI, false, CONSTANTS, - Optional.of(new AbsoluteEncoderIOCANCoderSim(Ports.RotarySubsystemEncoder, - NAME + "Encoder", getCANcoderConfig(true))))); - case REPLAY: - return new Rotary(new RotaryMechanism(NAME, CONSTANTS) {}); - default: - throw new IllegalStateException("Unrecognized Robot Mode"); - } - } -} diff --git a/src/main/java/frc/robot/subsystems/w8_examples/servo1/Servo1.java b/src/main/java/frc/robot/subsystems/w8_examples/servo1/Servo1.java deleted file mode 100644 index 9fd9304..0000000 --- a/src/main/java/frc/robot/subsystems/w8_examples/servo1/Servo1.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (C) 2025 Windham Windup - * - * This program is free software: you can redistribute it and/or modify it under the terms of the - * GNU General Public License as published by the Free Software Foundation, either version 3 of the - * License, or any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without - * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program. If - * not, see . - */ - -package frc.robot.subsystems.servo1; - -import edu.wpi.first.units.measure.Angle; -import edu.wpi.first.wpilibj2.command.Command; -import edu.wpi.first.wpilibj2.command.SubsystemBase; -import frc.lib.devices.Servo; -import frc.lib.io.servo.ServoIO; -import frc.lib.util.LoggedTunableNumber; -import lombok.Getter; -import lombok.RequiredArgsConstructor; -import static edu.wpi.first.units.Units.Degrees; -import org.littletonrobotics.junction.Logger; - -public class Servo1 extends SubsystemBase { - - private static final LoggedTunableNumber RETRACTED_SETPOINT = - new LoggedTunableNumber("Servo1/Retracted", 0.0); - private static final LoggedTunableNumber EXTENDED_SETPOINT = - new LoggedTunableNumber("Servo1/Extended", 180.0); - - @RequiredArgsConstructor - @SuppressWarnings("Immutable") - @Getter - public enum Setpoint { - IDLE(null), - RETRACTED(Degrees.of(RETRACTED_SETPOINT.get())), - EXTENDED(Degrees.of(EXTENDED_SETPOINT.get())); - - private final Angle output; - } - - Setpoint setpoint = Setpoint.IDLE; - - private final Servo servo; - - public Servo1(ServoIO io) - { - servo = new Servo(io); - } - - @Override - public void periodic() - { - Logger.recordOutput(Servo1Constants.NAME + "/Setpoint", setpoint.toString()); - } - - public Command setGoal(Setpoint setpoint) - { - return this.runOnce(() -> { - switch (setpoint) { - case IDLE -> servo.stop(); - default -> servo.setAngle(setpoint.getOutput()); - } - this.setpoint = setpoint; - }); - } -} diff --git a/src/main/java/frc/robot/subsystems/w8_examples/servo1/Servo1Constants.java b/src/main/java/frc/robot/subsystems/w8_examples/servo1/Servo1Constants.java deleted file mode 100644 index 4e4200e..0000000 --- a/src/main/java/frc/robot/subsystems/w8_examples/servo1/Servo1Constants.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (C) 2025 Windham Windup - * - * This program is free software: you can redistribute it and/or modify it under the terms of the - * GNU General Public License as published by the Free Software Foundation, either version 3 of the - * License, or any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without - * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program. If - * not, see . - */ - -package frc.robot.subsystems.servo1; - -import static edu.wpi.first.units.Units.Degrees; -import edu.wpi.first.units.measure.Angle; -import frc.lib.io.servo.ServoIO; -import frc.lib.io.servo.ServoIOPWM; -import frc.lib.io.servo.ServoIOSim; -import frc.robot.Constants; -import frc.robot.Ports; - -public class Servo1Constants { - - public final static String NAME = "Servo #1"; - - public final static Angle MINIMUM_ANGLE = Degrees.of(0.0); - // Change as necessary - public final static Angle MAXIMUM_ANGLE = Degrees.of(180.0); - - public static Servo1 get() - { - switch (Constants.currentMode) { - case REAL: - return new Servo1(new ServoIOPWM(Ports.servo1, NAME, MINIMUM_ANGLE, MAXIMUM_ANGLE)); - case SIM: - return new Servo1(new ServoIOSim(NAME, MINIMUM_ANGLE, MAXIMUM_ANGLE)); - case REPLAY: - return new Servo1(new ServoIO() {}); - default: - throw new IllegalStateException("Unrecognized Robot Mode"); - } - } -} diff --git a/src/main/java/frc/robot/subsystems/w8_examples/vision/Vision.java b/src/main/java/frc/robot/subsystems/w8_examples/vision/Vision.java deleted file mode 100644 index 69fe3f3..0000000 --- a/src/main/java/frc/robot/subsystems/w8_examples/vision/Vision.java +++ /dev/null @@ -1,229 +0,0 @@ -/* - * Copyright (C) 2025 Windham Windup - * - * This program is free software: you can redistribute it and/or modify it under the terms of the - * GNU General Public License as published by the Free Software Foundation, either version 3 of the - * License, or any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without - * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program. If - * not, see . - */ - -package frc.robot.subsystems.vision; - -import static edu.wpi.first.units.Units.Meters; -import static frc.robot.subsystems.vision.VisionConstants.*; - -import edu.wpi.first.math.Matrix; -import edu.wpi.first.math.VecBuilder; -import edu.wpi.first.math.geometry.Pose2d; -import edu.wpi.first.math.geometry.Pose3d; -import edu.wpi.first.math.geometry.Rotation2d; -import edu.wpi.first.math.numbers.N1; -import edu.wpi.first.math.numbers.N3; -import edu.wpi.first.units.measure.Time; -import edu.wpi.first.wpilibj.Alert; -import edu.wpi.first.wpilibj.Alert.AlertType; -import edu.wpi.first.wpilibj2.command.SubsystemBase; -import frc.lib.io.vision.VisionIOInputsAutoLogged; -import frc.lib.io.vision.VisionIO.TagObservation; -import frc.lib.util.Timestamped; -import lombok.Getter; -import frc.lib.io.vision.VisionIO; - -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; -import java.util.function.Supplier; -import org.littletonrobotics.junction.Logger; - -public class Vision extends SubsystemBase { - private final VisionConsumer consumer; - private final VisionIO[] io; - private final VisionIOInputsAutoLogged[] inputs; - private final Alert[] disconnectedAlerts; - - private final Supplier> timestampedHeadingSupplier; - - @Getter - private Optional closestTagObservation = Optional.empty(); - - public Vision(VisionConsumer consumer, - Supplier> timestampedHeadingSupplier, VisionIO... io) - { - this.consumer = consumer; - this.timestampedHeadingSupplier = timestampedHeadingSupplier; - this.io = io; - - - // Initialize inputs - this.inputs = new VisionIOInputsAutoLogged[io.length]; - for (int i = 0; i < inputs.length; i++) { - inputs[i] = new VisionIOInputsAutoLogged(); - } - - // Initialize disconnected alerts - this.disconnectedAlerts = new Alert[io.length]; - for (int i = 0; i < inputs.length; i++) { - disconnectedAlerts[i] = new Alert( - "Vision camera " + Integer.toString(i) + " is disconnected.", AlertType.kWarning); - } - } - - @Override - public void periodic() - { - for (int i = 0; i < io.length; i++) { - io[i].updateInputs(inputs[i], timestampedHeadingSupplier.get()); - Logger.processInputs("Vision/Camera" + Integer.toString(i), inputs[i]); - } - - // Initialize logging values - List allTagPoses = new ArrayList<>(); - List allRobotPoses = new ArrayList<>(); - List allRobotPosesAccepted = new ArrayList<>(); - List allRobotPosesRejected = new ArrayList<>(); - - List allAlignmentTargets = new ArrayList<>(); - closestTagObservation = Optional.ofNullable(null); - - // Loop over cameras - for (int cameraIndex = 0; cameraIndex < io.length; cameraIndex++) { - // Update disconnected alert - disconnectedAlerts[cameraIndex].set(!inputs[cameraIndex].connected); - - // Initialize logging values - List tagPoses = new ArrayList<>(); - List robotPoses = new ArrayList<>(); - List robotPosesAccepted = new ArrayList<>(); - List robotPosesRejected = new ArrayList<>(); - - List alignmentTargets = new ArrayList<>(); - - // Add tag poses - for (int tagId : inputs[cameraIndex].tagIds) { - var tagPose = aprilTagLayout.getTagPose(tagId); - if (tagPose.isPresent()) { - tagPoses.add(tagPose.get()); - } - } - - // Loop over pose observations - for (var observation : inputs[cameraIndex].poseObservations) { - // Check whether to reject pose - boolean rejectPose = observation.tagCount() == 0 // Must have at least one tag - || (observation.tagCount() == 1 - && observation.ambiguity() > maxAmbiguity) // Cannot be high ambiguity - || Math.abs(observation.pose().getZ()) > maxZError // Must have realistic Z - // coordinate - - // Must be within the field boundaries - || observation.pose().getX() < 0.0 - || observation.pose().getX() > aprilTagLayout.getFieldLength() - || observation.pose().getY() < 0.0 - || observation.pose().getY() > aprilTagLayout.getFieldWidth(); - - // Add pose to log - robotPoses.add(observation.pose()); - if (rejectPose) { - robotPosesRejected.add(observation.pose()); - } else { - robotPosesAccepted.add(observation.pose()); - } - - // Skip if rejected - if (rejectPose) { - continue; - } - - // Calculate standard deviations - double stdDevFactor = - (Math.pow(observation.averageTagDistance().in(Meters), 2.0) - + 10 * observation.ambiguity()) - / observation.tagCount(); - double linearStdDev = linearStdDevBaseline * stdDevFactor; - double angularStdDev = angularStdDevBaseline * stdDevFactor; - if (cameraIndex < cameraStdDevFactors.length) { - linearStdDev *= cameraStdDevFactors[cameraIndex]; - angularStdDev *= cameraStdDevFactors[cameraIndex]; - } - - // Send vision observation - consumer.accept( - observation.pose().toPose2d(), - observation.timestamp(), - VecBuilder.fill(linearStdDev, linearStdDev, angularStdDev)); - } - - for (var tagObservation : inputs[cameraIndex].allTargets) { - if (alignmentTags.contains(tagObservation.id())) { - alignmentTargets.add(tagObservation); - - } - } - - // Log camera datadata - Logger.recordOutput( - "Vision/Camera" + Integer.toString(cameraIndex) + "/TagPoses", - tagPoses.toArray(new Pose3d[tagPoses.size()])); - Logger.recordOutput( - "Vision/Camera" + Integer.toString(cameraIndex) + "/RobotPoses", - robotPoses.toArray(new Pose3d[robotPoses.size()])); - Logger.recordOutput( - "Vision/Camera" + Integer.toString(cameraIndex) + "/RobotPosesAccepted", - robotPosesAccepted.toArray(new Pose3d[robotPosesAccepted.size()])); - Logger.recordOutput( - "Vision/Camera" + Integer.toString(cameraIndex) + "/RobotPosesRejected", - robotPosesRejected.toArray(new Pose3d[robotPosesRejected.size()])); - Logger.recordOutput( - "Vision/Camera" + Integer.toString(cameraIndex) + "/AlignmentTargets", - alignmentTargets.toArray(new TagObservation[alignmentTargets.size()])); - - allTagPoses.addAll(tagPoses); - allRobotPoses.addAll(robotPoses); - allRobotPosesAccepted.addAll(robotPosesAccepted); - allRobotPosesRejected.addAll(robotPosesRejected); - - allAlignmentTargets.addAll(alignmentTargets); - - - } - - for (var target : allAlignmentTargets) { - if (closestTagObservation.isEmpty()) { - closestTagObservation = Optional.of(target); - } else if (target.area() > closestTagObservation.get().area()) { - closestTagObservation = Optional.of(target); - } - } - - // Log summary data - Logger.recordOutput( - "Vision/Summary/TagPoses", allTagPoses.toArray(new Pose3d[allTagPoses.size()])); - Logger.recordOutput( - "Vision/Summary/RobotPoses", allRobotPoses.toArray(new Pose3d[allRobotPoses.size()])); - Logger.recordOutput( - "Vision/Summary/RobotPosesAccepted", - allRobotPosesAccepted.toArray(new Pose3d[allRobotPosesAccepted.size()])); - Logger.recordOutput( - "Vision/Summary/RobotPosesRejected", - allRobotPosesRejected.toArray(new Pose3d[allRobotPosesRejected.size()])); - - if (closestTagObservation.isPresent()) { - Logger.recordOutput("Vision/Summary/ClosestAlignmentTarget", - closestTagObservation.get()); - } - } - - @FunctionalInterface - public static interface VisionConsumer { - public void accept( - Pose2d visionRobotPoseMeters, - Time timestampSeconds, - Matrix visionMeasurementStdDevs); - } -} diff --git a/src/main/java/frc/robot/subsystems/w8_examples/vision/VisionConstants.java b/src/main/java/frc/robot/subsystems/w8_examples/vision/VisionConstants.java deleted file mode 100644 index cd5b565..0000000 --- a/src/main/java/frc/robot/subsystems/w8_examples/vision/VisionConstants.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (C) 2025 Windham Windup - * - * This program is free software: you can redistribute it and/or modify it under the terms of the - * GNU General Public License as published by the Free Software Foundation, either version 3 of the - * License, or any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without - * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program. If - * not, see . - */ - -package frc.robot.subsystems.vision; - -import java.util.Arrays; -import java.util.List; -import org.photonvision.PhotonPoseEstimator.PoseStrategy; -import org.photonvision.simulation.VisionSystemSim; -import edu.wpi.first.apriltag.AprilTagFieldLayout; -import edu.wpi.first.apriltag.AprilTagFields; -import edu.wpi.first.math.geometry.Rotation3d; -import edu.wpi.first.math.geometry.Transform3d; -import frc.lib.io.vision.VisionIO; -import frc.lib.io.vision.VisionIOPhotonVision; -import frc.lib.io.vision.VisionIOPhotonVisionSim; -import frc.robot.Constants; -import frc.robot.subsystems.drive.Drive; - -public class VisionConstants { - // AprilTag layout - public static AprilTagFieldLayout aprilTagLayout = - AprilTagFieldLayout.loadField(AprilTagFields.kDefaultField); - - // Camera names, must match names configured on coprocessor - public static String camera0Name = "camera_0"; - public static String camera1Name = "camera_1"; - - // Robot to camera transforms - // (Not used by Limelight, configure in web UI instead) - public static Transform3d robotToCamera0 = - new Transform3d(0.2, 0.0, 0.2, new Rotation3d(0.0, -0.4, 0.0)); - public static Transform3d robotToCamera1 = - new Transform3d(-0.2, 0.0, 0.2, new Rotation3d(0.0, -0.4, Math.PI)); - - // Basic filtering thresholds - public static double maxAmbiguity = 0.3; - public static double maxZError = 0.75; - - // Standard deviation baselines, for 1 meter distance and 1 tag - // (Adjusted automatically based on distance and # of tags) - public static double linearStdDevBaseline = 0.02; // Meters - public static double angularStdDevBaseline = 0.06; // Radians - - // Standard deviation multipliers for each camera - // (Adjust to trust some cameras more than others) - public static double[] cameraStdDevFactors = new double[] { - 1.0, // Camera 0 - 1.0 // Camera 1 - }; - - /** - * Tags used for reef alignment - */ - public static List alignmentTags = - Arrays.asList(6, 7, 8, 9, 10, 11, 17, 18, 19, 20, 21, 22); - - public static VisionSystemSim getSystemSim() - { - var system = new VisionSystemSim("main"); - system.addAprilTags(aprilTagLayout); - return system; - } - - public static Vision get(Drive drive) - { - switch (Constants.currentMode) { - case REAL: - return new Vision( - drive::addVisionMeasurement, - () -> drive.getTimestampedHeading(), - new VisionIOPhotonVision( - VisionConstants.camera0Name, - VisionConstants.robotToCamera0, - VisionConstants.aprilTagLayout, - PoseStrategy.CONSTRAINED_SOLVEPNP)); - case SIM: - return new Vision( - drive::addVisionMeasurement, - () -> drive.getTimestampedHeading(), - new VisionIOPhotonVisionSim( - () -> drive.getPose(), - VisionConstants.camera0Name, - VisionConstants.robotToCamera0, - VisionConstants.aprilTagLayout, - PoseStrategy.CONSTRAINED_SOLVEPNP, - getSystemSim())); - case REPLAY: - return new Vision( - drive::addVisionMeasurement, - () -> drive.getTimestampedHeading(), - new VisionIO() {}); - default: - throw new IllegalStateException("Unrecognized Robot Mode"); - } - } -}