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 com.ctre.phoenix6.swerve.ffi.SwerveNative.*;
010import static org.wpilib.units.Units.*;
011
012import java.lang.foreign.Arena;
013import java.lang.foreign.ValueLayout;
014import java.util.HashMap;
015
016import com.ctre.phoenix6.StatusCode;
017import com.ctre.phoenix6.controls.CoastOut;
018import com.ctre.phoenix6.controls.PositionTorqueCurrentFOC;
019import com.ctre.phoenix6.controls.PositionVoltage;
020import com.ctre.phoenix6.controls.VoltageOut;
021import com.ctre.phoenix6.swerve.SwerveDrivetrain.SwerveControlParameters;
022import com.ctre.phoenix6.swerve.utility.PhoenixPIDController;
023
024import org.wpilib.math.geometry.Rotation2d;
025import org.wpilib.math.geometry.Translation2d;
026import org.wpilib.math.kinematics.ChassisVelocities;
027import org.wpilib.math.kinematics.SwerveDriveKinematics;
028import org.wpilib.units.measure.*;
029
030/**
031 * Container for all the Swerve Requests. Use this to find all applicable swerve
032 * drive requests.
033 * <p>
034 * This is also an interface common to all swerve drive control requests that
035 * allow the request to calculate the state to apply to the modules.
036 */
037public interface SwerveRequest {
038    /**
039     * In field-centric control, the direction of "forward" is sometimes different
040     * depending on perspective. This addresses which forward to use.
041     */
042    public enum ForwardPerspectiveValue {
043        /**
044         * "Forward" (positive X) is determined from the operator's perspective. This
045         * is important for most teleop driven field-centric requests, where positive
046         * X means to drive away from the operator.
047         * <p>
048         * Important: Users must specify the OperatorForwardDirection in the SwerveDrivetrain object.
049         */
050        OperatorPerspective(0),
051        /**
052         * "Forward" (positive X) is always from the perspective of the blue alliance (i.e. towards
053         * the red alliance). This is important in situations such as path following where positive
054         * X is always from the blue alliance perspective, regardless of where the operator is
055         * physically located.
056         */
057        BlueAlliance(1);
058
059        public final int value;
060
061        ForwardPerspectiveValue(int initValue) {
062            this.value = initValue;
063        }
064
065        private static HashMap<Integer, ForwardPerspectiveValue> _map = null;
066        static {
067            _map = new HashMap<Integer, ForwardPerspectiveValue>();
068            for (ForwardPerspectiveValue type : ForwardPerspectiveValue.values()) {
069                _map.put(type.value, type);
070            }
071        }
072
073        /**
074         * Gets ForwardPerspectiveValue from specified value
075         *
076         * @param value Value of ForwardPerspectiveValue
077         * @return ForwardPerspectiveValue of specified value
078         */
079        public static ForwardPerspectiveValue valueOf(int value) {
080            ForwardPerspectiveValue retval = _map.get(value);
081            if (retval != null)
082                return retval;
083            return ForwardPerspectiveValue.values()[0];
084        }
085    }
086
087    /**
088     * In field-centric control, the direction of "forward" for the target direction sometimes
089     * differs from "forward" for translation. This addresses which forward to use.
090     */
091    public enum TargetDirectionPerspectiveValue {
092        /**
093         * Match the ForwardPerspective parameter for heading control.
094         */
095        UseForwardPerspective(0),
096        /**
097         * "Forward" (0 deg) is always from the perspective of the blue alliance (i.e.
098         * towards the red alliance). This can be used to allow for the robot rotation to track
099         * vision targets while using operator-perspective joystick control for translation.
100         */
101        BlueAlliance(1);
102
103        public final int value;
104
105        TargetDirectionPerspectiveValue(int initValue) {
106            this.value = initValue;
107        }
108
109        private static HashMap<Integer, TargetDirectionPerspectiveValue> _map = null;
110        static {
111            _map = new HashMap<Integer, TargetDirectionPerspectiveValue>();
112            for (TargetDirectionPerspectiveValue type : TargetDirectionPerspectiveValue.values()) {
113                _map.put(type.value, type);
114            }
115        }
116
117        /**
118         * Gets TargetDirectionPerspectiveValue from specified value
119         *
120         * @param value Value of TargetDirectionPerspectiveValue
121         * @return TargetDirectionPerspectiveValue of specified value
122         */
123        public static TargetDirectionPerspectiveValue valueOf(int value) {
124            TargetDirectionPerspectiveValue retval = _map.get(value);
125            if (retval != null)
126                return retval;
127            return TargetDirectionPerspectiveValue.values()[0];
128        }
129    }
130
131    /**
132     * Applies this swerve request to the given modules. This is
133     * typically called by the SwerveDrivetrain odometry thread.
134     * <p>
135     * For native swerve requests, this API can be called from a
136     * non-native request's {@code apply} to compose the two together.
137     *
138     * @param parameters Parameters the control request needs to calculate the module state
139     * @param modulesToApply Modules to which the control request is applied
140     * @return Status code of sending the request
141     */
142    public StatusCode apply(SwerveControlParameters parameters, SwerveModule<?, ?, ?>... modulesToApply);
143
144    /** Swerve requests implemented in native code. */
145    public interface NativeSwerveRequest extends SwerveRequest {
146        /**
147         * Applies a native swerve request to the native drivetrain with the provided ID.
148         * <p>
149         * When this is implemented, the regular {@link #apply} function should do nothing
150         * (return OK). Additionally, this cannot be called from another swerve request's
151         * apply method, as this overrides the native swerve request of the drivetrain.
152         * <p>
153         * Unlike {@link #apply}, this function is called every time {@link SwerveDrivetrain#setControl}
154         * is run, not every loop of the odometry thread. Instead, the underlying native
155         * request is run at the full update frequency of the odometry thread.
156         *
157         * @param id ID of the native swerve drivetrain
158         */
159        public void applyNative(int id);
160    }
161
162
163    /**
164     * Does nothing to the swerve module state. This is the default state of a newly
165     * created swerve drive mechanism.
166     */
167    public static class Idle implements NativeSwerveRequest {
168
169
170
171        public StatusCode apply(SwerveControlParameters parameters, SwerveModule<?, ?, ?>... modulesToApply) {
172            return StatusCode.valueOf(c_ctre_phoenix6_swerve_request_apply_idle(
173                parameters.drivetrainId
174            ));
175        }
176
177        public void applyNative(int id) {
178            c_ctre_phoenix6_swerve_drivetrain_set_control_idle(
179                id
180            );
181        }
182    }
183
184    /**
185     * Sets the swerve drive module states to point inward on the robot in an "X"
186     * fashion, creating a natural brake which will oppose any motion.
187     */
188    public static class SwerveDriveBrake implements NativeSwerveRequest {
189        /**
190         * The type of control request to use for the drive motor.
191         */
192        public SwerveModule.DriveRequestType DriveRequestType = SwerveModule.DriveRequestType.OpenLoopVoltage;
193        /**
194         * The type of control request to use for the drive motor.
195         */
196        public SwerveModule.SteerRequestType SteerRequestType = SwerveModule.SteerRequestType.Position;
197
198        /**
199         * Modifies the DriveRequestType parameter and returns itself.
200         * <p>
201         * The type of control request to use for the drive motor.
202         *
203         * @param newDriveRequestType Parameter to modify
204         * @return this object
205         */
206        public final SwerveDriveBrake withDriveRequestType(SwerveModule.DriveRequestType newDriveRequestType) {
207            this.DriveRequestType = newDriveRequestType;
208            return this;
209        }
210
211        /**
212         * Modifies the SteerRequestType parameter and returns itself.
213         * <p>
214         * The type of control request to use for the drive motor.
215         *
216         * @param newSteerRequestType Parameter to modify
217         * @return this object
218         */
219        public final SwerveDriveBrake withSteerRequestType(SwerveModule.SteerRequestType newSteerRequestType) {
220            this.SteerRequestType = newSteerRequestType;
221            return this;
222        }
223
224        public StatusCode apply(SwerveControlParameters parameters, SwerveModule<?, ?, ?>... modulesToApply) {
225            return StatusCode.valueOf(c_ctre_phoenix6_swerve_request_apply_swerve_drive_brake(
226                parameters.drivetrainId,
227                DriveRequestType.value,
228                SteerRequestType.value
229            ));
230        }
231
232        public void applyNative(int id) {
233            c_ctre_phoenix6_swerve_drivetrain_set_control_swerve_drive_brake(
234                id,
235                DriveRequestType.value,
236                SteerRequestType.value
237            );
238        }
239    }
240
241    /**
242     * Drives the swerve drivetrain in a field-centric manner. This request is
243     * optimized for joystick control during teleop with built-in deadbands.
244     * <p>
245     * This request specifies the direction the robot should travel oriented against
246     * the field, and the rate at which their robot should rotate about the center
247     * of the robot.
248     * <p>
249     * An example scenario is that the robot is oriented to the field +Y (left), the
250     * VelocityX is +5 m/s, VelocityY is 0 m/s, and RotationRate is 0.5 rad/s. In
251     * this scenario, the robot would drive along the field +X (forward) at 5 m/s
252     * and turn counterclockwise at 0.5 rad/s.
253     */
254    public static class FieldCentric implements NativeSwerveRequest {
255        /**
256         * The velocity in the X direction, in m/s. X is defined as forward according to
257         * WPILib convention, so this determines how fast to travel forward.
258         */
259        public double VelocityX = 0;
260        /**
261         * The velocity in the Y direction, in m/s. Y is defined as to the left
262         * according to WPILib convention, so this determines how fast to travel to the
263         * left.
264         */
265        public double VelocityY = 0;
266        /**
267         * The angular rate to rotate at, in radians per second. Angular rate is defined
268         * as counterclockwise positive, so this determines how fast to turn
269         * counterclockwise.
270         */
271        public double RotationalRate = 0;
272        /**
273         * The allowable deadband of the request, in m/s.
274         */
275        public double Deadband = 0;
276        /**
277         * The rotational deadband of the request, in radians per second.
278         */
279        public double RotationalDeadband = 0;
280        /**
281         * The center of rotation the robot should rotate around. This is (0,0) by
282         * default, which will rotate around the center of the robot.
283         */
284        public Translation2d CenterOfRotation = new Translation2d();
285        /**
286         * The type of control request to use for the drive motor.
287         */
288        public SwerveModule.DriveRequestType DriveRequestType = SwerveModule.DriveRequestType.OpenLoopVoltage;
289        /**
290         * The type of control request to use for the drive motor.
291         */
292        public SwerveModule.SteerRequestType SteerRequestType = SwerveModule.SteerRequestType.Position;
293        /**
294         * Whether to desaturate wheel velocities before applying. For more information,
295         * see the documentation of {@link
296         * SwerveDriveKinematics#desaturateWheelVelocities}.
297         */
298        public boolean DesaturateWheelVelocities = true;
299        /**
300         * The perspective to use when determining which direction is forward.
301         */
302        public ForwardPerspectiveValue ForwardPerspective = ForwardPerspectiveValue.OperatorPerspective;
303
304        /**
305         * Modifies the VelocityX parameter and returns itself.
306         * <p>
307         * The velocity in the X direction, in m/s. X is defined as forward according to
308         * WPILib convention, so this determines how fast to travel forward.
309         *
310         * @param newVelocityX Parameter to modify
311         * @return this object
312         */
313        public final FieldCentric withVelocityX(double newVelocityX) {
314            this.VelocityX = newVelocityX;
315            return this;
316        }
317
318        /**
319         * Modifies the VelocityX parameter and returns itself.
320         * <p>
321         * The velocity in the X direction, in m/s. X is defined as forward according to
322         * WPILib convention, so this determines how fast to travel forward.
323         *
324         * @param newVelocityX Parameter to modify
325         * @return this object
326         */
327        public final FieldCentric withVelocityX(LinearVelocity newVelocityX) {
328            this.VelocityX = newVelocityX.in(MetersPerSecond);
329            return this;
330        }
331
332        /**
333         * Modifies the VelocityY parameter and returns itself.
334         * <p>
335         * The velocity in the Y direction, in m/s. Y is defined as to the left
336         * according to WPILib convention, so this determines how fast to travel to the
337         * left.
338         *
339         * @param newVelocityY Parameter to modify
340         * @return this object
341         */
342        public final FieldCentric withVelocityY(double newVelocityY) {
343            this.VelocityY = newVelocityY;
344            return this;
345        }
346
347        /**
348         * Modifies the VelocityY parameter and returns itself.
349         * <p>
350         * The velocity in the Y direction, in m/s. Y is defined as to the left
351         * according to WPILib convention, so this determines how fast to travel to the
352         * left.
353         *
354         * @param newVelocityY Parameter to modify
355         * @return this object
356         */
357        public final FieldCentric withVelocityY(LinearVelocity newVelocityY) {
358            this.VelocityY = newVelocityY.in(MetersPerSecond);
359            return this;
360        }
361
362        /**
363         * Modifies the RotationalRate parameter and returns itself.
364         * <p>
365         * The angular rate to rotate at, in radians per second. Angular rate is defined
366         * as counterclockwise positive, so this determines how fast to turn
367         * counterclockwise.
368         *
369         * @param newRotationalRate Parameter to modify
370         * @return this object
371         */
372        public final FieldCentric withRotationalRate(double newRotationalRate) {
373            this.RotationalRate = newRotationalRate;
374            return this;
375        }
376
377        /**
378         * Modifies the RotationalRate parameter and returns itself.
379         * <p>
380         * The angular rate to rotate at, in radians per second. Angular rate is defined
381         * as counterclockwise positive, so this determines how fast to turn
382         * counterclockwise.
383         *
384         * @param newRotationalRate Parameter to modify
385         * @return this object
386         */
387        public final FieldCentric withRotationalRate(AngularVelocity newRotationalRate) {
388            this.RotationalRate = newRotationalRate.in(RadiansPerSecond);
389            return this;
390        }
391
392        /**
393         * Modifies the Deadband parameter and returns itself.
394         * <p>
395         * The allowable deadband of the request, in m/s.
396         *
397         * @param newDeadband Parameter to modify
398         * @return this object
399         */
400        public final FieldCentric withDeadband(double newDeadband) {
401            this.Deadband = newDeadband;
402            return this;
403        }
404
405        /**
406         * Modifies the Deadband parameter and returns itself.
407         * <p>
408         * The allowable deadband of the request, in m/s.
409         *
410         * @param newDeadband Parameter to modify
411         * @return this object
412         */
413        public final FieldCentric withDeadband(LinearVelocity newDeadband) {
414            this.Deadband = newDeadband.in(MetersPerSecond);
415            return this;
416        }
417
418        /**
419         * Modifies the RotationalDeadband parameter and returns itself.
420         * <p>
421         * The rotational deadband of the request, in radians per second.
422         *
423         * @param newRotationalDeadband Parameter to modify
424         * @return this object
425         */
426        public final FieldCentric withRotationalDeadband(double newRotationalDeadband) {
427            this.RotationalDeadband = newRotationalDeadband;
428            return this;
429        }
430
431        /**
432         * Modifies the RotationalDeadband parameter and returns itself.
433         * <p>
434         * The rotational deadband of the request, in radians per second.
435         *
436         * @param newRotationalDeadband Parameter to modify
437         * @return this object
438         */
439        public final FieldCentric withRotationalDeadband(AngularVelocity newRotationalDeadband) {
440            this.RotationalDeadband = newRotationalDeadband.in(RadiansPerSecond);
441            return this;
442        }
443
444        /**
445         * Modifies the CenterOfRotation parameter and returns itself.
446         * <p>
447         * The center of rotation the robot should rotate around. This is (0,0) by
448         * default, which will rotate around the center of the robot.
449         *
450         * @param newCenterOfRotation Parameter to modify
451         * @return this object
452         */
453        public final FieldCentric withCenterOfRotation(Translation2d newCenterOfRotation) {
454            this.CenterOfRotation = newCenterOfRotation;
455            return this;
456        }
457
458        /**
459         * Modifies the DriveRequestType parameter and returns itself.
460         * <p>
461         * The type of control request to use for the drive motor.
462         *
463         * @param newDriveRequestType Parameter to modify
464         * @return this object
465         */
466        public final FieldCentric withDriveRequestType(SwerveModule.DriveRequestType newDriveRequestType) {
467            this.DriveRequestType = newDriveRequestType;
468            return this;
469        }
470
471        /**
472         * Modifies the SteerRequestType parameter and returns itself.
473         * <p>
474         * The type of control request to use for the drive motor.
475         *
476         * @param newSteerRequestType Parameter to modify
477         * @return this object
478         */
479        public final FieldCentric withSteerRequestType(SwerveModule.SteerRequestType newSteerRequestType) {
480            this.SteerRequestType = newSteerRequestType;
481            return this;
482        }
483
484        /**
485         * Modifies the DesaturateWheelVelocities parameter and returns itself.
486         * <p>
487         * Whether to desaturate wheel velocities before applying. For more information,
488         * see the documentation of {@link
489         * SwerveDriveKinematics#desaturateWheelVelocities}.
490         *
491         * @param newDesaturateWheelVelocities Parameter to modify
492         * @return this object
493         */
494        public final FieldCentric withDesaturateWheelVelocities(boolean newDesaturateWheelVelocities) {
495            this.DesaturateWheelVelocities = newDesaturateWheelVelocities;
496            return this;
497        }
498
499        /**
500         * Modifies the ForwardPerspective parameter and returns itself.
501         * <p>
502         * The perspective to use when determining which direction is forward.
503         *
504         * @param newForwardPerspective Parameter to modify
505         * @return this object
506         */
507        public final FieldCentric withForwardPerspective(ForwardPerspectiveValue newForwardPerspective) {
508            this.ForwardPerspective = newForwardPerspective;
509            return this;
510        }
511
512        public StatusCode apply(SwerveControlParameters parameters, SwerveModule<?, ?, ?>... modulesToApply) {
513            return StatusCode.valueOf(c_ctre_phoenix6_swerve_request_apply_field_centric(
514                parameters.drivetrainId,
515                VelocityX,
516                VelocityY,
517                RotationalRate,
518                Deadband,
519                RotationalDeadband,
520                CenterOfRotation.getX(),
521                CenterOfRotation.getY(),
522                DriveRequestType.value,
523                SteerRequestType.value,
524                DesaturateWheelVelocities,
525                ForwardPerspective.value
526            ));
527        }
528
529        public void applyNative(int id) {
530            c_ctre_phoenix6_swerve_drivetrain_set_control_field_centric(
531                id,
532                VelocityX,
533                VelocityY,
534                RotationalRate,
535                Deadband,
536                RotationalDeadband,
537                CenterOfRotation.getX(),
538                CenterOfRotation.getY(),
539                DriveRequestType.value,
540                SteerRequestType.value,
541                DesaturateWheelVelocities,
542                ForwardPerspective.value
543            );
544        }
545    }
546
547    /**
548     * Drives the swerve drivetrain in a robot-centric manner. This request is
549     * optimized for joystick control during teleop with built-in deadbands.
550     * <p>
551     * This request specifies the direction the robot should travel oriented against
552     * the robot itself, and the rate at which their robot should rotate about the
553     * center of the robot.
554     * <p>
555     * An example scenario is that the robot is oriented to the field +Y (left), the
556     * VelocityX is +5 m/s, VelocityY is 0 m/s, and RotationRate is 0.5 rad/s. In
557     * this scenario, the robot would drive forward relative to itself (or left
558     * along the field +Y) at 5 m/s and turn counterclockwise at 0.5 rad/s.
559     */
560    public static class RobotCentric implements NativeSwerveRequest {
561        /**
562         * The velocity in the X direction, in m/s. X is defined as forward according to
563         * WPILib convention, so this determines how fast to travel forward.
564         */
565        public double VelocityX = 0;
566        /**
567         * The velocity in the Y direction, in m/s. Y is defined as to the left
568         * according to WPILib convention, so this determines how fast to travel to the
569         * left.
570         */
571        public double VelocityY = 0;
572        /**
573         * The angular rate to rotate at, in radians per second. Angular rate is defined
574         * as counterclockwise positive, so this determines how fast to turn
575         * counterclockwise.
576         */
577        public double RotationalRate = 0;
578        /**
579         * The allowable deadband of the request, in m/s.
580         */
581        public double Deadband = 0;
582        /**
583         * The rotational deadband of the request, in radians per second.
584         */
585        public double RotationalDeadband = 0;
586        /**
587         * The center of rotation the robot should rotate around. This is (0,0) by
588         * default, which will rotate around the center of the robot.
589         */
590        public Translation2d CenterOfRotation = new Translation2d();
591        /**
592         * The type of control request to use for the drive motor.
593         */
594        public SwerveModule.DriveRequestType DriveRequestType = SwerveModule.DriveRequestType.OpenLoopVoltage;
595        /**
596         * The type of control request to use for the drive motor.
597         */
598        public SwerveModule.SteerRequestType SteerRequestType = SwerveModule.SteerRequestType.Position;
599        /**
600         * Whether to desaturate wheel velocities before applying. For more information,
601         * see the documentation of {@link
602         * SwerveDriveKinematics#desaturateWheelVelocities}.
603         */
604        public boolean DesaturateWheelVelocities = true;
605
606        /**
607         * Modifies the VelocityX parameter and returns itself.
608         * <p>
609         * The velocity in the X direction, in m/s. X is defined as forward according to
610         * WPILib convention, so this determines how fast to travel forward.
611         *
612         * @param newVelocityX Parameter to modify
613         * @return this object
614         */
615        public final RobotCentric withVelocityX(double newVelocityX) {
616            this.VelocityX = newVelocityX;
617            return this;
618        }
619
620        /**
621         * Modifies the VelocityX parameter and returns itself.
622         * <p>
623         * The velocity in the X direction, in m/s. X is defined as forward according to
624         * WPILib convention, so this determines how fast to travel forward.
625         *
626         * @param newVelocityX Parameter to modify
627         * @return this object
628         */
629        public final RobotCentric withVelocityX(LinearVelocity newVelocityX) {
630            this.VelocityX = newVelocityX.in(MetersPerSecond);
631            return this;
632        }
633
634        /**
635         * Modifies the VelocityY parameter and returns itself.
636         * <p>
637         * The velocity in the Y direction, in m/s. Y is defined as to the left
638         * according to WPILib convention, so this determines how fast to travel to the
639         * left.
640         *
641         * @param newVelocityY Parameter to modify
642         * @return this object
643         */
644        public final RobotCentric withVelocityY(double newVelocityY) {
645            this.VelocityY = newVelocityY;
646            return this;
647        }
648
649        /**
650         * Modifies the VelocityY parameter and returns itself.
651         * <p>
652         * The velocity in the Y direction, in m/s. Y is defined as to the left
653         * according to WPILib convention, so this determines how fast to travel to the
654         * left.
655         *
656         * @param newVelocityY Parameter to modify
657         * @return this object
658         */
659        public final RobotCentric withVelocityY(LinearVelocity newVelocityY) {
660            this.VelocityY = newVelocityY.in(MetersPerSecond);
661            return this;
662        }
663
664        /**
665         * Modifies the RotationalRate parameter and returns itself.
666         * <p>
667         * The angular rate to rotate at, in radians per second. Angular rate is defined
668         * as counterclockwise positive, so this determines how fast to turn
669         * counterclockwise.
670         *
671         * @param newRotationalRate Parameter to modify
672         * @return this object
673         */
674        public final RobotCentric withRotationalRate(double newRotationalRate) {
675            this.RotationalRate = newRotationalRate;
676            return this;
677        }
678
679        /**
680         * Modifies the RotationalRate parameter and returns itself.
681         * <p>
682         * The angular rate to rotate at, in radians per second. Angular rate is defined
683         * as counterclockwise positive, so this determines how fast to turn
684         * counterclockwise.
685         *
686         * @param newRotationalRate Parameter to modify
687         * @return this object
688         */
689        public final RobotCentric withRotationalRate(AngularVelocity newRotationalRate) {
690            this.RotationalRate = newRotationalRate.in(RadiansPerSecond);
691            return this;
692        }
693
694        /**
695         * Modifies the Deadband parameter and returns itself.
696         * <p>
697         * The allowable deadband of the request, in m/s.
698         *
699         * @param newDeadband Parameter to modify
700         * @return this object
701         */
702        public final RobotCentric withDeadband(double newDeadband) {
703            this.Deadband = newDeadband;
704            return this;
705        }
706
707        /**
708         * Modifies the Deadband parameter and returns itself.
709         * <p>
710         * The allowable deadband of the request, in m/s.
711         *
712         * @param newDeadband Parameter to modify
713         * @return this object
714         */
715        public final RobotCentric withDeadband(LinearVelocity newDeadband) {
716            this.Deadband = newDeadband.in(MetersPerSecond);
717            return this;
718        }
719
720        /**
721         * Modifies the RotationalDeadband parameter and returns itself.
722         * <p>
723         * The rotational deadband of the request, in radians per second.
724         *
725         * @param newRotationalDeadband Parameter to modify
726         * @return this object
727         */
728        public final RobotCentric withRotationalDeadband(double newRotationalDeadband) {
729            this.RotationalDeadband = newRotationalDeadband;
730            return this;
731        }
732
733        /**
734         * Modifies the RotationalDeadband parameter and returns itself.
735         * <p>
736         * The rotational deadband of the request, in radians per second.
737         *
738         * @param newRotationalDeadband Parameter to modify
739         * @return this object
740         */
741        public final RobotCentric withRotationalDeadband(AngularVelocity newRotationalDeadband) {
742            this.RotationalDeadband = newRotationalDeadband.in(RadiansPerSecond);
743            return this;
744        }
745
746        /**
747         * Modifies the CenterOfRotation parameter and returns itself.
748         * <p>
749         * The center of rotation the robot should rotate around. This is (0,0) by
750         * default, which will rotate around the center of the robot.
751         *
752         * @param newCenterOfRotation Parameter to modify
753         * @return this object
754         */
755        public final RobotCentric withCenterOfRotation(Translation2d newCenterOfRotation) {
756            this.CenterOfRotation = newCenterOfRotation;
757            return this;
758        }
759
760        /**
761         * Modifies the DriveRequestType parameter and returns itself.
762         * <p>
763         * The type of control request to use for the drive motor.
764         *
765         * @param newDriveRequestType Parameter to modify
766         * @return this object
767         */
768        public final RobotCentric withDriveRequestType(SwerveModule.DriveRequestType newDriveRequestType) {
769            this.DriveRequestType = newDriveRequestType;
770            return this;
771        }
772
773        /**
774         * Modifies the SteerRequestType parameter and returns itself.
775         * <p>
776         * The type of control request to use for the drive motor.
777         *
778         * @param newSteerRequestType Parameter to modify
779         * @return this object
780         */
781        public final RobotCentric withSteerRequestType(SwerveModule.SteerRequestType newSteerRequestType) {
782            this.SteerRequestType = newSteerRequestType;
783            return this;
784        }
785
786        /**
787         * Modifies the DesaturateWheelVelocities parameter and returns itself.
788         * <p>
789         * Whether to desaturate wheel velocities before applying. For more information,
790         * see the documentation of {@link
791         * SwerveDriveKinematics#desaturateWheelVelocities}.
792         *
793         * @param newDesaturateWheelVelocities Parameter to modify
794         * @return this object
795         */
796        public final RobotCentric withDesaturateWheelVelocities(boolean newDesaturateWheelVelocities) {
797            this.DesaturateWheelVelocities = newDesaturateWheelVelocities;
798            return this;
799        }
800
801        public StatusCode apply(SwerveControlParameters parameters, SwerveModule<?, ?, ?>... modulesToApply) {
802            return StatusCode.valueOf(c_ctre_phoenix6_swerve_request_apply_robot_centric(
803                parameters.drivetrainId,
804                VelocityX,
805                VelocityY,
806                RotationalRate,
807                Deadband,
808                RotationalDeadband,
809                CenterOfRotation.getX(),
810                CenterOfRotation.getY(),
811                DriveRequestType.value,
812                SteerRequestType.value,
813                DesaturateWheelVelocities
814            ));
815        }
816
817        public void applyNative(int id) {
818            c_ctre_phoenix6_swerve_drivetrain_set_control_robot_centric(
819                id,
820                VelocityX,
821                VelocityY,
822                RotationalRate,
823                Deadband,
824                RotationalDeadband,
825                CenterOfRotation.getX(),
826                CenterOfRotation.getY(),
827                DriveRequestType.value,
828                SteerRequestType.value,
829                DesaturateWheelVelocities
830            );
831        }
832    }
833
834    /**
835     * Sets the swerve drive modules to point to a specified direction.
836     */
837    public static class PointWheelsAt implements NativeSwerveRequest {
838        /**
839         * The direction to point the modules toward. This direction is still optimized
840         * to what the module was previously at.
841         */
842        public Rotation2d ModuleDirection = new Rotation2d();
843        /**
844         * The type of control request to use for the drive motor.
845         */
846        public SwerveModule.DriveRequestType DriveRequestType = SwerveModule.DriveRequestType.OpenLoopVoltage;
847        /**
848         * The type of control request to use for the drive motor.
849         */
850        public SwerveModule.SteerRequestType SteerRequestType = SwerveModule.SteerRequestType.Position;
851
852        /**
853         * Modifies the ModuleDirection parameter and returns itself.
854         * <p>
855         * The direction to point the modules toward. This direction is still optimized
856         * to what the module was previously at.
857         *
858         * @param newModuleDirection Parameter to modify
859         * @return this object
860         */
861        public final PointWheelsAt withModuleDirection(Rotation2d newModuleDirection) {
862            this.ModuleDirection = newModuleDirection;
863            return this;
864        }
865
866        /**
867         * Modifies the DriveRequestType parameter and returns itself.
868         * <p>
869         * The type of control request to use for the drive motor.
870         *
871         * @param newDriveRequestType Parameter to modify
872         * @return this object
873         */
874        public final PointWheelsAt withDriveRequestType(SwerveModule.DriveRequestType newDriveRequestType) {
875            this.DriveRequestType = newDriveRequestType;
876            return this;
877        }
878
879        /**
880         * Modifies the SteerRequestType parameter and returns itself.
881         * <p>
882         * The type of control request to use for the drive motor.
883         *
884         * @param newSteerRequestType Parameter to modify
885         * @return this object
886         */
887        public final PointWheelsAt withSteerRequestType(SwerveModule.SteerRequestType newSteerRequestType) {
888            this.SteerRequestType = newSteerRequestType;
889            return this;
890        }
891
892        public StatusCode apply(SwerveControlParameters parameters, SwerveModule<?, ?, ?>... modulesToApply) {
893            return StatusCode.valueOf(c_ctre_phoenix6_swerve_request_apply_point_wheels_at(
894                parameters.drivetrainId,
895                ModuleDirection.getRadians(),
896                DriveRequestType.value,
897                SteerRequestType.value
898            ));
899        }
900
901        public void applyNative(int id) {
902            c_ctre_phoenix6_swerve_drivetrain_set_control_point_wheels_at(
903                id,
904                ModuleDirection.getRadians(),
905                DriveRequestType.value,
906                SteerRequestType.value
907            );
908        }
909    }
910
911    /**
912     * Accepts a generic robot-centric ChassisVelocities to apply to the drivetrain.
913     * This request is optimized for autonomous or profiled control, which typically
914     * directly provides ChassisVelocities and optionally wheel force feedforwards.
915     * <p>
916     * Unlike the field-centric requests, this request does not automatically
917     * discretize the provided ChassisVelocities.
918     */
919    public static class ApplyRobotVelocity implements NativeSwerveRequest {
920        /**
921         * The robot-centric chassis velocity to apply to the drivetrain.
922         * Users must manually discretize the velocity if appropriate.
923         */
924        public ChassisVelocities Velocity = new ChassisVelocities();
925        /**
926         * Robot-centric wheel force feedforwards to apply in the X direction, in
927         * newtons. X is defined as forward according to WPILib convention, so this
928         * determines the forward forces to apply.
929         * <p>
930         * These forces should include friction applied to the ground.
931         * <p>
932         * The order of the forces should match the order of the modules returned from
933         * SwerveDrivetrain.
934         */
935        public double[] WheelForceFeedforwardsX = {};
936        /**
937         * Robot-centric wheel force feedforwards to apply in the Y direction, in
938         * newtons. Y is defined as to the left according to WPILib convention, so this
939         * determines the forces to apply to the left.
940         * <p>
941         * These forces should include friction applied to the ground.
942         * <p>
943         * The order of the forces should match the order of the modules returned from
944         * SwerveDrivetrain.
945         */
946        public double[] WheelForceFeedforwardsY = {};
947        /**
948         * The center of rotation the robot should rotate around. This is (0,0) by
949         * default, which will rotate around the center of the robot.
950         */
951        public Translation2d CenterOfRotation = new Translation2d();
952        /**
953         * The type of control request to use for the drive motor.
954         */
955        public SwerveModule.DriveRequestType DriveRequestType = SwerveModule.DriveRequestType.OpenLoopVoltage;
956        /**
957         * The type of control request to use for the drive motor.
958         */
959        public SwerveModule.SteerRequestType SteerRequestType = SwerveModule.SteerRequestType.Position;
960        /**
961         * Whether to desaturate wheel velocities before applying. For more information, see
962         * the documentation of {@link SwerveDriveKinematics#desaturateWheelVelocities}.
963         */
964        public boolean DesaturateWheelVelocities = true;
965    
966        /**
967         * Modifies the Velocity parameter and returns itself.
968         * <p>
969         * The robot-centric chassis velocity to apply to the drivetrain.
970         * Users must manually discretize the velocity if appropriate.
971         *
972         * @param newVelocity Parameter to modify
973         * @return this object
974         */
975        public final ApplyRobotVelocity withVelocity(ChassisVelocities newVelocity) {
976            this.Velocity = newVelocity;
977            return this;
978        }
979        
980        /**
981         * Modifies the WheelForceFeedforwardsX parameter and returns itself.
982         * <p>
983         * Robot-centric wheel force feedforwards to apply in the X direction, in
984         * newtons. X is defined as forward according to WPILib convention, so this
985         * determines the forward forces to apply.
986         * <p>
987         * These forces should include friction applied to the ground.
988         * <p>
989         * The order of the forces should match the order of the modules returned from
990         * SwerveDrivetrain.
991         *
992         * @param newWheelForceFeedforwardsX Parameter to modify
993         * @return this object
994         */
995        public final ApplyRobotVelocity withWheelForceFeedforwardsX(double[] newWheelForceFeedforwardsX) {
996            this.WheelForceFeedforwardsX = newWheelForceFeedforwardsX;
997            return this;
998        }
999        
1000        /**
1001         * Modifies the WheelForceFeedforwardsX parameter and returns itself.
1002         * <p>
1003         * Robot-centric wheel force feedforwards to apply in the X direction, in
1004         * newtons. X is defined as forward according to WPILib convention, so this
1005         * determines the forward forces to apply.
1006         * <p>
1007         * These forces should include friction applied to the ground.
1008         * <p>
1009         * The order of the forces should match the order of the modules returned from
1010         * SwerveDrivetrain.
1011         *
1012         * @param newWheelForceFeedforwardsX Parameter to modify
1013         * @return this object
1014         */
1015        public final ApplyRobotVelocity withWheelForceFeedforwardsX(Force[] newWheelForceFeedforwardsX) {
1016            if (this.WheelForceFeedforwardsX.length != newWheelForceFeedforwardsX.length) {
1017                this.WheelForceFeedforwardsX = new double[newWheelForceFeedforwardsX.length];
1018            }
1019            for (int i = 0; i < this.WheelForceFeedforwardsX.length; ++i) {
1020                this.WheelForceFeedforwardsX[i] = newWheelForceFeedforwardsX[i].in(Newtons);
1021            }
1022
1023            return this;
1024        }
1025        
1026        /**
1027         * Modifies the WheelForceFeedforwardsY parameter and returns itself.
1028         * <p>
1029         * Robot-centric wheel force feedforwards to apply in the Y direction, in
1030         * newtons. Y is defined as to the left according to WPILib convention, so this
1031         * determines the forces to apply to the left.
1032         * <p>
1033         * These forces should include friction applied to the ground.
1034         * <p>
1035         * The order of the forces should match the order of the modules returned from
1036         * SwerveDrivetrain.
1037         *
1038         * @param newWheelForceFeedforwardsY Parameter to modify
1039         * @return this object
1040         */
1041        public final ApplyRobotVelocity withWheelForceFeedforwardsY(double[] newWheelForceFeedforwardsY) {
1042            this.WheelForceFeedforwardsY = newWheelForceFeedforwardsY;
1043            return this;
1044        }
1045        
1046        /**
1047         * Modifies the WheelForceFeedforwardsY parameter and returns itself.
1048         * <p>
1049         * Robot-centric wheel force feedforwards to apply in the Y direction, in
1050         * newtons. Y is defined as to the left according to WPILib convention, so this
1051         * determines the forces to apply to the left.
1052         * <p>
1053         * These forces should include friction applied to the ground.
1054         * <p>
1055         * The order of the forces should match the order of the modules returned from
1056         * SwerveDrivetrain.
1057         *
1058         * @param newWheelForceFeedforwardsY Parameter to modify
1059         * @return this object
1060         */
1061        public final ApplyRobotVelocity withWheelForceFeedforwardsY(Force[] newWheelForceFeedforwardsY) {
1062            if (this.WheelForceFeedforwardsY.length != newWheelForceFeedforwardsY.length) {
1063                this.WheelForceFeedforwardsY = new double[newWheelForceFeedforwardsY.length];
1064            }
1065            for (int i = 0; i < this.WheelForceFeedforwardsY.length; ++i) {
1066                this.WheelForceFeedforwardsY[i] = newWheelForceFeedforwardsY[i].in(Newtons);
1067            }
1068
1069            return this;
1070        }
1071        
1072        /**
1073         * Modifies the CenterOfRotation parameter and returns itself.
1074         * <p>
1075         * The center of rotation the robot should rotate around. This is (0,0) by
1076         * default, which will rotate around the center of the robot.
1077         *
1078         * @param newCenterOfRotation Parameter to modify
1079         * @return this object
1080         */
1081        public final ApplyRobotVelocity withCenterOfRotation(Translation2d newCenterOfRotation) {
1082            this.CenterOfRotation = newCenterOfRotation;
1083            return this;
1084        }
1085        
1086        /**
1087         * Modifies the DriveRequestType parameter and returns itself.
1088         * <p>
1089         * The type of control request to use for the drive motor.
1090         *
1091         * @param newDriveRequestType Parameter to modify
1092         * @return this object
1093         */
1094        public final ApplyRobotVelocity withDriveRequestType(SwerveModule.DriveRequestType newDriveRequestType) {
1095            this.DriveRequestType = newDriveRequestType;
1096            return this;
1097        }
1098        
1099        /**
1100         * Modifies the SteerRequestType parameter and returns itself.
1101         * <p>
1102         * The type of control request to use for the drive motor.
1103         *
1104         * @param newSteerRequestType Parameter to modify
1105         * @return this object
1106         */
1107        public final ApplyRobotVelocity withSteerRequestType(SwerveModule.SteerRequestType newSteerRequestType) {
1108            this.SteerRequestType = newSteerRequestType;
1109            return this;
1110        }
1111        
1112        /**
1113         * Modifies the DesaturateWheelVelocities parameter and returns itself.
1114         * <p>
1115         * Whether to desaturate wheel velocities before applying. For more information, see
1116         * the documentation of {@link SwerveDriveKinematics#desaturateWheelVelocities}.
1117         *
1118         * @param newDesaturateWheelVelocities Parameter to modify
1119         * @return this object
1120         */
1121        public final ApplyRobotVelocity withDesaturateWheelVelocities(boolean newDesaturateWheelVelocities) {
1122            this.DesaturateWheelVelocities = newDesaturateWheelVelocities;
1123            return this;
1124        }
1125        
1126        public StatusCode apply(SwerveControlParameters parameters, SwerveModule<?, ?, ?>... modulesToApply) {
1127            try (final var arena = Arena.ofConfined()) {
1128                return StatusCode.valueOf(c_ctre_phoenix6_swerve_request_apply_apply_robot_velocity(
1129                    parameters.drivetrainId,
1130                    Velocity.vx,
1131                    Velocity.vy,
1132                    Velocity.omega,
1133                    arena.allocateFrom(ValueLayout.JAVA_DOUBLE, WheelForceFeedforwardsX),
1134                    WheelForceFeedforwardsX.length,
1135                    arena.allocateFrom(ValueLayout.JAVA_DOUBLE, WheelForceFeedforwardsY),
1136                    WheelForceFeedforwardsY.length,
1137                    CenterOfRotation.getX(),
1138                    CenterOfRotation.getY(),
1139                    DriveRequestType.value,
1140                    SteerRequestType.value,
1141                    DesaturateWheelVelocities
1142                ));
1143            }
1144        }
1145        
1146        public void applyNative(int id) {
1147            try (final var arena = Arena.ofConfined()) {
1148                c_ctre_phoenix6_swerve_drivetrain_set_control_apply_robot_velocity(
1149                    id,
1150                    Velocity.vx,
1151                    Velocity.vy,
1152                    Velocity.omega,
1153                    arena.allocateFrom(ValueLayout.JAVA_DOUBLE, WheelForceFeedforwardsX),
1154                    WheelForceFeedforwardsX.length,
1155                    arena.allocateFrom(ValueLayout.JAVA_DOUBLE, WheelForceFeedforwardsY),
1156                    WheelForceFeedforwardsY.length,
1157                    CenterOfRotation.getX(),
1158                    CenterOfRotation.getY(),
1159                    DriveRequestType.value,
1160                    SteerRequestType.value,
1161                    DesaturateWheelVelocities
1162                );
1163            }
1164        }
1165    }
1166
1167    /**
1168     * Accepts a generic field-centric ChassisVelocities to apply to the drivetrain.
1169     * This request is optimized for autonomous or profiled control, which typically
1170     * directly provides ChassisVelocities and optionally wheel force feedforwards.
1171     */
1172    public static class ApplyFieldVelocity implements NativeSwerveRequest {
1173        /**
1174         * The field-centric chassis velocity to apply to the drivetrain.
1175         */
1176        public ChassisVelocities Velocity = new ChassisVelocities();
1177        /**
1178         * Field-centric wheel force feedforwards to apply in the X direction, in
1179         * newtons. X is defined as forward according to WPILib convention, so this
1180         * determines the forward forces to apply.
1181         * <p>
1182         * These forces should include friction applied to the ground.
1183         * <p>
1184         * The order of the forces should match the order of the modules returned from
1185         * SwerveDrivetrain.
1186         */
1187        public double[] WheelForceFeedforwardsX = {};
1188        /**
1189         * Field-centric wheel force feedforwards to apply in the Y direction, in
1190         * newtons. Y is defined as to the left according to WPILib convention, so this
1191         * determines the forces to apply to the left.
1192         * <p>
1193         * These forces should include friction applied to the ground.
1194         * <p>
1195         * The order of the forces should match the order of the modules returned from
1196         * SwerveDrivetrain.
1197         */
1198        public double[] WheelForceFeedforwardsY = {};
1199        /**
1200         * The center of rotation the robot should rotate around. This is (0,0) by
1201         * default, which will rotate around the center of the robot.
1202         */
1203        public Translation2d CenterOfRotation = new Translation2d();
1204        /**
1205         * The type of control request to use for the drive motor.
1206         */
1207        public SwerveModule.DriveRequestType DriveRequestType = SwerveModule.DriveRequestType.OpenLoopVoltage;
1208        /**
1209         * The type of control request to use for the drive motor.
1210         */
1211        public SwerveModule.SteerRequestType SteerRequestType = SwerveModule.SteerRequestType.Position;
1212        /**
1213         * Whether to desaturate wheel velocities before applying. For more information, see
1214         * the documentation of {@link SwerveDriveKinematics#desaturateWheelVelocities}.
1215         */
1216        public boolean DesaturateWheelVelocities = true;
1217        /**
1218         * The perspective to use when determining which direction is forward.
1219         */
1220        public ForwardPerspectiveValue ForwardPerspective = ForwardPerspectiveValue.BlueAlliance;
1221    
1222        /**
1223         * Modifies the Velocity parameter and returns itself.
1224         * <p>
1225         * The field-centric chassis velocity to apply to the drivetrain.
1226         *
1227         * @param newVelocity Parameter to modify
1228         * @return this object
1229         */
1230        public final ApplyFieldVelocity withVelocity(ChassisVelocities newVelocity) {
1231            this.Velocity = newVelocity;
1232            return this;
1233        }
1234        
1235        /**
1236         * Modifies the WheelForceFeedforwardsX parameter and returns itself.
1237         * <p>
1238         * Field-centric wheel force feedforwards to apply in the X direction, in
1239         * newtons. X is defined as forward according to WPILib convention, so this
1240         * determines the forward forces to apply.
1241         * <p>
1242         * These forces should include friction applied to the ground.
1243         * <p>
1244         * The order of the forces should match the order of the modules returned from
1245         * SwerveDrivetrain.
1246         *
1247         * @param newWheelForceFeedforwardsX Parameter to modify
1248         * @return this object
1249         */
1250        public final ApplyFieldVelocity withWheelForceFeedforwardsX(double[] newWheelForceFeedforwardsX) {
1251            this.WheelForceFeedforwardsX = newWheelForceFeedforwardsX;
1252            return this;
1253        }
1254        
1255        /**
1256         * Modifies the WheelForceFeedforwardsX parameter and returns itself.
1257         * <p>
1258         * Field-centric wheel force feedforwards to apply in the X direction, in
1259         * newtons. X is defined as forward according to WPILib convention, so this
1260         * determines the forward forces to apply.
1261         * <p>
1262         * These forces should include friction applied to the ground.
1263         * <p>
1264         * The order of the forces should match the order of the modules returned from
1265         * SwerveDrivetrain.
1266         *
1267         * @param newWheelForceFeedforwardsX Parameter to modify
1268         * @return this object
1269         */
1270        public final ApplyFieldVelocity withWheelForceFeedforwardsX(Force[] newWheelForceFeedforwardsX) {
1271            if (this.WheelForceFeedforwardsX.length != newWheelForceFeedforwardsX.length) {
1272                this.WheelForceFeedforwardsX = new double[newWheelForceFeedforwardsX.length];
1273            }
1274            for (int i = 0; i < this.WheelForceFeedforwardsX.length; ++i) {
1275                this.WheelForceFeedforwardsX[i] = newWheelForceFeedforwardsX[i].in(Newtons);
1276            }
1277
1278            return this;
1279        }
1280        
1281        /**
1282         * Modifies the WheelForceFeedforwardsY parameter and returns itself.
1283         * <p>
1284         * Field-centric wheel force feedforwards to apply in the Y direction, in
1285         * newtons. Y is defined as to the left according to WPILib convention, so this
1286         * determines the forces to apply to the left.
1287         * <p>
1288         * These forces should include friction applied to the ground.
1289         * <p>
1290         * The order of the forces should match the order of the modules returned from
1291         * SwerveDrivetrain.
1292         *
1293         * @param newWheelForceFeedforwardsY Parameter to modify
1294         * @return this object
1295         */
1296        public final ApplyFieldVelocity withWheelForceFeedforwardsY(double[] newWheelForceFeedforwardsY) {
1297            this.WheelForceFeedforwardsY = newWheelForceFeedforwardsY;
1298            return this;
1299        }
1300        
1301        /**
1302         * Modifies the WheelForceFeedforwardsY parameter and returns itself.
1303         * <p>
1304         * Field-centric wheel force feedforwards to apply in the Y direction, in
1305         * newtons. Y is defined as to the left according to WPILib convention, so this
1306         * determines the forces to apply to the left.
1307         * <p>
1308         * These forces should include friction applied to the ground.
1309         * <p>
1310         * The order of the forces should match the order of the modules returned from
1311         * SwerveDrivetrain.
1312         *
1313         * @param newWheelForceFeedforwardsY Parameter to modify
1314         * @return this object
1315         */
1316        public final ApplyFieldVelocity withWheelForceFeedforwardsY(Force[] newWheelForceFeedforwardsY) {
1317            if (this.WheelForceFeedforwardsY.length != newWheelForceFeedforwardsY.length) {
1318                this.WheelForceFeedforwardsY = new double[newWheelForceFeedforwardsY.length];
1319            }
1320            for (int i = 0; i < this.WheelForceFeedforwardsY.length; ++i) {
1321                this.WheelForceFeedforwardsY[i] = newWheelForceFeedforwardsY[i].in(Newtons);
1322            }
1323
1324            return this;
1325        }
1326        
1327        /**
1328         * Modifies the CenterOfRotation parameter and returns itself.
1329         * <p>
1330         * The center of rotation the robot should rotate around. This is (0,0) by
1331         * default, which will rotate around the center of the robot.
1332         *
1333         * @param newCenterOfRotation Parameter to modify
1334         * @return this object
1335         */
1336        public final ApplyFieldVelocity withCenterOfRotation(Translation2d newCenterOfRotation) {
1337            this.CenterOfRotation = newCenterOfRotation;
1338            return this;
1339        }
1340        
1341        /**
1342         * Modifies the DriveRequestType parameter and returns itself.
1343         * <p>
1344         * The type of control request to use for the drive motor.
1345         *
1346         * @param newDriveRequestType Parameter to modify
1347         * @return this object
1348         */
1349        public final ApplyFieldVelocity withDriveRequestType(SwerveModule.DriveRequestType newDriveRequestType) {
1350            this.DriveRequestType = newDriveRequestType;
1351            return this;
1352        }
1353        
1354        /**
1355         * Modifies the SteerRequestType parameter and returns itself.
1356         * <p>
1357         * The type of control request to use for the drive motor.
1358         *
1359         * @param newSteerRequestType Parameter to modify
1360         * @return this object
1361         */
1362        public final ApplyFieldVelocity withSteerRequestType(SwerveModule.SteerRequestType newSteerRequestType) {
1363            this.SteerRequestType = newSteerRequestType;
1364            return this;
1365        }
1366        
1367        /**
1368         * Modifies the DesaturateWheelVelocities parameter and returns itself.
1369         * <p>
1370         * Whether to desaturate wheel velocities before applying. For more information, see
1371         * the documentation of {@link SwerveDriveKinematics#desaturateWheelVelocities}.
1372         *
1373         * @param newDesaturateWheelVelocities Parameter to modify
1374         * @return this object
1375         */
1376        public final ApplyFieldVelocity withDesaturateWheelVelocities(boolean newDesaturateWheelVelocities) {
1377            this.DesaturateWheelVelocities = newDesaturateWheelVelocities;
1378            return this;
1379        }
1380        
1381        /**
1382         * Modifies the ForwardPerspective parameter and returns itself.
1383         * <p>
1384         * The perspective to use when determining which direction is forward.
1385         *
1386         * @param newForwardPerspective Parameter to modify
1387         * @return this object
1388         */
1389        public final ApplyFieldVelocity withForwardPerspective(ForwardPerspectiveValue newForwardPerspective) {
1390            this.ForwardPerspective = newForwardPerspective;
1391            return this;
1392        }
1393        
1394        public StatusCode apply(SwerveControlParameters parameters, SwerveModule<?, ?, ?>... modulesToApply) {
1395            try (final var arena = Arena.ofConfined()) {
1396                return StatusCode.valueOf(c_ctre_phoenix6_swerve_request_apply_apply_field_velocity(
1397                    parameters.drivetrainId,
1398                    Velocity.vx,
1399                    Velocity.vy,
1400                    Velocity.omega,
1401                    arena.allocateFrom(ValueLayout.JAVA_DOUBLE, WheelForceFeedforwardsX),
1402                    WheelForceFeedforwardsX.length,
1403                    arena.allocateFrom(ValueLayout.JAVA_DOUBLE, WheelForceFeedforwardsY),
1404                    WheelForceFeedforwardsY.length,
1405                    CenterOfRotation.getX(),
1406                    CenterOfRotation.getY(),
1407                    DriveRequestType.value,
1408                    SteerRequestType.value,
1409                    DesaturateWheelVelocities,
1410                    ForwardPerspective.value
1411                ));
1412            }
1413        }
1414        
1415        public void applyNative(int id) {
1416            try (final var arena = Arena.ofConfined()) {
1417                c_ctre_phoenix6_swerve_drivetrain_set_control_apply_field_velocity(
1418                    id,
1419                    Velocity.vx,
1420                    Velocity.vy,
1421                    Velocity.omega,
1422                    arena.allocateFrom(ValueLayout.JAVA_DOUBLE, WheelForceFeedforwardsX),
1423                    WheelForceFeedforwardsX.length,
1424                    arena.allocateFrom(ValueLayout.JAVA_DOUBLE, WheelForceFeedforwardsY),
1425                    WheelForceFeedforwardsY.length,
1426                    CenterOfRotation.getX(),
1427                    CenterOfRotation.getY(),
1428                    DriveRequestType.value,
1429                    SteerRequestType.value,
1430                    DesaturateWheelVelocities,
1431                    ForwardPerspective.value
1432                );
1433            }
1434        }
1435    }
1436
1437    /**
1438     * Drives the swerve drivetrain in a field-centric manner, maintaining a
1439     * specified heading angle to ensure the robot is facing the desired direction
1440     * <p>
1441     * When users use this request, they specify the direction the robot should
1442     * travel oriented against the field, and the direction the robot should be facing.
1443     * <p>
1444     * An example scenario is that the robot is oriented to the east, the VelocityX
1445     * is +5 m/s, VelocityY is 0 m/s, and TargetDirection is 180 degrees.
1446     * In this scenario, the robot would drive northward at 5 m/s and turn clockwise
1447     * to a target of 180 degrees.
1448     * <p>
1449     * This control request is especially useful for autonomous control, where the
1450     * robot should be facing a changing direction throughout the motion.
1451     */
1452    public static class FieldCentricFacingAngle implements SwerveRequest {
1453        /**
1454         * The velocity in the X direction, in m/s.
1455         * X is defined as forward according to WPILib convention,
1456         * so this determines how fast to travel forward.
1457         */
1458        public double VelocityX = 0;
1459        /**
1460         * The velocity in the Y direction, in m/s.
1461         * Y is defined as to the left according to WPILib convention,
1462         * so this determines how fast to travel to the left.
1463         */
1464        public double VelocityY = 0;
1465        /**
1466         * The desired direction to face.
1467         * 0 Degrees is defined as in the direction of the X axis.
1468         * As a result, a TargetDirection of 90 degrees will point along
1469         * the Y axis, or to the left.
1470         */
1471        public Rotation2d TargetDirection = new Rotation2d();
1472        /**
1473         * The rotational rate feedforward to add to the output of the heading
1474         * controller, in radians per second. When using a motion profile for the
1475         * target direction, this can be set to the current velocity reference of
1476         * the profile.
1477         */
1478        public double TargetRateFeedforward = 0;
1479
1480        /**
1481         * The allowable deadband of the request, in m/s.
1482         */
1483        public double Deadband = 0;
1484        /**
1485         * The rotational deadband of the request, in radians per second.
1486         */
1487        public double RotationalDeadband = 0;
1488        /**
1489         * The maximum absolute rotational rate to allow, in radians per second.
1490         * Setting this to 0 results in no cap to rotational rate.
1491         */
1492        public double MaxAbsRotationalRate = 0;
1493        /**
1494         * The center of rotation the robot should rotate around.
1495         * This is (0,0) by default, which will rotate around the center of the robot.
1496         */
1497        public Translation2d CenterOfRotation = new Translation2d();
1498
1499        /**
1500         * The type of control request to use for the drive motor.
1501         */
1502        public SwerveModule.DriveRequestType DriveRequestType = SwerveModule.DriveRequestType.OpenLoopVoltage;
1503        /**
1504         * The type of control request to use for the steer motor.
1505         */
1506        public SwerveModule.SteerRequestType SteerRequestType = SwerveModule.SteerRequestType.Position;
1507        /**
1508         * Whether to desaturate wheel velocities before applying.
1509         * For more information, see the documentation of {@link SwerveDriveKinematics#desaturateWheelVelocities}.
1510         */
1511        public boolean DesaturateWheelVelocities = true;
1512
1513        /**
1514         * The perspective to use when determining which direction is forward.
1515         */
1516        public ForwardPerspectiveValue ForwardPerspective = ForwardPerspectiveValue.OperatorPerspective;
1517        /**
1518         * The perspective to use when determining which direction is forward for the
1519         * {@link #TargetDirection}. This allows for the heading control to use a different
1520         * perspective from the translation control.
1521         */
1522        public TargetDirectionPerspectiveValue TargetDirectionPerspective = TargetDirectionPerspectiveValue.UseForwardPerspective;
1523
1524        /**
1525         * The PID controller used to maintain the desired heading.
1526         * Users can specify the PID gains to change how aggressively to maintain
1527         * heading.
1528         * <p>
1529         * This PID controller operates on heading radians and outputs a target
1530         * rotational rate in radians per second. Note that continuous input should
1531         * be enabled on the range [-pi, pi].
1532         */
1533        public PhoenixPIDController HeadingController = new PhoenixPIDController(0, 0, 0);
1534
1535        private final FieldCentric m_fieldCentric = new FieldCentric();
1536
1537        public FieldCentricFacingAngle() {
1538            HeadingController.enableContinuousInput(-Math.PI, Math.PI);
1539        }
1540
1541        public StatusCode apply(SwerveControlParameters parameters, SwerveModule<?, ?, ?>... modulesToApply) {
1542            Rotation2d angleToFace = TargetDirection;
1543            if (
1544                TargetDirectionPerspective == TargetDirectionPerspectiveValue.UseForwardPerspective &&
1545                ForwardPerspective == ForwardPerspectiveValue.OperatorPerspective
1546            ) {
1547                /* If we're operator perspective, rotate the direction we want to face by the angle */
1548                angleToFace = angleToFace.rotateBy(parameters.operatorForwardDirection);
1549            }
1550
1551            double toApplyOmega = TargetRateFeedforward +
1552                HeadingController.calculate(
1553                    parameters.currentPose.getRotation().getRadians(),
1554                    angleToFace.getRadians(),
1555                    parameters.timestamp
1556                );
1557            if (MaxAbsRotationalRate > 0.0) {
1558                if (toApplyOmega > MaxAbsRotationalRate) {
1559                    toApplyOmega = MaxAbsRotationalRate;
1560                } else if (toApplyOmega < -MaxAbsRotationalRate) {
1561                    toApplyOmega = -MaxAbsRotationalRate;
1562                }
1563            }
1564
1565            return m_fieldCentric
1566                .withVelocityX(VelocityX)
1567                .withVelocityY(VelocityY)
1568                .withRotationalRate(toApplyOmega)
1569                .withDeadband(Deadband)
1570                .withRotationalDeadband(RotationalDeadband)
1571                .withCenterOfRotation(CenterOfRotation)
1572                .withDriveRequestType(DriveRequestType)
1573                .withSteerRequestType(SteerRequestType)
1574                .withDesaturateWheelVelocities(DesaturateWheelVelocities)
1575                .withForwardPerspective(ForwardPerspective)
1576                .apply(parameters, modulesToApply);
1577        }
1578
1579        /**
1580         * Modifies the PID gains of the HeadingController parameter and returns itself.
1581         * <p>
1582         * Sets the proportional, integral, and differential coefficients used to maintain
1583         * the desired heading. Users can specify the PID gains to change how aggressively to
1584         * maintain heading.
1585         * <p>
1586         * This PID controller operates on heading radians and outputs a target
1587         * rotational rate in radians per second.
1588         *
1589         * @param kP The proportional coefficient; must be >= 0
1590         * @param kI The integral coefficient; must be >= 0
1591         * @param kD The differential coefficient; must be >= 0
1592         * @return this object
1593         */
1594        public final FieldCentricFacingAngle withHeadingPID(double kP, double kI, double kD)
1595        {
1596            this.HeadingController.setPID(kP, kI, kD);
1597            return this;
1598        }
1599
1600        /**
1601         * Modifies the VelocityX parameter and returns itself.
1602         * <p>
1603         * The velocity in the X direction, in m/s. X is defined as forward according to
1604         * WPILib convention, so this determines how fast to travel forward.
1605         *
1606         * @param newVelocityX Parameter to modify
1607         * @return this object
1608         */
1609        public final FieldCentricFacingAngle withVelocityX(double newVelocityX) {
1610            this.VelocityX = newVelocityX;
1611            return this;
1612        }
1613
1614        /**
1615         * Modifies the VelocityX parameter and returns itself.
1616         * <p>
1617         * The velocity in the X direction, in m/s. X is defined as forward according to
1618         * WPILib convention, so this determines how fast to travel forward.
1619         *
1620         * @param newVelocityX Parameter to modify
1621         * @return this object
1622         */
1623        public final FieldCentricFacingAngle withVelocityX(LinearVelocity newVelocityX) {
1624            this.VelocityX = newVelocityX.in(MetersPerSecond);
1625            return this;
1626        }
1627
1628        /**
1629         * Modifies the VelocityY parameter and returns itself.
1630         * <p>
1631         * The velocity in the Y direction, in m/s. Y is defined as to the left
1632         * according to WPILib convention, so this determines how fast to travel to the
1633         * left.
1634         *
1635         * @param newVelocityY Parameter to modify
1636         * @return this object
1637         */
1638        public final FieldCentricFacingAngle withVelocityY(double newVelocityY) {
1639            this.VelocityY = newVelocityY;
1640            return this;
1641        }
1642
1643        /**
1644         * Modifies the VelocityY parameter and returns itself.
1645         * <p>
1646         * The velocity in the Y direction, in m/s. Y is defined as to the left
1647         * according to WPILib convention, so this determines how fast to travel to the
1648         * left.
1649         *
1650         * @param newVelocityY Parameter to modify
1651         * @return this object
1652         */
1653        public final FieldCentricFacingAngle withVelocityY(LinearVelocity newVelocityY) {
1654            this.VelocityY = newVelocityY.in(MetersPerSecond);
1655            return this;
1656        }
1657
1658        /**
1659         * Modifies the TargetDirection parameter and returns itself.
1660         * <p>
1661         * The desired direction to face. 0 Degrees is defined as in the direction of
1662         * the X axis. As a result, a TargetDirection of 90 degrees will point along
1663         * the Y axis, or to the left.
1664         *
1665         * @param newTargetDirection Parameter to modify
1666         * @return this object
1667         */
1668        public final FieldCentricFacingAngle withTargetDirection(Rotation2d newTargetDirection) {
1669            this.TargetDirection = newTargetDirection;
1670            return this;
1671        }
1672
1673        /**
1674         * Modifies the TargetRateFeedforward parameter and returns itself.
1675         * <p>
1676         * The rotational rate feedforward to add to the output of the heading
1677         * controller, in radians per second. When using a motion profile for the
1678         * target direction, this can be set to the current velocity reference of
1679         * the profile.
1680         *
1681         * @param newTargetRateFeedforward Parameter to modify
1682         * @return this object
1683         */
1684        public final FieldCentricFacingAngle withTargetRateFeedforward(double newTargetRateFeedforward) {
1685            this.TargetRateFeedforward = newTargetRateFeedforward;
1686            return this;
1687        }
1688        /**
1689         * Modifies the TargetRateFeedforward parameter and returns itself.
1690         * <p>
1691         * The rotational rate feedforward to add to the output of the heading
1692         * controller, in radians per second. When using a motion profile for the
1693         * target direction, this can be set to the current velocity reference of
1694         * the profile.
1695         *
1696         * @param newTargetRateFeedforward Parameter to modify
1697         * @return this object
1698         */
1699        public final FieldCentricFacingAngle withTargetRateFeedforward(AngularVelocity newTargetRateFeedforward) {
1700            this.TargetRateFeedforward = newTargetRateFeedforward.in(RadiansPerSecond);
1701            return this;
1702        }
1703
1704        /**
1705         * Modifies the Deadband parameter and returns itself.
1706         * <p>
1707         * The allowable deadband of the request, in m/s.
1708         *
1709         * @param newDeadband Parameter to modify
1710         * @return this object
1711         */
1712        public final FieldCentricFacingAngle withDeadband(double newDeadband) {
1713            this.Deadband = newDeadband;
1714            return this;
1715        }
1716
1717        /**
1718         * Modifies the Deadband parameter and returns itself.
1719         * <p>
1720         * The allowable deadband of the request, in m/s.
1721         *
1722         * @param newDeadband Parameter to modify
1723         * @return this object
1724         */
1725        public final FieldCentricFacingAngle withDeadband(LinearVelocity newDeadband) {
1726            this.Deadband = newDeadband.in(MetersPerSecond);
1727            return this;
1728        }
1729
1730        /**
1731         * Modifies the RotationalDeadband parameter and returns itself.
1732         * <p>
1733         * The rotational deadband of the request, in radians per second.
1734         *
1735         * @param newRotationalDeadband Parameter to modify
1736         * @return this object
1737         */
1738        public final FieldCentricFacingAngle withRotationalDeadband(double newRotationalDeadband) {
1739            this.RotationalDeadband = newRotationalDeadband;
1740            return this;
1741        }
1742
1743        /**
1744         * Modifies the RotationalDeadband parameter and returns itself.
1745         * <p>
1746         * The rotational deadband of the request, in radians per second.
1747         *
1748         * @param newRotationalDeadband Parameter to modify
1749         * @return this object
1750         */
1751        public final FieldCentricFacingAngle withRotationalDeadband(AngularVelocity newRotationalDeadband) {
1752            this.RotationalDeadband = newRotationalDeadband.in(RadiansPerSecond);
1753            return this;
1754        }
1755
1756        /**
1757         * Modifies the MaxAbsRotationalRate parameter and returns itself.
1758         * <p>
1759         * The maximum absolute rotational rate to allow, in radians per second.
1760         * Setting this to 0 results in no cap to rotational rate.
1761         *
1762         * @param newMaxAbsRotationalRate Parameter to modify
1763         * @return this object
1764         */
1765        public final FieldCentricFacingAngle withMaxAbsRotationalRate(double newMaxAbsRotationalRate) {
1766            this.MaxAbsRotationalRate = newMaxAbsRotationalRate;
1767            return this;
1768        }
1769
1770        /**
1771         * Modifies the MaxAbsRotationalRate parameter and returns itself.
1772         * <p>
1773         * The maximum absolute rotational rate to allow, in radians per second.
1774         * Setting this to 0 results in no cap to rotational rate.
1775         *
1776         * @param newMaxAbsRotationalRate Parameter to modify
1777         * @return this object
1778         */
1779        public final FieldCentricFacingAngle withMaxAbsRotationalRate(AngularVelocity newMaxAbsRotationalRate) {
1780            this.MaxAbsRotationalRate = newMaxAbsRotationalRate.in(RadiansPerSecond);
1781            return this;
1782        }
1783
1784        /**
1785         * Modifies the CenterOfRotation parameter and returns itself.
1786         * <p>
1787         * The center of rotation the robot should rotate around. This is (0,0) by
1788         * default, which will rotate around the center of the robot.
1789         *
1790         * @param newCenterOfRotation Parameter to modify
1791         * @return this object
1792         */
1793        public final FieldCentricFacingAngle withCenterOfRotation(Translation2d newCenterOfRotation) {
1794            this.CenterOfRotation = newCenterOfRotation;
1795            return this;
1796        }
1797
1798        /**
1799         * Modifies the DriveRequestType parameter and returns itself.
1800         * <p>
1801         * The type of control request to use for the drive motor.
1802         *
1803         * @param newDriveRequestType Parameter to modify
1804         * @return this object
1805         */
1806        public final FieldCentricFacingAngle withDriveRequestType(SwerveModule.DriveRequestType newDriveRequestType) {
1807            this.DriveRequestType = newDriveRequestType;
1808            return this;
1809        }
1810
1811        /**
1812         * Modifies the SteerRequestType parameter and returns itself.
1813         * <p>
1814         * The type of control request to use for the drive motor.
1815         *
1816         * @param newSteerRequestType Parameter to modify
1817         * @return this object
1818         */
1819        public final FieldCentricFacingAngle withSteerRequestType(SwerveModule.SteerRequestType newSteerRequestType) {
1820            this.SteerRequestType = newSteerRequestType;
1821            return this;
1822        }
1823
1824        /**
1825         * Modifies the DesaturateWheelVelocities parameter and returns itself.
1826         * <p>
1827         * Whether to desaturate wheel velocities before applying. For more information, see
1828         * the documentation of {@link SwerveDriveKinematics#desaturateWheelVelocities}.
1829         *
1830         * @param newDesaturateWheelVelocities Parameter to modify
1831         * @return this object
1832         */
1833        public final FieldCentricFacingAngle withDesaturateWheelVelocities(boolean newDesaturateWheelVelocities) {
1834            this.DesaturateWheelVelocities = newDesaturateWheelVelocities;
1835            return this;
1836        }
1837
1838        /**
1839         * Modifies the ForwardPerspective parameter and returns itself.
1840         * <p>
1841         * The perspective to use when determining which direction is forward.
1842         *
1843         * @param newForwardPerspective Parameter to modify
1844         * @return this object
1845         */
1846        public final FieldCentricFacingAngle withForwardPerspective(ForwardPerspectiveValue newForwardPerspective) {
1847            this.ForwardPerspective = newForwardPerspective;
1848            return this;
1849        }
1850
1851        /**
1852         * Modifies the TargetDirectionPerspective parameter and returns itself.
1853         * <p>
1854         * The perspective to use when determining which direction is forward for the
1855         * {@link #TargetDirection}. This allows for the heading control to use a different
1856         * perspective from the translation control.
1857         *
1858         * @param newTargetDirectionPerspective Parameter to modify
1859         * @return this object
1860         */
1861        public final FieldCentricFacingAngle withTargetDirectionPerspective(TargetDirectionPerspectiveValue newTargetDirectionPerspective) {
1862            this.TargetDirectionPerspective = newTargetDirectionPerspective;
1863            return this;
1864        }
1865    }
1866
1867    /**
1868     * Drives the swerve drivetrain in a robot-centric manner, maintaining a
1869     * specified heading angle to ensure the robot is facing the desired direction
1870     * <p>
1871     * When users use this request, they specify the direction the robot should
1872     * travel oriented against the robot itself, and the direction the robot should
1873     * be facing relative to the field.
1874     * <p>
1875     * An example scenario is that the robot is oriented to the east, the VelocityX
1876     * is +5 m/s, VelocityY is 0 m/s, and TargetDirection is 180 degrees.
1877     * In this scenario, the robot would drive forward at 5 m/s and turn clockwise
1878     * to a target of 180 degrees.
1879     * <p>
1880     * This control request is especially useful for vision control, where the
1881     * robot should be facing a vision target throughout the motion.
1882     */
1883    public static class RobotCentricFacingAngle implements SwerveRequest {
1884        /**
1885         * The velocity in the X direction, in m/s.
1886         * X is defined as forward according to WPILib convention,
1887         * so this determines how fast to travel forward.
1888         */
1889        public double VelocityX = 0;
1890        /**
1891         * The velocity in the Y direction, in m/s.
1892         * Y is defined as to the left according to WPILib convention,
1893         * so this determines how fast to travel to the left.
1894         */
1895        public double VelocityY = 0;
1896        /**
1897         * The desired direction to face.
1898         * 0 Degrees is defined as in the direction of the X axis.
1899         * As a result, a TargetDirection of 90 degrees will point along
1900         * the Y axis, or to the left.
1901         */
1902        public Rotation2d TargetDirection = new Rotation2d();
1903        /**
1904         * The rotational rate feedforward to add to the output of the heading
1905         * controller, in radians per second. When using a motion profile for the
1906         * target direction, this can be set to the current velocity reference of
1907         * the profile.
1908         */
1909        public double TargetRateFeedforward = 0;
1910
1911        /**
1912         * The allowable deadband of the request, in m/s.
1913         */
1914        public double Deadband = 0;
1915        /**
1916         * The rotational deadband of the request, in radians per second.
1917         */
1918        public double RotationalDeadband = 0;
1919        /**
1920         * The maximum absolute rotational rate to allow, in radians per second.
1921         * Setting this to 0 results in no cap to rotational rate.
1922         */
1923        public double MaxAbsRotationalRate = 0;
1924        /**
1925         * The center of rotation the robot should rotate around.
1926         * This is (0,0) by default, which will rotate around the center of the robot.
1927         */
1928        public Translation2d CenterOfRotation = new Translation2d();
1929
1930        /**
1931         * The type of control request to use for the drive motor.
1932         */
1933        public SwerveModule.DriveRequestType DriveRequestType = SwerveModule.DriveRequestType.OpenLoopVoltage;
1934        /**
1935         * The type of control request to use for the steer motor.
1936         */
1937        public SwerveModule.SteerRequestType SteerRequestType = SwerveModule.SteerRequestType.Position;
1938        /**
1939         * Whether to desaturate wheel velocities before applying.
1940         * For more information, see the documentation of {@link SwerveDriveKinematics#desaturateWheelVelocities}.
1941         */
1942        public boolean DesaturateWheelVelocities = true;
1943
1944        /**
1945         * The perspective to use when determining which direction is forward
1946         * for the target heading.
1947         */
1948        public ForwardPerspectiveValue ForwardPerspective = ForwardPerspectiveValue.OperatorPerspective;
1949
1950        /**
1951         * The PID controller used to maintain the desired heading.
1952         * Users can specify the PID gains to change how aggressively to maintain
1953         * heading.
1954         * <p>
1955         * This PID controller operates on heading radians and outputs a target
1956         * rotational rate in radians per second. Note that continuous input should
1957         * be enabled on the range [-pi, pi].
1958         */
1959        public PhoenixPIDController HeadingController = new PhoenixPIDController(0, 0, 0);
1960
1961        private final RobotCentric m_robotCentric = new RobotCentric();
1962
1963        public RobotCentricFacingAngle() {
1964            HeadingController.enableContinuousInput(-Math.PI, Math.PI);
1965        }
1966
1967        public StatusCode apply(SwerveControlParameters parameters, SwerveModule<?, ?, ?>... modulesToApply) {
1968            Rotation2d angleToFace = TargetDirection;
1969            if (ForwardPerspective == ForwardPerspectiveValue.OperatorPerspective) {
1970                /* If we're operator perspective, rotate the direction we want to face by the angle */
1971                angleToFace = angleToFace.rotateBy(parameters.operatorForwardDirection);
1972            }
1973
1974            double toApplyOmega = TargetRateFeedforward +
1975                HeadingController.calculate(
1976                    parameters.currentPose.getRotation().getRadians(),
1977                    angleToFace.getRadians(),
1978                    parameters.timestamp
1979                );
1980            if (MaxAbsRotationalRate > 0.0) {
1981                if (toApplyOmega > MaxAbsRotationalRate) {
1982                    toApplyOmega = MaxAbsRotationalRate;
1983                } else if (toApplyOmega < -MaxAbsRotationalRate) {
1984                    toApplyOmega = -MaxAbsRotationalRate;
1985                }
1986            }
1987
1988            return m_robotCentric
1989                .withVelocityX(VelocityX)
1990                .withVelocityY(VelocityY)
1991                .withRotationalRate(toApplyOmega)
1992                .withDeadband(Deadband)
1993                .withRotationalDeadband(RotationalDeadband)
1994                .withCenterOfRotation(CenterOfRotation)
1995                .withDriveRequestType(DriveRequestType)
1996                .withSteerRequestType(SteerRequestType)
1997                .withDesaturateWheelVelocities(DesaturateWheelVelocities)
1998                .apply(parameters, modulesToApply);
1999        }
2000
2001        /**
2002         * Modifies the PID gains of the HeadingController parameter and returns itself.
2003         * <p>
2004         * Sets the proportional, integral, and differential coefficients used to maintain
2005         * the desired heading. Users can specify the PID gains to change how aggressively to
2006         * maintain heading.
2007         * <p>
2008         * This PID controller operates on heading radians and outputs a target
2009         * rotational rate in radians per second.
2010         *
2011         * @param kP The proportional coefficient; must be >= 0
2012         * @param kI The integral coefficient; must be >= 0
2013         * @param kD The differential coefficient; must be >= 0
2014         * @return this object
2015         */
2016        public final RobotCentricFacingAngle withHeadingPID(double kP, double kI, double kD)
2017        {
2018            this.HeadingController.setPID(kP, kI, kD);
2019            return this;
2020        }
2021
2022        /**
2023         * Modifies the VelocityX parameter and returns itself.
2024         * <p>
2025         * The velocity in the X direction, in m/s. X is defined as forward according to
2026         * WPILib convention, so this determines how fast to travel forward.
2027         *
2028         * @param newVelocityX Parameter to modify
2029         * @return this object
2030         */
2031        public final RobotCentricFacingAngle withVelocityX(double newVelocityX) {
2032            this.VelocityX = newVelocityX;
2033            return this;
2034        }
2035
2036        /**
2037         * Modifies the VelocityX parameter and returns itself.
2038         * <p>
2039         * The velocity in the X direction, in m/s. X is defined as forward according to
2040         * WPILib convention, so this determines how fast to travel forward.
2041         *
2042         * @param newVelocityX Parameter to modify
2043         * @return this object
2044         */
2045        public final RobotCentricFacingAngle withVelocityX(LinearVelocity newVelocityX) {
2046            this.VelocityX = newVelocityX.in(MetersPerSecond);
2047            return this;
2048        }
2049
2050        /**
2051         * Modifies the VelocityY parameter and returns itself.
2052         * <p>
2053         * The velocity in the Y direction, in m/s. Y is defined as to the left
2054         * according to WPILib convention, so this determines how fast to travel to the
2055         * left.
2056         *
2057         * @param newVelocityY Parameter to modify
2058         * @return this object
2059         */
2060        public final RobotCentricFacingAngle withVelocityY(double newVelocityY) {
2061            this.VelocityY = newVelocityY;
2062            return this;
2063        }
2064
2065        /**
2066         * Modifies the VelocityY parameter and returns itself.
2067         * <p>
2068         * The velocity in the Y direction, in m/s. Y is defined as to the left
2069         * according to WPILib convention, so this determines how fast to travel to the
2070         * left.
2071         *
2072         * @param newVelocityY Parameter to modify
2073         * @return this object
2074         */
2075        public final RobotCentricFacingAngle withVelocityY(LinearVelocity newVelocityY) {
2076            this.VelocityY = newVelocityY.in(MetersPerSecond);
2077            return this;
2078        }
2079
2080        /**
2081         * Modifies the TargetDirection parameter and returns itself.
2082         * <p>
2083         * The desired direction to face. 0 Degrees is defined as in the direction of
2084         * the X axis. As a result, a TargetDirection of 90 degrees will point along
2085         * the Y axis, or to the left.
2086         *
2087         * @param newTargetDirection Parameter to modify
2088         * @return this object
2089         */
2090        public final RobotCentricFacingAngle withTargetDirection(Rotation2d newTargetDirection) {
2091            this.TargetDirection = newTargetDirection;
2092            return this;
2093        }
2094
2095        /**
2096         * Modifies the TargetRateFeedforward parameter and returns itself.
2097         * <p>
2098         * The rotational rate feedforward to add to the output of the heading
2099         * controller, in radians per second. When using a motion profile for the
2100         * target direction, this can be set to the current velocity reference of
2101         * the profile.
2102         *
2103         * @param newTargetRateFeedforward Parameter to modify
2104         * @return this object
2105         */
2106        public final RobotCentricFacingAngle withTargetRateFeedforward(double newTargetRateFeedforward) {
2107            this.TargetRateFeedforward = newTargetRateFeedforward;
2108            return this;
2109        }
2110        /**
2111         * Modifies the TargetRateFeedforward parameter and returns itself.
2112         * <p>
2113         * The rotational rate feedforward to add to the output of the heading
2114         * controller, in radians per second. When using a motion profile for the
2115         * target direction, this can be set to the current velocity reference of
2116         * the profile.
2117         *
2118         * @param newTargetRateFeedforward Parameter to modify
2119         * @return this object
2120         */
2121        public final RobotCentricFacingAngle withTargetRateFeedforward(AngularVelocity newTargetRateFeedforward) {
2122            this.TargetRateFeedforward = newTargetRateFeedforward.in(RadiansPerSecond);
2123            return this;
2124        }
2125
2126        /**
2127         * Modifies the Deadband parameter and returns itself.
2128         * <p>
2129         * The allowable deadband of the request, in m/s.
2130         *
2131         * @param newDeadband Parameter to modify
2132         * @return this object
2133         */
2134        public final RobotCentricFacingAngle withDeadband(double newDeadband) {
2135            this.Deadband = newDeadband;
2136            return this;
2137        }
2138
2139        /**
2140         * Modifies the Deadband parameter and returns itself.
2141         * <p>
2142         * The allowable deadband of the request, in m/s.
2143         *
2144         * @param newDeadband Parameter to modify
2145         * @return this object
2146         */
2147        public final RobotCentricFacingAngle withDeadband(LinearVelocity newDeadband) {
2148            this.Deadband = newDeadband.in(MetersPerSecond);
2149            return this;
2150        }
2151
2152        /**
2153         * Modifies the RotationalDeadband parameter and returns itself.
2154         * <p>
2155         * The rotational deadband of the request, in radians per second.
2156         *
2157         * @param newRotationalDeadband Parameter to modify
2158         * @return this object
2159         */
2160        public final RobotCentricFacingAngle withRotationalDeadband(double newRotationalDeadband) {
2161            this.RotationalDeadband = newRotationalDeadband;
2162            return this;
2163        }
2164
2165        /**
2166         * Modifies the RotationalDeadband parameter and returns itself.
2167         * <p>
2168         * The rotational deadband of the request, in radians per second.
2169         *
2170         * @param newRotationalDeadband Parameter to modify
2171         * @return this object
2172         */
2173        public final RobotCentricFacingAngle withRotationalDeadband(AngularVelocity newRotationalDeadband) {
2174            this.RotationalDeadband = newRotationalDeadband.in(RadiansPerSecond);
2175            return this;
2176        }
2177
2178        /**
2179         * Modifies the MaxAbsRotationalRate parameter and returns itself.
2180         * <p>
2181         * The maximum absolute rotational rate to allow, in radians per second.
2182         * Setting this to 0 results in no cap to rotational rate.
2183         *
2184         * @param newMaxAbsRotationalRate Parameter to modify
2185         * @return this object
2186         */
2187        public final RobotCentricFacingAngle withMaxAbsRotationalRate(double newMaxAbsRotationalRate) {
2188            this.MaxAbsRotationalRate = newMaxAbsRotationalRate;
2189            return this;
2190        }
2191
2192        /**
2193         * Modifies the MaxAbsRotationalRate parameter and returns itself.
2194         * <p>
2195         * The maximum absolute rotational rate to allow, in radians per second.
2196         * Setting this to 0 results in no cap to rotational rate.
2197         *
2198         * @param newMaxAbsRotationalRate Parameter to modify
2199         * @return this object
2200         */
2201        public final RobotCentricFacingAngle withMaxAbsRotationalRate(AngularVelocity newMaxAbsRotationalRate) {
2202            this.MaxAbsRotationalRate = newMaxAbsRotationalRate.in(RadiansPerSecond);
2203            return this;
2204        }
2205
2206        /**
2207         * Modifies the CenterOfRotation parameter and returns itself.
2208         * <p>
2209         * The center of rotation the robot should rotate around. This is (0,0) by
2210         * default, which will rotate around the center of the robot.
2211         *
2212         * @param newCenterOfRotation Parameter to modify
2213         * @return this object
2214         */
2215        public final RobotCentricFacingAngle withCenterOfRotation(Translation2d newCenterOfRotation) {
2216            this.CenterOfRotation = newCenterOfRotation;
2217            return this;
2218        }
2219
2220        /**
2221         * Modifies the DriveRequestType parameter and returns itself.
2222         * <p>
2223         * The type of control request to use for the drive motor.
2224         *
2225         * @param newDriveRequestType Parameter to modify
2226         * @return this object
2227         */
2228        public final RobotCentricFacingAngle withDriveRequestType(SwerveModule.DriveRequestType newDriveRequestType) {
2229            this.DriveRequestType = newDriveRequestType;
2230            return this;
2231        }
2232
2233        /**
2234         * Modifies the SteerRequestType parameter and returns itself.
2235         * <p>
2236         * The type of control request to use for the drive motor.
2237         *
2238         * @param newSteerRequestType Parameter to modify
2239         * @return this object
2240         */
2241        public final RobotCentricFacingAngle withSteerRequestType(SwerveModule.SteerRequestType newSteerRequestType) {
2242            this.SteerRequestType = newSteerRequestType;
2243            return this;
2244        }
2245
2246        /**
2247         * Modifies the DesaturateWheelVelocities parameter and returns itself.
2248         * <p>
2249         * Whether to desaturate wheel velocities before applying. For more information, see
2250         * the documentation of {@link SwerveDriveKinematics#desaturateWheelVelocities}.
2251         *
2252         * @param newDesaturateWheelVelocities Parameter to modify
2253         * @return this object
2254         */
2255        public final RobotCentricFacingAngle withDesaturateWheelVelocities(boolean newDesaturateWheelVelocities) {
2256            this.DesaturateWheelVelocities = newDesaturateWheelVelocities;
2257            return this;
2258        }
2259
2260        /**
2261         * Modifies the ForwardPerspective parameter and returns itself.
2262         * <p>
2263         * The perspective to use when determining which direction is forward
2264         * for the target heading.
2265         *
2266         * @param newForwardPerspective Parameter to modify
2267         * @return this object
2268         */
2269        public final RobotCentricFacingAngle withForwardPerspective(ForwardPerspectiveValue newForwardPerspective) {
2270            this.ForwardPerspective = newForwardPerspective;
2271            return this;
2272        }
2273    }
2274
2275    /**
2276     * SysId-specific SwerveRequest to characterize the translational
2277     * characteristics of a swerve drivetrain.
2278     */
2279    public static class SysIdSwerveTranslation implements SwerveRequest {
2280        /**
2281         * Voltage to apply to drive wheels.
2282         */
2283        public double VoltsToApply = 0;
2284
2285        /** Local reference to a voltage request for the drive motors */
2286        private final VoltageOut m_driveRequest = new VoltageOut(0);
2287        /** Local reference to a position voltage request for the steer motors */
2288        private final PositionVoltage m_steerRequest_Voltage = new PositionVoltage(0);
2289        /** Local reference to a position torque current request for the steer motors */
2290        private final PositionTorqueCurrentFOC m_steerRequest_TorqueCurrent = new PositionTorqueCurrentFOC(0);
2291
2292        public StatusCode apply(SwerveControlParameters parameters, SwerveModule<?, ?, ?>... modulesToApply) {
2293            for (int i = 0; i < modulesToApply.length; ++i) {
2294                switch (modulesToApply[i].getSteerClosedLoopOutputType()) {
2295                    case Voltage:
2296                        modulesToApply[i].apply(
2297                            m_driveRequest.withOutput(VoltsToApply),
2298                            m_steerRequest_Voltage.withPosition(0)
2299                        );
2300                        break;
2301                    case TorqueCurrentFOC:
2302                        modulesToApply[i].apply(
2303                            m_driveRequest.withOutput(VoltsToApply),
2304                            m_steerRequest_TorqueCurrent.withPosition(0)
2305                        );
2306                        break;
2307                }
2308            }
2309            return StatusCode.OK;
2310        }
2311
2312        /**
2313         * Sets the voltage to apply to the drive wheels.
2314         *
2315         * @param volts Voltage to apply
2316         * @return this request
2317         */
2318        public final SysIdSwerveTranslation withVolts(double volts) {
2319            VoltsToApply = volts;
2320            return this;
2321        }
2322        /**
2323         * Sets the voltage to apply to the drive wheels.
2324         *
2325         * @param volts Voltage to apply
2326         * @return this request
2327         */
2328        public final SysIdSwerveTranslation withVolts(Voltage volts) {
2329            VoltsToApply = volts.in(Volts);
2330            return this;
2331        }
2332    }
2333
2334    /**
2335     * SysId-specific SwerveRequest to characterize the rotational
2336     * characteristics of a swerve drivetrain. This is useful to
2337     * characterize the heading controller for FieldCentricFacingAngle.
2338     * <p>
2339     * The RotationalRate of this swerve request should be logged.
2340     * When importing the log to SysId, set the "voltage" to
2341     * RotationalRate, "position" to the Pigeon 2 Yaw, and "velocity"
2342     * to the Pigeon 2 AngularVelocityZWorld. Note that the position
2343     * and velocity will both need to be scaled by pi/180.
2344     * <p>
2345     * Alternatively, the MotorVoltage of one of the drive motors can
2346     * be loaded into the SysId "voltage" field, which can be useful
2347     * when determining the MOI of the robot.
2348     */
2349    public static class SysIdSwerveRotation implements SwerveRequest {
2350        /**
2351         * The angular rate to rotate at, in radians per second.
2352         */
2353        public double RotationalRate = 0;
2354
2355        /** Local reference to a voltage request for the drive motors */
2356        private final VoltageOut m_driveRequest = new VoltageOut(0);
2357        /** Local reference to a position voltage request for the steer motors */
2358        private final PositionVoltage m_steerRequest_Voltage = new PositionVoltage(0);
2359        /** Local reference to a position torque current request for the steer motors */
2360        private final PositionTorqueCurrentFOC m_steerRequest_TorqueCurrent = new PositionTorqueCurrentFOC(0);
2361
2362        public StatusCode apply(SwerveControlParameters parameters, SwerveModule<?, ?, ?>... modulesToApply) {
2363            for (int i = 0; i < modulesToApply.length; ++i) {
2364                var velocityMps = RotationalRate * parameters.moduleLocations[i].getNorm();
2365                var driveVoltage = velocityMps / parameters.kMaxSpeedMps * 12.0;
2366
2367                var angle = parameters.moduleLocations[i].getAngle().orElse(Rotation2d.ZERO).plus(Rotation2d.CCW_90DEG);
2368
2369                switch (modulesToApply[i].getSteerClosedLoopOutputType()) {
2370                    case Voltage:
2371                        modulesToApply[i].apply(
2372                            m_driveRequest.withOutput(driveVoltage),
2373                            m_steerRequest_Voltage.withPosition(angle.getRotations())
2374                        );
2375                        break;
2376                    case TorqueCurrentFOC:
2377                        modulesToApply[i].apply(
2378                            m_driveRequest.withOutput(driveVoltage),
2379                            m_steerRequest_TorqueCurrent.withPosition(angle.getRotations())
2380                        );
2381                        break;
2382                }
2383            }
2384            return StatusCode.OK;
2385        }
2386
2387        /**
2388         * Update the angular rate to rotate at, in radians per second.
2389         *
2390         * @param newRotationalRate Angular rate to rotate at
2391         * @return this request
2392         */
2393        public final SysIdSwerveRotation withRotationalRate(double newRotationalRate) {
2394            RotationalRate = newRotationalRate;
2395            return this;
2396        }
2397        /**
2398         * Update the angular rate to rotate at.
2399         *
2400         * @param newRotationalRate The angular rate to rotate at
2401         * @return this request
2402         */
2403        public final SysIdSwerveRotation withRotationalRate(AngularVelocity newRotationalRate) {
2404            RotationalRate = newRotationalRate.in(RadiansPerSecond);
2405            return this;
2406        }
2407    }
2408
2409    /**
2410     * SysId-specific SwerveRequest to characterize the steer module
2411     * characteristics of a swerve drivetrain.
2412     */
2413    public static class SysIdSwerveSteerGains implements SwerveRequest {
2414        /**
2415         * Voltage to apply to steer motors.
2416         */
2417        public double VoltsToApply = 0;
2418
2419        /** Local reference to a coast request for the drive motors */
2420        private final CoastOut m_driveRequest = new CoastOut();
2421        /** Local reference to a voltage request for the steer motors */
2422        private final VoltageOut m_steerRequest = new VoltageOut(0);
2423
2424        public StatusCode apply(SwerveControlParameters parameters, SwerveModule<?, ?, ?>... modulesToApply) {
2425            for (int i = 0; i < modulesToApply.length; ++i) {
2426                modulesToApply[i].apply(m_driveRequest, m_steerRequest.withOutput(VoltsToApply));
2427            }
2428            return StatusCode.OK;
2429        }
2430
2431        /**
2432         * Sets the voltage to apply to the steer motors.
2433         *
2434         * @param volts Voltage to apply
2435         * @return this request
2436         */
2437        public final SysIdSwerveSteerGains withVolts(double volts) {
2438            VoltsToApply = volts;
2439            return this;
2440        }
2441        /**
2442         * Sets the voltage to apply to the steer motors.
2443         *
2444         * @param volts Voltage to apply
2445         * @return this request
2446         */
2447        public final SysIdSwerveSteerGains withVolts(Voltage volts) {
2448            VoltsToApply = volts.in(Volts);
2449            return this;
2450        }
2451    }
2452}