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