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