Skip to content
CHAPTER 32 / 33

Use PID feedback with output limits and anti-windup

API v3 provides bounded deterministic loops inside the isolated JavaScript controller.

BotSims test bench showing design diagnostics and the mass and drive assessment.
Experiments run your current controller against the supported model and your chosen thresholds. Export the result to retain its assumptions and trace. View full size ↗

robot.pid(id, target, measurement, options) returns a normalized output. Each ID has independent private state, with at most 32 loops and one update per loop per controller tick. robot.pidReset(id) resets one loop; robot.pidReset() resets all. Existing API v1/v2 programs continue to run.

javascript
function step(robot) {
  const omega = robot.motors[0]?.omega;
  if (robot.brownout || !Number.isFinite(omega)) {
    robot.pidReset(); robot.drive(0, 0); return;
  }
  // Illustrative gains; target/measurement are shaft rad/s.
  const u = robot.pid("left-speed", 2, omega, {
    kp: 0.08, ki: 0.15, kd: 0, min: -0.6, max: 0.6
  });
  robot.drive(u, u);
}

The loop uses consecutive simulation-time samples, with P only on the first sample. An optional explicit dt of 0.0001–1 seconds is for deliberately scheduled control; it integrates the first sample. The derivative acts on measurement to avoid setpoint kick and uses a backward-Euler filter (filterTau defaults to 0.02 s). Conditional integration prevents further windup at output limits and allows unwinding; integralLimit bounds the integral output contribution.