Iterative learning control
The tracking error repeats almost exactly from run to run. Iterative learning control (ILC) uses the error of one run to correct the commands of the next run:
cmd[k+1](/mycobot-280-lab/results/ilc/t/) = cmd[k](/mycobot-280-lab/results/ilc/t/) + gain · w(t) · Q[ref − measured](t + lead_j)| Term | Value | Purpose |
|---|---|---|
gain |
0.5 | Corrects half of the error per run. A low gain is stable. |
Q |
forward-backward moving average, 80 ms | Learns only the slow, repeatable part. No phase shift. |
lead_j |
the joint’s lag (DEFAULT_LAG) |
The command at t shows in the measurement near t + lead_j. |
w(t) |
1 inside, 0 within 0.3 s of the ends | The plan still starts and ends at rest. |
ILC does not model the servos. It learns a correction for one trajectory. A new trajectory starts from zero again.
On a model plant with delay, lag and sticking (the test suite), the error goes down in every iteration and halves in five.
Results on the circle
Section titled “Results on the circle”| Run | Laptop, ~300 Hz (RMS / max) | ATOM, 500 Hz (RMS / max) |
|---|---|---|
| Lag compensation only | 5.0 mm / 12.4 mm | 5.0 mm / 12.5 mm |
| ILC iteration 1 | 2.5 mm / 6.5 mm | 2.6 mm / 6.8 mm |
| ILC iteration 2 | 1.3 mm / 4.0 mm | 1.5 mm / 4.0 mm |
| ILC iteration 3 | 0.8 mm / 2.2 mm | 1.0 mm / 3.4 mm |
The error halves in each iteration, including the peaks where J2 and J3 stick. The largest correction in a step was 0.9°.

With our gains (firmware 4.0, 2026-10-04)
Section titled “With our gains (firmware 4.0, 2026-10-04)”The table above used the servos’ stored gains (32/8/0). With our gains (integral action on J1–J3), ILC with gain 0.5 improved once (2.6 → 1.4 mm) and then got worse. With gain 0.3 it converges again. ATOM, 500 Hz, 50 Hz cubic plans:
| Run | Error RMS / max | IMU acceleration RMS |
|---|---|---|
| Lag compensation only | 2.8 mm / 8.0 mm | 159 mg |
| ILC 1 | 2.4 mm / 8.2 mm | 170 mg |
| ILC 2 | 1.8 mm / 7.4 mm | 155 mg |
| ILC 3 | 1.7 mm / 7.2 mm | 148 mg |
| ILC 4 | 1.5 mm / 6.1 mm | 145 mg |
| ILC 5 | 1.2 mm / 4.4 mm | 136 mg |
| ILC 6 | 1.4 mm / 6.2 mm | 142 mg |
| ILC 7 | 1.4 mm / 3.9 mm | 154 mg |
| ILC 8 | 1.1 mm / 2.8 mm | 145 mg |
- The RMS error levels off at ~1.1–1.4 mm, about the same as with the stored gains (1.0 mm). The maximum keeps falling, to 2.8 mm.
- The integral action makes the servos slower to settle, so a lower ILC gain is
needed. Use
scripts/ilc_step.jl ... --gain=0.3with our gains. - What is left (~1 mm) changes from run to run (sticking after reversals), so ILC cannot learn it.
Run it
Section titled “Run it”julia --project=. scripts/ilc_step.jl tools/python/plans/circle.csv tools/python/recordings/<last recording>.csvjulia --project=. scripts/play_plan.jl tools/python/plans/circle_ilc1.csv [--atom=<ip>]Keep separate plan names for the laptop series and the ATOM series. The ATOM
series uses circle_atom.csv → circle_atom_ilc1.csv …