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