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 maximum absolute rotational rate to allow, in radians per second.
1393         * Setting this to 0 results in no cap to rotational rate.
1394         */
1395        public double MaxAbsRotationalRate = 0;
1396        /**
1397         * The center of rotation the robot should rotate around.
1398         * This is (0,0) by default, which will rotate around the center of the robot.
1399         */
1400        public Translation2d CenterOfRotation = new Translation2d();
1401
1402        /**
1403         * The type of control request to use for the drive motor.
1404         */
1405        public SwerveModule.DriveRequestType DriveRequestType = SwerveModule.DriveRequestType.OpenLoopVoltage;
1406        /**
1407         * The type of control request to use for the steer motor.
1408         */
1409        public SwerveModule.SteerRequestType SteerRequestType = SwerveModule.SteerRequestType.Position;
1410        /**
1411         * Whether to desaturate wheel speeds before applying.
1412         * For more information, see the documentation of {@link SwerveDriveKinematics#desaturateWheelSpeeds}.
1413         */
1414        public boolean DesaturateWheelSpeeds = true;
1415
1416        /**
1417         * The perspective to use when determining which direction is forward.
1418         */
1419        public ForwardPerspectiveValue ForwardPerspective = ForwardPerspectiveValue.OperatorPerspective;
1420
1421        /**
1422         * The PID controller used to maintain the desired heading.
1423         * Users can specify the PID gains to change how aggressively to maintain
1424         * heading.
1425         * <p>
1426         * This PID controller operates on heading radians and outputs a target
1427         * rotational rate in radians per second. Note that continuous input should
1428         * be enabled on the range [-pi, pi].
1429         */
1430        public PhoenixPIDController HeadingController = new PhoenixPIDController(0, 0, 0);
1431
1432        private final FieldCentric m_fieldCentric = new FieldCentric();
1433
1434        public FieldCentricFacingAngle() {
1435            HeadingController.enableContinuousInput(-Math.PI, Math.PI);
1436        }
1437
1438        public StatusCode apply(SwerveControlParameters parameters, SwerveModule<?, ?, ?>... modulesToApply) {
1439            Rotation2d angleToFace = TargetDirection;
1440            if (ForwardPerspective == ForwardPerspectiveValue.OperatorPerspective) {
1441                /* If we're operator perspective, rotate the direction we want to face by the angle */
1442                angleToFace = angleToFace.rotateBy(parameters.operatorForwardDirection);
1443            }
1444
1445            double toApplyOmega = TargetRateFeedforward +
1446                HeadingController.calculate(
1447                    parameters.currentPose.getRotation().getRadians(),
1448                    angleToFace.getRadians(),
1449                    parameters.timestamp
1450                );
1451            if (MaxAbsRotationalRate > 0.0) {
1452                if (toApplyOmega > MaxAbsRotationalRate) {
1453                    toApplyOmega = MaxAbsRotationalRate;
1454                } else if (toApplyOmega < -MaxAbsRotationalRate) {
1455                    toApplyOmega = -MaxAbsRotationalRate;
1456                }
1457            }
1458
1459            return m_fieldCentric
1460                .withVelocityX(VelocityX)
1461                .withVelocityY(VelocityY)
1462                .withRotationalRate(toApplyOmega)
1463                .withDeadband(Deadband)
1464                .withRotationalDeadband(RotationalDeadband)
1465                .withCenterOfRotation(CenterOfRotation)
1466                .withDriveRequestType(DriveRequestType)
1467                .withSteerRequestType(SteerRequestType)
1468                .withDesaturateWheelSpeeds(DesaturateWheelSpeeds)
1469                .withForwardPerspective(ForwardPerspective)
1470                .apply(parameters, modulesToApply);
1471        }
1472
1473        /**
1474         * Modifies the PID gains of the HeadingController parameter and returns itself.
1475         * <p>
1476         * Sets the proportional, integral, and differential coefficients used to maintain
1477         * the desired heading. Users can specify the PID gains to change how aggressively to
1478         * maintain heading.
1479         * <p>
1480         * This PID controller operates on heading radians and outputs a target
1481         * rotational rate in radians per second.
1482         *
1483         * @param kP The proportional coefficient; must be >= 0
1484         * @param kI The integral coefficient; must be >= 0
1485         * @param kD The differential coefficient; must be >= 0
1486         * @return this object
1487         */
1488        public FieldCentricFacingAngle withHeadingPID(double kP, double kI, double kD)
1489        {
1490            this.HeadingController.setPID(kP, kI, kD);
1491            return this;
1492        }
1493
1494        /**
1495         * Modifies the VelocityX parameter and returns itself.
1496         * <p>
1497         * The velocity in the X direction, in m/s. X is defined as forward according to
1498         * WPILib convention, so this determines how fast to travel forward.
1499         *
1500         * @param newVelocityX Parameter to modify
1501         * @return this object
1502         */
1503        public FieldCentricFacingAngle withVelocityX(double newVelocityX) {
1504            this.VelocityX = newVelocityX;
1505            return this;
1506        }
1507
1508        /**
1509         * Modifies the VelocityX parameter and returns itself.
1510         * <p>
1511         * The velocity in the X direction, in m/s. X is defined as forward according to
1512         * WPILib convention, so this determines how fast to travel forward.
1513         *
1514         * @param newVelocityX Parameter to modify
1515         * @return this object
1516         */
1517        public FieldCentricFacingAngle withVelocityX(LinearVelocity newVelocityX) {
1518            this.VelocityX = newVelocityX.in(MetersPerSecond);
1519            return this;
1520        }
1521
1522        /**
1523         * Modifies the VelocityY parameter and returns itself.
1524         * <p>
1525         * The velocity in the Y direction, in m/s. Y is defined as to the left
1526         * according to WPILib convention, so this determines how fast to travel to the
1527         * left.
1528         *
1529         * @param newVelocityY Parameter to modify
1530         * @return this object
1531         */
1532        public FieldCentricFacingAngle withVelocityY(double newVelocityY) {
1533            this.VelocityY = newVelocityY;
1534            return this;
1535        }
1536
1537        /**
1538         * Modifies the VelocityY parameter and returns itself.
1539         * <p>
1540         * The velocity in the Y direction, in m/s. Y is defined as to the left
1541         * according to WPILib convention, so this determines how fast to travel to the
1542         * left.
1543         *
1544         * @param newVelocityY Parameter to modify
1545         * @return this object
1546         */
1547        public FieldCentricFacingAngle withVelocityY(LinearVelocity newVelocityY) {
1548            this.VelocityY = newVelocityY.in(MetersPerSecond);
1549            return this;
1550        }
1551
1552        /**
1553         * Modifies the TargetDirection parameter and returns itself.
1554         * <p>
1555         * The desired direction to face. 0 Degrees is defined as in the direction of
1556         * the X axis. As a result, a TargetDirection of 90 degrees will point along
1557         * the Y axis, or to the left.
1558         *
1559         * @param newTargetDirection Parameter to modify
1560         * @return this object
1561         */
1562        public FieldCentricFacingAngle withTargetDirection(Rotation2d newTargetDirection) {
1563            this.TargetDirection = newTargetDirection;
1564            return this;
1565        }
1566
1567        /**
1568         * Modifies the TargetRateFeedforward parameter and returns itself.
1569         * <p>
1570         * The rotational rate feedforward to add to the output of the heading
1571         * controller, in radians per second. When using a motion profile for the
1572         * target direction, this can be set to the current velocity reference of
1573         * the profile.
1574         *
1575         * @param newTargetRateFeedforward Parameter to modify
1576         * @return this object
1577         */
1578        public FieldCentricFacingAngle withTargetRateFeedforward(double newTargetRateFeedforward) {
1579            this.TargetRateFeedforward = newTargetRateFeedforward;
1580            return this;
1581        }
1582        /**
1583         * Modifies the TargetRateFeedforward parameter and returns itself.
1584         * <p>
1585         * The rotational rate feedforward to add to the output of the heading
1586         * controller, in radians per second. When using a motion profile for the
1587         * target direction, this can be set to the current velocity reference of
1588         * the profile.
1589         *
1590         * @param newTargetRateFeedforward Parameter to modify
1591         * @return this object
1592         */
1593        public FieldCentricFacingAngle withTargetRateFeedforward(AngularVelocity newTargetRateFeedforward) {
1594            this.TargetRateFeedforward = newTargetRateFeedforward.in(RadiansPerSecond);
1595            return this;
1596        }
1597
1598        /**
1599         * Modifies the Deadband parameter and returns itself.
1600         * <p>
1601         * The allowable deadband of the request, in m/s.
1602         *
1603         * @param newDeadband Parameter to modify
1604         * @return this object
1605         */
1606        public FieldCentricFacingAngle withDeadband(double newDeadband) {
1607            this.Deadband = newDeadband;
1608            return this;
1609        }
1610
1611        /**
1612         * Modifies the Deadband parameter and returns itself.
1613         * <p>
1614         * The allowable deadband of the request, in m/s.
1615         *
1616         * @param newDeadband Parameter to modify
1617         * @return this object
1618         */
1619        public FieldCentricFacingAngle withDeadband(LinearVelocity newDeadband) {
1620            this.Deadband = newDeadband.in(MetersPerSecond);
1621            return this;
1622        }
1623
1624        /**
1625         * Modifies the RotationalDeadband parameter and returns itself.
1626         * <p>
1627         * The rotational deadband of the request, in radians per second.
1628         *
1629         * @param newRotationalDeadband Parameter to modify
1630         * @return this object
1631         */
1632        public FieldCentricFacingAngle withRotationalDeadband(double newRotationalDeadband) {
1633            this.RotationalDeadband = newRotationalDeadband;
1634            return this;
1635        }
1636
1637        /**
1638         * Modifies the RotationalDeadband parameter and returns itself.
1639         * <p>
1640         * The rotational deadband of the request, in radians per second.
1641         *
1642         * @param newRotationalDeadband Parameter to modify
1643         * @return this object
1644         */
1645        public FieldCentricFacingAngle withRotationalDeadband(AngularVelocity newRotationalDeadband) {
1646            this.RotationalDeadband = newRotationalDeadband.in(RadiansPerSecond);
1647            return this;
1648        }
1649
1650        /**
1651         * Modifies the MaxAbsRotationalRate parameter and returns itself.
1652         * <p>
1653         * The maximum absolute rotational rate to allow, in radians per second.
1654         * Setting this to 0 results in no cap to rotational rate.
1655         *
1656         * @param newMaxAbsRotationalRate Parameter to modify
1657         * @return this object
1658         */
1659        public FieldCentricFacingAngle withMaxAbsRotationalRate(double newMaxAbsRotationalRate) {
1660            this.MaxAbsRotationalRate = newMaxAbsRotationalRate;
1661            return this;
1662        }
1663
1664        /**
1665         * Modifies the MaxAbsRotationalRate parameter and returns itself.
1666         * <p>
1667         * The maximum absolute rotational rate to allow, in radians per second.
1668         * Setting this to 0 results in no cap to rotational rate.
1669         *
1670         * @param newMaxAbsRotationalRate Parameter to modify
1671         * @return this object
1672         */
1673        public FieldCentricFacingAngle withMaxAbsRotationalRate(AngularVelocity newMaxAbsRotationalRate) {
1674            this.MaxAbsRotationalRate = newMaxAbsRotationalRate.in(RadiansPerSecond);
1675            return this;
1676        }
1677
1678        /**
1679         * Modifies the CenterOfRotation parameter and returns itself.
1680         * <p>
1681         * The center of rotation the robot should rotate around. This is (0,0) by
1682         * default, which will rotate around the center of the robot.
1683         *
1684         * @param newCenterOfRotation Parameter to modify
1685         * @return this object
1686         */
1687        public FieldCentricFacingAngle withCenterOfRotation(Translation2d newCenterOfRotation) {
1688            this.CenterOfRotation = newCenterOfRotation;
1689            return this;
1690        }
1691
1692        /**
1693         * Modifies the DriveRequestType parameter and returns itself.
1694         * <p>
1695         * The type of control request to use for the drive motor.
1696         *
1697         * @param newDriveRequestType Parameter to modify
1698         * @return this object
1699         */
1700        public FieldCentricFacingAngle withDriveRequestType(SwerveModule.DriveRequestType newDriveRequestType) {
1701            this.DriveRequestType = newDriveRequestType;
1702            return this;
1703        }
1704
1705        /**
1706         * Modifies the SteerRequestType parameter and returns itself.
1707         * <p>
1708         * The type of control request to use for the drive motor.
1709         *
1710         * @param newSteerRequestType Parameter to modify
1711         * @return this object
1712         */
1713        public FieldCentricFacingAngle withSteerRequestType(SwerveModule.SteerRequestType newSteerRequestType) {
1714            this.SteerRequestType = newSteerRequestType;
1715            return this;
1716        }
1717
1718        /**
1719         * Modifies the DesaturateWheelSpeeds parameter and returns itself.
1720         * <p>
1721         * Whether to desaturate wheel speeds before applying. For more information, see
1722         * the documentation of {@link SwerveDriveKinematics#desaturateWheelSpeeds}.
1723         *
1724         * @param newDesaturateWheelSpeeds Parameter to modify
1725         * @return this object
1726         */
1727        public FieldCentricFacingAngle withDesaturateWheelSpeeds(boolean newDesaturateWheelSpeeds) {
1728            this.DesaturateWheelSpeeds = newDesaturateWheelSpeeds;
1729            return this;
1730        }
1731
1732        /**
1733         * Modifies the ForwardPerspective parameter and returns itself.
1734         * <p>
1735         * The perspective to use when determining which direction is forward.
1736         *
1737         * @param newForwardPerspective Parameter to modify
1738         * @return this object
1739         */
1740        public FieldCentricFacingAngle withForwardPerspective(ForwardPerspectiveValue newForwardPerspective) {
1741            this.ForwardPerspective = newForwardPerspective;
1742            return this;
1743        }
1744    }
1745
1746    /**
1747     * Drives the swerve drivetrain in a robot-centric manner, maintaining a
1748     * specified heading angle to ensure the robot is facing the desired direction
1749     * <p>
1750     * When users use this request, they specify the direction the robot should
1751     * travel oriented against the robot itself, and the direction the robot should
1752     * be facing relative to the field.
1753     * <p>
1754     * An example scenario is that the robot is oriented to the east, the VelocityX
1755     * is +5 m/s, VelocityY is 0 m/s, and TargetDirection is 180 degrees.
1756     * In this scenario, the robot would drive forward at 5 m/s and turn clockwise
1757     * to a target of 180 degrees.
1758     * <p>
1759     * This control request is especially useful for vision control, where the
1760     * robot should be facing a vision target throughout the motion.
1761     */
1762    public static class RobotCentricFacingAngle implements SwerveRequest {
1763        /**
1764         * The velocity in the X direction, in m/s.
1765         * X is defined as forward according to WPILib convention,
1766         * so this determines how fast to travel forward.
1767         */
1768        public double VelocityX = 0;
1769        /**
1770         * The velocity in the Y direction, in m/s.
1771         * Y is defined as to the left according to WPILib convention,
1772         * so this determines how fast to travel to the left.
1773         */
1774        public double VelocityY = 0;
1775        /**
1776         * The desired direction to face.
1777         * 0 Degrees is defined as in the direction of the X axis.
1778         * As a result, a TargetDirection of 90 degrees will point along
1779         * the Y axis, or to the left.
1780         */
1781        public Rotation2d TargetDirection = new Rotation2d();
1782        /**
1783         * The rotational rate feedforward to add to the output of the heading
1784         * controller, in radians per second. When using a motion profile for the
1785         * target direction, this can be set to the current velocity reference of
1786         * the profile.
1787         */
1788        public double TargetRateFeedforward = 0;
1789
1790        /**
1791         * The allowable deadband of the request, in m/s.
1792         */
1793        public double Deadband = 0;
1794        /**
1795         * The rotational deadband of the request, in radians per second.
1796         */
1797        public double RotationalDeadband = 0;
1798        /**
1799         * The maximum absolute rotational rate to allow, in radians per second.
1800         * Setting this to 0 results in no cap to rotational rate.
1801         */
1802        public double MaxAbsRotationalRate = 0;
1803        /**
1804         * The center of rotation the robot should rotate around.
1805         * This is (0,0) by default, which will rotate around the center of the robot.
1806         */
1807        public Translation2d CenterOfRotation = new Translation2d();
1808
1809        /**
1810         * The type of control request to use for the drive motor.
1811         */
1812        public SwerveModule.DriveRequestType DriveRequestType = SwerveModule.DriveRequestType.OpenLoopVoltage;
1813        /**
1814         * The type of control request to use for the steer motor.
1815         */
1816        public SwerveModule.SteerRequestType SteerRequestType = SwerveModule.SteerRequestType.Position;
1817        /**
1818         * Whether to desaturate wheel speeds before applying.
1819         * For more information, see the documentation of {@link SwerveDriveKinematics#desaturateWheelSpeeds}.
1820         */
1821        public boolean DesaturateWheelSpeeds = true;
1822
1823        /**
1824         * The perspective to use when determining which direction is forward
1825         * for the target heading.
1826         */
1827        public ForwardPerspectiveValue ForwardPerspective = ForwardPerspectiveValue.OperatorPerspective;
1828
1829        /**
1830         * The PID controller used to maintain the desired heading.
1831         * Users can specify the PID gains to change how aggressively to maintain
1832         * heading.
1833         * <p>
1834         * This PID controller operates on heading radians and outputs a target
1835         * rotational rate in radians per second. Note that continuous input should
1836         * be enabled on the range [-pi, pi].
1837         */
1838        public PhoenixPIDController HeadingController = new PhoenixPIDController(0, 0, 0);
1839
1840        private final RobotCentric m_robotCentric = new RobotCentric();
1841
1842        public RobotCentricFacingAngle() {
1843            HeadingController.enableContinuousInput(-Math.PI, Math.PI);
1844        }
1845
1846        public StatusCode apply(SwerveControlParameters parameters, SwerveModule<?, ?, ?>... modulesToApply) {
1847            Rotation2d angleToFace = TargetDirection;
1848            if (ForwardPerspective == ForwardPerspectiveValue.OperatorPerspective) {
1849                /* If we're operator perspective, rotate the direction we want to face by the angle */
1850                angleToFace = angleToFace.rotateBy(parameters.operatorForwardDirection);
1851            }
1852
1853            double toApplyOmega = TargetRateFeedforward +
1854                HeadingController.calculate(
1855                    parameters.currentPose.getRotation().getRadians(),
1856                    angleToFace.getRadians(),
1857                    parameters.timestamp
1858                );
1859            if (MaxAbsRotationalRate > 0.0) {
1860                if (toApplyOmega > MaxAbsRotationalRate) {
1861                    toApplyOmega = MaxAbsRotationalRate;
1862                } else if (toApplyOmega < -MaxAbsRotationalRate) {
1863                    toApplyOmega = -MaxAbsRotationalRate;
1864                }
1865            }
1866
1867            return m_robotCentric
1868                .withVelocityX(VelocityX)
1869                .withVelocityY(VelocityY)
1870                .withRotationalRate(toApplyOmega)
1871                .withDeadband(Deadband)
1872                .withRotationalDeadband(RotationalDeadband)
1873                .withCenterOfRotation(CenterOfRotation)
1874                .withDriveRequestType(DriveRequestType)
1875                .withSteerRequestType(SteerRequestType)
1876                .withDesaturateWheelSpeeds(DesaturateWheelSpeeds)
1877                .apply(parameters, modulesToApply);
1878        }
1879
1880        /**
1881         * Modifies the PID gains of the HeadingController parameter and returns itself.
1882         * <p>
1883         * Sets the proportional, integral, and differential coefficients used to maintain
1884         * the desired heading. Users can specify the PID gains to change how aggressively to
1885         * maintain heading.
1886         * <p>
1887         * This PID controller operates on heading radians and outputs a target
1888         * rotational rate in radians per second.
1889         *
1890         * @param kP The proportional coefficient; must be >= 0
1891         * @param kI The integral coefficient; must be >= 0
1892         * @param kD The differential coefficient; must be >= 0
1893         * @return this object
1894         */
1895        public RobotCentricFacingAngle withHeadingPID(double kP, double kI, double kD)
1896        {
1897            this.HeadingController.setPID(kP, kI, kD);
1898            return this;
1899        }
1900
1901        /**
1902         * Modifies the VelocityX parameter and returns itself.
1903         * <p>
1904         * The velocity in the X direction, in m/s. X is defined as forward according to
1905         * WPILib convention, so this determines how fast to travel forward.
1906         *
1907         * @param newVelocityX Parameter to modify
1908         * @return this object
1909         */
1910        public RobotCentricFacingAngle withVelocityX(double newVelocityX) {
1911            this.VelocityX = newVelocityX;
1912            return this;
1913        }
1914
1915        /**
1916         * Modifies the VelocityX parameter and returns itself.
1917         * <p>
1918         * The velocity in the X direction, in m/s. X is defined as forward according to
1919         * WPILib convention, so this determines how fast to travel forward.
1920         *
1921         * @param newVelocityX Parameter to modify
1922         * @return this object
1923         */
1924        public RobotCentricFacingAngle withVelocityX(LinearVelocity newVelocityX) {
1925            this.VelocityX = newVelocityX.in(MetersPerSecond);
1926            return this;
1927        }
1928
1929        /**
1930         * Modifies the VelocityY parameter and returns itself.
1931         * <p>
1932         * The velocity in the Y direction, in m/s. Y is defined as to the left
1933         * according to WPILib convention, so this determines how fast to travel to the
1934         * left.
1935         *
1936         * @param newVelocityY Parameter to modify
1937         * @return this object
1938         */
1939        public RobotCentricFacingAngle withVelocityY(double newVelocityY) {
1940            this.VelocityY = newVelocityY;
1941            return this;
1942        }
1943
1944        /**
1945         * Modifies the VelocityY parameter and returns itself.
1946         * <p>
1947         * The velocity in the Y direction, in m/s. Y is defined as to the left
1948         * according to WPILib convention, so this determines how fast to travel to the
1949         * left.
1950         *
1951         * @param newVelocityY Parameter to modify
1952         * @return this object
1953         */
1954        public RobotCentricFacingAngle withVelocityY(LinearVelocity newVelocityY) {
1955            this.VelocityY = newVelocityY.in(MetersPerSecond);
1956            return this;
1957        }
1958
1959        /**
1960         * Modifies the TargetDirection parameter and returns itself.
1961         * <p>
1962         * The desired direction to face. 0 Degrees is defined as in the direction of
1963         * the X axis. As a result, a TargetDirection of 90 degrees will point along
1964         * the Y axis, or to the left.
1965         *
1966         * @param newTargetDirection Parameter to modify
1967         * @return this object
1968         */
1969        public RobotCentricFacingAngle withTargetDirection(Rotation2d newTargetDirection) {
1970            this.TargetDirection = newTargetDirection;
1971            return this;
1972        }
1973
1974        /**
1975         * Modifies the TargetRateFeedforward parameter and returns itself.
1976         * <p>
1977         * The rotational rate feedforward to add to the output of the heading
1978         * controller, in radians per second. When using a motion profile for the
1979         * target direction, this can be set to the current velocity reference of
1980         * the profile.
1981         *
1982         * @param newTargetRateFeedforward Parameter to modify
1983         * @return this object
1984         */
1985        public RobotCentricFacingAngle withTargetRateFeedforward(double newTargetRateFeedforward) {
1986            this.TargetRateFeedforward = newTargetRateFeedforward;
1987            return this;
1988        }
1989        /**
1990         * Modifies the TargetRateFeedforward parameter and returns itself.
1991         * <p>
1992         * The rotational rate feedforward to add to the output of the heading
1993         * controller, in radians per second. When using a motion profile for the
1994         * target direction, this can be set to the current velocity reference of
1995         * the profile.
1996         *
1997         * @param newTargetRateFeedforward Parameter to modify
1998         * @return this object
1999         */
2000        public RobotCentricFacingAngle withTargetRateFeedforward(AngularVelocity newTargetRateFeedforward) {
2001            this.TargetRateFeedforward = newTargetRateFeedforward.in(RadiansPerSecond);
2002            return this;
2003        }
2004
2005        /**
2006         * Modifies the Deadband parameter and returns itself.
2007         * <p>
2008         * The allowable deadband of the request, in m/s.
2009         *
2010         * @param newDeadband Parameter to modify
2011         * @return this object
2012         */
2013        public RobotCentricFacingAngle withDeadband(double newDeadband) {
2014            this.Deadband = newDeadband;
2015            return this;
2016        }
2017
2018        /**
2019         * Modifies the Deadband parameter and returns itself.
2020         * <p>
2021         * The allowable deadband of the request, in m/s.
2022         *
2023         * @param newDeadband Parameter to modify
2024         * @return this object
2025         */
2026        public RobotCentricFacingAngle withDeadband(LinearVelocity newDeadband) {
2027            this.Deadband = newDeadband.in(MetersPerSecond);
2028            return this;
2029        }
2030
2031        /**
2032         * Modifies the RotationalDeadband parameter and returns itself.
2033         * <p>
2034         * The rotational deadband of the request, in radians per second.
2035         *
2036         * @param newRotationalDeadband Parameter to modify
2037         * @return this object
2038         */
2039        public RobotCentricFacingAngle withRotationalDeadband(double newRotationalDeadband) {
2040            this.RotationalDeadband = newRotationalDeadband;
2041            return this;
2042        }
2043
2044        /**
2045         * Modifies the RotationalDeadband parameter and returns itself.
2046         * <p>
2047         * The rotational deadband of the request, in radians per second.
2048         *
2049         * @param newRotationalDeadband Parameter to modify
2050         * @return this object
2051         */
2052        public RobotCentricFacingAngle withRotationalDeadband(AngularVelocity newRotationalDeadband) {
2053            this.RotationalDeadband = newRotationalDeadband.in(RadiansPerSecond);
2054            return this;
2055        }
2056
2057        /**
2058         * Modifies the MaxAbsRotationalRate parameter and returns itself.
2059         * <p>
2060         * The maximum absolute rotational rate to allow, in radians per second.
2061         * Setting this to 0 results in no cap to rotational rate.
2062         *
2063         * @param newMaxAbsRotationalRate Parameter to modify
2064         * @return this object
2065         */
2066        public RobotCentricFacingAngle withMaxAbsRotationalRate(double newMaxAbsRotationalRate) {
2067            this.MaxAbsRotationalRate = newMaxAbsRotationalRate;
2068            return this;
2069        }
2070
2071        /**
2072         * Modifies the MaxAbsRotationalRate parameter and returns itself.
2073         * <p>
2074         * The maximum absolute rotational rate to allow, in radians per second.
2075         * Setting this to 0 results in no cap to rotational rate.
2076         *
2077         * @param newMaxAbsRotationalRate Parameter to modify
2078         * @return this object
2079         */
2080        public RobotCentricFacingAngle withMaxAbsRotationalRate(AngularVelocity newMaxAbsRotationalRate) {
2081            this.MaxAbsRotationalRate = newMaxAbsRotationalRate.in(RadiansPerSecond);
2082            return this;
2083        }
2084
2085        /**
2086         * Modifies the CenterOfRotation parameter and returns itself.
2087         * <p>
2088         * The center of rotation the robot should rotate around. This is (0,0) by
2089         * default, which will rotate around the center of the robot.
2090         *
2091         * @param newCenterOfRotation Parameter to modify
2092         * @return this object
2093         */
2094        public RobotCentricFacingAngle withCenterOfRotation(Translation2d newCenterOfRotation) {
2095            this.CenterOfRotation = newCenterOfRotation;
2096            return this;
2097        }
2098
2099        /**
2100         * Modifies the DriveRequestType parameter and returns itself.
2101         * <p>
2102         * The type of control request to use for the drive motor.
2103         *
2104         * @param newDriveRequestType Parameter to modify
2105         * @return this object
2106         */
2107        public RobotCentricFacingAngle withDriveRequestType(SwerveModule.DriveRequestType newDriveRequestType) {
2108            this.DriveRequestType = newDriveRequestType;
2109            return this;
2110        }
2111
2112        /**
2113         * Modifies the SteerRequestType parameter and returns itself.
2114         * <p>
2115         * The type of control request to use for the drive motor.
2116         *
2117         * @param newSteerRequestType Parameter to modify
2118         * @return this object
2119         */
2120        public RobotCentricFacingAngle withSteerRequestType(SwerveModule.SteerRequestType newSteerRequestType) {
2121            this.SteerRequestType = newSteerRequestType;
2122            return this;
2123        }
2124
2125        /**
2126         * Modifies the DesaturateWheelSpeeds parameter and returns itself.
2127         * <p>
2128         * Whether to desaturate wheel speeds before applying. For more information, see
2129         * the documentation of {@link SwerveDriveKinematics#desaturateWheelSpeeds}.
2130         *
2131         * @param newDesaturateWheelSpeeds Parameter to modify
2132         * @return this object
2133         */
2134        public RobotCentricFacingAngle withDesaturateWheelSpeeds(boolean newDesaturateWheelSpeeds) {
2135            this.DesaturateWheelSpeeds = newDesaturateWheelSpeeds;
2136            return this;
2137        }
2138
2139        /**
2140         * Modifies the ForwardPerspective parameter and returns itself.
2141         * <p>
2142         * The perspective to use when determining which direction is forward
2143         * for the target heading.
2144         *
2145         * @param newForwardPerspective Parameter to modify
2146         * @return this object
2147         */
2148        public RobotCentricFacingAngle withForwardPerspective(ForwardPerspectiveValue newForwardPerspective) {
2149            this.ForwardPerspective = newForwardPerspective;
2150            return this;
2151        }
2152    }
2153
2154    /**
2155     * SysId-specific SwerveRequest to characterize the translational
2156     * characteristics of a swerve drivetrain.
2157     */
2158    public static class SysIdSwerveTranslation implements SwerveRequest {
2159        /**
2160         * Voltage to apply to drive wheels.
2161         */
2162        public double VoltsToApply = 0;
2163
2164        /** Local reference to a voltage request for the drive motors */
2165        private final VoltageOut m_driveRequest = new VoltageOut(0);
2166        /** Local reference to a position voltage request for the steer motors */
2167        private final PositionVoltage m_steerRequest_Voltage = new PositionVoltage(0);
2168        /** Local reference to a position torque current request for the steer motors */
2169        private final PositionTorqueCurrentFOC m_steerRequest_TorqueCurrent = new PositionTorqueCurrentFOC(0);
2170
2171        public StatusCode apply(SwerveControlParameters parameters, SwerveModule<?, ?, ?>... modulesToApply) {
2172            for (int i = 0; i < modulesToApply.length; ++i) {
2173                switch (modulesToApply[i].getSteerClosedLoopOutputType()) {
2174                    case Voltage:
2175                        modulesToApply[i].apply(
2176                            m_driveRequest.withOutput(VoltsToApply),
2177                            m_steerRequest_Voltage.withPosition(0)
2178                        );
2179                        break;
2180                    case TorqueCurrentFOC:
2181                        modulesToApply[i].apply(
2182                            m_driveRequest.withOutput(VoltsToApply),
2183                            m_steerRequest_TorqueCurrent.withPosition(0)
2184                        );
2185                        break;
2186                }
2187            }
2188            return StatusCode.OK;
2189        }
2190
2191        /**
2192         * Sets the voltage to apply to the drive wheels.
2193         *
2194         * @param volts Voltage to apply
2195         * @return this request
2196         */
2197        public SysIdSwerveTranslation withVolts(double volts) {
2198            VoltsToApply = volts;
2199            return this;
2200        }
2201        /**
2202         * Sets the voltage to apply to the drive wheels.
2203         *
2204         * @param volts Voltage to apply
2205         * @return this request
2206         */
2207        public SysIdSwerveTranslation withVolts(Voltage volts) {
2208            VoltsToApply = volts.in(Volts);
2209            return this;
2210        }
2211    }
2212
2213    /**
2214     * SysId-specific SwerveRequest to characterize the rotational
2215     * characteristics of a swerve drivetrain. This is useful to
2216     * characterize the heading controller for FieldCentricFacingAngle.
2217     * <p>
2218     * The RotationalRate of this swerve request should be logged.
2219     * When importing the log to SysId, set the "voltage" to
2220     * RotationalRate, "position" to the Pigeon 2 Yaw, and "velocity"
2221     * to the Pigeon 2 AngularVelocityZWorld. Note that the position
2222     * and velocity will both need to be scaled by pi/180.
2223     * <p>
2224     * Alternatively, the MotorVoltage of one of the drive motors can
2225     * be loaded into the SysId "voltage" field, which can be useful
2226     * when determining the MOI of the robot.
2227     */
2228    public static class SysIdSwerveRotation implements SwerveRequest {
2229        /**
2230         * The angular rate to rotate at, in radians per second.
2231         */
2232        public double RotationalRate = 0;
2233
2234        /** Local reference to a voltage request for the drive motors */
2235        private final VoltageOut m_driveRequest = new VoltageOut(0);
2236        /** Local reference to a position voltage request for the steer motors */
2237        private final PositionVoltage m_steerRequest_Voltage = new PositionVoltage(0);
2238        /** Local reference to a position torque current request for the steer motors */
2239        private final PositionTorqueCurrentFOC m_steerRequest_TorqueCurrent = new PositionTorqueCurrentFOC(0);
2240
2241        public StatusCode apply(SwerveControlParameters parameters, SwerveModule<?, ?, ?>... modulesToApply) {
2242            for (int i = 0; i < modulesToApply.length; ++i) {
2243                var speedMps = RotationalRate * parameters.moduleLocations[i].getNorm();
2244                var driveVoltage = speedMps / parameters.kMaxSpeedMps * 12.0;
2245
2246                var angle = parameters.moduleLocations[i].getAngle().plus(Rotation2d.kCCW_90deg);
2247
2248                switch (modulesToApply[i].getSteerClosedLoopOutputType()) {
2249                    case Voltage:
2250                        modulesToApply[i].apply(
2251                            m_driveRequest.withOutput(driveVoltage),
2252                            m_steerRequest_Voltage.withPosition(angle.getRotations())
2253                        );
2254                        break;
2255                    case TorqueCurrentFOC:
2256                        modulesToApply[i].apply(
2257                            m_driveRequest.withOutput(driveVoltage),
2258                            m_steerRequest_TorqueCurrent.withPosition(angle.getRotations())
2259                        );
2260                        break;
2261                }
2262            }
2263            return StatusCode.OK;
2264        }
2265
2266        /**
2267         * Update the angular rate to rotate at, in radians per second.
2268         *
2269         * @param newRotationalRate Angular rate to rotate at
2270         * @return this request
2271         */
2272        public SysIdSwerveRotation withRotationalRate(double newRotationalRate) {
2273            RotationalRate = newRotationalRate;
2274            return this;
2275        }
2276        /**
2277         * Update the angular rate to rotate at.
2278         *
2279         * @param newRotationalRate The angular rate to rotate at
2280         * @return this request
2281         */
2282        public SysIdSwerveRotation withRotationalRate(AngularVelocity newRotationalRate) {
2283            RotationalRate = newRotationalRate.in(RadiansPerSecond);
2284            return this;
2285        }
2286    }
2287
2288    /**
2289     * SysId-specific SwerveRequest to characterize the steer module
2290     * characteristics of a swerve drivetrain.
2291     */
2292    public static class SysIdSwerveSteerGains implements SwerveRequest {
2293        /**
2294         * Voltage to apply to steer motors.
2295         */
2296        public double VoltsToApply = 0;
2297
2298        /** Local reference to a coast request for the drive motors */
2299        private final CoastOut m_driveRequest = new CoastOut();
2300        /** Local reference to a voltage request for the steer motors */
2301        private final VoltageOut m_steerRequest = new VoltageOut(0);
2302
2303        public StatusCode apply(SwerveControlParameters parameters, SwerveModule<?, ?, ?>... modulesToApply) {
2304            for (int i = 0; i < modulesToApply.length; ++i) {
2305                modulesToApply[i].apply(m_driveRequest, m_steerRequest.withOutput(VoltsToApply));
2306            }
2307            return StatusCode.OK;
2308        }
2309
2310        /**
2311         * Sets the voltage to apply to the steer motors.
2312         *
2313         * @param volts Voltage to apply
2314         * @return this request
2315         */
2316        public SysIdSwerveSteerGains withVolts(double volts) {
2317            VoltsToApply = volts;
2318            return this;
2319        }
2320        /**
2321         * Sets the voltage to apply to the steer motors.
2322         *
2323         * @param volts Voltage to apply
2324         * @return this request
2325         */
2326        public SysIdSwerveSteerGains withVolts(Voltage volts) {
2327            VoltsToApply = volts.in(Volts);
2328            return this;
2329        }
2330    }
2331}