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