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