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