001/* 002 * Copyright (C) Cross The Road Electronics. All rights reserved. 003 * License information can be found in CTRE_LICENSE.txt 004 * For support and suggestions contact support@ctr-electronics.com or file 005 * an issue tracker at https://github.com/CrossTheRoadElec/Phoenix-Releases 006 */ 007package com.ctre.phoenix6.mechanisms.swerve; 008 009import static edu.wpi.first.units.Units.Volts; 010 011import com.ctre.phoenix6.StatusCode; 012import com.ctre.phoenix6.controls.VoltageOut; 013import com.ctre.phoenix6.mechanisms.swerve.utility.LegacyPhoenixPIDController; 014 015import edu.wpi.first.math.geometry.Pose2d; 016import edu.wpi.first.math.geometry.Rotation2d; 017import edu.wpi.first.math.geometry.Translation2d; 018import edu.wpi.first.math.kinematics.ChassisSpeeds; 019import edu.wpi.first.math.kinematics.SwerveDriveKinematics; 020import edu.wpi.first.math.kinematics.SwerveModuleState; 021import edu.wpi.first.units.measure.MutVoltage; 022import edu.wpi.first.units.measure.Voltage; 023 024/** 025 * Container for all the Swerve Requests. Use this to find all applicable swerve 026 * drive requests. 027 * <p> 028 * This is also an interface common to all swerve drive control requests that 029 * allow the request to calculate the state to apply to the modules. 030 */ 031public interface LegacySwerveRequest { 032 033 /** 034 * The reference for "forward" is sometimes different if you're talking 035 * about field relative. This addresses which forward to use. 036 */ 037 public enum ForwardReference { 038 /** 039 * This forward reference makes it so "forward" (positive X) is always towards the red alliance. 040 * This is important in situations such as path following where positive X is always towards the 041 * red alliance wall, regardless of where the operator physically are located. 042 */ 043 RedAlliance, 044 /** 045 * This forward references makes it so "forward" (positive X) is determined from the operator's 046 * perspective. This is important for most teleop driven field-centric requests, where positive 047 * X really means to drive away from the operator. 048 * <p> 049 * <b>Important</b>: Users must specify the OperatorPerspective with {@link LegacySwerveDrivetrain} object 050 */ 051 OperatorPerspective 052 } 053 054 /* 055 * Contains everything the control requests need to calculate the module state. 056 */ 057 public class LegacySwerveControlRequestParameters { 058 public double maxSpeedMps; 059 public SwerveDriveKinematics kinematics; 060 public ChassisSpeeds currentChassisSpeed; 061 public Pose2d currentPose; 062 public double timestamp; 063 public Translation2d[] swervePositions; 064 public Rotation2d operatorForwardDirection; 065 public double updatePeriod; 066 } 067 068 /** 069 * Applies this swerve request to the given modules. 070 * This is typically called by the SwerveDrivetrain. 071 * 072 * @param parameters Parameters the control request needs to calculate the module state 073 * @param modulesToApply Modules to which the control request is applied 074 * @return Status code of sending the request 075 */ 076 public StatusCode apply(LegacySwerveControlRequestParameters parameters, LegacySwerveModule... modulesToApply); 077 078 /** 079 * Sets the swerve drive module states to point inward on the 080 * robot in an "X" fashion, creating a natural brake which will 081 * oppose any motion. 082 */ 083 public class SwerveDriveBrake implements LegacySwerveRequest { 084 085 /** 086 * The type of control request to use for the drive motor. 087 */ 088 public LegacySwerveModule.DriveRequestType DriveRequestType = LegacySwerveModule.DriveRequestType.OpenLoopVoltage; 089 /** 090 * The type of control request to use for the steer motor. 091 */ 092 public LegacySwerveModule.SteerRequestType SteerRequestType = LegacySwerveModule.SteerRequestType.MotionMagic; 093 094 public StatusCode apply(LegacySwerveControlRequestParameters parameters, LegacySwerveModule... modulesToApply) { 095 096 for (int i = 0; i < modulesToApply.length; ++i) { 097 SwerveModuleState state = new SwerveModuleState(0, parameters.swervePositions[i].getAngle()); 098 modulesToApply[i].apply(state, DriveRequestType, SteerRequestType); 099 } 100 101 return StatusCode.OK; 102 } 103 104 /** 105 * Sets the type of control request to use for the drive motor. 106 * 107 * @param driveRequestType The type of control request to use for the drive motor 108 * @return this request 109 */ 110 public SwerveDriveBrake withDriveRequestType(LegacySwerveModule.DriveRequestType driveRequestType) { 111 this.DriveRequestType = driveRequestType; 112 return this; 113 } 114 /** 115 * Sets the type of control request to use for the steer motor. 116 * 117 * @param steerRequestType The type of control request to use for the steer motor 118 * @return this request 119 */ 120 public SwerveDriveBrake withSteerRequestType(LegacySwerveModule.SteerRequestType steerRequestType) { 121 this.SteerRequestType = steerRequestType; 122 return this; 123 } 124 } 125 126 /** 127 * Drives the swerve drivetrain in a field-centric manner. 128 * <p> 129 * When users use this request, they specify the direction the robot should 130 * travel oriented against the field, and the rate at which their robot should 131 * rotate about the center of the robot. 132 * <p> 133 * An example scenario is that the robot is oriented to the east, the 134 * VelocityX is +5 m/s, VelocityY is 0 m/s, and RotationRate is 0.5 rad/s. 135 * In this scenario, the robot would drive northward at 5 m/s and turn 136 * counterclockwise at 0.5 rad/s. 137 */ 138 public class FieldCentric implements LegacySwerveRequest { 139 /** 140 * The velocity in the X direction, in m/s. 141 * X is defined as forward according to WPILib convention, 142 * so this determines how fast to travel forward. 143 */ 144 public double VelocityX = 0; 145 /** 146 * The velocity in the Y direction, in m/s. 147 * Y is defined as to the left according to WPILib convention, 148 * so this determines how fast to travel to the left. 149 */ 150 public double VelocityY = 0; 151 /** 152 * The angular rate to rotate at, in radians per second. 153 * Angular rate is defined as counterclockwise positive, 154 * so this determines how fast to turn counterclockwise. 155 */ 156 public double RotationalRate = 0; 157 /** 158 * The allowable deadband of the request. 159 */ 160 public double Deadband = 0; 161 /** 162 * The rotational deadband of the request. 163 */ 164 public double RotationalDeadband = 0; 165 /** 166 * The center of rotation the robot should rotate around. 167 * This is (0,0) by default, which will rotate around the center of the robot. 168 */ 169 public Translation2d CenterOfRotation = new Translation2d(); 170 171 /** 172 * The type of control request to use for the drive motor. 173 */ 174 public LegacySwerveModule.DriveRequestType DriveRequestType = LegacySwerveModule.DriveRequestType.OpenLoopVoltage; 175 /** 176 * The type of control request to use for the steer motor. 177 */ 178 public LegacySwerveModule.SteerRequestType SteerRequestType = LegacySwerveModule.SteerRequestType.MotionMagic; 179 /** 180 * Whether to desaturate wheel speeds before applying. 181 * For more information, see the documentation of {@link SwerveDriveKinematics#desaturateWheelSpeeds}. 182 */ 183 public boolean DesaturateWheelSpeeds = true; 184 185 /** 186 * The perspective to use when determining which direction is forward. 187 */ 188 public ForwardReference ForwardReference = LegacySwerveRequest.ForwardReference.OperatorPerspective; 189 190 /** 191 * The last applied state in case we don't have anything to drive. 192 */ 193 protected SwerveModuleState[] m_lastAppliedState = null; 194 195 public StatusCode apply(LegacySwerveControlRequestParameters parameters, LegacySwerveModule... modulesToApply) { 196 double toApplyX = VelocityX; 197 double toApplyY = VelocityY; 198 if (ForwardReference == LegacySwerveRequest.ForwardReference.OperatorPerspective) { 199 /* If we're operator perspective, modify the X/Y translation by the angle */ 200 Translation2d tmp = new Translation2d(toApplyX, toApplyY); 201 tmp = tmp.rotateBy(parameters.operatorForwardDirection); 202 toApplyX = tmp.getX(); 203 toApplyY = tmp.getY(); 204 } 205 double toApplyOmega = RotationalRate; 206 if (Math.sqrt(toApplyX * toApplyX + toApplyY * toApplyY) < Deadband) { 207 toApplyX = 0; 208 toApplyY = 0; 209 } 210 if (Math.abs(toApplyOmega) < RotationalDeadband) { 211 toApplyOmega = 0; 212 } 213 214 ChassisSpeeds speeds = ChassisSpeeds.discretize( 215 ChassisSpeeds.fromFieldRelativeSpeeds( 216 toApplyX, toApplyY, toApplyOmega, 217 parameters.currentPose.getRotation() 218 ), 219 parameters.updatePeriod 220 ); 221 222 var states = parameters.kinematics.toSwerveModuleStates(speeds, CenterOfRotation); 223 if (DesaturateWheelSpeeds && parameters.maxSpeedMps > 0.0) { 224 SwerveDriveKinematics.desaturateWheelSpeeds(states, parameters.maxSpeedMps); 225 } 226 227 for (int i = 0; i < modulesToApply.length; ++i) { 228 modulesToApply[i].apply(states[i], DriveRequestType, SteerRequestType); 229 } 230 231 return StatusCode.OK; 232 } 233 234 /** 235 * Sets the velocity in the X direction, in m/s. 236 * X is defined as forward according to WPILib convention, 237 * so this determines how fast to travel forward. 238 * 239 * @param velocityX Velocity in the X direction, in m/s 240 * @return this request 241 */ 242 public FieldCentric withVelocityX(double velocityX) { 243 this.VelocityX = velocityX; 244 return this; 245 } 246 247 /** 248 * Sets the velocity in the Y direction, in m/s. 249 * Y is defined as to the left according to WPILib convention, 250 * so this determines how fast to travel to the left. 251 * 252 * @param velocityY Velocity in the Y direction, in m/s 253 * @return this request 254 */ 255 public FieldCentric withVelocityY(double velocityY) { 256 this.VelocityY = velocityY; 257 return this; 258 } 259 260 /** 261 * The angular rate to rotate at, in radians per second. 262 * Angular rate is defined as counterclockwise positive, 263 * so this determines how fast to turn counterclockwise. 264 * 265 * @param rotationalRate Angular rate to rotate at, in radians per second 266 * @return this request 267 */ 268 public FieldCentric withRotationalRate(double rotationalRate) { 269 this.RotationalRate = rotationalRate; 270 return this; 271 } 272 273 /** 274 * Sets the allowable deadband of the request. 275 * 276 * @param deadband Allowable deadband of the request 277 * @return this request 278 */ 279 public FieldCentric withDeadband(double deadband) { 280 this.Deadband = deadband; 281 return this; 282 } 283 /** 284 * Sets the rotational deadband of the request. 285 * 286 * @param rotationalDeadband Rotational deadband of the request 287 * @return this request 288 */ 289 public FieldCentric withRotationalDeadband(double rotationalDeadband) { 290 this.RotationalDeadband = rotationalDeadband; 291 return this; 292 } 293 /** 294 * Sets the center of rotation of the request 295 * 296 * @param centerOfRotation The center of rotation the robot should rotate around. 297 * @return this request 298 */ 299 public FieldCentric withCenterOfRotation(Translation2d centerOfRotation) { 300 this.CenterOfRotation = centerOfRotation; 301 return this; 302 } 303 304 /** 305 * Sets the type of control request to use for the drive motor. 306 * 307 * @param driveRequestType The type of control request to use for the drive motor 308 * @return this request 309 */ 310 public FieldCentric withDriveRequestType(LegacySwerveModule.DriveRequestType driveRequestType) { 311 this.DriveRequestType = driveRequestType; 312 return this; 313 } 314 /** 315 * Sets the type of control request to use for the steer motor. 316 * 317 * @param steerRequestType The type of control request to use for the steer motor 318 * @return this request 319 */ 320 public FieldCentric withSteerRequestType(LegacySwerveModule.SteerRequestType steerRequestType) { 321 this.SteerRequestType = steerRequestType; 322 return this; 323 } 324 325 /** 326 * Sets whether to desaturate wheel speeds before applying. 327 * For more information, see the documentation of {@link SwerveDriveKinematics#desaturateWheelSpeeds}. 328 * 329 * @param desaturateWheelSpeeds Whether to desaturate wheel speeds 330 * @return this request 331 */ 332 public FieldCentric withDesaturateWheelSpeeds(boolean desaturateWheelSpeeds) { 333 this.DesaturateWheelSpeeds = desaturateWheelSpeeds; 334 return this; 335 } 336 } 337 338 /** 339 * Drives the swerve drivetrain in a field-centric manner, maintaining a 340 * specified heading angle to ensure the robot is facing the desired direction 341 * <p> 342 * When users use this request, they specify the direction the robot should 343 * travel oriented against the field, and the direction the robot should be facing. 344 * <p> 345 * An example scenario is that the robot is oriented to the east, the VelocityX 346 * is +5 m/s, VelocityY is 0 m/s, and TargetDirection is 180 degrees. 347 * In this scenario, the robot would drive northward at 5 m/s and turn clockwise 348 * to a target of 180 degrees. 349 * <p> 350 * This control request is especially useful for autonomous control, where the 351 * robot should be facing a changing direction throughout the motion. 352 */ 353 public class FieldCentricFacingAngle implements LegacySwerveRequest { 354 /** 355 * The velocity in the X direction, in m/s. 356 * X is defined as forward according to WPILib convention, 357 * so this determines how fast to travel forward. 358 */ 359 public double VelocityX = 0; 360 /** 361 * The velocity in the Y direction, in m/s. 362 * Y is defined as to the left according to WPILib convention, 363 * so this determines how fast to travel to the left. 364 */ 365 public double VelocityY = 0; 366 /** 367 * The desired direction to face. 368 * 0 Degrees is defined as in the direction of the X axis. 369 * As a result, a TargetDirection of 90 degrees will point along 370 * the Y axis, or to the left. 371 */ 372 public Rotation2d TargetDirection = new Rotation2d(); 373 374 /** 375 * The allowable deadband of the request. 376 */ 377 public double Deadband = 0; 378 /** 379 * The rotational deadband of the request. 380 */ 381 public double RotationalDeadband = 0; 382 /** 383 * The center of rotation the robot should rotate around. 384 * This is (0,0) by default, which will rotate around the center of the robot. 385 */ 386 public Translation2d CenterOfRotation = new Translation2d(); 387 388 /** 389 * The type of control request to use for the drive motor. 390 */ 391 public LegacySwerveModule.DriveRequestType DriveRequestType = LegacySwerveModule.DriveRequestType.OpenLoopVoltage; 392 /** 393 * The type of control request to use for the steer motor. 394 */ 395 public LegacySwerveModule.SteerRequestType SteerRequestType = LegacySwerveModule.SteerRequestType.MotionMagic; 396 /** 397 * Whether to desaturate wheel speeds before applying. 398 * For more information, see the documentation of {@link SwerveDriveKinematics#desaturateWheelSpeeds}. 399 */ 400 public boolean DesaturateWheelSpeeds = true; 401 402 /** 403 * The PID controller used to maintain the desired heading. 404 * Users can specify the PID gains to change how aggressively to maintain 405 * heading. 406 * <p> 407 * This PID controller operates on heading radians and outputs a target 408 * rotational rate in radians per second. 409 */ 410 public LegacyPhoenixPIDController HeadingController = new LegacyPhoenixPIDController(0, 0, 0); 411 412 /** 413 * The perspective to use when determining which direction is forward. 414 */ 415 public ForwardReference ForwardReference = LegacySwerveRequest.ForwardReference.OperatorPerspective; 416 417 public StatusCode apply(LegacySwerveControlRequestParameters parameters, LegacySwerveModule... modulesToApply) { 418 double toApplyX = VelocityX; 419 double toApplyY = VelocityY; 420 Rotation2d angleToFace = TargetDirection; 421 if (ForwardReference == LegacySwerveRequest.ForwardReference.OperatorPerspective) { 422 /* If we're operator perspective, modify the X/Y translation by the angle */ 423 Translation2d tmp = new Translation2d(toApplyX, toApplyY); 424 tmp = tmp.rotateBy(parameters.operatorForwardDirection); 425 toApplyX = tmp.getX(); 426 toApplyY = tmp.getY(); 427 /* And rotate the direction we want to face by the angle */ 428 angleToFace = angleToFace.rotateBy(parameters.operatorForwardDirection); 429 } 430 431 double rotationRate = HeadingController.calculate(parameters.currentPose.getRotation().getRadians(), 432 angleToFace.getRadians(), parameters.timestamp); 433 434 double toApplyOmega = rotationRate; 435 if (Math.sqrt(toApplyX * toApplyX + toApplyY * toApplyY) < Deadband) { 436 toApplyX = 0; 437 toApplyY = 0; 438 } 439 if (Math.abs(toApplyOmega) < RotationalDeadband) { 440 toApplyOmega = 0; 441 } 442 443 ChassisSpeeds speeds = ChassisSpeeds.discretize( 444 ChassisSpeeds.fromFieldRelativeSpeeds( 445 toApplyX, toApplyY, toApplyOmega, 446 parameters.currentPose.getRotation() 447 ), 448 parameters.updatePeriod 449 ); 450 451 var states = parameters.kinematics.toSwerveModuleStates(speeds, CenterOfRotation); 452 if (DesaturateWheelSpeeds && parameters.maxSpeedMps > 0.0) { 453 SwerveDriveKinematics.desaturateWheelSpeeds(states, parameters.maxSpeedMps); 454 } 455 456 for (int i = 0; i < modulesToApply.length; ++i) { 457 modulesToApply[i].apply(states[i], DriveRequestType, SteerRequestType); 458 } 459 460 return StatusCode.OK; 461 } 462 463 /** 464 * Sets the velocity in the X direction, in m/s. 465 * X is defined as forward according to WPILib convention, 466 * so this determines how fast to travel forward. 467 * 468 * @param velocityX Velocity in the X direction, in m/s 469 * @return this request 470 */ 471 public FieldCentricFacingAngle withVelocityX(double velocityX) { 472 this.VelocityX = velocityX; 473 return this; 474 } 475 476 /** 477 * Sets the velocity in the Y direction, in m/s. 478 * Y is defined as to the left according to WPILib convention, 479 * so this determines how fast to travel to the left. 480 * 481 * @param velocityY Velocity in the Y direction, in m/s 482 * @return this request 483 */ 484 public FieldCentricFacingAngle withVelocityY(double velocityY) { 485 this.VelocityY = velocityY; 486 return this; 487 } 488 489 /** 490 * Sets the desired direction to face. 491 * 0 Degrees is defined as in the direction of the X axis. 492 * As a result, a TargetDirection of 90 degrees will point along 493 * the Y axis, or to the left. 494 * 495 * @param targetDirection Desired direction to face 496 * @return this request 497 */ 498 public FieldCentricFacingAngle withTargetDirection(Rotation2d targetDirection) { 499 this.TargetDirection = targetDirection; 500 return this; 501 } 502 503 /** 504 * Sets the allowable deadband of the request. 505 * 506 * @param deadband Allowable deadband of the request 507 * @return this request 508 */ 509 public FieldCentricFacingAngle withDeadband(double deadband) { 510 this.Deadband = deadband; 511 return this; 512 } 513 /** 514 * Sets the rotational deadband of the request. 515 * 516 * @param rotationalDeadband Rotational deadband of the request 517 * @return this request 518 */ 519 public FieldCentricFacingAngle withRotationalDeadband(double rotationalDeadband) { 520 this.RotationalDeadband = rotationalDeadband; 521 return this; 522 } 523 /** 524 * Sets the center of rotation of the request 525 * 526 * @param centerOfRotation The center of rotation the robot should rotate around. 527 * @return this request 528 */ 529 public FieldCentricFacingAngle withCenterOfRotation(Translation2d centerOfRotation) { 530 this.CenterOfRotation = centerOfRotation; 531 return this; 532 } 533 534 /** 535 * Sets the type of control request to use for the drive motor. 536 * 537 * @param driveRequestType The type of control request to use for the drive motor 538 * @return this request 539 */ 540 public FieldCentricFacingAngle withDriveRequestType(LegacySwerveModule.DriveRequestType driveRequestType) { 541 this.DriveRequestType = driveRequestType; 542 return this; 543 } 544 /** 545 * Sets the type of control request to use for the steer motor. 546 * 547 * @param steerRequestType The type of control request to use for the steer motor 548 * @return this request 549 */ 550 public FieldCentricFacingAngle withSteerRequestType(LegacySwerveModule.SteerRequestType steerRequestType) { 551 this.SteerRequestType = steerRequestType; 552 return this; 553 } 554 555 /** 556 * Sets whether to desaturate wheel speeds before applying. 557 * For more information, see the documentation of {@link SwerveDriveKinematics#desaturateWheelSpeeds}. 558 * 559 * @param desaturateWheelSpeeds Whether to desaturate wheel speeds 560 * @return this request 561 */ 562 public FieldCentricFacingAngle withDesaturateWheelSpeeds(boolean desaturateWheelSpeeds) { 563 this.DesaturateWheelSpeeds = desaturateWheelSpeeds; 564 return this; 565 } 566 } 567 568 /** 569 * Does nothing to the swerve module state. This is the default state of a newly 570 * created swerve drive mechanism. 571 */ 572 public class Idle implements LegacySwerveRequest { 573 public StatusCode apply(LegacySwerveControlRequestParameters parameters, LegacySwerveModule... modulesToApply) { 574 return StatusCode.OK; 575 } 576 } 577 578 /** 579 * Sets the swerve drive modules to point to a specified direction. 580 */ 581 public class PointWheelsAt implements LegacySwerveRequest { 582 583 /** 584 * The direction to point the modules toward. 585 * This direction is still optimized to what the module was previously at. 586 */ 587 public Rotation2d ModuleDirection = new Rotation2d(); 588 /** 589 * The type of control request to use for the drive motor. 590 */ 591 public LegacySwerveModule.DriveRequestType DriveRequestType = LegacySwerveModule.DriveRequestType.OpenLoopVoltage; 592 /** 593 * The type of control request to use for the steer motor. 594 */ 595 public LegacySwerveModule.SteerRequestType SteerRequestType = LegacySwerveModule.SteerRequestType.MotionMagic; 596 597 public StatusCode apply(LegacySwerveControlRequestParameters parameters, LegacySwerveModule... modulesToApply) { 598 599 for (int i = 0; i < modulesToApply.length; ++i) { 600 SwerveModuleState state = new SwerveModuleState(0, ModuleDirection); 601 modulesToApply[i].apply(state, DriveRequestType, SteerRequestType); 602 } 603 604 return StatusCode.OK; 605 } 606 607 /** 608 * Sets the direction to point the modules toward. 609 * This direction is still optimized to what the module was previously at. 610 * 611 * @param moduleDirection Direction to point the modules toward 612 * @return this request 613 */ 614 public PointWheelsAt withModuleDirection(Rotation2d moduleDirection) { 615 this.ModuleDirection = moduleDirection; 616 return this; 617 } 618 619 /** 620 * Sets the type of control request to use for the drive motor. 621 * 622 * @param driveRequestType The type of control request to use for the drive motor 623 * @return this request 624 */ 625 public PointWheelsAt withDriveRequestType(LegacySwerveModule.DriveRequestType driveRequestType) { 626 this.DriveRequestType = driveRequestType; 627 return this; 628 } 629 /** 630 * Sets the type of control request to use for the steer motor. 631 * 632 * @param steerRequestType The type of control request to use for the steer motor 633 * @return this request 634 */ 635 public PointWheelsAt withSteerRequestType(LegacySwerveModule.SteerRequestType steerRequestType) { 636 this.SteerRequestType = steerRequestType; 637 return this; 638 } 639 } 640 641 /** 642 * Drives the swerve drivetrain in a robot-centric manner. 643 * <p> 644 * When users use this request, they specify the direction the robot should 645 * travel oriented against the robot itself, and the rate at which their 646 * robot should rotate about the center of the robot. 647 * <p> 648 * An example scenario is that the robot is oriented to the east, the 649 * VelocityX is +5 m/s, VelocityY is 0 m/s, and RotationRate is 0.5 rad/s. 650 * In this scenario, the robot would drive eastward at 5 m/s and turn 651 * counterclockwise at 0.5 rad/s. 652 */ 653 public class RobotCentric implements LegacySwerveRequest { 654 /** 655 * The velocity in the X direction, in m/s. 656 * X is defined as forward according to WPILib convention, 657 * so this determines how fast to travel forward. 658 */ 659 public double VelocityX = 0; 660 /** 661 * The velocity in the Y direction, in m/s. 662 * Y is defined as to the left according to WPILib convention, 663 * so this determines how fast to travel to the left. 664 */ 665 public double VelocityY = 0; 666 /** 667 * The angular rate to rotate at, in radians per second. 668 * Angular rate is defined as counterclockwise positive, 669 * so this determines how fast to turn counterclockwise. 670 */ 671 public double RotationalRate = 0; 672 673 /** 674 * The allowable deadband of the request. 675 */ 676 public double Deadband = 0; 677 /** 678 * The rotational deadband of the request. 679 */ 680 public double RotationalDeadband = 0; 681 /** 682 * The center of rotation the robot should rotate around. 683 * This is (0,0) by default, which will rotate around the center of the robot. 684 */ 685 public Translation2d CenterOfRotation = new Translation2d(); 686 687 /** 688 * The type of control request to use for the drive motor. 689 */ 690 public LegacySwerveModule.DriveRequestType DriveRequestType = LegacySwerveModule.DriveRequestType.OpenLoopVoltage; 691 /** 692 * The type of control request to use for the steer motor. 693 */ 694 public LegacySwerveModule.SteerRequestType SteerRequestType = LegacySwerveModule.SteerRequestType.MotionMagic; 695 /** 696 * Whether to desaturate wheel speeds before applying. 697 * For more information, see the documentation of {@link SwerveDriveKinematics#desaturateWheelSpeeds}. 698 */ 699 public boolean DesaturateWheelSpeeds = true; 700 701 public StatusCode apply(LegacySwerveControlRequestParameters parameters, LegacySwerveModule... modulesToApply) { 702 double toApplyX = VelocityX; 703 double toApplyY = VelocityY; 704 double toApplyOmega = RotationalRate; 705 if (Math.sqrt(toApplyX * toApplyX + toApplyY * toApplyY) < Deadband) { 706 toApplyX = 0; 707 toApplyY = 0; 708 } 709 if (Math.abs(toApplyOmega) < RotationalDeadband) { 710 toApplyOmega = 0; 711 } 712 ChassisSpeeds speeds = new ChassisSpeeds(toApplyX, toApplyY, toApplyOmega); 713 714 var states = parameters.kinematics.toSwerveModuleStates(speeds, CenterOfRotation); 715 if (DesaturateWheelSpeeds && parameters.maxSpeedMps > 0.0) { 716 SwerveDriveKinematics.desaturateWheelSpeeds(states, parameters.maxSpeedMps); 717 } 718 719 for (int i = 0; i < modulesToApply.length; ++i) { 720 modulesToApply[i].apply(states[i], DriveRequestType, SteerRequestType); 721 } 722 723 return StatusCode.OK; 724 } 725 726 /** 727 * Sets the velocity in the X direction, in m/s. 728 * X is defined as forward according to WPILib convention, 729 * so this determines how fast to travel forward. 730 * 731 * @param velocityX Velocity in the X direction, in m/s 732 * @return this request 733 */ 734 public RobotCentric withVelocityX(double velocityX) { 735 this.VelocityX = velocityX; 736 return this; 737 } 738 739 /** 740 * Sets the velocity in the Y direction, in m/s. 741 * Y is defined as to the left according to WPILib convention, 742 * so this determines how fast to travel to the left. 743 * 744 * @param velocityY Velocity in the Y direction, in m/s 745 * @return this request 746 */ 747 public RobotCentric withVelocityY(double velocityY) { 748 this.VelocityY = velocityY; 749 return this; 750 } 751 752 /** 753 * The angular rate to rotate at, in radians per second. 754 * Angular rate is defined as counterclockwise positive, 755 * so this determines how fast to turn counterclockwise. 756 * 757 * @param rotationalRate Angular rate to rotate at, in radians per second 758 * @return this request 759 */ 760 public RobotCentric withRotationalRate(double rotationalRate) { 761 this.RotationalRate = rotationalRate; 762 return this; 763 } 764 765 /** 766 * Sets the allowable deadband of the request. 767 * 768 * @param deadband Allowable deadband of the request 769 * @return this request 770 */ 771 public RobotCentric withDeadband(double deadband) { 772 this.Deadband = deadband; 773 return this; 774 } 775 /** 776 * Sets the rotational deadband of the request. 777 * 778 * @param rotationalDeadband Rotational deadband of the request 779 * @return this request 780 */ 781 public RobotCentric withRotationalDeadband(double rotationalDeadband) { 782 this.RotationalDeadband = rotationalDeadband; 783 return this; 784 } 785 /** 786 * Sets the center of rotation of the request 787 * 788 * @param centerOfRotation The center of rotation the robot should rotate around. 789 * @return this request 790 */ 791 public RobotCentric withCenterOfRotation(Translation2d centerOfRotation) { 792 this.CenterOfRotation = centerOfRotation; 793 return this; 794 } 795 796 /** 797 * Sets the type of control request to use for the drive motor. 798 * 799 * @param driveRequestType The type of control request to use for the drive motor 800 * @return this request 801 */ 802 public RobotCentric withDriveRequestType(LegacySwerveModule.DriveRequestType driveRequestType) { 803 this.DriveRequestType = driveRequestType; 804 return this; 805 } 806 /** 807 * Sets the type of control request to use for the steer motor. 808 * 809 * @param steerRequestType The type of control request to use for the steer motor 810 * @return this request 811 */ 812 public RobotCentric withSteerRequestType(LegacySwerveModule.SteerRequestType steerRequestType) { 813 this.SteerRequestType = steerRequestType; 814 return this; 815 } 816 817 /** 818 * Sets whether to desaturate wheel speeds before applying. 819 * For more information, see the documentation of {@link SwerveDriveKinematics#desaturateWheelSpeeds}. 820 * 821 * @param desaturateWheelSpeeds Whether to desaturate wheel speeds 822 * @return this request 823 */ 824 public RobotCentric withDesaturateWheelSpeeds(boolean desaturateWheelSpeeds) { 825 this.DesaturateWheelSpeeds = desaturateWheelSpeeds; 826 return this; 827 } 828 } 829 830 /** 831 * Accepts a generic ChassisSpeeds to apply to the drivetrain. 832 */ 833 public class ApplyChassisSpeeds implements LegacySwerveRequest { 834 835 /** 836 * The chassis speeds to apply to the drivetrain. 837 */ 838 public ChassisSpeeds Speeds = new ChassisSpeeds(); 839 /** 840 * The center of rotation to rotate around. 841 */ 842 public Translation2d CenterOfRotation = new Translation2d(0, 0); 843 /** 844 * The type of control request to use for the drive motor. 845 */ 846 public LegacySwerveModule.DriveRequestType DriveRequestType = LegacySwerveModule.DriveRequestType.OpenLoopVoltage; 847 /** 848 * The type of control request to use for the steer motor. 849 */ 850 public LegacySwerveModule.SteerRequestType SteerRequestType = LegacySwerveModule.SteerRequestType.MotionMagic; 851 /** 852 * Whether to desaturate wheel speeds before applying. 853 * For more information, see the documentation of {@link SwerveDriveKinematics#desaturateWheelSpeeds}. 854 */ 855 public boolean DesaturateWheelSpeeds = true; 856 857 public StatusCode apply(LegacySwerveControlRequestParameters parameters, LegacySwerveModule... modulesToApply) { 858 var states = parameters.kinematics.toSwerveModuleStates(Speeds, CenterOfRotation); 859 if (DesaturateWheelSpeeds && parameters.maxSpeedMps > 0.0) { 860 SwerveDriveKinematics.desaturateWheelSpeeds(states, parameters.maxSpeedMps); 861 } 862 863 for (int i = 0; i < modulesToApply.length; ++i) { 864 modulesToApply[i].apply(states[i], DriveRequestType, SteerRequestType); 865 } 866 867 return StatusCode.OK; 868 } 869 870 /** 871 * Sets the chassis speeds to apply to the drivetrain. 872 * 873 * @param speeds Chassis speeds to apply to the drivetrain 874 * @return this request 875 */ 876 public ApplyChassisSpeeds withSpeeds(ChassisSpeeds speeds) { 877 this.Speeds = speeds; 878 return this; 879 } 880 /** 881 * Sets the center of rotation to rotate around. 882 * 883 * @param centerOfRotation Center of rotation to rotate around 884 * @return this request 885 */ 886 public ApplyChassisSpeeds withCenterOfRotation(Translation2d centerOfRotation) { 887 this.CenterOfRotation = centerOfRotation; 888 return this; 889 } 890 891 /** 892 * Sets the type of control request to use for the drive motor. 893 * 894 * @param driveRequestType The type of control request to use for the drive motor 895 * @return this request 896 */ 897 public ApplyChassisSpeeds withDriveRequestType(LegacySwerveModule.DriveRequestType driveRequestType) { 898 this.DriveRequestType = driveRequestType; 899 return this; 900 } 901 /** 902 * Sets the type of control request to use for the steer motor. 903 * 904 * @param steerRequestType The type of control request to use for the steer motor 905 * @return this request 906 */ 907 public ApplyChassisSpeeds withSteerRequestType(LegacySwerveModule.SteerRequestType steerRequestType) { 908 this.SteerRequestType = steerRequestType; 909 return this; 910 } 911 912 /** 913 * Sets whether to desaturate wheel speeds before applying. 914 * For more information, see the documentation of {@link SwerveDriveKinematics#desaturateWheelSpeeds}. 915 * 916 * @param desaturateWheelSpeeds Whether to desaturate wheel speeds 917 * @return this request 918 */ 919 public ApplyChassisSpeeds withDesaturateWheelSpeeds(boolean desaturateWheelSpeeds) { 920 this.DesaturateWheelSpeeds = desaturateWheelSpeeds; 921 return this; 922 } 923 } 924 925 /** 926 * SysId-specific SwerveRequest to characterize the translational 927 * characteristics of a swerve drivetrain. 928 */ 929 public class SysIdSwerveTranslation implements LegacySwerveRequest { 930 /** 931 * Voltage to apply to drive wheels. This is final to enforce mutating the value. 932 */ 933 public final MutVoltage VoltsToApply = Volts.mutable(0); 934 935 /* Local reference to a voltage request to drive the motors with */ 936 private VoltageOut m_voltRequest = new VoltageOut(0); 937 938 public StatusCode apply(LegacySwerveControlRequestParameters parameters, LegacySwerveModule... modulesToApply) { 939 for (int i = 0; i < modulesToApply.length; ++i) { 940 modulesToApply[i].applyCharacterization(Rotation2d.fromDegrees(0), m_voltRequest.withOutput(VoltsToApply.in(Volts))); 941 } 942 return StatusCode.OK; 943 } 944 945 /** 946 * Sets the voltage to apply to the drive wheels. 947 * 948 * @param volts Voltage to apply 949 * @return this request 950 */ 951 public SysIdSwerveTranslation withVolts(Voltage volts) { 952 VoltsToApply.mut_replace(volts); 953 return this; 954 } 955 } 956 957 /** 958 * SysId-specific SwerveRequest to characterize the rotational 959 * characteristics of a swerve drivetrain. 960 */ 961 public class SysIdSwerveRotation implements LegacySwerveRequest { 962 /** 963 * Voltage to apply to drive wheels. This is final to enforce mutating the value. 964 */ 965 public final MutVoltage VoltsToApply = Volts.mutable(0); 966 967 /* Local reference to a voltage request to drive the motors with */ 968 private VoltageOut m_voltRequest = new VoltageOut(0); 969 970 public StatusCode apply(LegacySwerveControlRequestParameters parameters, LegacySwerveModule... modulesToApply) { 971 for (int i = 0; i < modulesToApply.length; ++i) { 972 modulesToApply[i].applyCharacterization(parameters.swervePositions[i].getAngle().plus(Rotation2d.fromDegrees(90)), 973 m_voltRequest.withOutput(VoltsToApply.in(Volts))); 974 } 975 return StatusCode.OK; 976 } 977 978 /** 979 * Update the voltage to apply to the drive wheels. 980 * 981 * @param volts Voltage to apply 982 * @return this request 983 */ 984 public SysIdSwerveRotation withVolts(Voltage volts) { 985 VoltsToApply.mut_replace(volts); 986 return this; 987 } 988 } 989 990 /** 991 * SysId-specific SwerveRequest to characterize the steer module 992 * characteristics of a swerve drivetrain. 993 */ 994 public class SysIdSwerveSteerGains implements LegacySwerveRequest { 995 /** 996 * Voltage to apply to steer motors. This is final to enforce mutating the value. 997 */ 998 public final MutVoltage VoltsToApply = Volts.mutable(0); 999 1000 /* Local reference to a voltage request to drive the motors with */ 1001 private VoltageOut m_voltRequest = new VoltageOut(0); 1002 1003 public StatusCode apply(LegacySwerveControlRequestParameters parameters, LegacySwerveModule... modulesToApply) { 1004 for (int i = 0; i < modulesToApply.length; ++i) { 1005 modulesToApply[i].getSteerMotor().setControl(m_voltRequest.withOutput(VoltsToApply.in(Volts))); 1006 modulesToApply[i].getDriveMotor().setControl(m_voltRequest.withOutput(0)); 1007 } 1008 return StatusCode.OK; 1009 } 1010 1011 /** 1012 * Sets the voltage to apply to the steer motors. 1013 * 1014 * @param volts Voltage to apply 1015 * @return this request 1016 */ 1017 public SysIdSwerveSteerGains withVolts(Voltage volts) { 1018 VoltsToApply.mut_replace(volts); 1019 return this; 1020 } 1021 } 1022}