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