2 Commits
Author SHA1 Message Date
OnDYCLaptop 132b231c36 新底盘 2026-07-03 21:43:14 +08:00
OnDYCLaptop 99a92af429 计时器 2026-06-16 12:12:24 +08:00
10 changed files with 259 additions and 126 deletions
+87
View File
@@ -91,6 +91,93 @@
"period": 0.06, "period": 0.06,
"sort_options": false "sort_options": false
} }
},
{
"title": "HubActive",
"x": 0.0,
"y": 0.0,
"width": 256.0,
"height": 128.0,
"type": "Boolean Box",
"properties": {
"topic": "/GameData2026/HubActive",
"period": 0.06,
"data_type": "boolean",
"true_color": 4283215696,
"false_color": 4294198070,
"true_icon": "None",
"false_icon": "None"
}
},
{
"title": "HubStatus",
"x": 256.0,
"y": 0.0,
"width": 256.0,
"height": 128.0,
"type": "Text Display",
"properties": {
"topic": "/GameData2026/HubStatus",
"period": 0.06,
"data_type": "string",
"show_submit_button": false
}
},
{
"title": "SecondsUntilHubOpens",
"x": 0.0,
"y": 128.0,
"width": 256.0,
"height": 128.0,
"type": "Text Display",
"properties": {
"topic": "/GameData2026/SecondsUntilHubOpens",
"period": 0.06,
"data_type": "double",
"show_submit_button": false
}
},
{
"title": "Shift",
"x": 256.0,
"y": 128.0,
"width": 256.0,
"height": 128.0,
"type": "Text Display",
"properties": {
"topic": "/GameData2026/Shift",
"period": 0.06,
"data_type": "string",
"show_submit_button": false
}
},
{
"title": "FirstInactiveAlliance",
"x": 0.0,
"y": 256.0,
"width": 256.0,
"height": 128.0,
"type": "Text Display",
"properties": {
"topic": "/GameData2026/FirstInactiveAlliance",
"period": 0.06,
"data_type": "string",
"show_submit_button": false
}
},
{
"title": "MatchTime",
"x": 256.0,
"y": 256.0,
"width": 256.0,
"height": 128.0,
"type": "Text Display",
"properties": {
"topic": "/GameData2026/MatchTime",
"period": 0.06,
"data_type": "double",
"show_submit_button": false
}
} }
] ]
} }
+2 -14
View File
@@ -6,18 +6,6 @@ import com.ctre.phoenix6.configs.Slot0Configs;
import edu.wpi.first.math.geometry.Pose2d; import edu.wpi.first.math.geometry.Pose2d;
public final class Constants { public final class Constants {
public static final class DemoMode {
public static final boolean ENABLED = true;
public static final double normalDriveScale = 0.12;
public static final double normalTurnScale = 0.20;
public static final double boostDriveScale = 0.25;
public static final double boostTurnScale = 0.30;
public static final double maxLinearSpeedMetersPerSecond = 2.4;
public static final double maxAngularRateRadiansPerSecond = 1.6;
}
public static final boolean LEDUsing = false; public static final boolean LEDUsing = false;
public enum RobotStatus{ public enum RobotStatus{
Stopped, Stopped,
@@ -29,7 +17,7 @@ public final class Constants {
CrossingTrench CrossingTrench
} }
public class Shooter { public class Shooter {
public static final double conveyorSpeed = 80; public static final double conveyorSpeed = 150;
public static final double conveyorSpeedForAuto = 10; public static final double conveyorSpeedForAuto = 10;
public static final Slot0Configs flyWheelSlot0Configs = new Slot0Configs() public static final Slot0Configs flyWheelSlot0Configs = new Slot0Configs()
.withKP(0.0).withKI(0).withKD(0) .withKP(0.0).withKI(0).withKD(0)
@@ -92,7 +80,7 @@ public final class Constants {
public class Limelight { public class Limelight {
public static final String LIMELIGHT_NAME_Shooter = "limelight-shooter"; public static final String LIMELIGHT_NAME_Shooter = "limelight-shooter";
public static final String LIMELIGHT_NAME_Intaker = "limelight-intaker"; public static final String LIMELIGHT_NAME_Intaker = "limelight-intaker";
public static final Boolean UsingMetaTag2 = false; // Use Limelight's own pose/yaw estimate instead of gyro-assisted MegaTag2. public static final Boolean UsingMetaTag2 = true; // 是否使用 MetaTag2(如果你们的 pipeline 配置了这个功能的话)
public static final int climbPipelineIndex = 8; public static final int climbPipelineIndex = 8;
public static final int locatePipelineIndex = 0; public static final int locatePipelineIndex = 0;
+1
View File
@@ -23,6 +23,7 @@ public class Robot extends TimedRobot {
public void robotPeriodic() { public void robotPeriodic() {
CommandScheduler.getInstance().run(); CommandScheduler.getInstance().run();
m_robotContainer.tunerPeriodic(); m_robotContainer.tunerPeriodic();
m_robotContainer.dashboardPeriodic();
} }
+10 -15
View File
@@ -30,15 +30,16 @@ import frc.robot.utils.LedBindings;
import frc.robot.controls.ClimberControls; import frc.robot.controls.ClimberControls;
import frc.robot.controls.Autocommand; import frc.robot.controls.Autocommand;
import frc.robot.subsystems.ClimberSubsystem; import frc.robot.subsystems.ClimberSubsystem;
import frc.robot.utils.GameData2026;
public class RobotContainer { public class RobotContainer {
/* ====================== */ /* ====================== */
/* 手柄 */ /* 手柄 */
/* ====================== */ /* ====================== */
// Demo mode uses one Xbox controller on port 0. // 使用2个 Xbox 手柄(端口 0,1)
private final CommandXboxController controllerlower = new CommandXboxController(0); private final CommandXboxController controllerlower = new CommandXboxController(0);
private final CommandXboxController controllerupper = controllerlower; private final CommandXboxController controllerupper = new CommandXboxController(1);
/* ====================== */ /* ====================== */
/* 子系统 */ /* 子系统 */
@@ -63,6 +64,7 @@ public class RobotContainer {
//private final ClimberControls climberControls = new ClimberControls(climberSubsystem, controllerupper); //private final ClimberControls climberControls = new ClimberControls(climberSubsystem, controllerupper);
private final IntakerControls intakerControls = new IntakerControls(IntakerSubsystem, shooterSubsystem, controllerupper); private final IntakerControls intakerControls = new IntakerControls(IntakerSubsystem, shooterSubsystem, controllerupper);
private final DriveGainsTuner driveGainsTuner = new DriveGainsTuner(drivetrain); private final DriveGainsTuner driveGainsTuner = new DriveGainsTuner(drivetrain);
private final GameData2026 gameData2026 = new GameData2026();
private ConfigTalonFXMotorTuner configFlywheelTuner = new ConfigTalonFXMotorTuner(shooterSubsystem.flywheelMotorLeft, "flywheel", Constants.Shooter.flyWheelSlot0Configs); private ConfigTalonFXMotorTuner configFlywheelTuner = new ConfigTalonFXMotorTuner(shooterSubsystem.flywheelMotorLeft, "flywheel", Constants.Shooter.flyWheelSlot0Configs);
private ConfigTalonFXMotorTuner configConveyorTuner = new ConfigTalonFXMotorTuner(shooterSubsystem.conveyorMotor, "conveyor", Constants.Shooter.conveyorSlot0Configs); private ConfigTalonFXMotorTuner configConveyorTuner = new ConfigTalonFXMotorTuner(shooterSubsystem.conveyorMotor, "conveyor", Constants.Shooter.conveyorSlot0Configs);
private ConfigTalonFXSMotorTuner configBackboardTuner = new ConfigTalonFXSMotorTuner(shooterSubsystem.backboardMotor, "backboard", Constants.Shooter.backboardSlot0Configs); private ConfigTalonFXSMotorTuner configBackboardTuner = new ConfigTalonFXSMotorTuner(shooterSubsystem.backboardMotor, "backboard", Constants.Shooter.backboardSlot0Configs);
@@ -124,8 +126,6 @@ public class RobotContainer {
// Disabled 时进入 idle(防止模块乱动) // Disabled 时进入 idle(防止模块乱动)
RobotModeTriggers.disabled().whileTrue(driveControls.idleCommand()); RobotModeTriggers.disabled().whileTrue(driveControls.idleCommand());
if (!Constants.DemoMode.ENABLED) {
//左保险:按住刹车 //左保险:按住刹车
controllerlower.leftBumper() controllerlower.leftBumper()
@@ -174,7 +174,6 @@ public class RobotContainer {
controllerlower.a() controllerlower.a()
.onTrue(robotStatusManager.setStatusCommand(RobotStatus.Climbing)) .onTrue(robotStatusManager.setStatusCommand(RobotStatus.Climbing))
.onFalse(robotStatusManager.setStatusCommand(RobotStatus.AllTelop)); .onFalse(robotStatusManager.setStatusCommand(RobotStatus.AllTelop));
}
} }
private void configueShooter(){ private void configueShooter(){
@@ -184,13 +183,7 @@ public class RobotContainer {
controllerupper.povUp().onTrue(Commands.runOnce(() -> shooterControls.adjustBackboardRateOffset(100))); controllerupper.povUp().onTrue(Commands.runOnce(() -> shooterControls.adjustBackboardRateOffset(100)));
controllerupper.povDown().onTrue(Commands.runOnce(() -> shooterControls.adjustBackboardRateOffset(-100))); controllerupper.povDown().onTrue(Commands.runOnce(() -> shooterControls.adjustBackboardRateOffset(-100)));
controllerupper.back().onTrue(Commands.runOnce(() -> shooterControls.resetOffsets())); controllerupper.back().onTrue(Commands.runOnce(() -> shooterControls.resetOffsets()));
if (Constants.DemoMode.ENABLED) { controllerupper.start().onTrue(Commands.runOnce(() -> shooterControls.resetBackboardCommand()));
controllerupper.rightTrigger()
.onTrue(robotStatusManager.setStatusCommand(RobotStatus.AutoAimming))
.onFalse(robotStatusManager.setStatusCommand(RobotStatus.AllTelop));
} else {
controllerupper.start().onTrue(shooterControls.resetBackboardCommand());
}
} }
@@ -199,9 +192,7 @@ public class RobotContainer {
} }
public Command getAutonomousCommand() { public Command getAutonomousCommand() {
if (Constants.DemoMode.ENABLED) {
return Commands.none();
}
return autoChooser.getSelected(); return autoChooser.getSelected();
} }
@@ -213,6 +204,10 @@ public class RobotContainer {
shooterSubsystem.setRightFollowLeft(); shooterSubsystem.setRightFollowLeft();
} }
public void dashboardPeriodic() {
gameData2026.periodic();
}
// private void configueClimber() { // private void configueClimber() {
// climberSubsystem.setDefaultCommand(climberControls.defaultClimberCommand()); // climberSubsystem.setDefaultCommand(climberControls.defaultClimberCommand());
// } // }
@@ -107,18 +107,9 @@ public class DriveControls {
SmartDashboard.putString("robotStatus",robotStatusManager.getStatus().name()); SmartDashboard.putString("robotStatus",robotStatusManager.getStatus().name());
double driveScale = boostEnabled ? boostDriveScale : normalDriveScale; double driveScale = boostEnabled ? boostDriveScale : normalDriveScale;
double turnScale = boostEnabled ? boostTurnScale : normalTurnScale; double turnScale = boostEnabled ? boostTurnScale : normalTurnScale;
if (Constants.DemoMode.ENABLED) {
driveScale = boostEnabled ? Constants.DemoMode.boostDriveScale : Constants.DemoMode.normalDriveScale;
turnScale = boostEnabled ? Constants.DemoMode.boostTurnScale : Constants.DemoMode.normalTurnScale;
}
double vx = -driver.getLeftY() * maxSpeed * driveScale; double vx = -driver.getLeftY() * maxSpeed * driveScale;
double vy = -driver.getLeftX() * maxSpeed * driveScale; double vy = -driver.getLeftX() * maxSpeed * driveScale;
double vomega = -driver.getRightX() * maxAngularRate * turnScale; double vomega = -driver.getRightX() * maxAngularRate * turnScale;
if (Constants.DemoMode.ENABLED) {
vx = clamp(vx, -Constants.DemoMode.maxLinearSpeedMetersPerSecond, Constants.DemoMode.maxLinearSpeedMetersPerSecond);
vy = clamp(vy, -Constants.DemoMode.maxLinearSpeedMetersPerSecond, Constants.DemoMode.maxLinearSpeedMetersPerSecond);
vomega = clamp(vomega, -Constants.DemoMode.maxAngularRateRadiansPerSecond, Constants.DemoMode.maxAngularRateRadiansPerSecond);
}
// ====== execute 内替换 limiter:只限加速、不限减速 ====== // ====== execute 内替换 limiter:只限加速、不限减速 ======
double limitedVx = limitAccelOnly(vx, lastVx, vxLimiter); double limitedVx = limitAccelOnly(vx, lastVx, vxLimiter);
double limitedVy = limitAccelOnly(vy, lastVy, vyLimiter); double limitedVy = limitAccelOnly(vy, lastVy, vyLimiter);
@@ -139,15 +130,7 @@ public class DriveControls {
autoControlNetworkTable.getEntry("distanceToPassball").setDouble(calculateDistanceAndRotationToPassBall()[0]); autoControlNetworkTable.getEntry("distanceToPassball").setDouble(calculateDistanceAndRotationToPassBall()[0]);
autoControlNetworkTable.getEntry("angleDifferenceToPassball").setDouble(calculateDistanceAndRotationToPassBall()[1]); autoControlNetworkTable.getEntry("angleDifferenceToPassball").setDouble(calculateDistanceAndRotationToPassBall()[1]);
RobotStatus currentStatus = robotStatusManager.getStatus(); switch (robotStatusManager.getStatus()) {
if (Constants.DemoMode.ENABLED
&& currentStatus != RobotStatus.Stopped
&& currentStatus != RobotStatus.AllTelop
&& currentStatus != RobotStatus.Climbing) {
currentStatus = RobotStatus.AllTelop;
}
switch (currentStatus) {
case Stopped: case Stopped:
vx = 0; vx = 0;
vy = 0; vy = 0;
@@ -229,9 +212,8 @@ public class DriveControls {
autoControlNetworkTable.getEntry("ActualVOmega").setDouble(vomega); autoControlNetworkTable.getEntry("ActualVOmega").setDouble(vomega);
boolean isAutoLike = boolean isAutoLike =
!Constants.DemoMode.ENABLED && (
robotStatusManager.getStatus() == RobotStatus.CrossingBump || robotStatusManager.getStatus() == RobotStatus.CrossingBump ||
robotStatusManager.getStatus() == RobotStatus.CrossingTrench); robotStatusManager.getStatus() == RobotStatus.CrossingTrench;
if (fieldCentricEnabled || isAutoLike) { if (fieldCentricEnabled || isAutoLike) {
@@ -249,9 +231,8 @@ public class DriveControls {
.withRotationalRate(vomega); .withRotationalRate(vomega);
} }
}, () -> fieldCentricEnabled || }, () -> fieldCentricEnabled ||
(!Constants.DemoMode.ENABLED && (
robotStatusManager.getStatus() == RobotStatus.CrossingBump || robotStatusManager.getStatus() == RobotStatus.CrossingBump ||
robotStatusManager.getStatus() == RobotStatus.CrossingTrench)) robotStatusManager.getStatus() == RobotStatus.CrossingTrench
? DriveMode.FIELD_CENTRIC : DriveMode.ROBOT_CENTRIC); ? DriveMode.FIELD_CENTRIC : DriveMode.ROBOT_CENTRIC);
} }
@@ -366,10 +347,6 @@ public class DriveControls {
return limiter.calculate(target); return limiter.calculate(target);
} }
private double clamp(double value, double min, double max) {
return Math.max(min, Math.min(max, value));
}
/** 紧急停止:清零限速器,让速度输出立刻归零 */ /** 紧急停止:清零限速器,让速度输出立刻归零 */
public void emergencyStop() { public void emergencyStop() {
vxLimiter.reset(0.0); vxLimiter.reset(0.0);
@@ -439,9 +416,6 @@ public class DriveControls {
// } // }
// } // }
public Command autoAimCommand() { public Command autoAimCommand() {
if (Constants.DemoMode.ENABLED) {
return Commands.runOnce(drivetrain::stop, drivetrain);
}
return drivetrain.applyRequest(() -> { return drivetrain.applyRequest(() -> {
double[] distanceAndRotation = calculateDistanceAndRotationToHub(); double[] distanceAndRotation = calculateDistanceAndRotationToHub();
double vomega = calculateRotationSpeedFromRotationAngle(distanceAndRotation[1]); double vomega = calculateRotationSpeedFromRotationAngle(distanceAndRotation[1]);
@@ -457,9 +431,6 @@ public class DriveControls {
}, drivetrain)); }, drivetrain));
} }
public Command shakeCommand(double amplitude, double switchPeriod, double totalTime) { public Command shakeCommand(double amplitude, double switchPeriod, double totalTime) {
if (Constants.DemoMode.ENABLED) {
return Commands.runOnce(drivetrain::stop, drivetrain);
}
Timer timer = new Timer(); Timer timer = new Timer();
return Commands.sequence( return Commands.sequence(
@@ -81,12 +81,6 @@ public class IntakerControls {
IntakerSubsystem.setIntakerGetterSpeed(getterspeed); IntakerSubsystem.setIntakerGetterSpeed(getterspeed);
boolean demoModeEnabled = Constants.DemoMode.ENABLED;
if (demoModeEnabled) {
IntakerSubsystem.stopIntakerotater();
return;
}
if(controller.getLeftY() < -0.5){ if(controller.getLeftY() < -0.5){
IntakerSubsystem.IntakerUpNonStop(); IntakerSubsystem.IntakerUpNonStop();
} else if(controller.getLeftY() > 0.5){ } else if(controller.getLeftY() > 0.5){
@@ -48,7 +48,7 @@ public class ShooterControls {
shooterSubsystem.outputBackboard(); shooterSubsystem.outputBackboard();
} }
shooterSubsystem.setFlywheelSpeedByRPS(0); shooterSubsystem.setFlywheelSpeedByRPS(0);
if(!Constants.DemoMode.ENABLED && controller.a().getAsBoolean()) { shooterSubsystem.setConveyorSpeedByRPS(Constants.Shooter.conveyorSpeed);} if(controller.a().getAsBoolean()) { shooterSubsystem.setConveyorSpeedByRPS(Constants.Shooter.conveyorSpeed);}
else{shooterSubsystem.setConveyorSpeedByRPS(0);} else{shooterSubsystem.setConveyorSpeedByRPS(0);}
break; break;
case PassingBall: case PassingBall:
@@ -81,11 +81,9 @@ public class ShooterControls {
case AutoAimming: case AutoAimming:
var x = shooterSubsystem.getDistanceToHub(); var x = shooterSubsystem.getDistanceToHub();
x = Math.max(1.2, Math.min(4.5, x)); x = Math.max(1.2, Math.min(4.5, x));
//flywheelSpeed = -1.4964026859575532*x*x*x*x*x*x*x+29.82445640241506*x*x*x*x*x*x-247.71603153159896*x*x*x*x*x+1108.8727302184625*x*x*x*x-2881.517500617481*x*x*x+4332.05363145275*x*x-3467.2508337871454*x+1192.1508062663759; flywheelSpeed = -1.4964026859575532*x*x*x*x*x*x*x+29.82445640241506*x*x*x*x*x*x-247.71603153159896*x*x*x*x*x+1108.8727302184625*x*x*x*x-2881.517500617481*x*x*x+4332.05363145275*x*x-3467.2508337871454*x+1192.1508062663759;
flywheelSpeed = 60;
flywheelSpeed += flywheelSpeedOffset; flywheelSpeed += flywheelSpeedOffset;
//backboardPosition = +34.5286998307899*x*x*x*x*x*x*x*x-788.5788623683884*x*x*x*x*x*x*x+7658.073303693148*x*x*x*x*x*x-41191.69338972519*x*x*x*x*x+133870.54588688645*x*x*x*x-268559.6987062158*x*x*x+324254.6530324262*x*x-215015.48893131423*x+59977.46545382827; backboardPosition = +34.5286998307899*x*x*x*x*x*x*x*x-788.5788623683884*x*x*x*x*x*x*x+7658.073303693148*x*x*x*x*x*x-41191.69338972519*x*x*x*x*x+133870.54588688645*x*x*x*x-268559.6987062158*x*x*x+324254.6530324262*x*x-215015.48893131423*x+59977.46545382827;
backboardPosition = 500;
backboardPosition += backboardPositionOffset; backboardPosition += backboardPositionOffset;
conveyorSpeed = Constants.Shooter.conveyorSpeed; conveyorSpeed = Constants.Shooter.conveyorSpeed;
if (controller.getRightTriggerAxis() < 0.1) { if (controller.getRightTriggerAxis() < 0.1) {
@@ -24,14 +24,14 @@ public class TunerConstants {
// The steer motor uses any SwerveModule.SteerRequestType control request with the // The steer motor uses any SwerveModule.SteerRequestType control request with the
// output type specified by SwerveModuleConstants.SteerMotorClosedLoopOutput // output type specified by SwerveModuleConstants.SteerMotorClosedLoopOutput
private static final Slot0Configs steerGains = new Slot0Configs() private static final Slot0Configs steerGains = new Slot0Configs()
.withKP(70).withKI(0).withKD(0.5) .withKP(100).withKI(0).withKD(0.5)
.withKS(0.1).withKV(1.59).withKA(0) .withKS(0.1).withKV(1.59).withKA(0)
.withStaticFeedforwardSign(StaticFeedforwardSignValue.UseClosedLoopSign); .withStaticFeedforwardSign(StaticFeedforwardSignValue.UseClosedLoopSign);
// When using closed-loop control, the drive motor uses the control // When using closed-loop control, the drive motor uses the control
// output type specified by SwerveModuleConstants.DriveMotorClosedLoopOutput // output type specified by SwerveModuleConstants.DriveMotorClosedLoopOutput
private static final Slot0Configs driveGains = new Slot0Configs() private static final Slot0Configs driveGains = new Slot0Configs()
.withKP(0.01).withKI(0).withKD(0) .withKP(0.1).withKI(0).withKD(0)
.withKS(0.05).withKV(0.117); .withKS(0).withKV(0.124);
// The closed-loop output type to use for the steer motors; // The closed-loop output type to use for the steer motors;
// This affects the PID/FF gains for the steer motors // This affects the PID/FF gains for the steer motors
@@ -42,7 +42,7 @@ public class TunerConstants {
// The type of motor used for the drive motor // The type of motor used for the drive motor
private static final DriveMotorArrangement kDriveMotorType = DriveMotorArrangement.TalonFX_Integrated; private static final DriveMotorArrangement kDriveMotorType = DriveMotorArrangement.TalonFX_Integrated;
// The type of motor used for the drive motor // The type of motor used for the steer motor
private static final SteerMotorArrangement kSteerMotorType = SteerMotorArrangement.TalonFX_Integrated; private static final SteerMotorArrangement kSteerMotorType = SteerMotorArrangement.TalonFX_Integrated;
// The remote sensor feedback type to use for the steer motors; // The remote sensor feedback type to use for the steer motors;
@@ -55,7 +55,14 @@ public class TunerConstants {
// Initial configs for the drive and steer motors and the azimuth encoder; these cannot be null. // 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. // Some configs will be overwritten; check the `with*InitialConfigs()` API documentation.
private static final TalonFXConfiguration driveInitialConfigs = new TalonFXConfiguration(); private static final TalonFXConfiguration driveInitialConfigs = new TalonFXConfiguration()
.withCurrentLimits(
new CurrentLimitsConfigs()
// Default supply current limit is 70 A, but it can be lowered to avoid brownouts.
// Supply current limits can be larger than the breaker current rating.
.withSupplyCurrentLimit(Amps.of(70))
.withSupplyCurrentLimitEnable(true)
);
private static final TalonFXConfiguration steerInitialConfigs = new TalonFXConfiguration() private static final TalonFXConfiguration steerInitialConfigs = new TalonFXConfiguration()
.withCurrentLimits( .withCurrentLimits(
new CurrentLimitsConfigs() new CurrentLimitsConfigs()
@@ -66,23 +73,14 @@ public class TunerConstants {
); );
private static final CANcoderConfiguration encoderInitialConfigs = new CANcoderConfiguration(); private static final CANcoderConfiguration encoderInitialConfigs = new CANcoderConfiguration();
// Configs for the Pigeon 2; leave this null to skip applying Pigeon 2 configs // Configs for the Pigeon 2; leave this null to skip applying Pigeon 2 configs
private static final Pigeon2Configuration pigeonConfigs = private static final Pigeon2Configuration pigeonConfigs = null;
new Pigeon2Configuration()
.withGyroTrim(
new GyroTrimConfigs()
.withGyroScalarZ(-5.0)
)
.withPigeon2Features(
new Pigeon2FeaturesConfigs()
.withEnableCompass(false)
);
// CAN bus that the devices are located on; // CAN bus that the devices are located on;
// All swerve devices must share the same CAN bus // All swerve devices must share the same CAN bus
public static final CANBus kCANBus = new CANBus("", "./logs/example.hoot"); public static final CANBus kCANBus = new CANBus("", "./logs/example.hoot");
// Theoretical free speed (m/s) at 12 V applied output; // Measured robot speed (m/s) at 12 V applied output;
// This is NOT the desired max robot speed - see MaxSpeed in RobotContainer instead;
// This needs to be tuned to your individual robot // This needs to be tuned to your individual robot
public static final LinearVelocity kSpeedAt12Volts = MetersPerSecond.of(4.73); public static final LinearVelocity kSpeedAt12Volts = MetersPerSecond.of(4.73);
@@ -101,7 +99,7 @@ public class TunerConstants {
// These are only used for simulation // These are only used for simulation
private static final MomentOfInertia kSteerInertia = KilogramSquareMeters.of(0.01); private static final MomentOfInertia kSteerInertia = KilogramSquareMeters.of(0.01);
private static final MomentOfInertia kDriveInertia = KilogramSquareMeters.of(0.01); private static final MomentOfInertia kDriveInertia = KilogramSquareMeters.of(0.035);
// Simulated voltage necessary to overcome friction // Simulated voltage necessary to overcome friction
private static final Voltage kSteerFrictionVoltage = Volts.of(0.2); private static final Voltage kSteerFrictionVoltage = Volts.of(0.2);
private static final Voltage kDriveFrictionVoltage = Volts.of(0.2); private static final Voltage kDriveFrictionVoltage = Volts.of(0.2);
@@ -136,10 +134,10 @@ public class TunerConstants {
// Front Left // Front Left
private static final int kFrontLeftDriveMotorId = 11; private static final int kFrontLeftDriveMotorId = 1;
private static final int kFrontLeftSteerMotorId = 12; private static final int kFrontLeftSteerMotorId = 2;
private static final int kFrontLeftEncoderId = 13; private static final int kFrontLeftEncoderId = 3;
private static final Angle kFrontLeftEncoderOffset = Rotations.of(-0.412841796875); private static final Angle kFrontLeftEncoderOffset = Rotations.of(-0.18115234375);
private static final boolean kFrontLeftSteerMotorInverted = false; private static final boolean kFrontLeftSteerMotorInverted = false;
private static final boolean kFrontLeftEncoderInverted = false; private static final boolean kFrontLeftEncoderInverted = false;
@@ -147,10 +145,10 @@ public class TunerConstants {
private static final Distance kFrontLeftYPos = Inches.of(11.375); private static final Distance kFrontLeftYPos = Inches.of(11.375);
// Front Right // Front Right
private static final int kFrontRightDriveMotorId = 21; private static final int kFrontRightDriveMotorId = 11;
private static final int kFrontRightSteerMotorId = 22; private static final int kFrontRightSteerMotorId = 12;
private static final int kFrontRightEncoderId = 23; private static final int kFrontRightEncoderId = 13;
private static final Angle kFrontRightEncoderOffset = Rotations.of(-0.012939453125); private static final Angle kFrontRightEncoderOffset = Rotations.of(-0.16162109375);
private static final boolean kFrontRightSteerMotorInverted = false; private static final boolean kFrontRightSteerMotorInverted = false;
private static final boolean kFrontRightEncoderInverted = false; private static final boolean kFrontRightEncoderInverted = false;
@@ -158,10 +156,10 @@ public class TunerConstants {
private static final Distance kFrontRightYPos = Inches.of(-11.375); private static final Distance kFrontRightYPos = Inches.of(-11.375);
// Back Left // Back Left
private static final int kBackLeftDriveMotorId = 1; private static final int kBackLeftDriveMotorId = 21;
private static final int kBackLeftSteerMotorId = 2; private static final int kBackLeftSteerMotorId = 22;
private static final int kBackLeftEncoderId = 3; private static final int kBackLeftEncoderId = 23;
private static final Angle kBackLeftEncoderOffset = Rotations.of(0.07275390625); private static final Angle kBackLeftEncoderOffset = Rotations.of(-0.017822265625);
private static final boolean kBackLeftSteerMotorInverted = false; private static final boolean kBackLeftSteerMotorInverted = false;
private static final boolean kBackLeftEncoderInverted = false; private static final boolean kBackLeftEncoderInverted = false;
@@ -172,7 +170,7 @@ public class TunerConstants {
private static final int kBackRightDriveMotorId = 31; private static final int kBackRightDriveMotorId = 31;
private static final int kBackRightSteerMotorId = 32; private static final int kBackRightSteerMotorId = 32;
private static final int kBackRightEncoderId = 33; private static final int kBackRightEncoderId = 33;
private static final Angle kBackRightEncoderOffset = Rotations.of(-0.4892578125); private static final Angle kBackRightEncoderOffset = Rotations.of(-0.490234375);
private static final boolean kBackRightSteerMotorInverted = false; private static final boolean kBackRightSteerMotorInverted = false;
private static final boolean kBackRightEncoderInverted = false; private static final boolean kBackRightEncoderInverted = false;
@@ -203,7 +201,7 @@ public class TunerConstants {
/** /**
* Creates a CommandSwerveDrivetrain instance. * Creates a CommandSwerveDrivetrain instance.
* This should only be called once in your robot program,. * This should only be called once in your robot program.
*/ */
public static CommandSwerveDrivetrain createDrivetrain() { public static CommandSwerveDrivetrain createDrivetrain() {
return new CommandSwerveDrivetrain( return new CommandSwerveDrivetrain(
@@ -162,9 +162,6 @@ public class CommandSwerveDrivetrain extends TunerSwerveDrivetrain implements Su
} }
public void forceUsingLimelightmt2() { public void forceUsingLimelightmt2() {
if (Constants.DemoMode.ENABLED) {
return;
}
LimelightHelpers.PoseEstimate mt2 = LimelightHelpers.PoseEstimate mt2 =
LimelightHelpers.getBotPoseEstimate_wpiBlue_MegaTag2(Constants.Limelight.LIMELIGHT_NAME_Shooter); LimelightHelpers.getBotPoseEstimate_wpiBlue_MegaTag2(Constants.Limelight.LIMELIGHT_NAME_Shooter);
@@ -177,9 +174,6 @@ public class CommandSwerveDrivetrain extends TunerSwerveDrivetrain implements Su
} }
public void forceUsingLimelightmt2WithllName(String llString) { public void forceUsingLimelightmt2WithllName(String llString) {
if (Constants.DemoMode.ENABLED) {
return;
}
LimelightHelpers.PoseEstimate mt2 = LimelightHelpers.PoseEstimate mt2 =
LimelightHelpers.getBotPoseEstimate_wpiBlue_MegaTag2(llString); LimelightHelpers.getBotPoseEstimate_wpiBlue_MegaTag2(llString);
@@ -432,16 +426,8 @@ public class CommandSwerveDrivetrain extends TunerSwerveDrivetrain implements Su
Pose2d pose = getState().Pose; Pose2d pose = getState().Pose;
m_field.setRobotPose(pose); m_field.setRobotPose(pose);
posePub.set(pose); posePub.set(pose);
LimelightHelpers.PoseEstimate shooterEstimate = shooter_ll_field.setRobotPose(LimelightHelpers.getBotPoseEstimate_wpiBlue_MegaTag2(Constants.Limelight.LIMELIGHT_NAME_Shooter).pose);
LimelightHelpers.getBotPoseEstimate_wpiBlue_MegaTag2(Constants.Limelight.LIMELIGHT_NAME_Shooter); intaker_ll_field.setRobotPose(LimelightHelpers.getBotPoseEstimate_wpiBlue_MegaTag2(Constants.Limelight.LIMELIGHT_NAME_Intaker).pose);
LimelightHelpers.PoseEstimate intakerEstimate =
LimelightHelpers.getBotPoseEstimate_wpiBlue_MegaTag2(Constants.Limelight.LIMELIGHT_NAME_Intaker);
if (shooterEstimate != null && shooterEstimate.tagCount > 0) {
shooter_ll_field.setRobotPose(shooterEstimate.pose);
}
if (intakerEstimate != null && intakerEstimate.tagCount > 0) {
intaker_ll_field.setRobotPose(intakerEstimate.pose);
}
driveNetworkTable.getEntry("YawFromState").setDouble(getState().Pose.getRotation().getDegrees()); driveNetworkTable.getEntry("YawFromState").setDouble(getState().Pose.getRotation().getDegrees());
driveNetworkTable.getEntry("DriveMode").setString(m_driveMode.name()); driveNetworkTable.getEntry("DriveMode").setString(m_driveMode.name());
driveNetworkTable.getEntry("IsFieldCentric").setBoolean(m_driveMode == DriveMode.FIELD_CENTRIC); driveNetworkTable.getEntry("IsFieldCentric").setBoolean(m_driveMode == DriveMode.FIELD_CENTRIC);
@@ -462,9 +448,7 @@ public class CommandSwerveDrivetrain extends TunerSwerveDrivetrain implements Su
0, 0, 0, 0, 0 0, 0, 0, 0, 0
); );
if (!Constants.DemoMode.ENABLED) { fuseLimelightmt2();
fuseLimelightmt2();
}
if (!m_hasAppliedOperatorPerspective || DriverStation.isDisabled()) { if (!m_hasAppliedOperatorPerspective || DriverStation.isDisabled()) {
DriverStation.getAlliance().ifPresent(allianceColor -> { DriverStation.getAlliance().ifPresent(allianceColor -> {
@@ -0,0 +1,117 @@
package frc.robot.utils;
import java.util.Optional;
import edu.wpi.first.networktables.NetworkTable;
import edu.wpi.first.networktables.NetworkTableInstance;
import edu.wpi.first.wpilibj.DriverStation;
import edu.wpi.first.wpilibj.DriverStation.Alliance;
public class GameData2026 {
private static final double SHIFT_1_END_TIME = 105.0;
private static final double SHIFT_2_END_TIME = 80.0;
private static final double SHIFT_3_END_TIME = 55.0;
private static final double SHIFT_4_END_TIME = 30.0;
private static final double TRANSITION_END_TIME = 130.0;
private final NetworkTable table = NetworkTableInstance.getDefault().getTable("GameData2026");
public void periodic() {
Optional<Alliance> alliance = DriverStation.getAlliance();
double matchTime = DriverStation.getMatchTime();
String gameData = DriverStation.getGameSpecificMessage();
HubWindow window = calculateHubWindow(alliance, matchTime, gameData);
table.getEntry("HubActive").setBoolean(window.hubActive);
table.getEntry("HubStatus").setString(window.status);
table.getEntry("SecondsUntilHubOpens").setDouble(window.secondsUntilHubOpens);
table.getEntry("SecondsUntilHubChanges").setDouble(window.secondsUntilHubChanges);
table.getEntry("Shift").setString(window.shift);
table.getEntry("MatchTime").setDouble(matchTime);
table.getEntry("GameData").setString(gameData);
table.getEntry("Alliance").setString(alliance.map(Enum::name).orElse("Unknown"));
table.getEntry("FirstInactiveAlliance").setString(getFirstInactiveAlliance(gameData));
}
private HubWindow calculateHubWindow(Optional<Alliance> alliance, double matchTime, String gameData) {
if (alliance.isEmpty()) {
return new HubWindow(false, "NO_ALLIANCE", "Disabled", Double.NaN, Double.NaN);
}
if (DriverStation.isAutonomousEnabled()) {
return new HubWindow(true, "OPEN", "Auto", 0.0, Double.NaN);
}
if (!DriverStation.isTeleopEnabled()) {
return new HubWindow(false, "DISABLED", "Disabled", Double.NaN, Double.NaN);
}
if (matchTime < 0.0) {
return new HubWindow(true, "OPEN_TIME_UNKNOWN", "Unknown", 0.0, Double.NaN);
}
Boolean redInactiveFirst = getRedInactiveFirst(gameData);
if (redInactiveFirst == null) {
return new HubWindow(true, "WAITING_DATA", "WaitingData", 0.0, Double.NaN);
}
boolean shift1Active = switch (alliance.get()) {
case Red -> !redInactiveFirst;
case Blue -> redInactiveFirst;
};
if (matchTime > TRANSITION_END_TIME) {
return new HubWindow(true, "OPEN", "Transition", 0.0, matchTime - TRANSITION_END_TIME);
} else if (matchTime > SHIFT_1_END_TIME) {
return fromShift("Shift1", shift1Active, matchTime, SHIFT_1_END_TIME);
} else if (matchTime > SHIFT_2_END_TIME) {
return fromShift("Shift2", !shift1Active, matchTime, SHIFT_2_END_TIME);
} else if (matchTime > SHIFT_3_END_TIME) {
return fromShift("Shift3", shift1Active, matchTime, SHIFT_3_END_TIME);
} else if (matchTime > SHIFT_4_END_TIME) {
return fromShift("Shift4", !shift1Active, matchTime, SHIFT_4_END_TIME);
} else {
return new HubWindow(true, "OPEN", "Endgame", 0.0, Math.max(matchTime, 0.0));
}
}
private HubWindow fromShift(String shift, boolean hubActive, double matchTime, double nextBoundary) {
double secondsUntilChange = Math.max(matchTime - nextBoundary, 0.0);
double secondsUntilOpen = hubActive ? 0.0 : secondsUntilChange;
String status = hubActive ? "OPEN" : "CLOSED";
return new HubWindow(hubActive, status, shift, secondsUntilOpen, secondsUntilChange);
}
private Boolean getRedInactiveFirst(String gameData) {
if (gameData.isEmpty()) {
return null;
}
return switch (gameData.charAt(0)) {
case 'R' -> true;
case 'B' -> false;
default -> null;
};
}
private String getFirstInactiveAlliance(String gameData) {
if (gameData.isEmpty()) {
return "None";
}
return switch (gameData.charAt(0)) {
case 'R' -> "Red";
case 'B' -> "Blue";
default -> "Invalid";
};
}
private record HubWindow(
boolean hubActive,
String status,
String shift,
double secondsUntilHubOpens,
double secondsUntilHubChanges
) {}
}