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.controls;
008
009import com.ctre.phoenix6.CANBus;
010import com.ctre.phoenix6.StatusCode;
011import com.ctre.phoenix6.controls.jni.ControlJNI;
012import com.ctre.phoenix6.hardware.traits.*;
013
014import edu.wpi.first.units.*;
015import edu.wpi.first.units.measure.*;
016import static edu.wpi.first.units.Units.*;
017
018import java.util.HashMap;
019import java.util.Map;
020
021/**
022 * Requires Phoenix Pro and CANivore;
023 * Requests Motion Magic® to target a final position using a motion profile. 
024 * This dynamic request allows runtime changes to Cruise Velocity, Acceleration,
025 * and (optional) Jerk.  Users can optionally provide a duty cycle feedforward.
026 * <p>
027 * Motion Magic® produces a motion profile in real-time while attempting to honor the specified Cruise
028 * Velocity, Acceleration, and (optional) Jerk.  This control mode does not use the Expo_kV or Expo_kA
029 * configs.
030 * <p>
031 * Target position can be changed on-the-fly and Motion Magic® will do its best to adjust the profile. This
032 * control mode is duty cycle based, so relevant closed-loop gains will use fractional duty cycle for the
033 * numerator:  +1.0 represents full forward output.
034 */
035public final class DynamicMotionMagicDutyCycle implements ControlRequest, Cloneable {
036    /**
037     * Position to drive toward in rotations.
038     * 
039     * <ul>
040     *   <li> Units: rotations
041     * </ul>
042     * 
043     */
044    public double Position;
045    /**
046     * Cruise velocity for profiling.  The signage does not matter as the device
047     * will use the absolute value for profile generation.
048     * 
049     * <ul>
050     *   <li> Units: rotations per second
051     * </ul>
052     * 
053     */
054    public double Velocity;
055    /**
056     * Acceleration for profiling.  The signage does not matter as the device will
057     * use the absolute value for profile generation
058     * 
059     * <ul>
060     *   <li> Units: rotations per second²
061     * </ul>
062     * 
063     */
064    public double Acceleration;
065    /**
066     * Jerk for profiling.  The signage does not matter as the device will use the
067     * absolute value for profile generation.
068     * <p>
069     * Jerk is optional; if this is set to zero, then Motion Magic® will not apply a
070     * Jerk limit.
071     * 
072     * <ul>
073     *   <li> Units: rotations per second³
074     * </ul>
075     * 
076     */
077    public double Jerk = 0.0;
078    /**
079     * Set to true to use FOC commutation (requires Phoenix Pro), which increases
080     * peak power by ~15% on supported devices (see {@link SupportsFOC}). Set to
081     * false to use trapezoidal commutation.
082     * <p>
083     * FOC improves motor performance by leveraging torque (current) control. 
084     * However, this may be inconvenient for applications that require specifying
085     * duty cycle or voltage.  CTR-Electronics has developed a hybrid method that
086     * combines the performances gains of FOC while still allowing applications to
087     * provide duty cycle or voltage demand.  This not to be confused with simple
088     * sinusoidal control or phase voltage control which lacks the performance
089     * gains.
090     */
091    public boolean EnableFOC = true;
092    /**
093     * Feedforward to apply in fractional units between -1 and +1. This is added to
094     * the output of the onboard feedforward terms.
095     * 
096     * <ul>
097     *   <li> Units: fractional
098     * </ul>
099     * 
100     */
101    public double FeedForward = 0.0;
102    /**
103     * Select which gains are applied by selecting the slot.  Use the configuration
104     * api to set the gain values for the selected slot before enabling this
105     * feature. Slot must be within [0,2].
106     */
107    public int Slot = 0;
108    /**
109     * Set to true to static-brake the rotor when output is zero (or within
110     * deadband).  Set to false to use the NeutralMode configuration setting
111     * (default). This flag exists to provide the fundamental behavior of this
112     * control when output is zero, which is to provide 0V to the motor.
113     */
114    public boolean OverrideBrakeDurNeutral = false;
115    /**
116     * Set to true to force forward limiting.  This allows users to use other limit
117     * switch sensors connected to robot controller.  This also allows use of active
118     * sensors that require external power.
119     */
120    public boolean LimitForwardMotion = false;
121    /**
122     * Set to true to force reverse limiting.  This allows users to use other limit
123     * switch sensors connected to robot controller.  This also allows use of active
124     * sensors that require external power.
125     */
126    public boolean LimitReverseMotion = false;
127    /**
128     * Set to true to ignore hardware limit switches and the LimitForwardMotion and
129     * LimitReverseMotion parameters, instead allowing motion.
130     * <p>
131     * This can be useful on mechanisms such as an intake/feeder, where a limit
132     * switch stops motion while intaking but should be ignored when feeding to a
133     * shooter.
134     * <p>
135     * The hardware limit faults and Forward/ReverseLimit signals will still report
136     * the values of the limit switches regardless of this parameter.
137     */
138    public boolean IgnoreHardwareLimits = false;
139    /**
140     * Set to true to ignore software limits, instead allowing motion.
141     * <p>
142     * This can be useful when calibrating the zero point of a mechanism such as an
143     * elevator.
144     * <p>
145     * The software limit faults will still report the values of the software limits
146     * regardless of this parameter.
147     */
148    public boolean IgnoreSoftwareLimits = false;
149    /**
150     * Set to true to delay applying this control request until a timesync boundary
151     * (requires Phoenix Pro and CANivore). This eliminates the impact of
152     * nondeterministic network delays in exchange for a larger but deterministic
153     * control latency.
154     * <p>
155     * This requires setting the ControlTimesyncFreqHz config in MotorOutputConfigs.
156     * Additionally, when this is enabled, the UpdateFreqHz of this request should
157     * be set to 0 Hz.
158     */
159    public boolean UseTimesync = false;
160
161    /**
162     * The frequency at which this control will update.
163     * This is designated in Hertz, with a minimum of 20 Hz
164     * (every 50 ms) and a maximum of 1000 Hz (every 1 ms).
165     * Some update frequencies are not supported and will be
166     * promoted up to the next highest supported frequency.
167     * <p>
168     * If this field is set to 0 Hz, the control request will
169     * be sent immediately as a one-shot frame. This may be useful
170     * for advanced applications that require outputs to be
171     * synchronized with data acquisition. In this case, we
172     * recommend not exceeding 50 ms between control calls.
173     */
174    public double UpdateFreqHz = 100;
175
176    /**
177     * Requires Phoenix Pro and CANivore;
178     * Requests Motion Magic® to target a final position using a motion profile. 
179     * This dynamic request allows runtime changes to Cruise Velocity, Acceleration,
180     * and (optional) Jerk.  Users can optionally provide a duty cycle feedforward.
181     * <p>
182     * Motion Magic® produces a motion profile in real-time while attempting to
183     * honor the specified Cruise Velocity, Acceleration, and (optional) Jerk.  This
184     * control mode does not use the Expo_kV or Expo_kA configs.
185     * <p>
186     * Target position can be changed on-the-fly and Motion Magic® will do its best
187     * to adjust the profile. This control mode is duty cycle based, so relevant
188     * closed-loop gains will use fractional duty cycle for the numerator:  +1.0
189     * represents full forward output.
190     * 
191     * @param Position Position to drive toward in rotations.
192     * @param Velocity Cruise velocity for profiling.  The signage does not matter
193     *                 as the device will use the absolute value for profile
194     *                 generation.
195     * @param Acceleration Acceleration for profiling.  The signage does not matter
196     *                     as the device will use the absolute value for profile
197     *                     generation
198     */
199    public DynamicMotionMagicDutyCycle(double Position, double Velocity, double Acceleration) {
200        this.Position = Position;
201        this.Velocity = Velocity;
202        this.Acceleration = Acceleration;
203    }
204
205    /**
206     * Requires Phoenix Pro and CANivore;
207     * Requests Motion Magic® to target a final position using a motion profile. 
208     * This dynamic request allows runtime changes to Cruise Velocity, Acceleration,
209     * and (optional) Jerk.  Users can optionally provide a duty cycle feedforward.
210     * <p>
211     * Motion Magic® produces a motion profile in real-time while attempting to
212     * honor the specified Cruise Velocity, Acceleration, and (optional) Jerk.  This
213     * control mode does not use the Expo_kV or Expo_kA configs.
214     * <p>
215     * Target position can be changed on-the-fly and Motion Magic® will do its best
216     * to adjust the profile. This control mode is duty cycle based, so relevant
217     * closed-loop gains will use fractional duty cycle for the numerator:  +1.0
218     * represents full forward output.
219     * 
220     * @param Position Position to drive toward in rotations.
221     * @param Velocity Cruise velocity for profiling.  The signage does not matter
222     *                 as the device will use the absolute value for profile
223     *                 generation.
224     * @param Acceleration Acceleration for profiling.  The signage does not matter
225     *                     as the device will use the absolute value for profile
226     *                     generation
227     */
228    public DynamicMotionMagicDutyCycle(Angle Position, AngularVelocity Velocity, AngularAcceleration Acceleration) {
229        this(Position.in(Rotations), Velocity.in(RotationsPerSecond), Acceleration.in(RotationsPerSecondPerSecond));
230    }
231
232    @Override
233    public String getName() {
234        return "DynamicMotionMagicDutyCycle";
235    }
236
237    @Override
238    public String toString() {
239        String ss = "Control: DynamicMotionMagicDutyCycle\n";
240        ss += "    Position: " + Position + " rotations" + "\n";
241        ss += "    Velocity: " + Velocity + " rotations per second" + "\n";
242        ss += "    Acceleration: " + Acceleration + " rotations per second²" + "\n";
243        ss += "    Jerk: " + Jerk + " rotations per second³" + "\n";
244        ss += "    EnableFOC: " + EnableFOC + "\n";
245        ss += "    FeedForward: " + FeedForward + " fractional" + "\n";
246        ss += "    Slot: " + Slot + "\n";
247        ss += "    OverrideBrakeDurNeutral: " + OverrideBrakeDurNeutral + "\n";
248        ss += "    LimitForwardMotion: " + LimitForwardMotion + "\n";
249        ss += "    LimitReverseMotion: " + LimitReverseMotion + "\n";
250        ss += "    IgnoreHardwareLimits: " + IgnoreHardwareLimits + "\n";
251        ss += "    IgnoreSoftwareLimits: " + IgnoreSoftwareLimits + "\n";
252        ss += "    UseTimesync: " + UseTimesync + "\n";
253        return ss;
254    }
255
256    @Override
257    public StatusCode sendRequest(CANBus network, int deviceHash) {
258        return StatusCode.valueOf(ControlJNI.JNI_RequestControlDynamicMotionMagicDutyCycle(
259                network.getNameUTF8Bytes(), deviceHash, UpdateFreqHz, Position, Velocity, Acceleration, Jerk, EnableFOC, FeedForward, Slot, OverrideBrakeDurNeutral, LimitForwardMotion, LimitReverseMotion, IgnoreHardwareLimits, IgnoreSoftwareLimits, UseTimesync));
260    }
261
262    /**
263     * Gets information about this control request.
264     *
265     * @return Map of control parameter names and corresponding applied values
266     */
267    @Override
268    public Map<String, String> getControlInfo() {
269        var controlInfo = new HashMap<String, String>();
270        controlInfo.put("Name", getName());
271        controlInfo.put("Position", String.valueOf(this.Position));
272        controlInfo.put("Velocity", String.valueOf(this.Velocity));
273        controlInfo.put("Acceleration", String.valueOf(this.Acceleration));
274        controlInfo.put("Jerk", String.valueOf(this.Jerk));
275        controlInfo.put("EnableFOC", String.valueOf(this.EnableFOC));
276        controlInfo.put("FeedForward", String.valueOf(this.FeedForward));
277        controlInfo.put("Slot", String.valueOf(this.Slot));
278        controlInfo.put("OverrideBrakeDurNeutral", String.valueOf(this.OverrideBrakeDurNeutral));
279        controlInfo.put("LimitForwardMotion", String.valueOf(this.LimitForwardMotion));
280        controlInfo.put("LimitReverseMotion", String.valueOf(this.LimitReverseMotion));
281        controlInfo.put("IgnoreHardwareLimits", String.valueOf(this.IgnoreHardwareLimits));
282        controlInfo.put("IgnoreSoftwareLimits", String.valueOf(this.IgnoreSoftwareLimits));
283        controlInfo.put("UseTimesync", String.valueOf(this.UseTimesync));
284        return controlInfo;
285    }
286    
287    /**
288     * Modifies this Control Request's Position parameter and returns itself for
289     * method-chaining and easier to use request API.
290     * <p>
291     * Position to drive toward in rotations.
292     * 
293     * <ul>
294     *   <li> Units: rotations
295     * </ul>
296     * 
297     *
298     * @param newPosition Parameter to modify
299     * @return Itself
300     */
301    public DynamicMotionMagicDutyCycle withPosition(double newPosition) {
302        Position = newPosition;
303        return this;
304    }
305    
306    /**
307     * Modifies this Control Request's Position parameter and returns itself for
308     * method-chaining and easier to use request API.
309     * <p>
310     * Position to drive toward in rotations.
311     * 
312     * <ul>
313     *   <li> Units: rotations
314     * </ul>
315     * 
316     *
317     * @param newPosition Parameter to modify
318     * @return Itself
319     */
320    public DynamicMotionMagicDutyCycle withPosition(Angle newPosition) {
321        Position = newPosition.in(Rotations);
322        return this;
323    }
324    
325    /**
326     * Helper method to get this Control Request's Position parameter converted
327     * to a unit type. If not using the Java units library, {@link #Position}
328     * can be accessed directly instead.
329     * <p>
330     * Position to drive toward in rotations.
331     * 
332     * <ul>
333     *   <li> Units: rotations
334     * </ul>
335     * 
336     *
337     * @return Position
338     */
339    public Angle getPositionMeasure() {
340        return Rotations.of(Position);
341    }
342    
343    /**
344     * Modifies this Control Request's Velocity parameter and returns itself for
345     * method-chaining and easier to use request API.
346     * <p>
347     * Cruise velocity for profiling.  The signage does not matter as the device
348     * will use the absolute value for profile generation.
349     * 
350     * <ul>
351     *   <li> Units: rotations per second
352     * </ul>
353     * 
354     *
355     * @param newVelocity Parameter to modify
356     * @return Itself
357     */
358    public DynamicMotionMagicDutyCycle withVelocity(double newVelocity) {
359        Velocity = newVelocity;
360        return this;
361    }
362    
363    /**
364     * Modifies this Control Request's Velocity parameter and returns itself for
365     * method-chaining and easier to use request API.
366     * <p>
367     * Cruise velocity for profiling.  The signage does not matter as the device
368     * will use the absolute value for profile generation.
369     * 
370     * <ul>
371     *   <li> Units: rotations per second
372     * </ul>
373     * 
374     *
375     * @param newVelocity Parameter to modify
376     * @return Itself
377     */
378    public DynamicMotionMagicDutyCycle withVelocity(AngularVelocity newVelocity) {
379        Velocity = newVelocity.in(RotationsPerSecond);
380        return this;
381    }
382    
383    /**
384     * Helper method to get this Control Request's Velocity parameter converted
385     * to a unit type. If not using the Java units library, {@link #Velocity}
386     * can be accessed directly instead.
387     * <p>
388     * Cruise velocity for profiling.  The signage does not matter as the device
389     * will use the absolute value for profile generation.
390     * 
391     * <ul>
392     *   <li> Units: rotations per second
393     * </ul>
394     * 
395     *
396     * @return Velocity
397     */
398    public AngularVelocity getVelocityMeasure() {
399        return RotationsPerSecond.of(Velocity);
400    }
401    
402    /**
403     * Modifies this Control Request's Acceleration parameter and returns itself for
404     * method-chaining and easier to use request API.
405     * <p>
406     * Acceleration for profiling.  The signage does not matter as the device will
407     * use the absolute value for profile generation
408     * 
409     * <ul>
410     *   <li> Units: rotations per second²
411     * </ul>
412     * 
413     *
414     * @param newAcceleration Parameter to modify
415     * @return Itself
416     */
417    public DynamicMotionMagicDutyCycle withAcceleration(double newAcceleration) {
418        Acceleration = newAcceleration;
419        return this;
420    }
421    
422    /**
423     * Modifies this Control Request's Acceleration parameter and returns itself for
424     * method-chaining and easier to use request API.
425     * <p>
426     * Acceleration for profiling.  The signage does not matter as the device will
427     * use the absolute value for profile generation
428     * 
429     * <ul>
430     *   <li> Units: rotations per second²
431     * </ul>
432     * 
433     *
434     * @param newAcceleration Parameter to modify
435     * @return Itself
436     */
437    public DynamicMotionMagicDutyCycle withAcceleration(AngularAcceleration newAcceleration) {
438        Acceleration = newAcceleration.in(RotationsPerSecondPerSecond);
439        return this;
440    }
441    
442    /**
443     * Helper method to get this Control Request's Acceleration parameter converted
444     * to a unit type. If not using the Java units library, {@link #Acceleration}
445     * can be accessed directly instead.
446     * <p>
447     * Acceleration for profiling.  The signage does not matter as the device will
448     * use the absolute value for profile generation
449     * 
450     * <ul>
451     *   <li> Units: rotations per second²
452     * </ul>
453     * 
454     *
455     * @return Acceleration
456     */
457    public AngularAcceleration getAccelerationMeasure() {
458        return RotationsPerSecondPerSecond.of(Acceleration);
459    }
460    
461    /**
462     * Modifies this Control Request's Jerk parameter and returns itself for
463     * method-chaining and easier to use request API.
464     * <p>
465     * Jerk for profiling.  The signage does not matter as the device will use the
466     * absolute value for profile generation.
467     * <p>
468     * Jerk is optional; if this is set to zero, then Motion Magic® will not apply a
469     * Jerk limit.
470     * 
471     * <ul>
472     *   <li> Units: rotations per second³
473     * </ul>
474     * 
475     *
476     * @param newJerk Parameter to modify
477     * @return Itself
478     */
479    public DynamicMotionMagicDutyCycle withJerk(double newJerk) {
480        Jerk = newJerk;
481        return this;
482    }
483    
484    /**
485     * Modifies this Control Request's Jerk parameter and returns itself for
486     * method-chaining and easier to use request API.
487     * <p>
488     * Jerk for profiling.  The signage does not matter as the device will use the
489     * absolute value for profile generation.
490     * <p>
491     * Jerk is optional; if this is set to zero, then Motion Magic® will not apply a
492     * Jerk limit.
493     * 
494     * <ul>
495     *   <li> Units: rotations per second³
496     * </ul>
497     * 
498     *
499     * @param newJerk Parameter to modify
500     * @return Itself
501     */
502    public DynamicMotionMagicDutyCycle withJerk(Velocity<AngularAccelerationUnit> newJerk) {
503        Jerk = newJerk.in(RotationsPerSecondPerSecond.per(Second));
504        return this;
505    }
506    
507    /**
508     * Helper method to get this Control Request's Jerk parameter converted
509     * to a unit type. If not using the Java units library, {@link #Jerk}
510     * can be accessed directly instead.
511     * <p>
512     * Jerk for profiling.  The signage does not matter as the device will use the
513     * absolute value for profile generation.
514     * <p>
515     * Jerk is optional; if this is set to zero, then Motion Magic® will not apply a
516     * Jerk limit.
517     * 
518     * <ul>
519     *   <li> Units: rotations per second³
520     * </ul>
521     * 
522     *
523     * @return Jerk
524     */
525    public Velocity<AngularAccelerationUnit> getJerkMeasure() {
526        return RotationsPerSecondPerSecond.per(Second).of(Jerk);
527    }
528    
529    /**
530     * Modifies this Control Request's EnableFOC parameter and returns itself for
531     * method-chaining and easier to use request API.
532     * <p>
533     * Set to true to use FOC commutation (requires Phoenix Pro), which increases
534     * peak power by ~15% on supported devices (see {@link SupportsFOC}). Set to
535     * false to use trapezoidal commutation.
536     * <p>
537     * FOC improves motor performance by leveraging torque (current) control. 
538     * However, this may be inconvenient for applications that require specifying
539     * duty cycle or voltage.  CTR-Electronics has developed a hybrid method that
540     * combines the performances gains of FOC while still allowing applications to
541     * provide duty cycle or voltage demand.  This not to be confused with simple
542     * sinusoidal control or phase voltage control which lacks the performance
543     * gains.
544     *
545     * @param newEnableFOC Parameter to modify
546     * @return Itself
547     */
548    public DynamicMotionMagicDutyCycle withEnableFOC(boolean newEnableFOC) {
549        EnableFOC = newEnableFOC;
550        return this;
551    }
552    
553    /**
554     * Modifies this Control Request's FeedForward parameter and returns itself for
555     * method-chaining and easier to use request API.
556     * <p>
557     * Feedforward to apply in fractional units between -1 and +1. This is added to
558     * the output of the onboard feedforward terms.
559     * 
560     * <ul>
561     *   <li> Units: fractional
562     * </ul>
563     * 
564     *
565     * @param newFeedForward Parameter to modify
566     * @return Itself
567     */
568    public DynamicMotionMagicDutyCycle withFeedForward(double newFeedForward) {
569        FeedForward = newFeedForward;
570        return this;
571    }
572    
573    /**
574     * Modifies this Control Request's Slot parameter and returns itself for
575     * method-chaining and easier to use request API.
576     * <p>
577     * Select which gains are applied by selecting the slot.  Use the configuration
578     * api to set the gain values for the selected slot before enabling this
579     * feature. Slot must be within [0,2].
580     *
581     * @param newSlot Parameter to modify
582     * @return Itself
583     */
584    public DynamicMotionMagicDutyCycle withSlot(int newSlot) {
585        Slot = newSlot;
586        return this;
587    }
588    
589    /**
590     * Modifies this Control Request's OverrideBrakeDurNeutral parameter and returns itself for
591     * method-chaining and easier to use request API.
592     * <p>
593     * Set to true to static-brake the rotor when output is zero (or within
594     * deadband).  Set to false to use the NeutralMode configuration setting
595     * (default). This flag exists to provide the fundamental behavior of this
596     * control when output is zero, which is to provide 0V to the motor.
597     *
598     * @param newOverrideBrakeDurNeutral Parameter to modify
599     * @return Itself
600     */
601    public DynamicMotionMagicDutyCycle withOverrideBrakeDurNeutral(boolean newOverrideBrakeDurNeutral) {
602        OverrideBrakeDurNeutral = newOverrideBrakeDurNeutral;
603        return this;
604    }
605    
606    /**
607     * Modifies this Control Request's LimitForwardMotion parameter and returns itself for
608     * method-chaining and easier to use request API.
609     * <p>
610     * Set to true to force forward limiting.  This allows users to use other limit
611     * switch sensors connected to robot controller.  This also allows use of active
612     * sensors that require external power.
613     *
614     * @param newLimitForwardMotion Parameter to modify
615     * @return Itself
616     */
617    public DynamicMotionMagicDutyCycle withLimitForwardMotion(boolean newLimitForwardMotion) {
618        LimitForwardMotion = newLimitForwardMotion;
619        return this;
620    }
621    
622    /**
623     * Modifies this Control Request's LimitReverseMotion parameter and returns itself for
624     * method-chaining and easier to use request API.
625     * <p>
626     * Set to true to force reverse limiting.  This allows users to use other limit
627     * switch sensors connected to robot controller.  This also allows use of active
628     * sensors that require external power.
629     *
630     * @param newLimitReverseMotion Parameter to modify
631     * @return Itself
632     */
633    public DynamicMotionMagicDutyCycle withLimitReverseMotion(boolean newLimitReverseMotion) {
634        LimitReverseMotion = newLimitReverseMotion;
635        return this;
636    }
637    
638    /**
639     * Modifies this Control Request's IgnoreHardwareLimits parameter and returns itself for
640     * method-chaining and easier to use request API.
641     * <p>
642     * Set to true to ignore hardware limit switches and the LimitForwardMotion and
643     * LimitReverseMotion parameters, instead allowing motion.
644     * <p>
645     * This can be useful on mechanisms such as an intake/feeder, where a limit
646     * switch stops motion while intaking but should be ignored when feeding to a
647     * shooter.
648     * <p>
649     * The hardware limit faults and Forward/ReverseLimit signals will still report
650     * the values of the limit switches regardless of this parameter.
651     *
652     * @param newIgnoreHardwareLimits Parameter to modify
653     * @return Itself
654     */
655    public DynamicMotionMagicDutyCycle withIgnoreHardwareLimits(boolean newIgnoreHardwareLimits) {
656        IgnoreHardwareLimits = newIgnoreHardwareLimits;
657        return this;
658    }
659    
660    /**
661     * Modifies this Control Request's IgnoreSoftwareLimits parameter and returns itself for
662     * method-chaining and easier to use request API.
663     * <p>
664     * Set to true to ignore software limits, instead allowing motion.
665     * <p>
666     * This can be useful when calibrating the zero point of a mechanism such as an
667     * elevator.
668     * <p>
669     * The software limit faults will still report the values of the software limits
670     * regardless of this parameter.
671     *
672     * @param newIgnoreSoftwareLimits Parameter to modify
673     * @return Itself
674     */
675    public DynamicMotionMagicDutyCycle withIgnoreSoftwareLimits(boolean newIgnoreSoftwareLimits) {
676        IgnoreSoftwareLimits = newIgnoreSoftwareLimits;
677        return this;
678    }
679    
680    /**
681     * Modifies this Control Request's UseTimesync parameter and returns itself for
682     * method-chaining and easier to use request API.
683     * <p>
684     * Set to true to delay applying this control request until a timesync boundary
685     * (requires Phoenix Pro and CANivore). This eliminates the impact of
686     * nondeterministic network delays in exchange for a larger but deterministic
687     * control latency.
688     * <p>
689     * This requires setting the ControlTimesyncFreqHz config in MotorOutputConfigs.
690     * Additionally, when this is enabled, the UpdateFreqHz of this request should
691     * be set to 0 Hz.
692     *
693     * @param newUseTimesync Parameter to modify
694     * @return Itself
695     */
696    public DynamicMotionMagicDutyCycle withUseTimesync(boolean newUseTimesync) {
697        UseTimesync = newUseTimesync;
698        return this;
699    }
700
701    /**
702     * Sets the frequency at which this control will update.
703     * This is designated in Hertz, with a minimum of 20 Hz
704     * (every 50 ms) and a maximum of 1000 Hz (every 1 ms).
705     * Some update frequencies are not supported and will be
706     * promoted up to the next highest supported frequency.
707     * <p>
708     * If this field is set to 0 Hz, the control request will
709     * be sent immediately as a one-shot frame. This may be useful
710     * for advanced applications that require outputs to be
711     * synchronized with data acquisition. In this case, we
712     * recommend not exceeding 50 ms between control calls.
713     *
714     * @param newUpdateFreqHz Parameter to modify
715     * @return Itself
716     */
717    @Override
718    public DynamicMotionMagicDutyCycle withUpdateFreqHz(double newUpdateFreqHz) {
719        UpdateFreqHz = newUpdateFreqHz;
720        return this;
721    }
722
723    /**
724     * Sets the frequency at which this control will update.
725     * This is designated in Hertz, with a minimum of 20 Hz
726     * (every 50 ms) and a maximum of 1000 Hz (every 1 ms).
727     * Some update frequencies are not supported and will be
728     * promoted up to the next highest supported frequency.
729     * <p>
730     * If this field is set to 0 Hz, the control request will
731     * be sent immediately as a one-shot frame. This may be useful
732     * for advanced applications that require outputs to be
733     * synchronized with data acquisition. In this case, we
734     * recommend not exceeding 50 ms between control calls.
735     *
736     * @param newUpdateFreqHz Parameter to modify
737     * @return Itself
738     */
739    @Override
740    public DynamicMotionMagicDutyCycle withUpdateFreqHz(Frequency newUpdateFreqHz) {
741        UpdateFreqHz = newUpdateFreqHz.in(Hertz);
742        return this;
743    }
744
745    @Override
746    public DynamicMotionMagicDutyCycle clone() {
747        try {
748            return (DynamicMotionMagicDutyCycle)super.clone();
749        } catch (CloneNotSupportedException ex) {
750            /* this should never happen */
751            throw new RuntimeException(ex);
752        }
753    }
754}
755