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