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 a specified motor current (field oriented control). 022 * <p> 023 * This control request will drive the motor to the requested motor (stator) current value. This leverages 024 * field oriented control (FOC), which means greater peak power than what is documented. This scales to 025 * torque based on Motor's kT constant. 026 */ 027public class TorqueCurrentFOC extends ControlRequest implements Cloneable 028{ 029 /** 030 * Amount of motor current in Amperes 031 */ 032 public double Output; 033 /** 034 * The maximum absolute motor output that can be applied, which effectively 035 * limits the velocity. For example, 0.50 means no more than 50% output in 036 * either direction. This is useful for preventing the motor from spinning to 037 * its terminal velocity when there is no external torque applied unto the 038 * rotor. Note this is absolute maximum, so the value should be between zero 039 * and one. 040 */ 041 public double MaxAbsDutyCycle = 1.0; 042 /** 043 * Deadband in Amperes. If torque request is within deadband, the bridge output 044 * is neutral. If deadband is set to zero then there is effectively no deadband. 045 * Note if deadband is zero, a free spinning motor will spin for quite a while 046 * as the firmware attempts to hold the motor's bemf. If user expects motor to 047 * cease spinning quickly with a demand of zero, we recommend a deadband of one 048 * Ampere. This value will be converted to an integral value of amps. 049 */ 050 public double Deadband = 0.0; 051 /** 052 * Set to true to coast the rotor when output is zero (or within deadband). Set 053 * to false to use the NeutralMode configuration setting (default). This flag 054 * exists to provide the fundamental behavior of this control when output is 055 * zero, which is to provide 0A (zero torque). 056 */ 057 public boolean OverrideCoastDurNeutral = 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 * Requires Phoenix Pro; 109 * Request a specified motor current (field oriented control). 110 * <p> 111 * This control request will drive the motor to the requested motor (stator) 112 * current value. This leverages field oriented control (FOC), which means 113 * greater peak power than what is documented. This scales to torque based on 114 * Motor's kT constant. 115 * 116 * @param Output Amount of motor current in Amperes 117 */ 118 public TorqueCurrentFOC(double Output) 119 { 120 super("TorqueCurrentFOC"); 121 this.Output = Output; 122 } 123 124 /** 125 * Requires Phoenix Pro; 126 * Request a specified motor current (field oriented control). 127 * <p> 128 * This control request will drive the motor to the requested motor (stator) 129 * current value. This leverages field oriented control (FOC), which means 130 * greater peak power than what is documented. This scales to torque based on 131 * Motor's kT constant. 132 * 133 * @param Output Amount of motor current in Amperes 134 */ 135 public TorqueCurrentFOC(Current Output) 136 { 137 this(Output.in(Amps)); 138 } 139 140 @Override 141 public String toString() 142 { 143 String ss = "Control: TorqueCurrentFOC\n"; 144 ss += " Output: " + Output + " A" + "\n"; 145 ss += " MaxAbsDutyCycle: " + MaxAbsDutyCycle + " fractional" + "\n"; 146 ss += " Deadband: " + Deadband + " A" + "\n"; 147 ss += " OverrideCoastDurNeutral: " + OverrideCoastDurNeutral + "\n"; 148 ss += " LimitForwardMotion: " + LimitForwardMotion + "\n"; 149 ss += " LimitReverseMotion: " + LimitReverseMotion + "\n"; 150 ss += " IgnoreHardwareLimits: " + IgnoreHardwareLimits + "\n"; 151 ss += " UseTimesync: " + UseTimesync + "\n"; 152 return ss; 153 } 154 155 @Override 156 public StatusCode sendRequest(String network, int deviceHash) 157 { 158 return StatusCode.valueOf(ControlJNI.JNI_RequestControlTorqueCurrentFOC( 159 network, deviceHash, UpdateFreqHz, Output, MaxAbsDutyCycle, Deadband, OverrideCoastDurNeutral, LimitForwardMotion, LimitReverseMotion, IgnoreHardwareLimits, UseTimesync)); 160 } 161 162 /** 163 * Gets information about this control request. 164 * 165 * @return Map of control parameter names and corresponding applied values 166 */ 167 @Override 168 public Map<String, String> getControlInfo() 169 { 170 var controlInfo = new HashMap<String, String>(); 171 controlInfo.put("Name", getName()); 172 controlInfo.put("Output", String.valueOf(this.Output)); 173 controlInfo.put("MaxAbsDutyCycle", String.valueOf(this.MaxAbsDutyCycle)); 174 controlInfo.put("Deadband", String.valueOf(this.Deadband)); 175 controlInfo.put("OverrideCoastDurNeutral", String.valueOf(this.OverrideCoastDurNeutral)); 176 controlInfo.put("LimitForwardMotion", String.valueOf(this.LimitForwardMotion)); 177 controlInfo.put("LimitReverseMotion", String.valueOf(this.LimitReverseMotion)); 178 controlInfo.put("IgnoreHardwareLimits", String.valueOf(this.IgnoreHardwareLimits)); 179 controlInfo.put("UseTimesync", String.valueOf(this.UseTimesync)); 180 return controlInfo; 181 } 182 183 /** 184 * Modifies this Control Request's Output parameter and returns itself for 185 * method-chaining and easier to use request API. 186 * <p> 187 * Amount of motor current in Amperes 188 * 189 * @param newOutput Parameter to modify 190 * @return Itself 191 */ 192 public TorqueCurrentFOC withOutput(double newOutput) 193 { 194 Output = newOutput; 195 return this; 196 } 197 198 /** 199 * Modifies this Control Request's Output parameter and returns itself for 200 * method-chaining and easier to use request API. 201 * <p> 202 * Amount of motor current in Amperes 203 * 204 * @param newOutput Parameter to modify 205 * @return Itself 206 */ 207 public TorqueCurrentFOC withOutput(Current newOutput) 208 { 209 Output = newOutput.in(Amps); 210 return this; 211 } 212 213 /** 214 * Helper method to get this Control Request's Output parameter converted 215 * to a unit type. If not using the Java units library, {@link #Output} 216 * can be accessed directly instead. 217 * <p> 218 * Amount of motor current in Amperes 219 * 220 * @return Output 221 */ 222 public Current getOutputMeasure() 223 { 224 return Amps.of(Output); 225 } 226 227 /** 228 * Modifies this Control Request's MaxAbsDutyCycle parameter and returns itself for 229 * method-chaining and easier to use request API. 230 * <p> 231 * The maximum absolute motor output that can be applied, which effectively 232 * limits the velocity. For example, 0.50 means no more than 50% output in 233 * either direction. This is useful for preventing the motor from spinning to 234 * its terminal velocity when there is no external torque applied unto the 235 * rotor. Note this is absolute maximum, so the value should be between zero 236 * and one. 237 * 238 * @param newMaxAbsDutyCycle Parameter to modify 239 * @return Itself 240 */ 241 public TorqueCurrentFOC withMaxAbsDutyCycle(double newMaxAbsDutyCycle) 242 { 243 MaxAbsDutyCycle = newMaxAbsDutyCycle; 244 return this; 245 } 246 247 /** 248 * Modifies this Control Request's Deadband parameter and returns itself for 249 * method-chaining and easier to use request API. 250 * <p> 251 * Deadband in Amperes. If torque request is within deadband, the bridge output 252 * is neutral. If deadband is set to zero then there is effectively no deadband. 253 * Note if deadband is zero, a free spinning motor will spin for quite a while 254 * as the firmware attempts to hold the motor's bemf. If user expects motor to 255 * cease spinning quickly with a demand of zero, we recommend a deadband of one 256 * Ampere. This value will be converted to an integral value of amps. 257 * 258 * @param newDeadband Parameter to modify 259 * @return Itself 260 */ 261 public TorqueCurrentFOC withDeadband(double newDeadband) 262 { 263 Deadband = newDeadband; 264 return this; 265 } 266 267 /** 268 * Modifies this Control Request's Deadband parameter and returns itself for 269 * method-chaining and easier to use request API. 270 * <p> 271 * Deadband in Amperes. If torque request is within deadband, the bridge output 272 * is neutral. If deadband is set to zero then there is effectively no deadband. 273 * Note if deadband is zero, a free spinning motor will spin for quite a while 274 * as the firmware attempts to hold the motor's bemf. If user expects motor to 275 * cease spinning quickly with a demand of zero, we recommend a deadband of one 276 * Ampere. This value will be converted to an integral value of amps. 277 * 278 * @param newDeadband Parameter to modify 279 * @return Itself 280 */ 281 public TorqueCurrentFOC withDeadband(Current newDeadband) 282 { 283 Deadband = newDeadband.in(Amps); 284 return this; 285 } 286 287 /** 288 * Helper method to get this Control Request's Deadband parameter converted 289 * to a unit type. If not using the Java units library, {@link #Deadband} 290 * can be accessed directly instead. 291 * <p> 292 * Deadband in Amperes. If torque request is within deadband, the bridge output 293 * is neutral. If deadband is set to zero then there is effectively no deadband. 294 * Note if deadband is zero, a free spinning motor will spin for quite a while 295 * as the firmware attempts to hold the motor's bemf. If user expects motor to 296 * cease spinning quickly with a demand of zero, we recommend a deadband of one 297 * Ampere. This value will be converted to an integral value of amps. 298 * 299 * @return Deadband 300 */ 301 public Current getDeadbandMeasure() 302 { 303 return Amps.of(Deadband); 304 } 305 306 /** 307 * Modifies this Control Request's OverrideCoastDurNeutral parameter and returns itself for 308 * method-chaining and easier to use request API. 309 * <p> 310 * Set to true to coast the rotor when output is zero (or within deadband). Set 311 * to false to use the NeutralMode configuration setting (default). This flag 312 * exists to provide the fundamental behavior of this control when output is 313 * zero, which is to provide 0A (zero torque). 314 * 315 * @param newOverrideCoastDurNeutral Parameter to modify 316 * @return Itself 317 */ 318 public TorqueCurrentFOC withOverrideCoastDurNeutral(boolean newOverrideCoastDurNeutral) 319 { 320 OverrideCoastDurNeutral = newOverrideCoastDurNeutral; 321 return this; 322 } 323 324 /** 325 * Modifies this Control Request's LimitForwardMotion parameter and returns itself for 326 * method-chaining and easier to use request API. 327 * <p> 328 * Set to true to force forward limiting. This allows users to use other limit 329 * switch sensors connected to robot controller. This also allows use of active 330 * sensors that require external power. 331 * 332 * @param newLimitForwardMotion Parameter to modify 333 * @return Itself 334 */ 335 public TorqueCurrentFOC withLimitForwardMotion(boolean newLimitForwardMotion) 336 { 337 LimitForwardMotion = newLimitForwardMotion; 338 return this; 339 } 340 341 /** 342 * Modifies this Control Request's LimitReverseMotion parameter and returns itself for 343 * method-chaining and easier to use request API. 344 * <p> 345 * Set to true to force reverse limiting. This allows users to use other limit 346 * switch sensors connected to robot controller. This also allows use of active 347 * sensors that require external power. 348 * 349 * @param newLimitReverseMotion Parameter to modify 350 * @return Itself 351 */ 352 public TorqueCurrentFOC withLimitReverseMotion(boolean newLimitReverseMotion) 353 { 354 LimitReverseMotion = newLimitReverseMotion; 355 return this; 356 } 357 358 /** 359 * Modifies this Control Request's IgnoreHardwareLimits parameter and returns itself for 360 * method-chaining and easier to use request API. 361 * <p> 362 * Set to true to ignore hardware limit switches and the LimitForwardMotion and 363 * LimitReverseMotion parameters, instead allowing motion. 364 * <p> 365 * This can be useful on mechanisms such as an intake/feeder, where a limit 366 * switch stops motion while intaking but should be ignored when feeding to a 367 * shooter. 368 * <p> 369 * The hardware limit faults and Forward/ReverseLimit signals will still report 370 * the values of the limit switches regardless of this parameter. 371 * 372 * @param newIgnoreHardwareLimits Parameter to modify 373 * @return Itself 374 */ 375 public TorqueCurrentFOC withIgnoreHardwareLimits(boolean newIgnoreHardwareLimits) 376 { 377 IgnoreHardwareLimits = newIgnoreHardwareLimits; 378 return this; 379 } 380 381 /** 382 * Modifies this Control Request's UseTimesync parameter and returns itself for 383 * method-chaining and easier to use request API. 384 * <p> 385 * Set to true to delay applying this control request until a timesync boundary 386 * (requires Phoenix Pro and CANivore). This eliminates the impact of 387 * nondeterministic network delays in exchange for a larger but deterministic 388 * control latency. 389 * <p> 390 * This requires setting the ControlTimesyncFreqHz config in MotorOutputConfigs. 391 * Additionally, when this is enabled, the UpdateFreqHz of this request should 392 * be set to 0 Hz. 393 * 394 * @param newUseTimesync Parameter to modify 395 * @return Itself 396 */ 397 public TorqueCurrentFOC withUseTimesync(boolean newUseTimesync) 398 { 399 UseTimesync = newUseTimesync; 400 return this; 401 } 402 403 /** 404 * Sets the period at which this control will update at. 405 * This is designated in Hertz, with a minimum of 20 Hz 406 * (every 50 ms) and a maximum of 1000 Hz (every 1 ms). 407 * <p> 408 * If this field is set to 0 Hz, the control request will 409 * be sent immediately as a one-shot frame. This may be useful 410 * for advanced applications that require outputs to be 411 * synchronized with data acquisition. In this case, we 412 * recommend not exceeding 50 ms between control calls. 413 * 414 * @param newUpdateFreqHz Parameter to modify 415 * @return Itself 416 */ 417 @Override 418 public TorqueCurrentFOC withUpdateFreqHz(double newUpdateFreqHz) 419 { 420 UpdateFreqHz = newUpdateFreqHz; 421 return this; 422 } 423 424 /** 425 * Sets the period at which this control will update at. 426 * This is designated in Hertz, with a minimum of 20 Hz 427 * (every 50 ms) and a maximum of 1000 Hz (every 1 ms). 428 * <p> 429 * If this field is set to 0 Hz, the control request will 430 * be sent immediately as a one-shot frame. This may be useful 431 * for advanced applications that require outputs to be 432 * synchronized with data acquisition. In this case, we 433 * recommend not exceeding 50 ms between control calls. 434 * 435 * @param newUpdateFreqHz Parameter to modify 436 * @return Itself 437 */ 438 public TorqueCurrentFOC withUpdateFreqHz(Frequency newUpdateFreqHz) 439 { 440 UpdateFreqHz = newUpdateFreqHz.in(Hertz); 441 return this; 442 } 443 444 @Override 445 public TorqueCurrentFOC clone() 446 { 447 try { 448 return (TorqueCurrentFOC)super.clone(); 449 } catch (CloneNotSupportedException ex) { 450 /* this should never happen */ 451 throw new RuntimeException(ex); 452 } 453 } 454} 455