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;
023 * Request PID to target position with torque current feedforward.
024 * <p>
025 * This control mode will set the motor's position setpoint to the position specified by the user. In
026 * addition, it will apply an additional torque current as an arbitrary feedforward value.
027 */
028public final class PositionTorqueCurrentFOC implements ControlRequest, Cloneable {
029    /**
030     * Position to drive toward in rotations.
031     * 
032     * <ul>
033     *   <li> Units: rotations
034     * </ul>
035     * 
036     */
037    public double Position;
038    /**
039     * Velocity to drive toward in rotations per second. This is typically used for
040     * motion profiles generated by the robot program.
041     * 
042     * <ul>
043     *   <li> Units: rotations per second
044     * </ul>
045     * 
046     */
047    public double Velocity = 0.0;
048    /**
049     * Feedforward to apply in torque current in Amperes. This is added to the
050     * output of the onboard feedforward terms.
051     * <p>
052     * User can use motor's kT to scale Newton-meter to Amperes.
053     * 
054     * <ul>
055     *   <li> Units: A
056     * </ul>
057     * 
058     */
059    public double FeedForward = 0.0;
060    /**
061     * Select which gains are applied by selecting the slot.  Use the configuration
062     * api to set the gain values for the selected slot before enabling this
063     * feature. Slot must be within [0,2].
064     */
065    public int Slot = 0;
066    /**
067     * Set to true to coast the rotor when output is zero (or within deadband).  Set
068     * to false to use the NeutralMode configuration setting (default). This flag
069     * exists to provide the fundamental behavior of this control when output is
070     * zero, which is to provide 0A (zero torque).
071     */
072    public boolean OverrideCoastDurNeutral = false;
073    /**
074     * Set to true to force forward limiting.  This allows users to use other limit
075     * switch sensors connected to robot controller.  This also allows use of active
076     * sensors that require external power.
077     */
078    public boolean LimitForwardMotion = false;
079    /**
080     * Set to true to force reverse limiting.  This allows users to use other limit
081     * switch sensors connected to robot controller.  This also allows use of active
082     * sensors that require external power.
083     */
084    public boolean LimitReverseMotion = false;
085    /**
086     * Set to true to ignore hardware limit switches and the LimitForwardMotion and
087     * LimitReverseMotion parameters, instead allowing motion.
088     * <p>
089     * This can be useful on mechanisms such as an intake/feeder, where a limit
090     * switch stops motion while intaking but should be ignored when feeding to a
091     * shooter.
092     * <p>
093     * The hardware limit faults and Forward/ReverseLimit signals will still report
094     * the values of the limit switches regardless of this parameter.
095     */
096    public boolean IgnoreHardwareLimits = false;
097    /**
098     * Set to true to ignore software limits, instead allowing motion.
099     * <p>
100     * This can be useful when calibrating the zero point of a mechanism such as an
101     * elevator.
102     * <p>
103     * The software limit faults will still report the values of the software limits
104     * regardless of this parameter.
105     */
106    public boolean IgnoreSoftwareLimits = false;
107    /**
108     * Set to true to delay applying this control request until a timesync boundary
109     * (requires Phoenix Pro and CANivore). This eliminates the impact of
110     * nondeterministic network delays in exchange for a larger but deterministic
111     * control latency.
112     * <p>
113     * This requires setting the ControlTimesyncFreqHz config in MotorOutputConfigs.
114     * Additionally, when this is enabled, the UpdateFreqHz of this request should
115     * be set to 0 Hz.
116     */
117    public boolean UseTimesync = false;
118
119    /**
120     * The frequency at which this control will update.
121     * This is designated in Hertz, with a minimum of 20 Hz
122     * (every 50 ms) and a maximum of 1000 Hz (every 1 ms).
123     * Some update frequencies are not supported and will be
124     * promoted up to the next highest supported frequency.
125     * <p>
126     * If this field is set to 0 Hz, the control request will
127     * be sent immediately as a one-shot frame. This may be useful
128     * for advanced applications that require outputs to be
129     * synchronized with data acquisition. In this case, we
130     * recommend not exceeding 50 ms between control calls.
131     */
132    public double UpdateFreqHz = 100;
133
134    /**
135     * Requires Phoenix Pro;
136     * Request PID to target position with torque current feedforward.
137     * <p>
138     * This control mode will set the motor's position setpoint to the position
139     * specified by the user. In addition, it will apply an additional torque
140     * current as an arbitrary feedforward value.
141     * 
142     * @param Position Position to drive toward in rotations.
143     */
144    public PositionTorqueCurrentFOC(double Position) {
145        this.Position = Position;
146    }
147
148    /**
149     * Requires Phoenix Pro;
150     * Request PID to target position with torque current feedforward.
151     * <p>
152     * This control mode will set the motor's position setpoint to the position
153     * specified by the user. In addition, it will apply an additional torque
154     * current as an arbitrary feedforward value.
155     * 
156     * @param Position Position to drive toward in rotations.
157     */
158    public PositionTorqueCurrentFOC(Angle Position) {
159        this(Position.in(Rotations));
160    }
161
162    @Override
163    public String getName() {
164        return "PositionTorqueCurrentFOC";
165    }
166
167    @Override
168    public String toString() {
169        String ss = "Control: PositionTorqueCurrentFOC\n";
170        ss += "    Position: " + Position + " rotations" + "\n";
171        ss += "    Velocity: " + Velocity + " rotations per second" + "\n";
172        ss += "    FeedForward: " + FeedForward + " A" + "\n";
173        ss += "    Slot: " + Slot + "\n";
174        ss += "    OverrideCoastDurNeutral: " + OverrideCoastDurNeutral + "\n";
175        ss += "    LimitForwardMotion: " + LimitForwardMotion + "\n";
176        ss += "    LimitReverseMotion: " + LimitReverseMotion + "\n";
177        ss += "    IgnoreHardwareLimits: " + IgnoreHardwareLimits + "\n";
178        ss += "    IgnoreSoftwareLimits: " + IgnoreSoftwareLimits + "\n";
179        ss += "    UseTimesync: " + UseTimesync + "\n";
180        return ss;
181    }
182
183    @Override
184    public StatusCode sendRequest(CANBus network, int deviceHash) {
185        return StatusCode.valueOf(ControlJNI.JNI_RequestControlPositionTorqueCurrentFOC(
186                network.getNameUTF8Bytes(), deviceHash, UpdateFreqHz, Position, Velocity, FeedForward, Slot, OverrideCoastDurNeutral, LimitForwardMotion, LimitReverseMotion, IgnoreHardwareLimits, IgnoreSoftwareLimits, UseTimesync));
187    }
188
189    /**
190     * Gets information about this control request.
191     *
192     * @return Map of control parameter names and corresponding applied values
193     */
194    @Override
195    public Map<String, String> getControlInfo() {
196        var controlInfo = new HashMap<String, String>();
197        controlInfo.put("Name", getName());
198        controlInfo.put("Position", String.valueOf(this.Position));
199        controlInfo.put("Velocity", String.valueOf(this.Velocity));
200        controlInfo.put("FeedForward", String.valueOf(this.FeedForward));
201        controlInfo.put("Slot", String.valueOf(this.Slot));
202        controlInfo.put("OverrideCoastDurNeutral", String.valueOf(this.OverrideCoastDurNeutral));
203        controlInfo.put("LimitForwardMotion", String.valueOf(this.LimitForwardMotion));
204        controlInfo.put("LimitReverseMotion", String.valueOf(this.LimitReverseMotion));
205        controlInfo.put("IgnoreHardwareLimits", String.valueOf(this.IgnoreHardwareLimits));
206        controlInfo.put("IgnoreSoftwareLimits", String.valueOf(this.IgnoreSoftwareLimits));
207        controlInfo.put("UseTimesync", String.valueOf(this.UseTimesync));
208        return controlInfo;
209    }
210    
211    /**
212     * Modifies this Control Request's Position parameter and returns itself for
213     * method-chaining and easier to use request API.
214     * <p>
215     * Position to drive toward in rotations.
216     * 
217     * <ul>
218     *   <li> Units: rotations
219     * </ul>
220     * 
221     *
222     * @param newPosition Parameter to modify
223     * @return Itself
224     */
225    public PositionTorqueCurrentFOC withPosition(double newPosition) {
226        Position = newPosition;
227        return this;
228    }
229    
230    /**
231     * Modifies this Control Request's Position parameter and returns itself for
232     * method-chaining and easier to use request API.
233     * <p>
234     * Position to drive toward in rotations.
235     * 
236     * <ul>
237     *   <li> Units: rotations
238     * </ul>
239     * 
240     *
241     * @param newPosition Parameter to modify
242     * @return Itself
243     */
244    public PositionTorqueCurrentFOC withPosition(Angle newPosition) {
245        Position = newPosition.in(Rotations);
246        return this;
247    }
248    
249    /**
250     * Helper method to get this Control Request's Position parameter converted
251     * to a unit type. If not using the Java units library, {@link #Position}
252     * can be accessed directly instead.
253     * <p>
254     * Position to drive toward in rotations.
255     * 
256     * <ul>
257     *   <li> Units: rotations
258     * </ul>
259     * 
260     *
261     * @return Position
262     */
263    public Angle getPositionMeasure() {
264        return Rotations.of(Position);
265    }
266    
267    /**
268     * Modifies this Control Request's Velocity parameter and returns itself for
269     * method-chaining and easier to use request API.
270     * <p>
271     * Velocity to drive toward in rotations per second. This is typically used for
272     * motion profiles generated by the robot program.
273     * 
274     * <ul>
275     *   <li> Units: rotations per second
276     * </ul>
277     * 
278     *
279     * @param newVelocity Parameter to modify
280     * @return Itself
281     */
282    public PositionTorqueCurrentFOC withVelocity(double newVelocity) {
283        Velocity = newVelocity;
284        return this;
285    }
286    
287    /**
288     * Modifies this Control Request's Velocity parameter and returns itself for
289     * method-chaining and easier to use request API.
290     * <p>
291     * Velocity to drive toward in rotations per second. This is typically used for
292     * motion profiles generated by the robot program.
293     * 
294     * <ul>
295     *   <li> Units: rotations per second
296     * </ul>
297     * 
298     *
299     * @param newVelocity Parameter to modify
300     * @return Itself
301     */
302    public PositionTorqueCurrentFOC withVelocity(AngularVelocity newVelocity) {
303        Velocity = newVelocity.in(RotationsPerSecond);
304        return this;
305    }
306    
307    /**
308     * Helper method to get this Control Request's Velocity parameter converted
309     * to a unit type. If not using the Java units library, {@link #Velocity}
310     * can be accessed directly instead.
311     * <p>
312     * Velocity to drive toward in rotations per second. This is typically used for
313     * motion profiles generated by the robot program.
314     * 
315     * <ul>
316     *   <li> Units: rotations per second
317     * </ul>
318     * 
319     *
320     * @return Velocity
321     */
322    public AngularVelocity getVelocityMeasure() {
323        return RotationsPerSecond.of(Velocity);
324    }
325    
326    /**
327     * Modifies this Control Request's FeedForward parameter and returns itself for
328     * method-chaining and easier to use request API.
329     * <p>
330     * Feedforward to apply in torque current in Amperes. This is added to the
331     * output of the onboard feedforward terms.
332     * <p>
333     * User can use motor's kT to scale Newton-meter to Amperes.
334     * 
335     * <ul>
336     *   <li> Units: A
337     * </ul>
338     * 
339     *
340     * @param newFeedForward Parameter to modify
341     * @return Itself
342     */
343    public PositionTorqueCurrentFOC withFeedForward(double newFeedForward) {
344        FeedForward = newFeedForward;
345        return this;
346    }
347    
348    /**
349     * Modifies this Control Request's FeedForward parameter and returns itself for
350     * method-chaining and easier to use request API.
351     * <p>
352     * Feedforward to apply in torque current in Amperes. This is added to the
353     * output of the onboard feedforward terms.
354     * <p>
355     * User can use motor's kT to scale Newton-meter to Amperes.
356     * 
357     * <ul>
358     *   <li> Units: A
359     * </ul>
360     * 
361     *
362     * @param newFeedForward Parameter to modify
363     * @return Itself
364     */
365    public PositionTorqueCurrentFOC withFeedForward(Current newFeedForward) {
366        FeedForward = newFeedForward.in(Amps);
367        return this;
368    }
369    
370    /**
371     * Helper method to get this Control Request's FeedForward parameter converted
372     * to a unit type. If not using the Java units library, {@link #FeedForward}
373     * can be accessed directly instead.
374     * <p>
375     * Feedforward to apply in torque current in Amperes. This is added to the
376     * output of the onboard feedforward terms.
377     * <p>
378     * User can use motor's kT to scale Newton-meter to Amperes.
379     * 
380     * <ul>
381     *   <li> Units: A
382     * </ul>
383     * 
384     *
385     * @return FeedForward
386     */
387    public Current getFeedForwardMeasure() {
388        return Amps.of(FeedForward);
389    }
390    
391    /**
392     * Modifies this Control Request's Slot parameter and returns itself for
393     * method-chaining and easier to use request API.
394     * <p>
395     * Select which gains are applied by selecting the slot.  Use the configuration
396     * api to set the gain values for the selected slot before enabling this
397     * feature. Slot must be within [0,2].
398     *
399     * @param newSlot Parameter to modify
400     * @return Itself
401     */
402    public PositionTorqueCurrentFOC withSlot(int newSlot) {
403        Slot = newSlot;
404        return this;
405    }
406    
407    /**
408     * Modifies this Control Request's OverrideCoastDurNeutral parameter and returns itself for
409     * method-chaining and easier to use request API.
410     * <p>
411     * Set to true to coast the rotor when output is zero (or within deadband).  Set
412     * to false to use the NeutralMode configuration setting (default). This flag
413     * exists to provide the fundamental behavior of this control when output is
414     * zero, which is to provide 0A (zero torque).
415     *
416     * @param newOverrideCoastDurNeutral Parameter to modify
417     * @return Itself
418     */
419    public PositionTorqueCurrentFOC withOverrideCoastDurNeutral(boolean newOverrideCoastDurNeutral) {
420        OverrideCoastDurNeutral = newOverrideCoastDurNeutral;
421        return this;
422    }
423    
424    /**
425     * Modifies this Control Request's LimitForwardMotion parameter and returns itself for
426     * method-chaining and easier to use request API.
427     * <p>
428     * Set to true to force forward limiting.  This allows users to use other limit
429     * switch sensors connected to robot controller.  This also allows use of active
430     * sensors that require external power.
431     *
432     * @param newLimitForwardMotion Parameter to modify
433     * @return Itself
434     */
435    public PositionTorqueCurrentFOC withLimitForwardMotion(boolean newLimitForwardMotion) {
436        LimitForwardMotion = newLimitForwardMotion;
437        return this;
438    }
439    
440    /**
441     * Modifies this Control Request's LimitReverseMotion parameter and returns itself for
442     * method-chaining and easier to use request API.
443     * <p>
444     * Set to true to force reverse limiting.  This allows users to use other limit
445     * switch sensors connected to robot controller.  This also allows use of active
446     * sensors that require external power.
447     *
448     * @param newLimitReverseMotion Parameter to modify
449     * @return Itself
450     */
451    public PositionTorqueCurrentFOC withLimitReverseMotion(boolean newLimitReverseMotion) {
452        LimitReverseMotion = newLimitReverseMotion;
453        return this;
454    }
455    
456    /**
457     * Modifies this Control Request's IgnoreHardwareLimits parameter and returns itself for
458     * method-chaining and easier to use request API.
459     * <p>
460     * Set to true to ignore hardware limit switches and the LimitForwardMotion and
461     * LimitReverseMotion parameters, instead allowing motion.
462     * <p>
463     * This can be useful on mechanisms such as an intake/feeder, where a limit
464     * switch stops motion while intaking but should be ignored when feeding to a
465     * shooter.
466     * <p>
467     * The hardware limit faults and Forward/ReverseLimit signals will still report
468     * the values of the limit switches regardless of this parameter.
469     *
470     * @param newIgnoreHardwareLimits Parameter to modify
471     * @return Itself
472     */
473    public PositionTorqueCurrentFOC withIgnoreHardwareLimits(boolean newIgnoreHardwareLimits) {
474        IgnoreHardwareLimits = newIgnoreHardwareLimits;
475        return this;
476    }
477    
478    /**
479     * Modifies this Control Request's IgnoreSoftwareLimits parameter and returns itself for
480     * method-chaining and easier to use request API.
481     * <p>
482     * Set to true to ignore software limits, instead allowing motion.
483     * <p>
484     * This can be useful when calibrating the zero point of a mechanism such as an
485     * elevator.
486     * <p>
487     * The software limit faults will still report the values of the software limits
488     * regardless of this parameter.
489     *
490     * @param newIgnoreSoftwareLimits Parameter to modify
491     * @return Itself
492     */
493    public PositionTorqueCurrentFOC withIgnoreSoftwareLimits(boolean newIgnoreSoftwareLimits) {
494        IgnoreSoftwareLimits = newIgnoreSoftwareLimits;
495        return this;
496    }
497    
498    /**
499     * Modifies this Control Request's UseTimesync parameter and returns itself for
500     * method-chaining and easier to use request API.
501     * <p>
502     * Set to true to delay applying this control request until a timesync boundary
503     * (requires Phoenix Pro and CANivore). This eliminates the impact of
504     * nondeterministic network delays in exchange for a larger but deterministic
505     * control latency.
506     * <p>
507     * This requires setting the ControlTimesyncFreqHz config in MotorOutputConfigs.
508     * Additionally, when this is enabled, the UpdateFreqHz of this request should
509     * be set to 0 Hz.
510     *
511     * @param newUseTimesync Parameter to modify
512     * @return Itself
513     */
514    public PositionTorqueCurrentFOC withUseTimesync(boolean newUseTimesync) {
515        UseTimesync = newUseTimesync;
516        return this;
517    }
518
519    /**
520     * Sets the frequency at which this control will update.
521     * This is designated in Hertz, with a minimum of 20 Hz
522     * (every 50 ms) and a maximum of 1000 Hz (every 1 ms).
523     * Some update frequencies are not supported and will be
524     * promoted up to the next highest supported frequency.
525     * <p>
526     * If this field is set to 0 Hz, the control request will
527     * be sent immediately as a one-shot frame. This may be useful
528     * for advanced applications that require outputs to be
529     * synchronized with data acquisition. In this case, we
530     * recommend not exceeding 50 ms between control calls.
531     *
532     * @param newUpdateFreqHz Parameter to modify
533     * @return Itself
534     */
535    @Override
536    public PositionTorqueCurrentFOC withUpdateFreqHz(double newUpdateFreqHz) {
537        UpdateFreqHz = newUpdateFreqHz;
538        return this;
539    }
540
541    /**
542     * Sets the frequency at which this control will update.
543     * This is designated in Hertz, with a minimum of 20 Hz
544     * (every 50 ms) and a maximum of 1000 Hz (every 1 ms).
545     * Some update frequencies are not supported and will be
546     * promoted up to the next highest supported frequency.
547     * <p>
548     * If this field is set to 0 Hz, the control request will
549     * be sent immediately as a one-shot frame. This may be useful
550     * for advanced applications that require outputs to be
551     * synchronized with data acquisition. In this case, we
552     * recommend not exceeding 50 ms between control calls.
553     *
554     * @param newUpdateFreqHz Parameter to modify
555     * @return Itself
556     */
557    @Override
558    public PositionTorqueCurrentFOC withUpdateFreqHz(Frequency newUpdateFreqHz) {
559        UpdateFreqHz = newUpdateFreqHz.in(Hertz);
560        return this;
561    }
562
563    @Override
564    public PositionTorqueCurrentFOC clone() {
565        try {
566            return (PositionTorqueCurrentFOC)super.clone();
567        } catch (CloneNotSupportedException ex) {
568            /* this should never happen */
569            throw new RuntimeException(ex);
570        }
571    }
572}
573