CommandSwerveDrivetrain extends the Phoenix 6 TunerSwerveDrivetrain (which itself extends SwerveDrivetrain<TalonFX, TalonFX, CANcoder>) and implements WPILib’s Subsystem interface so it participates in the command scheduler. All hardware is constructed inside the drivetrain class—callers never instantiate motors or encoders directly.
Architecture
Controls.java sets the default command on drivebaseSubsystem using applyRequest():
Public API
Field-centric drive
The default drive request usesSwerveRequest.FieldCentric with a SWERVE_DEADBAND of 0.001 and DriveRequestType.Velocity:
MaxSpeed (sourced from kSpeedAt12Volts for the active robot type). A MaxAngularRate of 0.75 rotations per second is defined in Controls.java for reference but the rotation axis is multiplied by MaxSpeed * DRIVE_INPUT_SCALE in the same way as the translation axes. A deadband of 0.1 is applied to raw joystick inputs before scaling.
Operator perspective
periodic() checks alliance color and calls setOperatorPerspectiveForward() once per match to rotate the field-centric coordinate frame:
- Blue alliance →
Rotation2d.kZero(forward = toward red wall) - Red alliance →
Rotation2d.k180deg(forward = toward blue wall)
m_hasAppliedOperatorPerspective prevents re-applying the rotation during an enabled match unless the robot is disabled or code restarts mid-match.
Pose clamping
clampPoseToField() runs every periodic() loop. If the pose estimator walks off the field boundary (derived from the AprilTagFieldLayout), the pose is hard-clamped to the nearest valid field coordinate. This prevents errant vision measurements from accumulating unbounded translations.
SysId characterization
ThreeSysIdRoutine instances are available for characterizing drive gains:
Run quasistatic or dynamic tests via
sysIdQuasistatic(Direction) / sysIdDynamic(Direction). The active routine is pointed to by m_sysIdRoutineToApply (default: translation).
Simulation
WhenUtils.isSimulation() is true, startSimThread() spawns a Notifier that calls updateSimState() every 5 ms, faster than the 20 ms robot loop, so PID gains behave consistently in simulation:
RobotController.getBatteryVoltage() into the simulation model for realistic brownout behavior.
CAN bus
On the competition robot all swerve devices (TalonFX drive motors, TalonFX steer motors, CANcoders) are connected to the Phoenix 6 CANivore bus, referenced viaCompTunerConstants.kCANBus. On the alpha robot, devices are on CANBus.roboRIO().
Robot.java sets the minimum brownout voltage to 7.0 V (RobotController.setBrownoutVoltage(7.0)) to protect motor controllers during high-current maneuvers. The SysId translation routine deliberately caps dynamic voltage to 4 V for the same reason.