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 * Request a specified voltage.
022 * <p>
023 * This control mode will attempt to apply the specified voltage to the motor. If the supply voltage is below
024 * the requested voltage, the motor controller will output the supply voltage.
025 */
026public class VoltageOut extends ControlRequest implements Cloneable
027{
028    /**
029     * Voltage to attempt to drive at
030     * 
031     * <ul>
032     *   <li> Units: Volts
033     * </ul>
034     * 
035     */
036    public double Output;
037    /**
038     * Set to true to use FOC commutation (requires Phoenix Pro), which increases
039     * peak power by ~15% on supported devices (see {@link SupportsFOC}). Set to
040     * false to use trapezoidal commutation.
041     * <p>
042     * FOC improves motor performance by leveraging torque (current) control. 
043     * However, this may be inconvenient for applications that require specifying
044     * duty cycle or voltage.  CTR-Electronics has developed a hybrid method that
045     * combines the performances gains of FOC while still allowing applications to
046     * provide duty cycle or voltage demand.  This not to be confused with simple
047     * sinusoidal control or phase voltage control which lacks the performance
048     * gains.
049     */
050    public boolean EnableFOC = true;
051    /**
052     * Set to true to static-brake the rotor when output is zero (or within
053     * deadband).  Set to false to use the NeutralMode configuration setting
054     * (default). This flag exists to provide the fundamental behavior of this
055     * control when output is zero, which is to provide 0V to the motor.
056     */
057    public boolean OverrideBrakeDurNeutral = false;
058    /**
059     * Set to true to force forward limiting.  This allows users to use other limit
060     * switch sensors connected to robot controller.  This also allows use of active
061     * sensors that require external power.
062     */
063    public boolean LimitForwardMotion = false;
064    /**
065     * Set to true to force reverse limiting.  This allows users to use other limit
066     * switch sensors connected to robot controller.  This also allows use of active
067     * sensors that require external power.
068     */
069    public boolean LimitReverseMotion = false;
070    /**
071     * Set to true to ignore hardware limit switches and the LimitForwardMotion and
072     * LimitReverseMotion parameters, instead allowing motion.
073     * <p>
074     * This can be useful on mechanisms such as an intake/feeder, where a limit
075     * switch stops motion while intaking but should be ignored when feeding to a
076     * shooter.
077     * <p>
078     * The hardware limit faults and Forward/ReverseLimit signals will still report
079     * the values of the limit switches regardless of this parameter.
080     */
081    public boolean IgnoreHardwareLimits = false;
082    /**
083     * Set to true to delay applying this control request until a timesync boundary
084     * (requires Phoenix Pro and CANivore). This eliminates the impact of
085     * nondeterministic network delays in exchange for a larger but deterministic
086     * control latency.
087     * <p>
088     * This requires setting the ControlTimesyncFreqHz config in MotorOutputConfigs.
089     * Additionally, when this is enabled, the UpdateFreqHz of this request should
090     * be set to 0 Hz.
091     */
092    public boolean UseTimesync = false;
093
094    /**
095     * The period at which this control will update at.
096     * This is designated in Hertz, with a minimum of 20 Hz
097     * (every 50 ms) and a maximum of 1000 Hz (every 1 ms).
098     * <p>
099     * If this field is set to 0 Hz, the control request will
100     * be sent immediately as a one-shot frame. This may be useful
101     * for advanced applications that require outputs to be
102     * synchronized with data acquisition. In this case, we
103     * recommend not exceeding 50 ms between control calls.
104     */
105    public double UpdateFreqHz = 100;
106
107    /**
108     * Request a specified voltage.
109     * <p>
110     * This control mode will attempt to apply the specified voltage to the motor.
111     * If the supply voltage is below the requested voltage, the motor controller
112     * will output the supply voltage.
113     * 
114     * @param Output    Voltage to attempt to drive at
115     */
116    public VoltageOut(double Output)
117    {
118        super("VoltageOut");
119        this.Output = Output;
120    }
121
122    /**
123     * Request a specified voltage.
124     * <p>
125     * This control mode will attempt to apply the specified voltage to the motor.
126     * If the supply voltage is below the requested voltage, the motor controller
127     * will output the supply voltage.
128     * 
129     * @param Output    Voltage to attempt to drive at
130     */
131    public VoltageOut(Voltage Output)
132    {
133        this(Output.in(Volts));
134    }
135
136    @Override
137    public String toString()
138    {
139        String ss = "Control: VoltageOut\n";
140        ss += "    Output: " + Output + " Volts" + "\n";
141        ss += "    EnableFOC: " + EnableFOC + "\n";
142        ss += "    OverrideBrakeDurNeutral: " + OverrideBrakeDurNeutral + "\n";
143        ss += "    LimitForwardMotion: " + LimitForwardMotion + "\n";
144        ss += "    LimitReverseMotion: " + LimitReverseMotion + "\n";
145        ss += "    IgnoreHardwareLimits: " + IgnoreHardwareLimits + "\n";
146        ss += "    UseTimesync: " + UseTimesync + "\n";
147        return ss;
148    }
149
150    @Override
151    public StatusCode sendRequest(String network, int deviceHash)
152    {
153        return StatusCode.valueOf(ControlJNI.JNI_RequestControlVoltageOut(
154                network, deviceHash, UpdateFreqHz, Output, EnableFOC, OverrideBrakeDurNeutral, LimitForwardMotion, LimitReverseMotion, IgnoreHardwareLimits, UseTimesync));
155    }
156
157    /**
158     * Gets information about this control request.
159     *
160     * @return Map of control parameter names and corresponding applied values
161     */
162    @Override
163    public Map<String, String> getControlInfo()
164    {
165        var controlInfo = new HashMap<String, String>();
166        controlInfo.put("Name", getName());
167        controlInfo.put("Output", String.valueOf(this.Output));
168        controlInfo.put("EnableFOC", String.valueOf(this.EnableFOC));
169        controlInfo.put("OverrideBrakeDurNeutral", String.valueOf(this.OverrideBrakeDurNeutral));
170        controlInfo.put("LimitForwardMotion", String.valueOf(this.LimitForwardMotion));
171        controlInfo.put("LimitReverseMotion", String.valueOf(this.LimitReverseMotion));
172        controlInfo.put("IgnoreHardwareLimits", String.valueOf(this.IgnoreHardwareLimits));
173        controlInfo.put("UseTimesync", String.valueOf(this.UseTimesync));
174        return controlInfo;
175    }
176    
177    /**
178     * Modifies this Control Request's Output parameter and returns itself for
179     * method-chaining and easier to use request API.
180     * <p>
181     * Voltage to attempt to drive at
182     * 
183     * <ul>
184     *   <li> Units: Volts
185     * </ul>
186     * 
187     *
188     * @param newOutput Parameter to modify
189     * @return Itself
190     */
191    public VoltageOut withOutput(double newOutput)
192    {
193        Output = newOutput;
194        return this;
195    }
196    
197    /**
198     * Modifies this Control Request's Output parameter and returns itself for
199     * method-chaining and easier to use request API.
200     * <p>
201     * Voltage to attempt to drive at
202     * 
203     * <ul>
204     *   <li> Units: Volts
205     * </ul>
206     * 
207     *
208     * @param newOutput Parameter to modify
209     * @return Itself
210     */
211    public VoltageOut withOutput(Voltage newOutput)
212    {
213        Output = newOutput.in(Volts);
214        return this;
215    }
216    
217    /**
218     * Helper method to get this Control Request's Output parameter converted
219     * to a unit type. If not using the Java units library, {@link #Output}
220     * can be accessed directly instead.
221     * <p>
222     * Voltage to attempt to drive at
223     * 
224     * <ul>
225     *   <li> Units: Volts
226     * </ul>
227     * 
228     *
229     * @return Output
230     */
231    public Voltage getOutputMeasure()
232    {
233        return Volts.of(Output);
234    }
235    
236    /**
237     * Modifies this Control Request's EnableFOC parameter and returns itself for
238     * method-chaining and easier to use request API.
239     * <p>
240     * Set to true to use FOC commutation (requires Phoenix Pro), which increases
241     * peak power by ~15% on supported devices (see {@link SupportsFOC}). Set to
242     * false to use trapezoidal commutation.
243     * <p>
244     * FOC improves motor performance by leveraging torque (current) control. 
245     * However, this may be inconvenient for applications that require specifying
246     * duty cycle or voltage.  CTR-Electronics has developed a hybrid method that
247     * combines the performances gains of FOC while still allowing applications to
248     * provide duty cycle or voltage demand.  This not to be confused with simple
249     * sinusoidal control or phase voltage control which lacks the performance
250     * gains.
251     *
252     * @param newEnableFOC Parameter to modify
253     * @return Itself
254     */
255    public VoltageOut withEnableFOC(boolean newEnableFOC)
256    {
257        EnableFOC = newEnableFOC;
258        return this;
259    }
260    
261    /**
262     * Modifies this Control Request's OverrideBrakeDurNeutral parameter and returns itself for
263     * method-chaining and easier to use request API.
264     * <p>
265     * Set to true to static-brake the rotor when output is zero (or within
266     * deadband).  Set to false to use the NeutralMode configuration setting
267     * (default). This flag exists to provide the fundamental behavior of this
268     * control when output is zero, which is to provide 0V to the motor.
269     *
270     * @param newOverrideBrakeDurNeutral Parameter to modify
271     * @return Itself
272     */
273    public VoltageOut withOverrideBrakeDurNeutral(boolean newOverrideBrakeDurNeutral)
274    {
275        OverrideBrakeDurNeutral = newOverrideBrakeDurNeutral;
276        return this;
277    }
278    
279    /**
280     * Modifies this Control Request's LimitForwardMotion parameter and returns itself for
281     * method-chaining and easier to use request API.
282     * <p>
283     * Set to true to force forward limiting.  This allows users to use other limit
284     * switch sensors connected to robot controller.  This also allows use of active
285     * sensors that require external power.
286     *
287     * @param newLimitForwardMotion Parameter to modify
288     * @return Itself
289     */
290    public VoltageOut withLimitForwardMotion(boolean newLimitForwardMotion)
291    {
292        LimitForwardMotion = newLimitForwardMotion;
293        return this;
294    }
295    
296    /**
297     * Modifies this Control Request's LimitReverseMotion parameter and returns itself for
298     * method-chaining and easier to use request API.
299     * <p>
300     * Set to true to force reverse limiting.  This allows users to use other limit
301     * switch sensors connected to robot controller.  This also allows use of active
302     * sensors that require external power.
303     *
304     * @param newLimitReverseMotion Parameter to modify
305     * @return Itself
306     */
307    public VoltageOut withLimitReverseMotion(boolean newLimitReverseMotion)
308    {
309        LimitReverseMotion = newLimitReverseMotion;
310        return this;
311    }
312    
313    /**
314     * Modifies this Control Request's IgnoreHardwareLimits parameter and returns itself for
315     * method-chaining and easier to use request API.
316     * <p>
317     * Set to true to ignore hardware limit switches and the LimitForwardMotion and
318     * LimitReverseMotion parameters, instead allowing motion.
319     * <p>
320     * This can be useful on mechanisms such as an intake/feeder, where a limit
321     * switch stops motion while intaking but should be ignored when feeding to a
322     * shooter.
323     * <p>
324     * The hardware limit faults and Forward/ReverseLimit signals will still report
325     * the values of the limit switches regardless of this parameter.
326     *
327     * @param newIgnoreHardwareLimits Parameter to modify
328     * @return Itself
329     */
330    public VoltageOut withIgnoreHardwareLimits(boolean newIgnoreHardwareLimits)
331    {
332        IgnoreHardwareLimits = newIgnoreHardwareLimits;
333        return this;
334    }
335    
336    /**
337     * Modifies this Control Request's UseTimesync parameter and returns itself for
338     * method-chaining and easier to use request API.
339     * <p>
340     * Set to true to delay applying this control request until a timesync boundary
341     * (requires Phoenix Pro and CANivore). This eliminates the impact of
342     * nondeterministic network delays in exchange for a larger but deterministic
343     * control latency.
344     * <p>
345     * This requires setting the ControlTimesyncFreqHz config in MotorOutputConfigs.
346     * Additionally, when this is enabled, the UpdateFreqHz of this request should
347     * be set to 0 Hz.
348     *
349     * @param newUseTimesync Parameter to modify
350     * @return Itself
351     */
352    public VoltageOut withUseTimesync(boolean newUseTimesync)
353    {
354        UseTimesync = newUseTimesync;
355        return this;
356    }
357
358    /**
359     * Sets the period at which this control will update at.
360     * This is designated in Hertz, with a minimum of 20 Hz
361     * (every 50 ms) and a maximum of 1000 Hz (every 1 ms).
362     * <p>
363     * If this field is set to 0 Hz, the control request will
364     * be sent immediately as a one-shot frame. This may be useful
365     * for advanced applications that require outputs to be
366     * synchronized with data acquisition. In this case, we
367     * recommend not exceeding 50 ms between control calls.
368     *
369     * @param newUpdateFreqHz Parameter to modify
370     * @return Itself
371     */
372    @Override
373    public VoltageOut withUpdateFreqHz(double newUpdateFreqHz)
374    {
375        UpdateFreqHz = newUpdateFreqHz;
376        return this;
377    }
378
379    /**
380     * Sets the period at which this control will update at.
381     * This is designated in Hertz, with a minimum of 20 Hz
382     * (every 50 ms) and a maximum of 1000 Hz (every 1 ms).
383     * <p>
384     * If this field is set to 0 Hz, the control request will
385     * be sent immediately as a one-shot frame. This may be useful
386     * for advanced applications that require outputs to be
387     * synchronized with data acquisition. In this case, we
388     * recommend not exceeding 50 ms between control calls.
389     *
390     * @param newUpdateFreqHz Parameter to modify
391     * @return Itself
392     */
393    @Override
394    public VoltageOut withUpdateFreqHz(Frequency newUpdateFreqHz)
395    {
396        UpdateFreqHz = newUpdateFreqHz.in(Hertz);
397        return this;
398    }
399
400    @Override
401    public VoltageOut clone()
402    {
403        try {
404            return (VoltageOut)super.clone();
405        } catch (CloneNotSupportedException ex) {
406            /* this should never happen */
407            throw new RuntimeException(ex);
408        }
409    }
410}
411