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