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