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