Closed-loop control
Configure velocity and position control for your mechanism.
Java 0.33.0 / firmware 2.6.6: zero duty coasts; brake is unsupported. Stator and supply current-limit settings are inactive compatibility fields and do not limit amperes. Supply current is observational; stator current is unavailable. The speed-based duty governor can reduce applied output.
Closed-loop control compares the target with the measured motion and adjusts motor output to reduce the difference. Gains are the tuning values that determine how strongly it responds. Tune one mechanism at a time with space for it to move safely.
Set velocity gains
The public Java setter supports velocity kP, kI and kD. Pass gains you have selected for your setup; tune on measured response with an appropriate output bound; firmware 2.6.6 current-limit settings are inactive. Velocity error is the difference between requested and measured speed. Gains use this error in radians per second (rad/s), even though setVelocity() accepts RPM.
// motor is an existing controller; kP, kI and kD are your validated gains.
Slot0Configs velocityGains = new Slot0Configs();
velocityGains.kP = kP;
velocityGains.kI = kI;
velocityGains.kD = kD;
StatusCode gainResult = motor.getConfigurator().apply(velocityGains);
if (!gainResult.isOK()) System.err.println(gainResult.describe());With firmware 1.7.4 and Java 0.31.0, apply(Slot0Configs) writes kP, kI and kD with device readback. Unset gains are left alone. Other numbered Java slots are not selectable alternate tunes. Public feedforward setters remain unsupported.
What the velocity gains change
kP changes output in proportion to the current speed error. Too little can leave a slow response; too much can make speed overshoot or oscillate, repeatedly rising above and falling below the target. kI responds to error that remains over time. It can remove a lasting speed shortfall, but too much can also cause overshoot or oscillation.
| Java velocity gain | Accepted range |
|---|---|
| kP | 0.00005 to 0.01 |
| kI | 0.0002 to 0.05 |
| kD | 0 to 0.001; zero disables derivative action |
kD (derivative gain) adds damping based on how quickly measured motor speed changes. Cyclone applies D to measured velocity, with a 5 ms filter, so changing the target alone does not produce a derivative kick. Start at zero, tune kP and kI, then increase kD in small steps if the response needs damping. Too much D can amplify measurement noise and make output jitter. Its units are duty per rad/s², with a resolution of 0.00000001.
Velocity kD requires firmware 0.165.0 or later and Java library 0.28.0 or later. Configure it while output is disabled and check the result:
StatusCode result = motor.setVelocityDerivativeGain(0.00001); // Example, not a universal tune.
if (!result.isOK()) System.err.println(result.describe());
double appliedKD = motor.getVelocityDerivativeGain(); // NaN means unavailable/no reply.
// Save deliberately after testing: motor.saveConfiguration();These are accepted values, not recommended settings for every mechanism. The kP and kI setters reject zero; kD accepts zero to turn the derivative term off. All three reject values outside their ranges. The loop measures velocity in rad/s internally, even though Java speed requests use RPM.
Position gains
Firmware 1.7.4 and Java 0.31.0 expose all three position gains. Position error is measured in rotor radians. The outer position controller turns that error into a speed correction; a separate inner speed regulator drives the motor. A fresh configuration has zero position kP and refuses position entry until you configure a positive kP.
| Java field / device field | Meaning | Range and resolution |
|---|---|---|
| PositionKP / pos_kp | Speed correction per radian of position error; units 1/s. | 0–500, step 0.001 |
| PositionKI / pos_i_gain | Correction for position error that persists over time; units 1/s². | 0–500, step 0.001 |
| PositionKD / pos_d_gain | Damping from measured shaft speed, filtered over 5 ms; dimensionless. | 0–10, step 0.00001 |
Start with position I and D at zero. Establish direction, a valid mechanism reference and a stable P response before increasing them. I can reduce a persistent position error; too much can cause overshoot. D resists motion and can reduce oscillation; too much can slow the move or amplify noisy feedback. These are accepted ranges, not recommended gains. The controller bounds speed correction and limits integral growth during saturation. Stop, fault and mode changes reset accumulated control state.
// Use gains validated for this mechanism, while output is disabled.
ClosedLoopGeneralConfigs gains = new ClosedLoopGeneralConfigs();
gains.PositionKP = positionKp;
gains.PositionKI = positionKi;
gains.PositionKD = positionKd;
StatusCode result = motor.getConfigurator().apply(gains);
if (!result.isOK()) {
System.err.println(result.describe());
} else {
ClosedLoopGeneralConfigs confirmed = motor.getConfigurator().refresh(
new ClosedLoopGeneralConfigs());
System.out.println(confirmed.PositionKP + ", " + confirmed.PositionKI + ", " + confirmed.PositionKD);
// After validating the tune, check motor.saveConfigurationConfirmed().
}Apply verifies each accepted setting against device readback. Save confirmed settings deliberately to retain them after restart. Older firmware does not expose the new I/D fields and the library reports that they are unavailable. The old internal names pos_ki and pos_kd are not these position gains; do not copy them into this tuning procedure.
With position profiling enabled, a new move after a stop starts its profile from the measured shaft position. If a supported mechanism is moved while output is disabled, the next move starts from that new position. Changing the target during an active move continues the existing profile. This does not establish home after a power cycle: your robot code must still establish a valid mechanism reference.
For USB-C or SystemCore testing, follow Acceleration and cruise speed to adjust and confirm the profile settings. Those app fields are separate from the gain settings above.
Mechanism units
SensorToMechanismRatio is the number of motor-shaft turns for one turn of the mechanism. For example, enter 5.0 if the motor turns five times for one mechanism turn. The Java helpers use that ratio to convert your target into motor-shaft angle.
MechanismConfigs mechanism = new MechanismConfigs();
mechanism.SensorToMechanismRatio = 5.0;
mechanism.ContinuousWrap = false;
motor.configureMechanism(mechanism);
motor.setMechanismPosition(0.25); // Quarter mechanism turn.Tune from the measured response
- Record the current gains and limits so you can restore them. Verify direction and speed feedback with a small duty request first.
- Choose a reachable speed and repeat the same start and stop with the mechanism supported. Plot target speed, measured speed, applied duty, current, and supply voltage.
- If speed falls short, check whether duty or current has reached a limit, the mechanism is binding, or supply voltage is falling. Gain changes cannot remove these restrictions.
- Disable output before changing a gain. If the response is slow without overshoot or limiting, try a small increase in kP within its accepted range. Repeat the same test. If it overshoots or oscillates more, return to the previous value.
- Once the response is stable, a persistent speed shortfall under a steady load may need a small kI increase. Change only kI for that trial. Restore the earlier value if the response becomes less stable.
- Repeat at the speeds and loads the mechanism will actually use. Save supported settings deliberately, then confirm behavior after restarting.
Example of reading a plot: suppose the target is 1,500 RPM and speed settles at 1,350 RPM, with steady voltage and no current or output limit active. That is a 150 RPM steady error; it suggests investigating integral response. If speed repeatedly swings between 1,200 and 1,800 RPM, do not keep raising gains to chase the low points. These numbers illustrate how to interpret a plot; they are not measurements from a qualified Cyclone test.
Position control has its own inner speed-loop gains. Tuning velocity kP/kI above does not tune that position loop. Start with short position moves from a known reference and check overshoot and holding behavior. Use the reference example to translate a mechanism position into a rotor target.