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.mechanisms; 008 009import java.util.Optional; 010import java.util.OptionalInt; 011import java.util.concurrent.atomic.AtomicBoolean; 012import java.util.function.BooleanSupplier; 013 014import edu.wpi.first.units.measure.*; 015import edu.wpi.first.wpilibj.DriverStation; 016 017import static edu.wpi.first.units.Units.*; 018 019import com.ctre.phoenix6.BaseStatusSignal; 020import com.ctre.phoenix6.CANBus; 021import com.ctre.phoenix6.StatusCode; 022import com.ctre.phoenix6.StatusSignal; 023import com.ctre.phoenix6.configs.DifferentialSensorsConfigs; 024import com.ctre.phoenix6.configs.MotorOutputConfigs; 025import com.ctre.phoenix6.configs.TalonFXConfiguration; 026import com.ctre.phoenix6.configs.TalonFXSConfiguration; 027import com.ctre.phoenix6.controls.DifferentialFollower; 028import com.ctre.phoenix6.controls.NeutralOut; 029import com.ctre.phoenix6.controls.CoastOut; 030import com.ctre.phoenix6.controls.StaticBrake; 031import com.ctre.phoenix6.hardware.CANcoder; 032import com.ctre.phoenix6.hardware.CANdi; 033import com.ctre.phoenix6.hardware.Pigeon2; 034import com.ctre.phoenix6.hardware.TalonFX; 035import com.ctre.phoenix6.hardware.TalonFXS; 036import com.ctre.phoenix6.hardware.traits.CommonTalon; 037import com.ctre.phoenix6.mechanisms.DifferentialMotorConstants.*; 038import com.ctre.phoenix6.signals.DifferentialSensorSourceValue; 039import com.ctre.phoenix6.signals.InvertedValue; 040import com.ctre.phoenix6.signals.MotorAlignmentValue; 041import com.ctre.phoenix6.signals.NeutralModeValue; 042 043import com.ctre.phoenix6.controls.DifferentialDutyCycle; 044import com.ctre.phoenix6.controls.DifferentialMotionMagicDutyCycle; 045import com.ctre.phoenix6.controls.DifferentialMotionMagicExpoDutyCycle; 046import com.ctre.phoenix6.controls.DifferentialMotionMagicExpoVoltage; 047import com.ctre.phoenix6.controls.DifferentialMotionMagicVelocityDutyCycle; 048import com.ctre.phoenix6.controls.DifferentialMotionMagicVelocityVoltage; 049import com.ctre.phoenix6.controls.DifferentialMotionMagicVoltage; 050import com.ctre.phoenix6.controls.DifferentialPositionDutyCycle; 051import com.ctre.phoenix6.controls.DifferentialPositionVoltage; 052import com.ctre.phoenix6.controls.DifferentialVelocityDutyCycle; 053import com.ctre.phoenix6.controls.DifferentialVelocityVoltage; 054import com.ctre.phoenix6.controls.DifferentialVoltage; 055 056/** 057 * Manages control of a simple two-axis differential mechanism. 058 * <p> 059 * This mechanism provides limited differential functionality. Pro users 060 * on a CAN FD bus can use the {@link DifferentialMechanism} instead 061 * for full functionality. 062 * <p> 063 * A differential mechanism has two axes of motion, where the position 064 * along each axis is determined by two motors in separate gearboxes: 065 * <ul> 066 * <li>Driving both motors in a common direction causes the mechanism 067 * to move forward/reverse, up/down, etc. 068 * <ul> 069 * <li>This is the Average axis: position is determined by the 070 * average of the two motors' positions. 071 * </ul> 072 * <li>Driving the motors in opposing directions causes the mechanism 073 * to twist or rotate left/right. 074 * <ul> 075 * <li>This is the Difference axis: rotation is determined by half 076 * the difference of the two motors' positions. 077 * </ul> 078 * </ul> 079 */ 080public class SimpleDifferentialMechanism<MotorT extends CommonTalon> { 081 /** 082 * Functional interface for device constructors. 083 */ 084 @FunctionalInterface 085 public static interface DeviceConstructor<DeviceT> { 086 DeviceT create(int id, CANBus canbus); 087 } 088 089 /** 090 * Possible reasons for the mechanism to disable. 091 */ 092 public enum DisabledReasonValue { 093 /** 094 * No reason given. 095 */ 096 None, 097 /** 098 * A remote sensor is not present on CAN Bus. 099 */ 100 MissingRemoteSensor, 101 /** 102 * The remote Talon FX used for differential 103 * control is not present on CAN Bus. 104 */ 105 MissingDifferentialFX, 106 /** 107 * A remote sensor position has overflowed. Because of the nature 108 * of remote sensors, it is possible for a remote sensor position 109 * to overflow beyond what is supported by the status signal frame. 110 * However, this is rare and cannot occur over the course of an FRC 111 * match under normal use. 112 */ 113 RemoteSensorPosOverflow, 114 /** 115 * A device or remote sensor has reset. 116 */ 117 DeviceHasReset, 118 } 119 120 /** 121 * Possible reasons for the mechanism to require 122 * user action to resume control. 123 */ 124 public enum RequiresUserReasonValue { 125 /** 126 * No reason given. 127 */ 128 None, 129 /** 130 * A remote sensor position has overflowed. Because of the nature 131 * of remote sensors, it is possible for a remote sensor position 132 * to overflow beyond what is supported by the status signal frame. 133 * However, this is rare and cannot occur over the course of an FRC 134 * match under normal use. 135 */ 136 RemoteSensorPosOverflow, 137 /** 138 * A device or remote sensor has reset. 139 */ 140 DeviceHasReset, 141 } 142 143 /** Number of times to attempt config applies. */ 144 private static final int kNumConfigAttempts = 2; 145 146 private final MotorT _diffLeaderFX; 147 private final MotorT _diffFollowerFX; 148 149 private final double _sensorToDiffRatio; 150 151 private final BooleanSupplier _diffLeaderFXResetChecker; 152 private final BooleanSupplier _diffFollowerFXResetChecker; 153 private final Optional<BooleanSupplier> _diffSensorResetChecker; 154 155 private final DifferentialFollower _diffFollow; 156 157 private final NeutralOut _neutral = new NeutralOut(); 158 private final CoastOut _coast = new CoastOut(); 159 private final StaticBrake _brake = new StaticBrake(); 160 161 private final AtomicBoolean _mechanismDisabled = new AtomicBoolean(false); 162 private final AtomicBoolean _requiresUserAction = new AtomicBoolean(false); 163 164 private DisabledReasonValue _disabledReason = DisabledReasonValue.None; 165 private RequiresUserReasonValue _requiresUserReason = RequiresUserReasonValue.None; 166 167 /** 168 * Creates a new simple differential mechanism using two {@link CommonTalon} devices. 169 * The mechanism will use the average of the two Talon FX sensors on the primary axis, 170 * and half of the difference between the two Talon FX sensors on the differential axis. 171 * <p> 172 * This mechanism provides limited differential functionality. Pro users on a CAN FD 173 * bus can use the {@link DifferentialMechanism} class instead for full functionality. 174 * 175 * @param motorConstructor Constructor for the motors, such as {@code TalonFX::new} 176 * @param constants Constants used to construct the mechanism 177 */ 178 public SimpleDifferentialMechanism(DeviceConstructor<MotorT> motorConstructor, DifferentialMotorConstants<?> constants) { 179 final var canbus = new CANBus(constants.CANBusName); 180 _diffLeaderFX = motorConstructor.create(constants.LeaderId, canbus); 181 _diffFollowerFX = motorConstructor.create(constants.FollowerId, canbus); 182 _sensorToDiffRatio = constants.SensorToDifferentialRatio; 183 _diffLeaderFXResetChecker = _diffLeaderFX.getResetOccurredChecker(); 184 _diffFollowerFXResetChecker = _diffFollowerFX.getResetOccurredChecker(); 185 _diffFollow = new DifferentialFollower(_diffLeaderFX.getDeviceID(), constants.Alignment); 186 _diffSensorResetChecker = Optional.empty(); 187 188 applyConfigs(constants, DifferentialSensorSourceValue.RemoteTalonFX_HalfDiff, OptionalInt.empty()); 189 /* Set update frequency of relevant signals */ 190 BaseStatusSignal.setUpdateFrequencyForAll( 191 constants.ClosedLoopRate, 192 _diffLeaderFX.getDifferentialOutput(false), 193 _diffFollowerFX.getPosition(false), 194 _diffFollowerFX.getVelocity(false) 195 ); 196 } 197 198 /** 199 * Creates a new simple differential mechanism using two {@link CommonTalon} devices and 200 * a {@link Pigeon2}. The mechanism will use the average of the two Talon FX sensors on the 201 * primary axis, and the selected Pigeon 2 sensor source on the differential axis. 202 * <p> 203 * This mechanism provides limited differential functionality. Pro users on a CAN FD 204 * bus can use the {@link DifferentialMechanism} class instead for full functionality. 205 * 206 * @param motorConstructor Constructor for the motors, such as {@code TalonFX::new} 207 * @param constants Constants used to construct the mechanism 208 * @param pigeon2 The Pigeon 2 to use for the differential axis 209 * @param pigeonSource The sensor source to use for the Pigeon 2 (Yaw, Pitch, or Roll) 210 */ 211 public SimpleDifferentialMechanism(DeviceConstructor<MotorT> motorConstructor, DifferentialMotorConstants<?> constants, Pigeon2 pigeon2, DifferentialPigeon2Source pigeonSource) { 212 final var canbus = new CANBus(constants.CANBusName); 213 _diffLeaderFX = motorConstructor.create(constants.LeaderId, canbus); 214 _diffFollowerFX = motorConstructor.create(constants.FollowerId, canbus); 215 _sensorToDiffRatio = constants.SensorToDifferentialRatio; 216 _diffLeaderFXResetChecker = _diffLeaderFX.getResetOccurredChecker(); 217 _diffFollowerFXResetChecker = _diffFollowerFX.getResetOccurredChecker(); 218 _diffSensorResetChecker = Optional.of(pigeon2.getResetOccurredChecker()); 219 _diffFollow = new DifferentialFollower(_diffLeaderFX.getDeviceID(), constants.Alignment); 220 221 DifferentialSensorSourceValue diffSensorSource; 222 switch (pigeonSource) { 223 case Yaw: 224 default: 225 diffSensorSource = DifferentialSensorSourceValue.RemotePigeon2Yaw; 226 break; 227 case Pitch: 228 diffSensorSource = DifferentialSensorSourceValue.RemotePigeon2Pitch; 229 break; 230 case Roll: 231 diffSensorSource = DifferentialSensorSourceValue.RemotePigeon2Roll; 232 break; 233 } 234 applyConfigs(constants, diffSensorSource, OptionalInt.of(pigeon2.getDeviceID())); 235 236 /* Set update frequency of relevant signals */ 237 BaseStatusSignal.setUpdateFrequencyForAll( 238 constants.ClosedLoopRate, 239 _diffLeaderFX.getDifferentialOutput(false), 240 _diffFollowerFX.getPosition(false), 241 _diffFollowerFX.getVelocity(false) 242 ); 243 switch (pigeonSource) { 244 case Yaw: 245 pigeon2.getYaw(false).setUpdateFrequency(constants.ClosedLoopRate); 246 break; 247 case Pitch: 248 pigeon2.getPitch(false).setUpdateFrequency(constants.ClosedLoopRate); 249 break; 250 case Roll: 251 pigeon2.getRoll(false).setUpdateFrequency(constants.ClosedLoopRate); 252 break; 253 } 254 } 255 256 /** 257 * Creates a new simple differential mechanism using two {@link CommonTalon} devices and 258 * a {@link CANcoder}. The mechanism will use the average of the two Talon FX sensors on the 259 * primary axis, and the CANcoder position/velocity on the differential axis. 260 * <p> 261 * This mechanism provides limited differential functionality. Pro users on a CAN FD 262 * bus can use the {@link DifferentialMechanism} class instead for full functionality. 263 * 264 * @param motorConstructor Constructor for the motors, such as {@code TalonFX::new} 265 * @param constants Constants used to construct the mechanism 266 * @param cancoder The CANcoder to use for the differential axis 267 */ 268 public SimpleDifferentialMechanism(DeviceConstructor<MotorT> motorConstructor, DifferentialMotorConstants<?> constants, CANcoder cancoder) { 269 final var canbus = new CANBus(constants.CANBusName); 270 _diffLeaderFX = motorConstructor.create(constants.LeaderId, canbus); 271 _diffFollowerFX = motorConstructor.create(constants.FollowerId, canbus); 272 _sensorToDiffRatio = constants.SensorToDifferentialRatio; 273 _diffLeaderFXResetChecker = _diffLeaderFX.getResetOccurredChecker(); 274 _diffFollowerFXResetChecker = _diffFollowerFX.getResetOccurredChecker(); 275 _diffSensorResetChecker = Optional.of(cancoder.getResetOccurredChecker()); 276 _diffFollow = new DifferentialFollower(_diffLeaderFX.getDeviceID(), constants.Alignment); 277 278 applyConfigs(constants, DifferentialSensorSourceValue.RemoteCANcoder, OptionalInt.of(cancoder.getDeviceID())); 279 /* Set update frequency of relevant signals */ 280 BaseStatusSignal.setUpdateFrequencyForAll( 281 constants.ClosedLoopRate, 282 _diffLeaderFX.getDifferentialOutput(false), 283 _diffFollowerFX.getPosition(false), 284 _diffFollowerFX.getVelocity(false), 285 cancoder.getPosition(false), 286 cancoder.getVelocity(false) 287 ); 288 } 289 290 /** 291 * Creates a new simple differential mechanism using two hardware#traits#CommonTalon devices and a 292 * {@link CANdi}. The mechanism will use the average of the two Talon FX sensors on the primary 293 * axis, and the selected CTR Electronics' CANdi™ branded sensor source on the differential axis. 294 * <p> 295 * This mechanism provides limited differential functionality. Pro users on a CAN FD 296 * bus can use the {@link DifferentialMechanism} class instead for full functionality. 297 * 298 * @param motorConstructor Constructor for the motors, such as {@code TalonFX::new} 299 * @param constants Constants used to construct the mechanism 300 * @param candi The CTR Electronics' CANdi™ branded device to use for the differential axis 301 * @param candiSource The sensor source to use for the CTR Electronics' CANdi™ branded device 302 */ 303 public SimpleDifferentialMechanism(DeviceConstructor<MotorT> motorConstructor, DifferentialMotorConstants<?> constants, CANdi candi, DifferentialCANdiSource candiSource) { 304 final var canbus = new CANBus(constants.CANBusName); 305 _diffLeaderFX = motorConstructor.create(constants.LeaderId, canbus); 306 _diffFollowerFX = motorConstructor.create(constants.FollowerId, canbus); 307 _sensorToDiffRatio = constants.SensorToDifferentialRatio; 308 _diffLeaderFXResetChecker = _diffLeaderFX.getResetOccurredChecker(); 309 _diffFollowerFXResetChecker = _diffFollowerFX.getResetOccurredChecker(); 310 _diffSensorResetChecker = Optional.of(candi.getResetOccurredChecker()); 311 _diffFollow = new DifferentialFollower(_diffLeaderFX.getDeviceID(), constants.Alignment); 312 313 DifferentialSensorSourceValue diffSensorSource; 314 switch (candiSource) { 315 case PWM1: 316 default: 317 diffSensorSource = DifferentialSensorSourceValue.RemoteCANdiPWM1; 318 break; 319 case PWM2: 320 diffSensorSource = DifferentialSensorSourceValue.RemoteCANdiPWM2; 321 break; 322 case Quadrature: 323 diffSensorSource = DifferentialSensorSourceValue.RemoteCANdiQuadrature; 324 break; 325 } 326 applyConfigs(constants, diffSensorSource, OptionalInt.of(candi.getDeviceID())); 327 328 /* Set update frequency of relevant signals */ 329 BaseStatusSignal.setUpdateFrequencyForAll( 330 constants.ClosedLoopRate, 331 _diffLeaderFX.getDifferentialOutput(false), 332 _diffFollowerFX.getPosition(false), 333 _diffFollowerFX.getVelocity(false) 334 ); 335 switch (candiSource) { 336 case PWM1: 337 BaseStatusSignal.setUpdateFrequencyForAll( 338 constants.ClosedLoopRate, 339 candi.getPWM1Position(false), 340 candi.getPWM1Velocity(false) 341 ); 342 break; 343 case PWM2: 344 BaseStatusSignal.setUpdateFrequencyForAll( 345 constants.ClosedLoopRate, 346 candi.getPWM2Position(false), 347 candi.getPWM2Velocity(false) 348 ); 349 break; 350 case Quadrature: 351 BaseStatusSignal.setUpdateFrequencyForAll( 352 constants.ClosedLoopRate, 353 candi.getQuadraturePosition(false), 354 candi.getQuadratureVelocity(false) 355 ); 356 break; 357 } 358 } 359 360 private void applyConfigs(DifferentialMotorConstants<?> constants, DifferentialSensorSourceValue diffSensorSource, OptionalInt diffSensorID) { 361 /* 362 * The onboard differential controller adds the differential output to its own output 363 * and subtracts the differential output for differential followers, so use _diffLeaderFX 364 * as the primary controller. 365 */ 366 367 InvertedValue leaderInvert; 368 369 /* set up differential control on _diffLeaderFX */ 370 { 371 var diff_cfg = new DifferentialSensorsConfigs(); 372 373 diff_cfg.DifferentialTalonFXSensorID = _diffFollowerFX.getDeviceID(); 374 diff_cfg.DifferentialSensorSource = diffSensorSource; 375 diffSensorID.ifPresent(id -> diff_cfg.DifferentialRemoteSensorID = id); 376 diff_cfg.SensorToDifferentialRatio = constants.SensorToDifferentialRatio; 377 378 StatusCode response = StatusCode.OK; 379 380 if ( 381 _diffLeaderFX instanceof TalonFX diffLeaderFX && 382 (constants.LeaderInitialConfigs == null || constants.LeaderInitialConfigs instanceof TalonFXConfiguration) 383 ) { 384 var leaderConfigs = (TalonFXConfiguration)constants.LeaderInitialConfigs; 385 if (leaderConfigs == null) { 386 leaderConfigs = new TalonFXConfiguration(); 387 } 388 leaderInvert = leaderConfigs.MotorOutput.Inverted; 389 390 leaderConfigs.DifferentialSensors = diff_cfg; 391 for (int i = 0; i < kNumConfigAttempts; ++i) { 392 response = diffLeaderFX.getConfigurator().apply(leaderConfigs); 393 if (response.isOK()) break; 394 } 395 } else if ( 396 _diffLeaderFX instanceof TalonFXS diffLeaderFXS && 397 (constants.LeaderInitialConfigs == null || constants.LeaderInitialConfigs instanceof TalonFXSConfiguration) 398 ) { 399 var leaderConfigs = (TalonFXSConfiguration)constants.LeaderInitialConfigs; 400 if (leaderConfigs == null) { 401 leaderConfigs = new TalonFXSConfiguration(); 402 } 403 leaderInvert = leaderConfigs.MotorOutput.Inverted; 404 405 leaderConfigs.DifferentialSensors = diff_cfg; 406 for (int i = 0; i < kNumConfigAttempts; ++i) { 407 response = diffLeaderFXS.getConfigurator().apply(leaderConfigs); 408 if (response.isOK()) break; 409 } 410 } else { 411 DriverStation.reportError( 412 "[phoenix] DifferentialMechanism motor type does not match the DifferentialMotorConstants initial configs type. Ensure that the DifferentialMechanism and DifferentialMotorConstants instances are both constructed with the same motor type (TalonFX/TalonFXConfiguration, TalonFXS/TalonFXSConfiguration, etc.).", 413 true 414 ); 415 return; 416 } 417 418 if (!response.isOK()) { 419 System.out.println( 420 "Talon ID " + _diffLeaderFX.getDeviceID() + " failed config with error " + response.toString() 421 ); 422 } 423 } 424 425 /* disable differential control on _diffFollowerFX */ 426 { 427 StatusCode response = StatusCode.OK; 428 429 if (_diffFollowerFX instanceof TalonFX diffFollowerFX) { 430 var followerConfigs = (TalonFXConfiguration)constants.FollowerInitialConfigs; 431 if (followerConfigs == null) { 432 followerConfigs = new TalonFXConfiguration(); 433 } 434 followerConfigs.DifferentialSensors = new DifferentialSensorsConfigs(); 435 followerConfigs.MotorOutput.Inverted = constants.Alignment == MotorAlignmentValue.Aligned 436 ? leaderInvert 437 : leaderInvert == InvertedValue.CounterClockwise_Positive 438 ? InvertedValue.Clockwise_Positive 439 : InvertedValue.CounterClockwise_Positive; 440 441 if (constants.FollowerUsesCommonLeaderConfigs) { 442 /* copy over common config groups from the leader */ 443 var leaderConfigs = (TalonFXConfiguration)constants.LeaderInitialConfigs; 444 if (leaderConfigs == null) { 445 leaderConfigs = new TalonFXConfiguration(); 446 } 447 448 followerConfigs.Audio = leaderConfigs.Audio; 449 followerConfigs.CurrentLimits = leaderConfigs.CurrentLimits; 450 followerConfigs.MotorOutput = leaderConfigs.MotorOutput.clone() 451 .withInverted(followerConfigs.MotorOutput.Inverted); 452 followerConfigs.Voltage = leaderConfigs.Voltage; 453 followerConfigs.TorqueCurrent = leaderConfigs.TorqueCurrent; 454 } 455 456 for (int i = 0; i < kNumConfigAttempts; ++i) { 457 response = diffFollowerFX.getConfigurator().apply(followerConfigs); 458 if (response.isOK()) break; 459 } 460 } else if (_diffFollowerFX instanceof TalonFXS diffFollowerFXS) { 461 var followerConfigs = (TalonFXSConfiguration)constants.FollowerInitialConfigs; 462 if (followerConfigs == null) { 463 followerConfigs = new TalonFXSConfiguration(); 464 } 465 followerConfigs.DifferentialSensors = new DifferentialSensorsConfigs(); 466 followerConfigs.MotorOutput.Inverted = constants.Alignment == MotorAlignmentValue.Aligned 467 ? leaderInvert 468 : leaderInvert == InvertedValue.CounterClockwise_Positive 469 ? InvertedValue.Clockwise_Positive 470 : InvertedValue.CounterClockwise_Positive; 471 472 if (constants.FollowerUsesCommonLeaderConfigs) { 473 /* copy over common config groups from the leader */ 474 var leaderConfigs = (TalonFXSConfiguration)constants.LeaderInitialConfigs; 475 if (leaderConfigs == null) { 476 leaderConfigs = new TalonFXSConfiguration(); 477 } 478 479 followerConfigs.Audio = leaderConfigs.Audio; 480 followerConfigs.CurrentLimits = leaderConfigs.CurrentLimits; 481 followerConfigs.MotorOutput = leaderConfigs.MotorOutput.clone() 482 .withInverted(followerConfigs.MotorOutput.Inverted); 483 followerConfigs.Voltage = leaderConfigs.Voltage; 484 } 485 486 for (int i = 0; i < kNumConfigAttempts; ++i) { 487 response = diffFollowerFXS.getConfigurator().apply(followerConfigs); 488 if (response.isOK()) break; 489 } 490 } else { 491 DriverStation.reportError( 492 "[phoenix] DifferentialMechanism motor type does not match the DifferentialMotorConstants initial configs type. Ensure that the DifferentialMechanism and DifferentialMotorConstants instances are both constructed with the same motor type (TalonFX/TalonFXConfiguration, TalonFXS/TalonFXSConfiguration, etc.).", 493 true 494 ); 495 return; 496 } 497 498 if (!response.isOK()) { 499 System.out.println( 500 "Talon ID " + _diffFollowerFX.getDeviceID() + " failed config with error " + response.toString() 501 ); 502 } 503 } 504 } 505 506 private StatusCode configNeutralModeImpl(MotorT motor, NeutralModeValue neutralMode, double timeoutSeconds) { 507 StatusCode status = StatusCode.OK; 508 509 var motorOutCfg = new MotorOutputConfigs(); 510 if (motor instanceof TalonFX motorFX) { 511 /* First read the configs so they're up-to-date */ 512 status = motorFX.getConfigurator().refresh(motorOutCfg, timeoutSeconds); 513 if (status.isOK()) { 514 /* Then set the neutral mode config to the appropriate value */ 515 motorOutCfg.NeutralMode = neutralMode; 516 status = motorFX.getConfigurator().apply(motorOutCfg, timeoutSeconds); 517 } 518 } else if (motor instanceof TalonFXS motorFXS) { 519 /* First read the configs so they're up-to-date */ 520 status = motorFXS.getConfigurator().refresh(motorOutCfg, timeoutSeconds); 521 if (status.isOK()) { 522 /* Then set the neutral mode config to the appropriate value */ 523 motorOutCfg.NeutralMode = neutralMode; 524 status = motorFXS.getConfigurator().apply(motorOutCfg, timeoutSeconds); 525 } 526 } 527 528 if (!status.isOK()) { 529 System.out.println( 530 "Talon ID " + motor.getDeviceID() + " failed config with error " + status.toString() 531 ); 532 } 533 return status; 534 } 535 536 /** 537 * Configures the neutral mode to use for both motors in the mechanism. 538 * <p> 539 * This will wait up to 0.100 seconds (100ms) by default. 540 * 541 * @param neutralMode The state of the motor controller bridge when output is neutral or disabled 542 * @return Status code of the first failed config call, or OK if all succeeded 543 */ 544 public final StatusCode configNeutralMode(NeutralModeValue neutralMode) { 545 return configNeutralMode(neutralMode, 0.100); 546 } 547 548 /** 549 * Configures the neutral mode to use for both motors in the mechanism. 550 * 551 * @param neutralMode The state of the motor controller bridge when output is neutral or disabled 552 * @param timeoutSeconds Maximum amount of time to wait when performing each configuration 553 * @return Status code of the first failed config call, or OK if all succeeded 554 */ 555 public final StatusCode configNeutralMode(NeutralModeValue neutralMode, double timeoutSeconds) { 556 StatusCode retval = StatusCode.OK; 557 { 558 final var status = configNeutralModeImpl(_diffLeaderFX, neutralMode, timeoutSeconds); 559 if (retval.isOK()) retval = status; 560 } 561 { 562 final var status = configNeutralModeImpl(_diffFollowerFX, neutralMode, timeoutSeconds); 563 if (retval.isOK()) retval = status; 564 } 565 return retval; 566 } 567 568 /** 569 * Call this method periodically to automatically protect against dangerous 570 * fault conditions and keep {@link #getMechanismState()} updated. 571 */ 572 public final void periodic() { 573 StatusCode retval = StatusCode.OK; 574 575 /* handle remote sensor position overflow fault */ 576 if (_diffLeaderFX.getFault_RemoteSensorPosOverflow().getValue()) { 577 /* fault the mechanism until the user clears it manually */ 578 _requiresUserReason = RequiresUserReasonValue.RemoteSensorPosOverflow; 579 _requiresUserAction.setRelease(true); 580 581 _disabledReason = DisabledReasonValue.RemoteSensorPosOverflow; 582 retval = StatusCode.MechanismFaulted; 583 } 584 585 /* handle missing remote sensor fault */ 586 if (_diffLeaderFX.getFault_RemoteSensorDataInvalid().getValue() || 587 _diffFollowerFX.getFault_RemoteSensorDataInvalid().getValue() 588 ) { 589 /* temporarily fault the mechanism while the fault is active */ 590 _disabledReason = DisabledReasonValue.MissingRemoteSensor; 591 retval = StatusCode.MechanismFaulted; 592 } 593 /* handle missing differential Talon FX fault */ 594 if (_diffLeaderFX.getFault_MissingDifferentialFX().getValue()) { 595 /* temporarily fault the mechanism while the fault is active */ 596 _disabledReason = DisabledReasonValue.MissingDifferentialFX; 597 retval = StatusCode.MechanismFaulted; 598 } 599 600 /* handle if any of the devices have power cycled */ 601 final boolean diffLeaderFX_hasReset = _diffLeaderFXResetChecker.getAsBoolean(); 602 final boolean diffFollowerFX_hasReset = _diffFollowerFXResetChecker.getAsBoolean(); 603 final boolean diffSensor_hasReset = _diffSensorResetChecker.isPresent() && _diffSensorResetChecker.get().getAsBoolean(); 604 final boolean diffLeaderFX_remsens_hasReset = _diffLeaderFX.getStickyFault_RemoteSensorReset().getValue(); 605 final boolean diffFollowerFX_remsens_hasReset = _diffFollowerFX.getStickyFault_RemoteSensorReset().getValue(); 606 607 if (diffLeaderFX_hasReset || diffFollowerFX_hasReset || diffSensor_hasReset || 608 diffLeaderFX_remsens_hasReset || diffFollowerFX_remsens_hasReset 609 ) { 610 /* fault the mechanism until the user clears it manually */ 611 _requiresUserReason = RequiresUserReasonValue.DeviceHasReset; 612 _requiresUserAction.setRelease(true); 613 614 _disabledReason = DisabledReasonValue.DeviceHasReset; 615 retval = StatusCode.MechanismFaulted; 616 } 617 618 if (retval.isOK() && _requiresUserAction.getOpaque()) { 619 /* keep the mechanism faulted until user clears the fault */ 620 retval = StatusCode.MechanismFaulted; 621 } 622 623 if (!retval.isOK()) { 624 /* disable the mechanism */ 625 _mechanismDisabled.setRelease(true); 626 } else { 627 /* re-enable the mechanism */ 628 _disabledReason = DisabledReasonValue.None; 629 _mechanismDisabled.setRelease(false); 630 } 631 } 632 633 /** 634 * Get whether the mechanism is currently disabled due to an issue. 635 * 636 * @return true if the mechanism is temporarily disabled 637 */ 638 public final boolean isDisabled() { 639 return _mechanismDisabled.getAcquire(); 640 } 641 642 /** 643 * Get whether the mechanism is currently disabled and requires 644 * user action to re-enable mechanism control. 645 * 646 * @return true if the mechanism is disabled and the user must manually 647 * perform an action 648 */ 649 public final boolean requiresUserAction() { 650 return _requiresUserAction.getAcquire(); 651 } 652 653 /** 654 * Gets the state of the mechanism. 655 * 656 * @return MechanismState representing the state of the mechanism 657 */ 658 public final MechanismState getMechanismState() { 659 if (requiresUserAction()) { 660 return MechanismState.RequiresUserAction; 661 } else if (isDisabled()) { 662 return MechanismState.Disabled; 663 } else { 664 return MechanismState.OK; 665 } 666 } 667 668 /** 669 * Indicate to the mechanism that the user has performed the required 670 * action to resume mechanism control. 671 */ 672 public final void clearUserRequirement() { 673 if (_diffLeaderFX.getStickyFault_RemoteSensorReset().getValue()) { 674 _diffLeaderFX.clearStickyFault_RemoteSensorReset(); 675 } 676 if (_diffFollowerFX.getStickyFault_RemoteSensorReset().getValue()) { 677 _diffFollowerFX.clearStickyFault_RemoteSensorReset(); 678 } 679 _requiresUserReason = RequiresUserReasonValue.None; 680 _requiresUserAction.setRelease(false); 681 } 682 683 /** 684 * @return The reason for the mechanism being disabled 685 */ 686 public final DisabledReasonValue getDisabledReason() { 687 return _disabledReason; 688 } 689 /** 690 * @return The reason for the mechanism requiring user 691 * action to resume control 692 */ 693 public final RequiresUserReasonValue getRequiresUserReason() { 694 return _requiresUserReason; 695 } 696 697 /** 698 * Average component of the mechanism position. 699 * 700 * <ul> 701 * <li> <b>Minimum Value:</b> -16384.0 702 * <li> <b>Maximum Value:</b> 16383.999755859375 703 * <li> <b>Default Value:</b> 0 704 * <li> <b>Units:</b> rotations 705 * </ul> 706 * <p> 707 * This refreshes and returns a cached StatusSignal object. 708 * 709 * @return DifferentialAveragePosition Status Signal Object 710 */ 711 public final StatusSignal<Angle> getAveragePosition() { 712 return getAveragePosition(true); 713 } 714 /** 715 * Average component of the mechanism position. 716 * 717 * <ul> 718 * <li> <b>Minimum Value:</b> -16384.0 719 * <li> <b>Maximum Value:</b> 16383.999755859375 720 * <li> <b>Default Value:</b> 0 721 * <li> <b>Units:</b> rotations 722 * </ul> 723 * <p> 724 * This refreshes and returns a cached StatusSignal object. 725 * 726 * @param refresh Whether to refresh the StatusSignal before returning it; defaults to true 727 * @return DifferentialAveragePosition Status Signal Object 728 */ 729 public final StatusSignal<Angle> getAveragePosition(boolean refresh) { 730 return _diffLeaderFX.getDifferentialAveragePosition(refresh); 731 } 732 733 /** 734 * Average component of the mechanism velocity. 735 * 736 * <ul> 737 * <li> <b>Minimum Value:</b> -512.0 738 * <li> <b>Maximum Value:</b> 511.998046875 739 * <li> <b>Default Value:</b> 0 740 * <li> <b>Units:</b> rotations per second 741 * </ul> 742 * <p> 743 * This refreshes and returns a cached StatusSignal object. 744 * 745 * @return DifferentialAverageVelocity Status Signal Object 746 */ 747 public final StatusSignal<AngularVelocity> getAverageVelocity() { 748 return getAverageVelocity(true); 749 } 750 /** 751 * Average component of the mechanism velocity. 752 * 753 * <ul> 754 * <li> <b>Minimum Value:</b> -512.0 755 * <li> <b>Maximum Value:</b> 511.998046875 756 * <li> <b>Default Value:</b> 0 757 * <li> <b>Units:</b> rotations per second 758 * </ul> 759 * <p> 760 * This refreshes and returns a cached StatusSignal object. 761 * 762 * @param refresh Whether to refresh the StatusSignal before returning it; defaults to true 763 * @return DifferentialAverageVelocity Status Signal Object 764 */ 765 public final StatusSignal<AngularVelocity> getAverageVelocity(boolean refresh) { 766 return _diffLeaderFX.getDifferentialAverageVelocity(refresh); 767 } 768 769 /** 770 * Differential component of the mechanism position. 771 * 772 * <ul> 773 * <li> <b>Minimum Value:</b> -16384.0 774 * <li> <b>Maximum Value:</b> 16383.999755859375 775 * <li> <b>Default Value:</b> 0 776 * <li> <b>Units:</b> rotations 777 * </ul> 778 * <p> 779 * This refreshes and returns a cached StatusSignal object. 780 * 781 * @return DifferentialDifferencePosition Status Signal Object 782 */ 783 public final StatusSignal<Angle> getDifferentialPosition() { 784 return getDifferentialPosition(true); 785 } 786 /** 787 * Differential component of the mechanism position. 788 * 789 * <ul> 790 * <li> <b>Minimum Value:</b> -16384.0 791 * <li> <b>Maximum Value:</b> 16383.999755859375 792 * <li> <b>Default Value:</b> 0 793 * <li> <b>Units:</b> rotations 794 * </ul> 795 * <p> 796 * This refreshes and returns a cached StatusSignal object. 797 * 798 * @param refresh Whether to refresh the StatusSignal before returning it; defaults to true 799 * @return DifferentialDifferencePosition Status Signal Object 800 */ 801 public final StatusSignal<Angle> getDifferentialPosition(boolean refresh) { 802 return _diffLeaderFX.getDifferentialDifferencePosition(refresh); 803 } 804 805 /** 806 * Differential component of the mechanism velocity. 807 * 808 * <ul> 809 * <li> <b>Minimum Value:</b> -512.0 810 * <li> <b>Maximum Value:</b> 511.998046875 811 * <li> <b>Default Value:</b> 0 812 * <li> <b>Units:</b> rotations per second 813 * </ul> 814 * <p> 815 * This refreshes and returns a cached StatusSignal object. 816 * 817 * @return DifferentialDifferenceVelocity Status Signal Object 818 */ 819 public final StatusSignal<AngularVelocity> getDifferentialVelocity() { 820 return getDifferentialVelocity(true); 821 } 822 /** 823 * Differential component of the mechanism velocity. 824 * 825 * <ul> 826 * <li> <b>Minimum Value:</b> -512.0 827 * <li> <b>Maximum Value:</b> 511.998046875 828 * <li> <b>Default Value:</b> 0 829 * <li> <b>Units:</b> rotations per second 830 * </ul> 831 * <p> 832 * This refreshes and returns a cached StatusSignal object. 833 * 834 * @param refresh Whether to refresh the StatusSignal before returning it; defaults to true 835 * @return DifferentialDifferenceVelocity Status Signal Object 836 */ 837 public final StatusSignal<AngularVelocity> getDifferentialVelocity(boolean refresh) { 838 return _diffLeaderFX.getDifferentialDifferenceVelocity(refresh); 839 } 840 841 /** 842 * Value that the average closed loop is targeting. 843 * <p> 844 * This is the value that the closed loop PID controller targets. 845 * <p> 846 * This refreshes and returns a cached StatusSignal object. 847 * 848 * @return ClosedLoopReference Status Signal object 849 */ 850 public final StatusSignal<Double> getAverageClosedLoopReference() { 851 return getAverageClosedLoopReference(true); 852 } 853 /** 854 * Value that the average closed loop is targeting. 855 * <p> 856 * This is the value that the closed loop PID controller targets. 857 * <p> 858 * This refreshes and returns a cached StatusSignal object. 859 * 860 * @param refresh Whether to refresh the StatusSignal before returning it; defaults to true 861 * @return ClosedLoopReference Status Signal object 862 */ 863 public final StatusSignal<Double> getAverageClosedLoopReference(boolean refresh) { 864 return _diffLeaderFX.getClosedLoopReference(refresh); 865 } 866 867 /** 868 * Derivative of the target that the average closed loop is targeting. 869 * <p> 870 * This is the change in the closed loop reference. This may be used 871 * in the feed-forward calculation, the derivative-error, or in 872 * application of the signage for kS. Typically, this represents the 873 * target velocity during Motion Magic®. 874 * <p> 875 * This refreshes and returns a cached StatusSignal object. 876 * 877 * @return ClosedLoopReferenceSlope Status Signal object 878 */ 879 public final StatusSignal<Double> getAverageClosedLoopReferenceSlope() { 880 return getAverageClosedLoopReferenceSlope(true); 881 } 882 /** 883 * Derivative of the target that the average closed loop is targeting. 884 * <p> 885 * This is the change in the closed loop reference. This may be used 886 * in the feed-forward calculation, the derivative-error, or in 887 * application of the signage for kS. Typically, this represents the 888 * target velocity during Motion Magic®. 889 * <p> 890 * This refreshes and returns a cached StatusSignal object. 891 * 892 * @param refresh Whether to refresh the StatusSignal before returning it; defaults to true 893 * @return ClosedLoopReferenceSlope Status Signal object 894 */ 895 public final StatusSignal<Double> getAverageClosedLoopReferenceSlope(boolean refresh) { 896 return _diffLeaderFX.getClosedLoopReferenceSlope(refresh); 897 } 898 899 /** 900 * The difference between target average reference and current measurement. 901 * <p> 902 * This is the value that is treated as the error in the PID loop. 903 * <p> 904 * This refreshes and returns a cached StatusSignal object. 905 * 906 * @return ClosedLoopError Status Signal object 907 */ 908 public final StatusSignal<Double> getAverageClosedLoopError() { 909 return getAverageClosedLoopError(true); 910 } 911 /** 912 * The difference between target average reference and current measurement. 913 * <p> 914 * This is the value that is treated as the error in the PID loop. 915 * <p> 916 * This refreshes and returns a cached StatusSignal object. 917 * 918 * @param refresh Whether to refresh the StatusSignal before returning it; defaults to true 919 * @return ClosedLoopError Status Signal object 920 */ 921 public final StatusSignal<Double> getAverageClosedLoopError(boolean refresh) { 922 return _diffLeaderFX.getClosedLoopError(refresh); 923 } 924 925 /** 926 * Value that the differential closed loop is targeting. 927 * <p> 928 * This is the value that the differential closed loop PID controller 929 * targets (on the difference axis). 930 * <p> 931 * This refreshes and returns a cached StatusSignal object. 932 * 933 * @return DifferentialClosedLoopReference Status Signal object 934 */ 935 public final StatusSignal<Double> getDifferentialClosedLoopReference() { 936 return getDifferentialClosedLoopReference(true); 937 } 938 /** 939 * Value that the differential closed loop is targeting. 940 * <p> 941 * This is the value that the differential closed loop PID controller 942 * targets (on the difference axis). 943 * <p> 944 * This refreshes and returns a cached StatusSignal object. 945 * 946 * @param refresh Whether to refresh the StatusSignal before returning it; defaults to true 947 * @return DifferentialClosedLoopReference Status Signal object 948 */ 949 public final StatusSignal<Double> getDifferentialClosedLoopReference(boolean refresh) { 950 return _diffLeaderFX.getDifferentialClosedLoopReference(refresh); 951 } 952 953 /** 954 * Derivative of the target that the differential closed loop is 955 * targeting. 956 * <p> 957 * This is the change in the closed loop reference (on the difference 958 * axis). This may be used in the feed-forward calculation, the 959 * derivative-error, or in application of the signage for kS. 960 * Typically, this represents the target velocity during Motion 961 * Magic®. 962 * <p> 963 * This refreshes and returns a cached StatusSignal object. 964 * 965 * @return DifferentialClosedLoopReferenceSlope Status Signal object 966 */ 967 public final StatusSignal<Double> getDifferentialClosedLoopReferenceSlope() { 968 return getDifferentialClosedLoopReferenceSlope(true); 969 } 970 /** 971 * Derivative of the target that the differential closed loop is 972 * targeting. 973 * <p> 974 * This is the change in the closed loop reference (on the difference 975 * axis). This may be used in the feed-forward calculation, the 976 * derivative-error, or in application of the signage for kS. 977 * Typically, this represents the target velocity during Motion 978 * Magic®. 979 * <p> 980 * This refreshes and returns a cached StatusSignal object. 981 * 982 * @param refresh Whether to refresh the StatusSignal before returning it; defaults to true 983 * @return DifferentialClosedLoopReferenceSlope Status Signal object 984 */ 985 public final StatusSignal<Double> getDifferentialClosedLoopReferenceSlope(boolean refresh) { 986 return _diffLeaderFX.getDifferentialClosedLoopReferenceSlope(refresh); 987 } 988 989 /** 990 * The difference between target differential reference and current 991 * measurement. 992 * <p> 993 * This is the value that is treated as the error in the differential 994 * PID loop (on the difference axis). 995 * <p> 996 * This refreshes and returns a cached StatusSignal object. 997 * 998 * @return DifferentialClosedLoopError Status Signal object 999 */ 1000 public final StatusSignal<Double> getDifferentialClosedLoopError() { 1001 return getDifferentialClosedLoopError(true); 1002 } 1003 /** 1004 * The difference between target differential reference and current 1005 * measurement. 1006 * <p> 1007 * This is the value that is treated as the error in the differential 1008 * PID loop (on the difference axis). 1009 * <p> 1010 * This refreshes and returns a cached StatusSignal object. 1011 * 1012 * @param refresh Whether to refresh the StatusSignal before returning it; defaults to true 1013 * @return DifferentialClosedLoopError Status Signal object 1014 */ 1015 public final StatusSignal<Double> getDifferentialClosedLoopError(boolean refresh) { 1016 return _diffLeaderFX.getDifferentialClosedLoopError(refresh); 1017 } 1018 1019 /** 1020 * Sets the position of the mechanism in rotations, assuming a differential 1021 * position of 0 rotations. 1022 * <p> 1023 * This will wait up to 0.100 seconds (100ms) by default. 1024 * 1025 * @param avgPosition The average position of the mechanism, in rotations 1026 * @return StatusCode of the set command 1027 */ 1028 public final StatusCode setPosition(double avgPosition) { 1029 return setPosition(avgPosition, 0.0, 0.100); 1030 } 1031 /** 1032 * Sets the position of the mechanism in rotations. 1033 * <p> 1034 * This will wait up to 0.100 seconds (100ms) by default. 1035 * 1036 * @param avgPosition The average position of the mechanism, in rotations 1037 * @param diffPosition The differential position of the mechanism, in rotations 1038 * @return StatusCode of the set command 1039 */ 1040 public final StatusCode setPosition(double avgPosition, double diffPosition) { 1041 return setPosition(avgPosition, diffPosition, 0.100); 1042 } 1043 /** 1044 * Sets the position of the mechanism in rotations. 1045 * 1046 * @param avgPosition The average position of the mechanism, in rotations 1047 * @param diffPosition The differential position of the mechanism, in rotations 1048 * @param timeoutSeconds Maximum time to wait up to in seconds 1049 * @return StatusCode of the set command 1050 */ 1051 public final StatusCode setPosition(double avgPosition, double diffPosition, double timeoutSeconds) { 1052 var retval = StatusCode.OK; 1053 1054 var response = _diffLeaderFX.setPosition(avgPosition + diffPosition * _sensorToDiffRatio, timeoutSeconds); 1055 if (retval.isOK()) retval = response; 1056 response = _diffFollowerFX.setPosition(avgPosition - diffPosition * _sensorToDiffRatio, timeoutSeconds); 1057 if (retval.isOK()) retval = response; 1058 1059 return retval; 1060 } 1061 1062 /** 1063 * Sets the position of the mechanism, assuming a differential 1064 * position of 0 rotations. 1065 * <p> 1066 * This will wait up to 0.100 seconds (100ms) by default. 1067 * 1068 * @param avgPosition The average position of the mechanism 1069 * @return StatusCode of the set command 1070 */ 1071 public final StatusCode setPosition(Angle avgPosition) { 1072 return setPosition(avgPosition.in(Rotations)); 1073 } 1074 /** 1075 * Sets the position of the mechanism. 1076 * <p> 1077 * This will wait up to 0.100 seconds (100ms) by default. 1078 * 1079 * @param avgPosition The average position of the mechanism 1080 * @param diffPosition The differential position of the mechanism 1081 * @return StatusCode of the set command 1082 */ 1083 public final StatusCode setPosition(Angle avgPosition, Angle diffPosition) { 1084 return setPosition(avgPosition.in(Rotations), diffPosition.in(Rotations)); 1085 } 1086 /** 1087 * Sets the position of the mechanism. 1088 * 1089 * @param avgPosition The average position of the mechanism 1090 * @param diffPosition The differential position of the mechanism 1091 * @param timeoutSeconds Maximum time to wait up to in seconds 1092 * @return StatusCode of the set command 1093 */ 1094 public final StatusCode setPosition(Angle avgPosition, Angle diffPosition, double timeoutSeconds) { 1095 return setPosition(avgPosition.in(Rotations), diffPosition.in(Rotations), timeoutSeconds); 1096 } 1097 1098 /** 1099 * Get the Talon FX that is differential leader. The differential 1100 * leader calculates the output for the differential follower. The 1101 * differential leader is also useful for fault detection, and it 1102 * reports status signals for the differential controller. 1103 * 1104 * @return Differential leader Talon FX 1105 */ 1106 public final MotorT getLeader() { 1107 return _diffLeaderFX; 1108 } 1109 1110 /** 1111 * Get the Talon FX that is differential follower. The differential 1112 * follower's position and velocity are used by the differential leader 1113 * for the differential controller. 1114 * 1115 * @return Differential follower Talon FX 1116 */ 1117 public final MotorT getFollower() { 1118 return _diffFollowerFX; 1119 } 1120 1121 private StatusCode beforeControl() { 1122 StatusCode retval = StatusCode.OK; 1123 if (_mechanismDisabled.getOpaque()) { 1124 /* disable the mechanism */ 1125 retval = StatusCode.MechanismFaulted; 1126 } 1127 1128 if (!retval.isOK()) { 1129 /* neutral the output */ 1130 setNeutralOut(); 1131 } 1132 return retval; 1133 } 1134 1135 /** 1136 * Request neutral output of mechanism. The applied brake type 1137 * is determined by the NeutralMode configuration of each device. 1138 * <p> 1139 * Since the NeutralMode configuration of devices may not align, users 1140 * may prefer to use the {@link #setCoastOut()} or {@link #setStaticBrake()} method. 1141 * 1142 * @return Status Code of the request. 1143 */ 1144 public final StatusCode setNeutralOut() { 1145 var retval = StatusCode.OK; 1146 { 1147 final var _diffLeaderFX_retval = _diffLeaderFX.setControl(_neutral); 1148 if (retval.isOK()) { 1149 retval = _diffLeaderFX_retval; 1150 } 1151 } 1152 { 1153 final var _diffFollowerFX_retval = _diffFollowerFX.setControl(_neutral); 1154 if (retval.isOK()) { 1155 retval = _diffFollowerFX_retval; 1156 } 1157 } 1158 return retval; 1159 } 1160 1161 /** 1162 * Request coast neutral output of mechanism. The bridge is 1163 * disabled and the rotor is allowed to coast. 1164 * 1165 * @return Status Code of the request. 1166 */ 1167 public final StatusCode setCoastOut() { 1168 var retval = StatusCode.OK; 1169 { 1170 final var _diffLeaderFX_retval = _diffLeaderFX.setControl(_coast); 1171 if (retval.isOK()) { 1172 retval = _diffLeaderFX_retval; 1173 } 1174 } 1175 { 1176 final var _diffFollowerFX_retval = _diffFollowerFX.setControl(_coast); 1177 if (retval.isOK()) { 1178 retval = _diffFollowerFX_retval; 1179 } 1180 } 1181 return retval; 1182 } 1183 1184 /** 1185 * Applies full neutral-brake on the mechanism by shorting 1186 * motor leads together. 1187 * 1188 * @return Status Code of the request. 1189 */ 1190 public final StatusCode setStaticBrake() { 1191 var retval = StatusCode.OK; 1192 { 1193 final var _diffLeaderFX_retval = _diffLeaderFX.setControl(_brake); 1194 if (retval.isOK()) { 1195 retval = _diffLeaderFX_retval; 1196 } 1197 } 1198 { 1199 final var _diffFollowerFX_retval = _diffFollowerFX.setControl(_brake); 1200 if (retval.isOK()) { 1201 retval = _diffFollowerFX_retval; 1202 } 1203 } 1204 return retval; 1205 } 1206 1207 1208 1209 /** 1210 * Sets the control request for this mechanism. 1211 * 1212 * @param diffLeaderFXRequest Request a specified motor duty cycle with a 1213 * differential position closed-loop. 1214 * @return Status Code of the request. 1215 */ 1216 public final StatusCode setControl(DifferentialDutyCycle diffLeaderFXRequest) { 1217 var retval = StatusCode.OK; 1218 1219 retval = beforeControl(); 1220 if (!retval.isOK()) { 1221 return retval; 1222 } 1223 1224 { 1225 final var _diffLeaderFX_reqPtr = diffLeaderFXRequest; 1226 final var _diffLeaderFX_retval = _diffLeaderFX.setControl(_diffLeaderFX_reqPtr); 1227 if (retval.isOK()) { 1228 retval = _diffLeaderFX_retval; 1229 } 1230 } 1231 1232 { 1233 final var _diffFollowerFX_retval = _diffFollowerFX.setControl(_diffFollow); 1234 if (retval.isOK()) { 1235 retval = _diffFollowerFX_retval; 1236 } 1237 } 1238 1239 return retval; 1240 } 1241 1242 /** 1243 * Sets the control request for this mechanism. 1244 * 1245 * @param diffLeaderFXRequest Request a specified voltage with a differential 1246 * position closed-loop. 1247 * @return Status Code of the request. 1248 */ 1249 public final StatusCode setControl(DifferentialVoltage diffLeaderFXRequest) { 1250 var retval = StatusCode.OK; 1251 1252 retval = beforeControl(); 1253 if (!retval.isOK()) { 1254 return retval; 1255 } 1256 1257 { 1258 final var _diffLeaderFX_reqPtr = diffLeaderFXRequest; 1259 final var _diffLeaderFX_retval = _diffLeaderFX.setControl(_diffLeaderFX_reqPtr); 1260 if (retval.isOK()) { 1261 retval = _diffLeaderFX_retval; 1262 } 1263 } 1264 1265 { 1266 final var _diffFollowerFX_retval = _diffFollowerFX.setControl(_diffFollow); 1267 if (retval.isOK()) { 1268 retval = _diffFollowerFX_retval; 1269 } 1270 } 1271 1272 return retval; 1273 } 1274 1275 /** 1276 * Sets the control request for this mechanism. 1277 * 1278 * @param diffLeaderFXRequest Request PID to target position with a differential 1279 * position setpoint. 1280 * @return Status Code of the request. 1281 */ 1282 public final StatusCode setControl(DifferentialPositionDutyCycle diffLeaderFXRequest) { 1283 var retval = StatusCode.OK; 1284 1285 retval = beforeControl(); 1286 if (!retval.isOK()) { 1287 return retval; 1288 } 1289 1290 { 1291 final var _diffLeaderFX_reqPtr = diffLeaderFXRequest; 1292 final var _diffLeaderFX_retval = _diffLeaderFX.setControl(_diffLeaderFX_reqPtr); 1293 if (retval.isOK()) { 1294 retval = _diffLeaderFX_retval; 1295 } 1296 } 1297 1298 { 1299 final var _diffFollowerFX_retval = _diffFollowerFX.setControl(_diffFollow); 1300 if (retval.isOK()) { 1301 retval = _diffFollowerFX_retval; 1302 } 1303 } 1304 1305 return retval; 1306 } 1307 1308 /** 1309 * Sets the control request for this mechanism. 1310 * 1311 * @param diffLeaderFXRequest Request PID to target position with a differential 1312 * position setpoint 1313 * @return Status Code of the request. 1314 */ 1315 public final StatusCode setControl(DifferentialPositionVoltage diffLeaderFXRequest) { 1316 var retval = StatusCode.OK; 1317 1318 retval = beforeControl(); 1319 if (!retval.isOK()) { 1320 return retval; 1321 } 1322 1323 { 1324 final var _diffLeaderFX_reqPtr = diffLeaderFXRequest; 1325 final var _diffLeaderFX_retval = _diffLeaderFX.setControl(_diffLeaderFX_reqPtr); 1326 if (retval.isOK()) { 1327 retval = _diffLeaderFX_retval; 1328 } 1329 } 1330 1331 { 1332 final var _diffFollowerFX_retval = _diffFollowerFX.setControl(_diffFollow); 1333 if (retval.isOK()) { 1334 retval = _diffFollowerFX_retval; 1335 } 1336 } 1337 1338 return retval; 1339 } 1340 1341 /** 1342 * Sets the control request for this mechanism. 1343 * 1344 * @param diffLeaderFXRequest Request PID to target velocity with a differential 1345 * position setpoint. 1346 * @return Status Code of the request. 1347 */ 1348 public final StatusCode setControl(DifferentialVelocityDutyCycle diffLeaderFXRequest) { 1349 var retval = StatusCode.OK; 1350 1351 retval = beforeControl(); 1352 if (!retval.isOK()) { 1353 return retval; 1354 } 1355 1356 { 1357 final var _diffLeaderFX_reqPtr = diffLeaderFXRequest; 1358 final var _diffLeaderFX_retval = _diffLeaderFX.setControl(_diffLeaderFX_reqPtr); 1359 if (retval.isOK()) { 1360 retval = _diffLeaderFX_retval; 1361 } 1362 } 1363 1364 { 1365 final var _diffFollowerFX_retval = _diffFollowerFX.setControl(_diffFollow); 1366 if (retval.isOK()) { 1367 retval = _diffFollowerFX_retval; 1368 } 1369 } 1370 1371 return retval; 1372 } 1373 1374 /** 1375 * Sets the control request for this mechanism. 1376 * 1377 * @param diffLeaderFXRequest Request PID to target velocity with a differential 1378 * position setpoint. 1379 * @return Status Code of the request. 1380 */ 1381 public final StatusCode setControl(DifferentialVelocityVoltage diffLeaderFXRequest) { 1382 var retval = StatusCode.OK; 1383 1384 retval = beforeControl(); 1385 if (!retval.isOK()) { 1386 return retval; 1387 } 1388 1389 { 1390 final var _diffLeaderFX_reqPtr = diffLeaderFXRequest; 1391 final var _diffLeaderFX_retval = _diffLeaderFX.setControl(_diffLeaderFX_reqPtr); 1392 if (retval.isOK()) { 1393 retval = _diffLeaderFX_retval; 1394 } 1395 } 1396 1397 { 1398 final var _diffFollowerFX_retval = _diffFollowerFX.setControl(_diffFollow); 1399 if (retval.isOK()) { 1400 retval = _diffFollowerFX_retval; 1401 } 1402 } 1403 1404 return retval; 1405 } 1406 1407 /** 1408 * Sets the control request for this mechanism. 1409 * 1410 * @param diffLeaderFXRequest Requests Motion Magic® to target a final position 1411 * using a motion profile, and PID to a differential 1412 * position setpoint. 1413 * @return Status Code of the request. 1414 */ 1415 public final StatusCode setControl(DifferentialMotionMagicDutyCycle diffLeaderFXRequest) { 1416 var retval = StatusCode.OK; 1417 1418 retval = beforeControl(); 1419 if (!retval.isOK()) { 1420 return retval; 1421 } 1422 1423 { 1424 final var _diffLeaderFX_reqPtr = diffLeaderFXRequest; 1425 final var _diffLeaderFX_retval = _diffLeaderFX.setControl(_diffLeaderFX_reqPtr); 1426 if (retval.isOK()) { 1427 retval = _diffLeaderFX_retval; 1428 } 1429 } 1430 1431 { 1432 final var _diffFollowerFX_retval = _diffFollowerFX.setControl(_diffFollow); 1433 if (retval.isOK()) { 1434 retval = _diffFollowerFX_retval; 1435 } 1436 } 1437 1438 return retval; 1439 } 1440 1441 /** 1442 * Sets the control request for this mechanism. 1443 * 1444 * @param diffLeaderFXRequest Requests Motion Magic® to target a final position 1445 * using a motion profile, and PID to a differential 1446 * position setpoint. 1447 * @return Status Code of the request. 1448 */ 1449 public final StatusCode setControl(DifferentialMotionMagicVoltage diffLeaderFXRequest) { 1450 var retval = StatusCode.OK; 1451 1452 retval = beforeControl(); 1453 if (!retval.isOK()) { 1454 return retval; 1455 } 1456 1457 { 1458 final var _diffLeaderFX_reqPtr = diffLeaderFXRequest; 1459 final var _diffLeaderFX_retval = _diffLeaderFX.setControl(_diffLeaderFX_reqPtr); 1460 if (retval.isOK()) { 1461 retval = _diffLeaderFX_retval; 1462 } 1463 } 1464 1465 { 1466 final var _diffFollowerFX_retval = _diffFollowerFX.setControl(_diffFollow); 1467 if (retval.isOK()) { 1468 retval = _diffFollowerFX_retval; 1469 } 1470 } 1471 1472 return retval; 1473 } 1474 1475 /** 1476 * Sets the control request for this mechanism. 1477 * 1478 * @param diffLeaderFXRequest Requests Motion Magic® to target a final position 1479 * using an exponential motion profile, and PID to a 1480 * differential position setpoint. 1481 * @return Status Code of the request. 1482 */ 1483 public final StatusCode setControl(DifferentialMotionMagicExpoDutyCycle diffLeaderFXRequest) { 1484 var retval = StatusCode.OK; 1485 1486 retval = beforeControl(); 1487 if (!retval.isOK()) { 1488 return retval; 1489 } 1490 1491 { 1492 final var _diffLeaderFX_reqPtr = diffLeaderFXRequest; 1493 final var _diffLeaderFX_retval = _diffLeaderFX.setControl(_diffLeaderFX_reqPtr); 1494 if (retval.isOK()) { 1495 retval = _diffLeaderFX_retval; 1496 } 1497 } 1498 1499 { 1500 final var _diffFollowerFX_retval = _diffFollowerFX.setControl(_diffFollow); 1501 if (retval.isOK()) { 1502 retval = _diffFollowerFX_retval; 1503 } 1504 } 1505 1506 return retval; 1507 } 1508 1509 /** 1510 * Sets the control request for this mechanism. 1511 * 1512 * @param diffLeaderFXRequest Requests Motion Magic® to target a final position 1513 * using an exponential motion profile, and PID to a 1514 * differential position setpoint. 1515 * @return Status Code of the request. 1516 */ 1517 public final StatusCode setControl(DifferentialMotionMagicExpoVoltage diffLeaderFXRequest) { 1518 var retval = StatusCode.OK; 1519 1520 retval = beforeControl(); 1521 if (!retval.isOK()) { 1522 return retval; 1523 } 1524 1525 { 1526 final var _diffLeaderFX_reqPtr = diffLeaderFXRequest; 1527 final var _diffLeaderFX_retval = _diffLeaderFX.setControl(_diffLeaderFX_reqPtr); 1528 if (retval.isOK()) { 1529 retval = _diffLeaderFX_retval; 1530 } 1531 } 1532 1533 { 1534 final var _diffFollowerFX_retval = _diffFollowerFX.setControl(_diffFollow); 1535 if (retval.isOK()) { 1536 retval = _diffFollowerFX_retval; 1537 } 1538 } 1539 1540 return retval; 1541 } 1542 1543 /** 1544 * Sets the control request for this mechanism. 1545 * 1546 * @param diffLeaderFXRequest Requests Motion Magic® to target a final velocity 1547 * using a motion profile, and PID to a differential 1548 * position setpoint. This allows smooth transitions 1549 * between velocity set points. 1550 * @return Status Code of the request. 1551 */ 1552 public final StatusCode setControl(DifferentialMotionMagicVelocityDutyCycle diffLeaderFXRequest) { 1553 var retval = StatusCode.OK; 1554 1555 retval = beforeControl(); 1556 if (!retval.isOK()) { 1557 return retval; 1558 } 1559 1560 { 1561 final var _diffLeaderFX_reqPtr = diffLeaderFXRequest; 1562 final var _diffLeaderFX_retval = _diffLeaderFX.setControl(_diffLeaderFX_reqPtr); 1563 if (retval.isOK()) { 1564 retval = _diffLeaderFX_retval; 1565 } 1566 } 1567 1568 { 1569 final var _diffFollowerFX_retval = _diffFollowerFX.setControl(_diffFollow); 1570 if (retval.isOK()) { 1571 retval = _diffFollowerFX_retval; 1572 } 1573 } 1574 1575 return retval; 1576 } 1577 1578 /** 1579 * Sets the control request for this mechanism. 1580 * 1581 * @param diffLeaderFXRequest Requests Motion Magic® to target a final velocity 1582 * using a motion profile, and PID to a differential 1583 * position setpoint. This allows smooth transitions 1584 * between velocity set points. 1585 * @return Status Code of the request. 1586 */ 1587 public final StatusCode setControl(DifferentialMotionMagicVelocityVoltage diffLeaderFXRequest) { 1588 var retval = StatusCode.OK; 1589 1590 retval = beforeControl(); 1591 if (!retval.isOK()) { 1592 return retval; 1593 } 1594 1595 { 1596 final var _diffLeaderFX_reqPtr = diffLeaderFXRequest; 1597 final var _diffLeaderFX_retval = _diffLeaderFX.setControl(_diffLeaderFX_reqPtr); 1598 if (retval.isOK()) { 1599 retval = _diffLeaderFX_retval; 1600 } 1601 } 1602 1603 { 1604 final var _diffFollowerFX_retval = _diffFollowerFX.setControl(_diffFollow); 1605 if (retval.isOK()) { 1606 retval = _diffFollowerFX_retval; 1607 } 1608 } 1609 1610 return retval; 1611 } 1612 1613}