Use PID feedback with output limits and anti-windup
API v3 provides bounded deterministic loops inside the isolated JavaScript controller.

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.
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.