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