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