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.swerve;
008
009import static edu.wpi.first.units.Units.*;
010
011import java.util.HashMap;
012
013import com.ctre.phoenix6.StatusCode;
014import com.ctre.phoenix6.controls.CoastOut;
015import com.ctre.phoenix6.controls.PositionTorqueCurrentFOC;
016import com.ctre.phoenix6.controls.PositionVoltage;
017import com.ctre.phoenix6.controls.VoltageOut;
018import com.ctre.phoenix6.swerve.SwerveDrivetrain.SwerveControlParameters;
019import com.ctre.phoenix6.swerve.jni.SwerveJNI;
020import com.ctre.phoenix6.swerve.utility.PhoenixPIDController;
021
022import edu.wpi.first.math.geometry.Rotation2d;
023import edu.wpi.first.math.geometry.Translation2d;
024import edu.wpi.first.math.kinematics.ChassisSpeeds;
025import edu.wpi.first.math.kinematics.SwerveDriveKinematics;
026import edu.wpi.first.units.measure.*;
027
028/**
029 * Container for all the Swerve Requests. Use this to find all applicable swerve
030 * drive requests.
031 * <p>
032 * This is also an interface common to all swerve drive control requests that
033 * allow the request to calculate the state to apply to the modules.
034 */
035public interface SwerveRequest {
036    /**
037     * In field-centric control, the direction of "forward" is sometimes different
038     * depending on perspective. This addresses which forward to use.
039     */
040    public enum ForwardPerspectiveValue {
041        /**
042         * "Forward" (positive X) is determined from the operator's perspective. This
043         * is important for most teleop driven field-centric requests, where positive
044         * X means to drive away from the operator.
045         * <p>
046         * Important: Users must specify the OperatorPerspective in the SwerveDrivetrain object
047         */
048        OperatorPerspective(0),
049        /**
050         * "Forward" (positive X) is always from the perspective of the blue alliance (i.e. towards
051         * the red alliance). This is important in situations such as path following where positive
052         * X is always from the blue alliance perspective, regardless of where the operator is
053         * physically located.
054         */
055        BlueAlliance(1);
056
057        public final int value;
058
059        ForwardPerspectiveValue(int initValue) {
060            this.value = initValue;
061        }
062
063        private static HashMap<Integer, ForwardPerspectiveValue> _map = null;
064        static {
065            _map = new HashMap<Integer, ForwardPerspectiveValue>();
066            for (ForwardPerspectiveValue type : ForwardPerspectiveValue.values()) {
067                _map.put(type.value, type);
068            }
069        }
070
071        /**
072         * Gets ForwardPerspectiveValue from specified value
073         *
074         * @param value Value of ForwardPerspectiveValue
075         * @return ForwardPerspectiveValue of specified value
076         */
077        public static ForwardPerspectiveValue valueOf(int value) {
078            ForwardPerspectiveValue retval = _map.get(value);
079            if (retval != null)
080                return retval;
081            return ForwardPerspectiveValue.values()[0];
082        }
083    }
084
085    /**
086     * Applies this swerve request to the given modules. This is
087     * typically called by the SwerveDrivetrain odometry thread.
088     * <p>
089     * For native swerve requests, this API can be called from a
090     * non-native request's {@code apply} to compose the two together.
091     *
092     * @param parameters Parameters the control request needs to calculate the module state
093     * @param modulesToApply Modules to which the control request is applied
094     * @return Status code of sending the request
095     */
096    public StatusCode apply(SwerveControlParameters parameters, SwerveModule<?, ?, ?>... modulesToApply);
097
098    /** Swerve requests implemented in native code. */
099    public interface NativeSwerveRequest extends SwerveRequest {
100        /**
101         * Applies a native swerve request to the native drivetrain with the provided ID.
102         * <p>
103         * When this is implemented, the regular {@link #apply} function should do nothing
104         * (return OK). Additionally, this cannot be called from another swerve request's
105         * apply method, as this overrides the native swerve request of the drivetrain.
106         * <p>
107         * Unlike {@link #apply}, this function is called every time {@link SwerveDrivetrain#setControl}
108         * is run, not every loop of the odometry thread. Instead, the underlying native
109         * request is run at the full update frequency of the odometry thread.
110         *
111         * @param id ID of the native swerve drivetrain
112         */
113        public void applyNative(int id);
114    }
115
116    
117    /**
118     * Does nothing to the swerve module state. This is the default state of a newly
119     * created swerve drive mechanism.
120     */
121    public static class Idle implements NativeSwerveRequest {
122        
123        
124        
125        public StatusCode apply(SwerveControlParameters parameters, SwerveModule<?, ?, ?>... modulesToApply) {
126            return StatusCode.valueOf(SwerveJNI.JNI_Request_Apply_Idle(parameters.drivetrainId));
127        }
128        
129        public void applyNative(int id) {
130            SwerveJNI.JNI_SetControl_Idle(id);
131        }
132    }
133    
134    /**
135     * Sets the swerve drive module states to point inward on the robot in an "X"
136     * fashion, creating a natural brake which will oppose any motion.
137     */
138    public static class SwerveDriveBrake implements NativeSwerveRequest {
139        /**
140         * The type of control request to use for the drive motor.
141         */
142        public SwerveModule.DriveRequestType DriveRequestType = SwerveModule.DriveRequestType.OpenLoopVoltage;
143        /**
144         * The type of control request to use for the drive motor.
145         */
146        public SwerveModule.SteerRequestType SteerRequestType = SwerveModule.SteerRequestType.Position;
147        
148        /**
149         * Modifies the DriveRequestType parameter and returns itself.
150         * <p>
151         * The type of control request to use for the drive motor.
152         *
153         * @param newDriveRequestType Parameter to modify
154         * @return this object
155         */
156        public SwerveDriveBrake withDriveRequestType(SwerveModule.DriveRequestType newDriveRequestType) {
157            this.DriveRequestType = newDriveRequestType;
158            return this;
159        }
160        
161        /**
162         * Modifies the SteerRequestType parameter and returns itself.
163         * <p>
164         * The type of control request to use for the drive motor.
165         *
166         * @param newSteerRequestType Parameter to modify
167         * @return this object
168         */
169        public SwerveDriveBrake withSteerRequestType(SwerveModule.SteerRequestType newSteerRequestType) {
170            this.SteerRequestType = newSteerRequestType;
171            return this;
172        }
173        
174        public StatusCode apply(SwerveControlParameters parameters, SwerveModule<?, ?, ?>... modulesToApply) {
175            return StatusCode.valueOf(SwerveJNI.JNI_Request_Apply_SwerveDriveBrake(parameters.drivetrainId,
176                DriveRequestType.value,
177                SteerRequestType.value));
178        }
179        
180        public void applyNative(int id) {
181            SwerveJNI.JNI_SetControl_SwerveDriveBrake(id,
182                DriveRequestType.value,
183                SteerRequestType.value);
184        }
185    }
186    
187    /**
188     * Drives the swerve drivetrain in a field-centric manner.
189     * <p>
190     * When users use this request, they specify the direction the robot should
191     * travel oriented against the field, and the rate at which their robot should
192     * rotate about the center of the robot.
193     * <p>
194     * An example scenario is that the robot is oriented to the east, the VelocityX
195     * is +5 m/s, VelocityY is 0 m/s, and RotationRate is 0.5 rad/s. In this
196     * scenario, the robot would drive northward at 5 m/s and turn counterclockwise
197     * at 0.5 rad/s.
198     */
199    public static class FieldCentric implements NativeSwerveRequest {
200        /**
201         * The velocity in the X direction, in m/s. X is defined as forward according to
202         * WPILib convention, so this determines how fast to travel forward.
203         */
204        public double VelocityX = 0;
205        /**
206         * The velocity in the Y direction, in m/s. Y is defined as to the left
207         * according to WPILib convention, so this determines how fast to travel to the
208         * left.
209         */
210        public double VelocityY = 0;
211        /**
212         * The angular rate to rotate at, in radians per second. Angular rate is defined
213         * as counterclockwise positive, so this determines how fast to turn
214         * counterclockwise.
215         */
216        public double RotationalRate = 0;
217        /**
218         * The allowable deadband of the request, in m/s.
219         */
220        public double Deadband = 0;
221        /**
222         * The rotational deadband of the request, in radians per second.
223         */
224        public double RotationalDeadband = 0;
225        /**
226         * The center of rotation the robot should rotate around. This is (0,0) by
227         * default, which will rotate around the center of the robot.
228         */
229        public Translation2d CenterOfRotation = new Translation2d();
230        /**
231         * The type of control request to use for the drive motor.
232         */
233        public SwerveModule.DriveRequestType DriveRequestType = SwerveModule.DriveRequestType.OpenLoopVoltage;
234        /**
235         * The type of control request to use for the drive motor.
236         */
237        public SwerveModule.SteerRequestType SteerRequestType = SwerveModule.SteerRequestType.Position;
238        /**
239         * Whether to desaturate wheel speeds before applying. For more information, see
240         * the documentation of {@link SwerveDriveKinematics#desaturateWheelSpeeds}.
241         */
242        public boolean DesaturateWheelSpeeds = true;
243        /**
244         * The perspective to use when determining which direction is forward.
245         */
246        public ForwardPerspectiveValue ForwardPerspective = ForwardPerspectiveValue.OperatorPerspective;
247        
248        /**
249         * Modifies the VelocityX parameter and returns itself.
250         * <p>
251         * The velocity in the X direction, in m/s. X is defined as forward according to
252         * WPILib convention, so this determines how fast to travel forward.
253         *
254         * @param newVelocityX Parameter to modify
255         * @return this object
256         */
257        public FieldCentric withVelocityX(double newVelocityX) {
258            this.VelocityX = newVelocityX;
259            return this;
260        }
261        
262        /**
263         * Modifies the VelocityX parameter and returns itself.
264         * <p>
265         * The velocity in the X direction, in m/s. X is defined as forward according to
266         * WPILib convention, so this determines how fast to travel forward.
267         *
268         * @param newVelocityX Parameter to modify
269         * @return this object
270         */
271        public FieldCentric withVelocityX(LinearVelocity newVelocityX) {
272            this.VelocityX = newVelocityX.in(MetersPerSecond);
273            return this;
274        }
275        
276        /**
277         * Modifies the VelocityY parameter and returns itself.
278         * <p>
279         * The velocity in the Y direction, in m/s. Y is defined as to the left
280         * according to WPILib convention, so this determines how fast to travel to the
281         * left.
282         *
283         * @param newVelocityY Parameter to modify
284         * @return this object
285         */
286        public FieldCentric withVelocityY(double newVelocityY) {
287            this.VelocityY = newVelocityY;
288            return this;
289        }
290        
291        /**
292         * Modifies the VelocityY parameter and returns itself.
293         * <p>
294         * The velocity in the Y direction, in m/s. Y is defined as to the left
295         * according to WPILib convention, so this determines how fast to travel to the
296         * left.
297         *
298         * @param newVelocityY Parameter to modify
299         * @return this object
300         */
301        public FieldCentric withVelocityY(LinearVelocity newVelocityY) {
302            this.VelocityY = newVelocityY.in(MetersPerSecond);
303            return this;
304        }
305        
306        /**
307         * Modifies the RotationalRate parameter and returns itself.
308         * <p>
309         * The angular rate to rotate at, in radians per second. Angular rate is defined
310         * as counterclockwise positive, so this determines how fast to turn
311         * counterclockwise.
312         *
313         * @param newRotationalRate Parameter to modify
314         * @return this object
315         */
316        public FieldCentric withRotationalRate(double newRotationalRate) {
317            this.RotationalRate = newRotationalRate;
318            return this;
319        }
320        
321        /**
322         * Modifies the RotationalRate parameter and returns itself.
323         * <p>
324         * The angular rate to rotate at, in radians per second. Angular rate is defined
325         * as counterclockwise positive, so this determines how fast to turn
326         * counterclockwise.
327         *
328         * @param newRotationalRate Parameter to modify
329         * @return this object
330         */
331        public FieldCentric withRotationalRate(AngularVelocity newRotationalRate) {
332            this.RotationalRate = newRotationalRate.in(RadiansPerSecond);
333            return this;
334        }
335        
336        /**
337         * Modifies the Deadband parameter and returns itself.
338         * <p>
339         * The allowable deadband of the request, in m/s.
340         *
341         * @param newDeadband Parameter to modify
342         * @return this object
343         */
344        public FieldCentric withDeadband(double newDeadband) {
345            this.Deadband = newDeadband;
346            return this;
347        }
348        
349        /**
350         * Modifies the Deadband parameter and returns itself.
351         * <p>
352         * The allowable deadband of the request, in m/s.
353         *
354         * @param newDeadband Parameter to modify
355         * @return this object
356         */
357        public FieldCentric withDeadband(LinearVelocity newDeadband) {
358            this.Deadband = newDeadband.in(MetersPerSecond);
359            return this;
360        }
361        
362        /**
363         * Modifies the RotationalDeadband parameter and returns itself.
364         * <p>
365         * The rotational deadband of the request, in radians per second.
366         *
367         * @param newRotationalDeadband Parameter to modify
368         * @return this object
369         */
370        public FieldCentric withRotationalDeadband(double newRotationalDeadband) {
371            this.RotationalDeadband = newRotationalDeadband;
372            return this;
373        }
374        
375        /**
376         * Modifies the RotationalDeadband parameter and returns itself.
377         * <p>
378         * The rotational deadband of the request, in radians per second.
379         *
380         * @param newRotationalDeadband Parameter to modify
381         * @return this object
382         */
383        public FieldCentric withRotationalDeadband(AngularVelocity newRotationalDeadband) {
384            this.RotationalDeadband = newRotationalDeadband.in(RadiansPerSecond);
385            return this;
386        }
387        
388        /**
389         * Modifies the CenterOfRotation parameter and returns itself.
390         * <p>
391         * The center of rotation the robot should rotate around. This is (0,0) by
392         * default, which will rotate around the center of the robot.
393         *
394         * @param newCenterOfRotation Parameter to modify
395         * @return this object
396         */
397        public FieldCentric withCenterOfRotation(Translation2d newCenterOfRotation) {
398            this.CenterOfRotation = newCenterOfRotation;
399            return this;
400        }
401        
402        /**
403         * Modifies the DriveRequestType parameter and returns itself.
404         * <p>
405         * The type of control request to use for the drive motor.
406         *
407         * @param newDriveRequestType Parameter to modify
408         * @return this object
409         */
410        public FieldCentric withDriveRequestType(SwerveModule.DriveRequestType newDriveRequestType) {
411            this.DriveRequestType = newDriveRequestType;
412            return this;
413        }
414        
415        /**
416         * Modifies the SteerRequestType parameter and returns itself.
417         * <p>
418         * The type of control request to use for the drive motor.
419         *
420         * @param newSteerRequestType Parameter to modify
421         * @return this object
422         */
423        public FieldCentric withSteerRequestType(SwerveModule.SteerRequestType newSteerRequestType) {
424            this.SteerRequestType = newSteerRequestType;
425            return this;
426        }
427        
428        /**
429         * Modifies the DesaturateWheelSpeeds parameter and returns itself.
430         * <p>
431         * Whether to desaturate wheel speeds before applying. For more information, see
432         * the documentation of {@link SwerveDriveKinematics#desaturateWheelSpeeds}.
433         *
434         * @param newDesaturateWheelSpeeds Parameter to modify
435         * @return this object
436         */
437        public FieldCentric withDesaturateWheelSpeeds(boolean newDesaturateWheelSpeeds) {
438            this.DesaturateWheelSpeeds = newDesaturateWheelSpeeds;
439            return this;
440        }
441        
442        /**
443         * Modifies the ForwardPerspective parameter and returns itself.
444         * <p>
445         * The perspective to use when determining which direction is forward.
446         *
447         * @param newForwardPerspective Parameter to modify
448         * @return this object
449         */
450        public FieldCentric withForwardPerspective(ForwardPerspectiveValue newForwardPerspective) {
451            this.ForwardPerspective = newForwardPerspective;
452            return this;
453        }
454        
455        public StatusCode apply(SwerveControlParameters parameters, SwerveModule<?, ?, ?>... modulesToApply) {
456            return StatusCode.valueOf(SwerveJNI.JNI_Request_Apply_FieldCentric(parameters.drivetrainId,
457                VelocityX,
458                VelocityY,
459                RotationalRate,
460                Deadband,
461                RotationalDeadband,
462                CenterOfRotation.getX(),
463                CenterOfRotation.getY(),
464                DriveRequestType.value,
465                SteerRequestType.value,
466                DesaturateWheelSpeeds,
467                ForwardPerspective.value));
468        }
469        
470        public void applyNative(int id) {
471            SwerveJNI.JNI_SetControl_FieldCentric(id,
472                VelocityX,
473                VelocityY,
474                RotationalRate,
475                Deadband,
476                RotationalDeadband,
477                CenterOfRotation.getX(),
478                CenterOfRotation.getY(),
479                DriveRequestType.value,
480                SteerRequestType.value,
481                DesaturateWheelSpeeds,
482                ForwardPerspective.value);
483        }
484    }
485    
486    /**
487     * Drives the swerve drivetrain in a robot-centric manner.
488     * <p>
489     * When users use this request, they specify the direction the robot should
490     * travel oriented against the robot itself, and the rate at which their robot
491     * should rotate about the center of the robot.
492     * <p>
493     * An example scenario is that the robot is oriented to the east, the VelocityX
494     * is +5 m/s, VelocityY is 0 m/s, and RotationRate is 0.5 rad/s. In this
495     * scenario, the robot would drive eastward at 5 m/s and turn counterclockwise
496     * at 0.5 rad/s.
497     */
498    public static class RobotCentric implements NativeSwerveRequest {
499        /**
500         * The velocity in the X direction, in m/s. X is defined as forward according to
501         * WPILib convention, so this determines how fast to travel forward.
502         */
503        public double VelocityX = 0;
504        /**
505         * The velocity in the Y direction, in m/s. Y is defined as to the left
506         * according to WPILib convention, so this determines how fast to travel to the
507         * left.
508         */
509        public double VelocityY = 0;
510        /**
511         * The angular rate to rotate at, in radians per second. Angular rate is defined
512         * as counterclockwise positive, so this determines how fast to turn
513         * counterclockwise.
514         */
515        public double RotationalRate = 0;
516        /**
517         * The allowable deadband of the request, in m/s.
518         */
519        public double Deadband = 0;
520        /**
521         * The rotational deadband of the request, in radians per second.
522         */
523        public double RotationalDeadband = 0;
524        /**
525         * The center of rotation the robot should rotate around. This is (0,0) by
526         * default, which will rotate around the center of the robot.
527         */
528        public Translation2d CenterOfRotation = new Translation2d();
529        /**
530         * The type of control request to use for the drive motor.
531         */
532        public SwerveModule.DriveRequestType DriveRequestType = SwerveModule.DriveRequestType.OpenLoopVoltage;
533        /**
534         * The type of control request to use for the drive motor.
535         */
536        public SwerveModule.SteerRequestType SteerRequestType = SwerveModule.SteerRequestType.Position;
537        /**
538         * Whether to desaturate wheel speeds before applying. For more information, see
539         * the documentation of {@link SwerveDriveKinematics#desaturateWheelSpeeds}.
540         */
541        public boolean DesaturateWheelSpeeds = true;
542        
543        /**
544         * Modifies the VelocityX parameter and returns itself.
545         * <p>
546         * The velocity in the X direction, in m/s. X is defined as forward according to
547         * WPILib convention, so this determines how fast to travel forward.
548         *
549         * @param newVelocityX Parameter to modify
550         * @return this object
551         */
552        public RobotCentric withVelocityX(double newVelocityX) {
553            this.VelocityX = newVelocityX;
554            return this;
555        }
556        
557        /**
558         * Modifies the VelocityX parameter and returns itself.
559         * <p>
560         * The velocity in the X direction, in m/s. X is defined as forward according to
561         * WPILib convention, so this determines how fast to travel forward.
562         *
563         * @param newVelocityX Parameter to modify
564         * @return this object
565         */
566        public RobotCentric withVelocityX(LinearVelocity newVelocityX) {
567            this.VelocityX = newVelocityX.in(MetersPerSecond);
568            return this;
569        }
570        
571        /**
572         * Modifies the VelocityY parameter and returns itself.
573         * <p>
574         * The velocity in the Y direction, in m/s. Y is defined as to the left
575         * according to WPILib convention, so this determines how fast to travel to the
576         * left.
577         *
578         * @param newVelocityY Parameter to modify
579         * @return this object
580         */
581        public RobotCentric withVelocityY(double newVelocityY) {
582            this.VelocityY = newVelocityY;
583            return this;
584        }
585        
586        /**
587         * Modifies the VelocityY parameter and returns itself.
588         * <p>
589         * The velocity in the Y direction, in m/s. Y is defined as to the left
590         * according to WPILib convention, so this determines how fast to travel to the
591         * left.
592         *
593         * @param newVelocityY Parameter to modify
594         * @return this object
595         */
596        public RobotCentric withVelocityY(LinearVelocity newVelocityY) {
597            this.VelocityY = newVelocityY.in(MetersPerSecond);
598            return this;
599        }
600        
601        /**
602         * Modifies the RotationalRate parameter and returns itself.
603         * <p>
604         * The angular rate to rotate at, in radians per second. Angular rate is defined
605         * as counterclockwise positive, so this determines how fast to turn
606         * counterclockwise.
607         *
608         * @param newRotationalRate Parameter to modify
609         * @return this object
610         */
611        public RobotCentric withRotationalRate(double newRotationalRate) {
612            this.RotationalRate = newRotationalRate;
613            return this;
614        }
615        
616        /**
617         * Modifies the RotationalRate parameter and returns itself.
618         * <p>
619         * The angular rate to rotate at, in radians per second. Angular rate is defined
620         * as counterclockwise positive, so this determines how fast to turn
621         * counterclockwise.
622         *
623         * @param newRotationalRate Parameter to modify
624         * @return this object
625         */
626        public RobotCentric withRotationalRate(AngularVelocity newRotationalRate) {
627            this.RotationalRate = newRotationalRate.in(RadiansPerSecond);
628            return this;
629        }
630        
631        /**
632         * Modifies the Deadband parameter and returns itself.
633         * <p>
634         * The allowable deadband of the request, in m/s.
635         *
636         * @param newDeadband Parameter to modify
637         * @return this object
638         */
639        public RobotCentric withDeadband(double newDeadband) {
640            this.Deadband = newDeadband;
641            return this;
642        }
643        
644        /**
645         * Modifies the Deadband parameter and returns itself.
646         * <p>
647         * The allowable deadband of the request, in m/s.
648         *
649         * @param newDeadband Parameter to modify
650         * @return this object
651         */
652        public RobotCentric withDeadband(LinearVelocity newDeadband) {
653            this.Deadband = newDeadband.in(MetersPerSecond);
654            return this;
655        }
656        
657        /**
658         * Modifies the RotationalDeadband parameter and returns itself.
659         * <p>
660         * The rotational deadband of the request, in radians per second.
661         *
662         * @param newRotationalDeadband Parameter to modify
663         * @return this object
664         */
665        public RobotCentric withRotationalDeadband(double newRotationalDeadband) {
666            this.RotationalDeadband = newRotationalDeadband;
667            return this;
668        }
669        
670        /**
671         * Modifies the RotationalDeadband parameter and returns itself.
672         * <p>
673         * The rotational deadband of the request, in radians per second.
674         *
675         * @param newRotationalDeadband Parameter to modify
676         * @return this object
677         */
678        public RobotCentric withRotationalDeadband(AngularVelocity newRotationalDeadband) {
679            this.RotationalDeadband = newRotationalDeadband.in(RadiansPerSecond);
680            return this;
681        }
682        
683        /**
684         * Modifies the CenterOfRotation parameter and returns itself.
685         * <p>
686         * The center of rotation the robot should rotate around. This is (0,0) by
687         * default, which will rotate around the center of the robot.
688         *
689         * @param newCenterOfRotation Parameter to modify
690         * @return this object
691         */
692        public RobotCentric withCenterOfRotation(Translation2d newCenterOfRotation) {
693            this.CenterOfRotation = newCenterOfRotation;
694            return this;
695        }
696        
697        /**
698         * Modifies the DriveRequestType parameter and returns itself.
699         * <p>
700         * The type of control request to use for the drive motor.
701         *
702         * @param newDriveRequestType Parameter to modify
703         * @return this object
704         */
705        public RobotCentric withDriveRequestType(SwerveModule.DriveRequestType newDriveRequestType) {
706            this.DriveRequestType = newDriveRequestType;
707            return this;
708        }
709        
710        /**
711         * Modifies the SteerRequestType parameter and returns itself.
712         * <p>
713         * The type of control request to use for the drive motor.
714         *
715         * @param newSteerRequestType Parameter to modify
716         * @return this object
717         */
718        public RobotCentric withSteerRequestType(SwerveModule.SteerRequestType newSteerRequestType) {
719            this.SteerRequestType = newSteerRequestType;
720            return this;
721        }
722        
723        /**
724         * Modifies the DesaturateWheelSpeeds parameter and returns itself.
725         * <p>
726         * Whether to desaturate wheel speeds before applying. For more information, see
727         * the documentation of {@link SwerveDriveKinematics#desaturateWheelSpeeds}.
728         *
729         * @param newDesaturateWheelSpeeds Parameter to modify
730         * @return this object
731         */
732        public RobotCentric withDesaturateWheelSpeeds(boolean newDesaturateWheelSpeeds) {
733            this.DesaturateWheelSpeeds = newDesaturateWheelSpeeds;
734            return this;
735        }
736        
737        public StatusCode apply(SwerveControlParameters parameters, SwerveModule<?, ?, ?>... modulesToApply) {
738            return StatusCode.valueOf(SwerveJNI.JNI_Request_Apply_RobotCentric(parameters.drivetrainId,
739                VelocityX,
740                VelocityY,
741                RotationalRate,
742                Deadband,
743                RotationalDeadband,
744                CenterOfRotation.getX(),
745                CenterOfRotation.getY(),
746                DriveRequestType.value,
747                SteerRequestType.value,
748                DesaturateWheelSpeeds));
749        }
750        
751        public void applyNative(int id) {
752            SwerveJNI.JNI_SetControl_RobotCentric(id,
753                VelocityX,
754                VelocityY,
755                RotationalRate,
756                Deadband,
757                RotationalDeadband,
758                CenterOfRotation.getX(),
759                CenterOfRotation.getY(),
760                DriveRequestType.value,
761                SteerRequestType.value,
762                DesaturateWheelSpeeds);
763        }
764    }
765    
766    /**
767     * Sets the swerve drive modules to point to a specified direction.
768     */
769    public static class PointWheelsAt implements NativeSwerveRequest {
770        /**
771         * The direction to point the modules toward. This direction is still optimized
772         * to what the module was previously at.
773         */
774        public Rotation2d ModuleDirection = new Rotation2d();
775        /**
776         * The type of control request to use for the drive motor.
777         */
778        public SwerveModule.DriveRequestType DriveRequestType = SwerveModule.DriveRequestType.OpenLoopVoltage;
779        /**
780         * The type of control request to use for the drive motor.
781         */
782        public SwerveModule.SteerRequestType SteerRequestType = SwerveModule.SteerRequestType.Position;
783        
784        /**
785         * Modifies the ModuleDirection parameter and returns itself.
786         * <p>
787         * The direction to point the modules toward. This direction is still optimized
788         * to what the module was previously at.
789         *
790         * @param newModuleDirection Parameter to modify
791         * @return this object
792         */
793        public PointWheelsAt withModuleDirection(Rotation2d newModuleDirection) {
794            this.ModuleDirection = newModuleDirection;
795            return this;
796        }
797        
798        /**
799         * Modifies the DriveRequestType parameter and returns itself.
800         * <p>
801         * The type of control request to use for the drive motor.
802         *
803         * @param newDriveRequestType Parameter to modify
804         * @return this object
805         */
806        public PointWheelsAt withDriveRequestType(SwerveModule.DriveRequestType newDriveRequestType) {
807            this.DriveRequestType = newDriveRequestType;
808            return this;
809        }
810        
811        /**
812         * Modifies the SteerRequestType parameter and returns itself.
813         * <p>
814         * The type of control request to use for the drive motor.
815         *
816         * @param newSteerRequestType Parameter to modify
817         * @return this object
818         */
819        public PointWheelsAt withSteerRequestType(SwerveModule.SteerRequestType newSteerRequestType) {
820            this.SteerRequestType = newSteerRequestType;
821            return this;
822        }
823        
824        public StatusCode apply(SwerveControlParameters parameters, SwerveModule<?, ?, ?>... modulesToApply) {
825            return StatusCode.valueOf(SwerveJNI.JNI_Request_Apply_PointWheelsAt(parameters.drivetrainId,
826                ModuleDirection.getRadians(),
827                DriveRequestType.value,
828                SteerRequestType.value));
829        }
830        
831        public void applyNative(int id) {
832            SwerveJNI.JNI_SetControl_PointWheelsAt(id,
833                ModuleDirection.getRadians(),
834                DriveRequestType.value,
835                SteerRequestType.value);
836        }
837    }
838
839    /**
840     * Accepts a generic robot-centric ChassisSpeeds to apply to the drivetrain.
841     */
842    public static class ApplyRobotSpeeds implements NativeSwerveRequest {
843        /**
844         * The robot-centric chassis speeds to apply to the drivetrain.
845         */
846        public ChassisSpeeds Speeds = new ChassisSpeeds();
847        /**
848         * Robot-centric wheel force feedforwards to apply in the X direction, in
849         * newtons. X is defined as forward according to WPILib convention, so this
850         * determines the forward forces to apply.
851         * <p>
852         * These forces should include friction applied to the ground.
853         * <p>
854         * The order of the forces should match the order of the modules returned from
855         * SwerveDrivetrain.
856         */
857        public double[] WheelForceFeedforwardsX = {};
858        /**
859         * Robot-centric wheel force feedforwards to apply in the Y direction, in
860         * newtons. Y is defined as to the left according to WPILib convention, so this
861         * determines the forces to apply to the left.
862         * <p>
863         * These forces should include friction applied to the ground.
864         * <p>
865         * The order of the forces should match the order of the modules returned from
866         * SwerveDrivetrain.
867         */
868        public double[] WheelForceFeedforwardsY = {};
869        /**
870         * The center of rotation the robot should rotate around. This is (0,0) by
871         * default, which will rotate around the center of the robot.
872         */
873        public Translation2d CenterOfRotation = new Translation2d();
874        /**
875         * The type of control request to use for the drive motor.
876         */
877        public SwerveModule.DriveRequestType DriveRequestType = SwerveModule.DriveRequestType.OpenLoopVoltage;
878        /**
879         * The type of control request to use for the drive motor.
880         */
881        public SwerveModule.SteerRequestType SteerRequestType = SwerveModule.SteerRequestType.Position;
882        /**
883         * Whether to desaturate wheel speeds before applying. For more information, see
884         * the documentation of {@link SwerveDriveKinematics#desaturateWheelSpeeds}.
885         */
886        public boolean DesaturateWheelSpeeds = true;
887    
888        /**
889         * Modifies the Speeds parameter and returns itself.
890         * <p>
891         * The robot-centric chassis speeds to apply to the drivetrain.
892         *
893         * @param newSpeeds Parameter to modify
894         * @return this object
895         */
896        public ApplyRobotSpeeds withSpeeds(ChassisSpeeds newSpeeds) {
897            this.Speeds = newSpeeds;
898            return this;
899        }
900        
901        /**
902         * Modifies the WheelForceFeedforwardsX parameter and returns itself.
903         * <p>
904         * Robot-centric wheel force feedforwards to apply in the X direction, in
905         * newtons. X is defined as forward according to WPILib convention, so this
906         * determines the forward forces to apply.
907         * <p>
908         * These forces should include friction applied to the ground.
909         * <p>
910         * The order of the forces should match the order of the modules returned from
911         * SwerveDrivetrain.
912         *
913         * @param newWheelForceFeedforwardsX Parameter to modify
914         * @return this object
915         */
916        public ApplyRobotSpeeds withWheelForceFeedforwardsX(double[] newWheelForceFeedforwardsX) {
917            this.WheelForceFeedforwardsX = newWheelForceFeedforwardsX;
918            return this;
919        }
920        
921        /**
922         * Modifies the WheelForceFeedforwardsX parameter and returns itself.
923         * <p>
924         * Robot-centric wheel force feedforwards to apply in the X direction, in
925         * newtons. X is defined as forward according to WPILib convention, so this
926         * determines the forward forces to apply.
927         * <p>
928         * These forces should include friction applied to the ground.
929         * <p>
930         * The order of the forces should match the order of the modules returned from
931         * SwerveDrivetrain.
932         *
933         * @param newWheelForceFeedforwardsX Parameter to modify
934         * @return this object
935         */
936        public ApplyRobotSpeeds withWheelForceFeedforwardsX(Force[] newWheelForceFeedforwardsX) {
937            if (this.WheelForceFeedforwardsX.length != newWheelForceFeedforwardsX.length) {
938                this.WheelForceFeedforwardsX = new double[newWheelForceFeedforwardsX.length];
939            }
940            for (int i = 0; i < this.WheelForceFeedforwardsX.length; ++i) {
941                this.WheelForceFeedforwardsX[i] = newWheelForceFeedforwardsX[i].in(Newtons);
942            }
943
944            return this;
945        }
946        
947        /**
948         * Modifies the WheelForceFeedforwardsY parameter and returns itself.
949         * <p>
950         * Robot-centric wheel force feedforwards to apply in the Y direction, in
951         * newtons. Y is defined as to the left according to WPILib convention, so this
952         * determines the forces to apply to the left.
953         * <p>
954         * These forces should include friction applied to the ground.
955         * <p>
956         * The order of the forces should match the order of the modules returned from
957         * SwerveDrivetrain.
958         *
959         * @param newWheelForceFeedforwardsY Parameter to modify
960         * @return this object
961         */
962        public ApplyRobotSpeeds withWheelForceFeedforwardsY(double[] newWheelForceFeedforwardsY) {
963            this.WheelForceFeedforwardsY = newWheelForceFeedforwardsY;
964            return this;
965        }
966        
967        /**
968         * Modifies the WheelForceFeedforwardsY parameter and returns itself.
969         * <p>
970         * Robot-centric wheel force feedforwards to apply in the Y direction, in
971         * newtons. Y is defined as to the left according to WPILib convention, so this
972         * determines the forces to apply to the left.
973         * <p>
974         * These forces should include friction applied to the ground.
975         * <p>
976         * The order of the forces should match the order of the modules returned from
977         * SwerveDrivetrain.
978         *
979         * @param newWheelForceFeedforwardsY Parameter to modify
980         * @return this object
981         */
982        public ApplyRobotSpeeds withWheelForceFeedforwardsY(Force[] newWheelForceFeedforwardsY) {
983            if (this.WheelForceFeedforwardsY.length != newWheelForceFeedforwardsY.length) {
984                this.WheelForceFeedforwardsY = new double[newWheelForceFeedforwardsY.length];
985            }
986            for (int i = 0; i < this.WheelForceFeedforwardsY.length; ++i) {
987                this.WheelForceFeedforwardsY[i] = newWheelForceFeedforwardsY[i].in(Newtons);
988            }
989
990            return this;
991        }
992        
993        /**
994         * Modifies the CenterOfRotation parameter and returns itself.
995         * <p>
996         * The center of rotation the robot should rotate around. This is (0,0) by
997         * default, which will rotate around the center of the robot.
998         *
999         * @param newCenterOfRotation Parameter to modify
1000         * @return this object
1001         */
1002        public ApplyRobotSpeeds withCenterOfRotation(Translation2d newCenterOfRotation) {
1003            this.CenterOfRotation = newCenterOfRotation;
1004            return this;
1005        }
1006        
1007        /**
1008         * Modifies the DriveRequestType parameter and returns itself.
1009         * <p>
1010         * The type of control request to use for the drive motor.
1011         *
1012         * @param newDriveRequestType Parameter to modify
1013         * @return this object
1014         */
1015        public ApplyRobotSpeeds withDriveRequestType(SwerveModule.DriveRequestType newDriveRequestType) {
1016            this.DriveRequestType = newDriveRequestType;
1017            return this;
1018        }
1019        
1020        /**
1021         * Modifies the SteerRequestType parameter and returns itself.
1022         * <p>
1023         * The type of control request to use for the drive motor.
1024         *
1025         * @param newSteerRequestType Parameter to modify
1026         * @return this object
1027         */
1028        public ApplyRobotSpeeds withSteerRequestType(SwerveModule.SteerRequestType newSteerRequestType) {
1029            this.SteerRequestType = newSteerRequestType;
1030            return this;
1031        }
1032        
1033        /**
1034         * Modifies the DesaturateWheelSpeeds parameter and returns itself.
1035         * <p>
1036         * Whether to desaturate wheel speeds before applying. For more information, see
1037         * the documentation of {@link SwerveDriveKinematics#desaturateWheelSpeeds}.
1038         *
1039         * @param newDesaturateWheelSpeeds Parameter to modify
1040         * @return this object
1041         */
1042        public ApplyRobotSpeeds withDesaturateWheelSpeeds(boolean newDesaturateWheelSpeeds) {
1043            this.DesaturateWheelSpeeds = newDesaturateWheelSpeeds;
1044            return this;
1045        }
1046        
1047        public StatusCode apply(SwerveControlParameters parameters, SwerveModule<?, ?, ?>... modulesToApply) {
1048            return StatusCode.valueOf(SwerveJNI.JNI_Request_Apply_ApplyRobotSpeeds(parameters.drivetrainId,
1049                Speeds.vxMetersPerSecond,
1050                Speeds.vyMetersPerSecond,
1051                Speeds.omegaRadiansPerSecond,
1052                WheelForceFeedforwardsX,
1053                WheelForceFeedforwardsY,
1054                CenterOfRotation.getX(),
1055                CenterOfRotation.getY(),
1056                DriveRequestType.value,
1057                SteerRequestType.value,
1058                DesaturateWheelSpeeds));
1059        }
1060        
1061        public void applyNative(int id) {
1062            SwerveJNI.JNI_SetControl_ApplyRobotSpeeds(id,
1063                Speeds.vxMetersPerSecond,
1064                Speeds.vyMetersPerSecond,
1065                Speeds.omegaRadiansPerSecond,
1066                WheelForceFeedforwardsX,
1067                WheelForceFeedforwardsY,
1068                CenterOfRotation.getX(),
1069                CenterOfRotation.getY(),
1070                DriveRequestType.value,
1071                SteerRequestType.value,
1072                DesaturateWheelSpeeds);
1073        }
1074    }
1075
1076    /**
1077     * Accepts a generic robot-centric ChassisSpeeds to apply to the drivetrain.
1078     *
1079     * @deprecated Use {@link ApplyRobotSpeeds} instead
1080     */
1081    @Deprecated(forRemoval = true, since = "2025")
1082    public static class ApplyChassisSpeeds extends ApplyRobotSpeeds {}
1083
1084    /**
1085     * Accepts a generic field-centric ChassisSpeeds to apply to the drivetrain.
1086     */
1087    public static class ApplyFieldSpeeds implements NativeSwerveRequest {
1088        /**
1089         * The field-centric chassis speeds to apply to the drivetrain.
1090         */
1091        public ChassisSpeeds Speeds = new ChassisSpeeds();
1092        /**
1093         * Field-centric wheel force feedforwards to apply in the X direction, in
1094         * newtons. X is defined as forward according to WPILib convention, so this
1095         * determines the forward forces to apply.
1096         * <p>
1097         * These forces should include friction applied to the ground.
1098         * <p>
1099         * The order of the forces should match the order of the modules returned from
1100         * SwerveDrivetrain.
1101         */
1102        public double[] WheelForceFeedforwardsX = {};
1103        /**
1104         * Field-centric wheel force feedforwards to apply in the Y direction, in
1105         * newtons. Y is defined as to the left according to WPILib convention, so this
1106         * determines the forces to apply to the left.
1107         * <p>
1108         * These forces should include friction applied to the ground.
1109         * <p>
1110         * The order of the forces should match the order of the modules returned from
1111         * SwerveDrivetrain.
1112         */
1113        public double[] WheelForceFeedforwardsY = {};
1114        /**
1115         * The center of rotation the robot should rotate around. This is (0,0) by
1116         * default, which will rotate around the center of the robot.
1117         */
1118        public Translation2d CenterOfRotation = new Translation2d();
1119        /**
1120         * The type of control request to use for the drive motor.
1121         */
1122        public SwerveModule.DriveRequestType DriveRequestType = SwerveModule.DriveRequestType.OpenLoopVoltage;
1123        /**
1124         * The type of control request to use for the drive motor.
1125         */
1126        public SwerveModule.SteerRequestType SteerRequestType = SwerveModule.SteerRequestType.Position;
1127        /**
1128         * Whether to desaturate wheel speeds before applying. For more information, see
1129         * the documentation of {@link SwerveDriveKinematics#desaturateWheelSpeeds}.
1130         */
1131        public boolean DesaturateWheelSpeeds = true;
1132        /**
1133         * The perspective to use when determining which direction is forward.
1134         */
1135        public ForwardPerspectiveValue ForwardPerspective = ForwardPerspectiveValue.BlueAlliance;
1136    
1137        /**
1138         * Modifies the Speeds parameter and returns itself.
1139         * <p>
1140         * The field-centric chassis speeds to apply to the drivetrain.
1141         *
1142         * @param newSpeeds Parameter to modify
1143         * @return this object
1144         */
1145        public ApplyFieldSpeeds withSpeeds(ChassisSpeeds newSpeeds) {
1146            this.Speeds = newSpeeds;
1147            return this;
1148        }
1149        
1150        /**
1151         * Modifies the WheelForceFeedforwardsX parameter and returns itself.
1152         * <p>
1153         * Field-centric wheel force feedforwards to apply in the X direction, in
1154         * newtons. X is defined as forward according to WPILib convention, so this
1155         * determines the forward forces to apply.
1156         * <p>
1157         * These forces should include friction applied to the ground.
1158         * <p>
1159         * The order of the forces should match the order of the modules returned from
1160         * SwerveDrivetrain.
1161         *
1162         * @param newWheelForceFeedforwardsX Parameter to modify
1163         * @return this object
1164         */
1165        public ApplyFieldSpeeds withWheelForceFeedforwardsX(double[] newWheelForceFeedforwardsX) {
1166            this.WheelForceFeedforwardsX = newWheelForceFeedforwardsX;
1167            return this;
1168        }
1169        
1170        /**
1171         * Modifies the WheelForceFeedforwardsX parameter and returns itself.
1172         * <p>
1173         * Field-centric wheel force feedforwards to apply in the X direction, in
1174         * newtons. X is defined as forward according to WPILib convention, so this
1175         * determines the forward forces to apply.
1176         * <p>
1177         * These forces should include friction applied to the ground.
1178         * <p>
1179         * The order of the forces should match the order of the modules returned from
1180         * SwerveDrivetrain.
1181         *
1182         * @param newWheelForceFeedforwardsX Parameter to modify
1183         * @return this object
1184         */
1185        public ApplyFieldSpeeds withWheelForceFeedforwardsX(Force[] newWheelForceFeedforwardsX) {
1186            if (this.WheelForceFeedforwardsX.length != newWheelForceFeedforwardsX.length) {
1187                this.WheelForceFeedforwardsX = new double[newWheelForceFeedforwardsX.length];
1188            }
1189            for (int i = 0; i < this.WheelForceFeedforwardsX.length; ++i) {
1190                this.WheelForceFeedforwardsX[i] = newWheelForceFeedforwardsX[i].in(Newtons);
1191            }
1192
1193            return this;
1194        }
1195        
1196        /**
1197         * Modifies the WheelForceFeedforwardsY parameter and returns itself.
1198         * <p>
1199         * Field-centric wheel force feedforwards to apply in the Y direction, in
1200         * newtons. Y is defined as to the left according to WPILib convention, so this
1201         * determines the forces to apply to the left.
1202         * <p>
1203         * These forces should include friction applied to the ground.
1204         * <p>
1205         * The order of the forces should match the order of the modules returned from
1206         * SwerveDrivetrain.
1207         *
1208         * @param newWheelForceFeedforwardsY Parameter to modify
1209         * @return this object
1210         */
1211        public ApplyFieldSpeeds withWheelForceFeedforwardsY(double[] newWheelForceFeedforwardsY) {
1212            this.WheelForceFeedforwardsY = newWheelForceFeedforwardsY;
1213            return this;
1214        }
1215        
1216        /**
1217         * Modifies the WheelForceFeedforwardsY parameter and returns itself.
1218         * <p>
1219         * Field-centric wheel force feedforwards to apply in the Y direction, in
1220         * newtons. Y is defined as to the left according to WPILib convention, so this
1221         * determines the forces to apply to the left.
1222         * <p>
1223         * These forces should include friction applied to the ground.
1224         * <p>
1225         * The order of the forces should match the order of the modules returned from
1226         * SwerveDrivetrain.
1227         *
1228         * @param newWheelForceFeedforwardsY Parameter to modify
1229         * @return this object
1230         */
1231        public ApplyFieldSpeeds withWheelForceFeedforwardsY(Force[] newWheelForceFeedforwardsY) {
1232            if (this.WheelForceFeedforwardsY.length != newWheelForceFeedforwardsY.length) {
1233                this.WheelForceFeedforwardsY = new double[newWheelForceFeedforwardsY.length];
1234            }
1235            for (int i = 0; i < this.WheelForceFeedforwardsY.length; ++i) {
1236                this.WheelForceFeedforwardsY[i] = newWheelForceFeedforwardsY[i].in(Newtons);
1237            }
1238
1239            return this;
1240        }
1241        
1242        /**
1243         * Modifies the CenterOfRotation parameter and returns itself.
1244         * <p>
1245         * The center of rotation the robot should rotate around. This is (0,0) by
1246         * default, which will rotate around the center of the robot.
1247         *
1248         * @param newCenterOfRotation Parameter to modify
1249         * @return this object
1250         */
1251        public ApplyFieldSpeeds withCenterOfRotation(Translation2d newCenterOfRotation) {
1252            this.CenterOfRotation = newCenterOfRotation;
1253            return this;
1254        }
1255        
1256        /**
1257         * Modifies the DriveRequestType parameter and returns itself.
1258         * <p>
1259         * The type of control request to use for the drive motor.
1260         *
1261         * @param newDriveRequestType Parameter to modify
1262         * @return this object
1263         */
1264        public ApplyFieldSpeeds withDriveRequestType(SwerveModule.DriveRequestType newDriveRequestType) {
1265            this.DriveRequestType = newDriveRequestType;
1266            return this;
1267        }
1268        
1269        /**
1270         * Modifies the SteerRequestType parameter and returns itself.
1271         * <p>
1272         * The type of control request to use for the drive motor.
1273         *
1274         * @param newSteerRequestType Parameter to modify
1275         * @return this object
1276         */
1277        public ApplyFieldSpeeds withSteerRequestType(SwerveModule.SteerRequestType newSteerRequestType) {
1278            this.SteerRequestType = newSteerRequestType;
1279            return this;
1280        }
1281        
1282        /**
1283         * Modifies the DesaturateWheelSpeeds parameter and returns itself.
1284         * <p>
1285         * Whether to desaturate wheel speeds before applying. For more information, see
1286         * the documentation of {@link SwerveDriveKinematics#desaturateWheelSpeeds}.
1287         *
1288         * @param newDesaturateWheelSpeeds Parameter to modify
1289         * @return this object
1290         */
1291        public ApplyFieldSpeeds withDesaturateWheelSpeeds(boolean newDesaturateWheelSpeeds) {
1292            this.DesaturateWheelSpeeds = newDesaturateWheelSpeeds;
1293            return this;
1294        }
1295        
1296        /**
1297         * Modifies the ForwardPerspective parameter and returns itself.
1298         * <p>
1299         * The perspective to use when determining which direction is forward.
1300         *
1301         * @param newForwardPerspective Parameter to modify
1302         * @return this object
1303         */
1304        public ApplyFieldSpeeds withForwardPerspective(ForwardPerspectiveValue newForwardPerspective) {
1305            this.ForwardPerspective = newForwardPerspective;
1306            return this;
1307        }
1308        
1309        public StatusCode apply(SwerveControlParameters parameters, SwerveModule<?, ?, ?>... modulesToApply) {
1310            return StatusCode.valueOf(SwerveJNI.JNI_Request_Apply_ApplyFieldSpeeds(parameters.drivetrainId,
1311                Speeds.vxMetersPerSecond,
1312                Speeds.vyMetersPerSecond,
1313                Speeds.omegaRadiansPerSecond,
1314                WheelForceFeedforwardsX,
1315                WheelForceFeedforwardsY,
1316                CenterOfRotation.getX(),
1317                CenterOfRotation.getY(),
1318                DriveRequestType.value,
1319                SteerRequestType.value,
1320                DesaturateWheelSpeeds,
1321                ForwardPerspective.value));
1322        }
1323        
1324        public void applyNative(int id) {
1325            SwerveJNI.JNI_SetControl_ApplyFieldSpeeds(id,
1326                Speeds.vxMetersPerSecond,
1327                Speeds.vyMetersPerSecond,
1328                Speeds.omegaRadiansPerSecond,
1329                WheelForceFeedforwardsX,
1330                WheelForceFeedforwardsY,
1331                CenterOfRotation.getX(),
1332                CenterOfRotation.getY(),
1333                DriveRequestType.value,
1334                SteerRequestType.value,
1335                DesaturateWheelSpeeds,
1336                ForwardPerspective.value);
1337        }
1338    }
1339
1340    /**
1341     * Drives the swerve drivetrain in a field-centric manner, maintaining a
1342     * specified heading angle to ensure the robot is facing the desired direction
1343     * <p>
1344     * When users use this request, they specify the direction the robot should
1345     * travel oriented against the field, and the direction the robot should be facing.
1346     * <p>
1347     * An example scenario is that the robot is oriented to the east, the VelocityX
1348     * is +5 m/s, VelocityY is 0 m/s, and TargetDirection is 180 degrees.
1349     * In this scenario, the robot would drive northward at 5 m/s and turn clockwise
1350     * to a target of 180 degrees.
1351     * <p>
1352     * This control request is especially useful for autonomous control, where the
1353     * robot should be facing a changing direction throughout the motion.
1354     */
1355    public static class FieldCentricFacingAngle implements SwerveRequest {
1356        /**
1357         * The velocity in the X direction, in m/s.
1358         * X is defined as forward according to WPILib convention,
1359         * so this determines how fast to travel forward.
1360         */
1361        public double VelocityX = 0;
1362        /**
1363         * The velocity in the Y direction, in m/s.
1364         * Y is defined as to the left according to WPILib convention,
1365         * so this determines how fast to travel to the left.
1366         */
1367        public double VelocityY = 0;
1368        /**
1369         * The desired direction to face.
1370         * 0 Degrees is defined as in the direction of the X axis.
1371         * As a result, a TargetDirection of 90 degrees will point along
1372         * the Y axis, or to the left.
1373         */
1374        public Rotation2d TargetDirection = new Rotation2d();
1375        /**
1376         * The rotational rate feedforward to add to the output of the heading
1377         * controller, in radians per second. When using a motion profile for the
1378         * target direction, this can be set to the current velocity reference of
1379         * the profile.
1380         */
1381        public double TargetRateFeedforward = 0;
1382
1383        /**
1384         * The allowable deadband of the request, in m/s.
1385         */
1386        public double Deadband = 0;
1387        /**
1388         * The rotational deadband of the request, in radians per second.
1389         */
1390        public double RotationalDeadband = 0;
1391        /**
1392         * The center of rotation the robot should rotate around.
1393         * This is (0,0) by default, which will rotate around the center of the robot.
1394         */
1395        public Translation2d CenterOfRotation = new Translation2d();
1396
1397        /**
1398         * The type of control request to use for the drive motor.
1399         */
1400        public SwerveModule.DriveRequestType DriveRequestType = SwerveModule.DriveRequestType.OpenLoopVoltage;
1401        /**
1402         * The type of control request to use for the steer motor.
1403         */
1404        public SwerveModule.SteerRequestType SteerRequestType = SwerveModule.SteerRequestType.Position;
1405        /**
1406         * Whether to desaturate wheel speeds before applying.
1407         * For more information, see the documentation of {@link SwerveDriveKinematics#desaturateWheelSpeeds}.
1408         */
1409        public boolean DesaturateWheelSpeeds = true;
1410
1411        /**
1412         * The perspective to use when determining which direction is forward.
1413         */
1414        public ForwardPerspectiveValue ForwardPerspective = ForwardPerspectiveValue.OperatorPerspective;
1415
1416        /**
1417         * The PID controller used to maintain the desired heading.
1418         * Users can specify the PID gains to change how aggressively to maintain
1419         * heading.
1420         * <p>
1421         * This PID controller operates on heading radians and outputs a target
1422         * rotational rate in radians per second. Note that continuous input should
1423         * be enabled on the range [-pi, pi].
1424         */
1425        public PhoenixPIDController HeadingController = new PhoenixPIDController(0, 0, 0);
1426
1427        private final FieldCentric m_fieldCentric = new FieldCentric();
1428
1429        public FieldCentricFacingAngle() {
1430            HeadingController.enableContinuousInput(-Math.PI, Math.PI);
1431        }
1432
1433        public StatusCode apply(SwerveControlParameters parameters, SwerveModule<?, ?, ?>... modulesToApply) {
1434            Rotation2d angleToFace = TargetDirection;
1435            if (ForwardPerspective == ForwardPerspectiveValue.OperatorPerspective) {
1436                /* If we're operator perspective, rotate the direction we want to face by the angle */
1437                angleToFace = angleToFace.rotateBy(parameters.operatorForwardDirection);
1438            }
1439
1440            double toApplyOmega = TargetRateFeedforward +
1441                HeadingController.calculate(
1442                    parameters.currentPose.getRotation().getRadians(),
1443                    angleToFace.getRadians(),
1444                    parameters.timestamp
1445                );
1446
1447            return m_fieldCentric
1448                .withVelocityX(VelocityX)
1449                .withVelocityY(VelocityY)
1450                .withRotationalRate(toApplyOmega)
1451                .withDeadband(Deadband)
1452                .withRotationalDeadband(RotationalDeadband)
1453                .withCenterOfRotation(CenterOfRotation)
1454                .withDriveRequestType(DriveRequestType)
1455                .withSteerRequestType(SteerRequestType)
1456                .withDesaturateWheelSpeeds(DesaturateWheelSpeeds)
1457                .withForwardPerspective(ForwardPerspective)
1458                .apply(parameters, modulesToApply);
1459        }
1460
1461        /**
1462         * Modifies the VelocityX parameter and returns itself.
1463         * <p>
1464         * The velocity in the X direction, in m/s. X is defined as forward according to
1465         * WPILib convention, so this determines how fast to travel forward.
1466         *
1467         * @param newVelocityX Parameter to modify
1468         * @return this object
1469         */
1470        public FieldCentricFacingAngle withVelocityX(double newVelocityX) {
1471            this.VelocityX = newVelocityX;
1472            return this;
1473        }
1474
1475        /**
1476         * Modifies the VelocityX parameter and returns itself.
1477         * <p>
1478         * The velocity in the X direction, in m/s. X is defined as forward according to
1479         * WPILib convention, so this determines how fast to travel forward.
1480         *
1481         * @param newVelocityX Parameter to modify
1482         * @return this object
1483         */
1484        public FieldCentricFacingAngle withVelocityX(LinearVelocity newVelocityX) {
1485            this.VelocityX = newVelocityX.in(MetersPerSecond);
1486            return this;
1487        }
1488
1489        /**
1490         * Modifies the VelocityY parameter and returns itself.
1491         * <p>
1492         * The velocity in the Y direction, in m/s. Y is defined as to the left
1493         * according to WPILib convention, so this determines how fast to travel to the
1494         * left.
1495         *
1496         * @param newVelocityY Parameter to modify
1497         * @return this object
1498         */
1499        public FieldCentricFacingAngle withVelocityY(double newVelocityY) {
1500            this.VelocityY = newVelocityY;
1501            return this;
1502        }
1503
1504        /**
1505         * Modifies the VelocityY parameter and returns itself.
1506         * <p>
1507         * The velocity in the Y direction, in m/s. Y is defined as to the left
1508         * according to WPILib convention, so this determines how fast to travel to the
1509         * left.
1510         *
1511         * @param newVelocityY Parameter to modify
1512         * @return this object
1513         */
1514        public FieldCentricFacingAngle withVelocityY(LinearVelocity newVelocityY) {
1515            this.VelocityY = newVelocityY.in(MetersPerSecond);
1516            return this;
1517        }
1518
1519        /**
1520         * Modifies the TargetDirection parameter and returns itself.
1521         * <p>
1522         * The desired direction to face. 0 Degrees is defined as in the direction of
1523         * the X axis. As a result, a TargetDirection of 90 degrees will point along
1524         * the Y axis, or to the left.
1525         *
1526         * @param newTargetDirection Parameter to modify
1527         * @return this object
1528         */
1529        public FieldCentricFacingAngle withTargetDirection(Rotation2d newTargetDirection) {
1530            this.TargetDirection = newTargetDirection;
1531            return this;
1532        }
1533
1534        /**
1535         * Modifies the TargetRateFeedforward parameter and returns itself.
1536         * <p>
1537         * The rotational rate feedforward to add to the output of the heading
1538         * controller, in radians per second. When using a motion profile for the
1539         * target direction, this can be set to the current velocity reference of
1540         * the profile.
1541         *
1542         * @param newTargetRateFeedforward Parameter to modify
1543         * @return this object
1544         */
1545        public FieldCentricFacingAngle withTargetRateFeedforward(double newTargetRateFeedforward) {
1546            this.TargetRateFeedforward = newTargetRateFeedforward;
1547            return this;
1548        }
1549        /**
1550         * Modifies the TargetRateFeedforward parameter and returns itself.
1551         * <p>
1552         * The rotational rate feedforward to add to the output of the heading
1553         * controller, in radians per second. When using a motion profile for the
1554         * target direction, this can be set to the current velocity reference of
1555         * the profile.
1556         *
1557         * @param newTargetRateFeedforward Parameter to modify
1558         * @return this object
1559         */
1560        public FieldCentricFacingAngle withTargetRateFeedforward(AngularVelocity newTargetRateFeedforward) {
1561            this.TargetRateFeedforward = newTargetRateFeedforward.in(RadiansPerSecond);
1562            return this;
1563        }
1564
1565        /**
1566         * Modifies the Deadband parameter and returns itself.
1567         * <p>
1568         * The allowable deadband of the request, in m/s.
1569         *
1570         * @param newDeadband Parameter to modify
1571         * @return this object
1572         */
1573        public FieldCentricFacingAngle withDeadband(double newDeadband) {
1574            this.Deadband = newDeadband;
1575            return this;
1576        }
1577
1578        /**
1579         * Modifies the Deadband parameter and returns itself.
1580         * <p>
1581         * The allowable deadband of the request, in m/s.
1582         *
1583         * @param newDeadband Parameter to modify
1584         * @return this object
1585         */
1586        public FieldCentricFacingAngle withDeadband(LinearVelocity newDeadband) {
1587            this.Deadband = newDeadband.in(MetersPerSecond);
1588            return this;
1589        }
1590
1591        /**
1592         * Modifies the RotationalDeadband parameter and returns itself.
1593         * <p>
1594         * The rotational deadband of the request, in radians per second.
1595         *
1596         * @param newRotationalDeadband Parameter to modify
1597         * @return this object
1598         */
1599        public FieldCentricFacingAngle withRotationalDeadband(double newRotationalDeadband) {
1600            this.RotationalDeadband = newRotationalDeadband;
1601            return this;
1602        }
1603
1604        /**
1605         * Modifies the RotationalDeadband parameter and returns itself.
1606         * <p>
1607         * The rotational deadband of the request, in radians per second.
1608         *
1609         * @param newRotationalDeadband Parameter to modify
1610         * @return this object
1611         */
1612        public FieldCentricFacingAngle withRotationalDeadband(AngularVelocity newRotationalDeadband) {
1613            this.RotationalDeadband = newRotationalDeadband.in(RadiansPerSecond);
1614            return this;
1615        }
1616
1617        /**
1618         * Modifies the CenterOfRotation parameter and returns itself.
1619         * <p>
1620         * The center of rotation the robot should rotate around. This is (0,0) by
1621         * default, which will rotate around the center of the robot.
1622         *
1623         * @param newCenterOfRotation Parameter to modify
1624         * @return this object
1625         */
1626        public FieldCentricFacingAngle withCenterOfRotation(Translation2d newCenterOfRotation) {
1627            this.CenterOfRotation = newCenterOfRotation;
1628            return this;
1629        }
1630
1631        /**
1632         * Modifies the DriveRequestType parameter and returns itself.
1633         * <p>
1634         * The type of control request to use for the drive motor.
1635         *
1636         * @param newDriveRequestType Parameter to modify
1637         * @return this object
1638         */
1639        public FieldCentricFacingAngle withDriveRequestType(SwerveModule.DriveRequestType newDriveRequestType) {
1640            this.DriveRequestType = newDriveRequestType;
1641            return this;
1642        }
1643
1644        /**
1645         * Modifies the SteerRequestType parameter and returns itself.
1646         * <p>
1647         * The type of control request to use for the drive motor.
1648         *
1649         * @param newSteerRequestType Parameter to modify
1650         * @return this object
1651         */
1652        public FieldCentricFacingAngle withSteerRequestType(SwerveModule.SteerRequestType newSteerRequestType) {
1653            this.SteerRequestType = newSteerRequestType;
1654            return this;
1655        }
1656
1657        /**
1658         * Modifies the DesaturateWheelSpeeds parameter and returns itself.
1659         * <p>
1660         * Whether to desaturate wheel speeds before applying. For more information, see
1661         * the documentation of {@link SwerveDriveKinematics#desaturateWheelSpeeds}.
1662         *
1663         * @param newDesaturateWheelSpeeds Parameter to modify
1664         * @return this object
1665         */
1666        public FieldCentricFacingAngle withDesaturateWheelSpeeds(boolean newDesaturateWheelSpeeds) {
1667            this.DesaturateWheelSpeeds = newDesaturateWheelSpeeds;
1668            return this;
1669        }
1670
1671        /**
1672         * Modifies the ForwardPerspective parameter and returns itself.
1673         * <p>
1674         * The perspective to use when determining which direction is forward.
1675         *
1676         * @param newForwardPerspective Parameter to modify
1677         * @return this object
1678         */
1679        public FieldCentricFacingAngle withForwardPerspective(ForwardPerspectiveValue newForwardPerspective) {
1680            this.ForwardPerspective = newForwardPerspective;
1681            return this;
1682        }
1683    }
1684
1685    /**
1686     * SysId-specific SwerveRequest to characterize the translational
1687     * characteristics of a swerve drivetrain.
1688     */
1689    public static class SysIdSwerveTranslation implements SwerveRequest {
1690        /**
1691         * Voltage to apply to drive wheels.
1692         */
1693        public double VoltsToApply = 0;
1694
1695        /** Local reference to a voltage request for the drive motors */
1696        private final VoltageOut m_driveRequest = new VoltageOut(0);
1697        /** Local reference to a position voltage request for the steer motors */
1698        private final PositionVoltage m_steerRequest_Voltage = new PositionVoltage(0);
1699        /** Local reference to a position torque current request for the steer motors */
1700        private final PositionTorqueCurrentFOC m_steerRequest_TorqueCurrent = new PositionTorqueCurrentFOC(0);
1701
1702        public StatusCode apply(SwerveControlParameters parameters, SwerveModule<?, ?, ?>... modulesToApply) {
1703            for (int i = 0; i < modulesToApply.length; ++i) {
1704                switch (modulesToApply[i].getSteerClosedLoopOutputType()) {
1705                    case Voltage:
1706                        modulesToApply[i].apply(
1707                            m_driveRequest.withOutput(VoltsToApply),
1708                            m_steerRequest_Voltage.withPosition(0)
1709                        );
1710                        break;
1711                    case TorqueCurrentFOC:
1712                        modulesToApply[i].apply(
1713                            m_driveRequest.withOutput(VoltsToApply),
1714                            m_steerRequest_TorqueCurrent.withPosition(0)
1715                        );
1716                        break;
1717                }
1718            }
1719            return StatusCode.OK;
1720        }
1721
1722        /**
1723         * Sets the voltage to apply to the drive wheels.
1724         *
1725         * @param volts Voltage to apply
1726         * @return this request
1727         */
1728        public SysIdSwerveTranslation withVolts(double volts) {
1729            VoltsToApply = volts;
1730            return this;
1731        }
1732        /**
1733         * Sets the voltage to apply to the drive wheels.
1734         *
1735         * @param volts Voltage to apply
1736         * @return this request
1737         */
1738        public SysIdSwerveTranslation withVolts(Voltage volts) {
1739            VoltsToApply = volts.in(Volts);
1740            return this;
1741        }
1742    }
1743
1744    /**
1745     * SysId-specific SwerveRequest to characterize the rotational
1746     * characteristics of a swerve drivetrain. This is useful to
1747     * characterize the heading controller for FieldCentricFacingAngle.
1748     * <p>
1749     * The RotationalRate of this swerve request should be logged.
1750     * When importing the log to SysId, set the "voltage" to
1751     * RotationalRate, "position" to the Pigeon 2 Yaw, and "velocity"
1752     * to the Pigeon 2 AngularVelocityZWorld. Note that the position
1753     * and velocity will both need to be scaled by pi/180.
1754     * <p>
1755     * Alternatively, the MotorVoltage of one of the drive motors can
1756     * be loaded into the SysId "voltage" field, which can be useful
1757     * when determining the MOI of the robot.
1758     */
1759    public static class SysIdSwerveRotation implements SwerveRequest {
1760        /**
1761         * The angular rate to rotate at, in radians per second.
1762         */
1763        public double RotationalRate = 0;
1764
1765        /** Local reference to a voltage request for the drive motors */
1766        private final VoltageOut m_driveRequest = new VoltageOut(0);
1767        /** Local reference to a position voltage request for the steer motors */
1768        private final PositionVoltage m_steerRequest_Voltage = new PositionVoltage(0);
1769        /** Local reference to a position torque current request for the steer motors */
1770        private final PositionTorqueCurrentFOC m_steerRequest_TorqueCurrent = new PositionTorqueCurrentFOC(0);
1771
1772        public StatusCode apply(SwerveControlParameters parameters, SwerveModule<?, ?, ?>... modulesToApply) {
1773            for (int i = 0; i < modulesToApply.length; ++i) {
1774                var speedMps = RotationalRate * parameters.moduleLocations[i].getNorm();
1775                var driveVoltage = speedMps / parameters.kMaxSpeedMps * 12.0;
1776
1777                var angle = parameters.moduleLocations[i].getAngle().plus(Rotation2d.kCCW_90deg);
1778
1779                switch (modulesToApply[i].getSteerClosedLoopOutputType()) {
1780                    case Voltage:
1781                        modulesToApply[i].apply(
1782                            m_driveRequest.withOutput(driveVoltage),
1783                            m_steerRequest_Voltage.withPosition(angle.getRotations())
1784                        );
1785                        break;
1786                    case TorqueCurrentFOC:
1787                        modulesToApply[i].apply(
1788                            m_driveRequest.withOutput(driveVoltage),
1789                            m_steerRequest_TorqueCurrent.withPosition(angle.getRotations())
1790                        );
1791                        break;
1792                }
1793            }
1794            return StatusCode.OK;
1795        }
1796
1797        /**
1798         * Update the angular rate to rotate at, in radians per second.
1799         *
1800         * @param newRotationalRate Angular rate to rotate at
1801         * @return this request
1802         */
1803        public SysIdSwerveRotation withRotationalRate(double newRotationalRate) {
1804            RotationalRate = newRotationalRate;
1805            return this;
1806        }
1807        /**
1808         * Update the angular rate to rotate at.
1809         *
1810         * @param newRotationalRate The angular rate to rotate at
1811         * @return this request
1812         */
1813        public SysIdSwerveRotation withRotationalRate(AngularVelocity newRotationalRate) {
1814            RotationalRate = newRotationalRate.in(RadiansPerSecond);
1815            return this;
1816        }
1817    }
1818
1819    /**
1820     * SysId-specific SwerveRequest to characterize the steer module
1821     * characteristics of a swerve drivetrain.
1822     */
1823    public static class SysIdSwerveSteerGains implements SwerveRequest {
1824        /**
1825         * Voltage to apply to steer motors.
1826         */
1827        public double VoltsToApply = 0;
1828
1829        /** Local reference to a coast request for the drive motors */
1830        private final CoastOut m_driveRequest = new CoastOut();
1831        /** Local reference to a voltage request for the steer motors */
1832        private final VoltageOut m_steerRequest = new VoltageOut(0);
1833
1834        public StatusCode apply(SwerveControlParameters parameters, SwerveModule<?, ?, ?>... modulesToApply) {
1835            for (int i = 0; i < modulesToApply.length; ++i) {
1836                modulesToApply[i].apply(m_driveRequest, m_steerRequest.withOutput(VoltsToApply));
1837            }
1838            return StatusCode.OK;
1839        }
1840
1841        /**
1842         * Sets the voltage to apply to the steer motors.
1843         *
1844         * @param volts Voltage to apply
1845         * @return this request
1846         */
1847        public SysIdSwerveSteerGains withVolts(double volts) {
1848            VoltsToApply = volts;
1849            return this;
1850        }
1851        /**
1852         * Sets the voltage to apply to the steer motors.
1853         *
1854         * @param volts Voltage to apply
1855         * @return this request
1856         */
1857        public SysIdSwerveSteerGains withVolts(Voltage volts) {
1858            VoltsToApply = volts.in(Volts);
1859            return this;
1860        }
1861    }
1862}