Φferromotion · textbook · chapter 5 rust → wasm · on-device
Teach a robot a motion by demonstrating it a single time, and have it reproduce not just that motion but its shape — to targets you never showed it, always arriving. This page learns and replays with the same Rust movement primitive the native tools use.
The most natural way to give a robot a skill is to show it once — guide its hand through a pour, a reach, a wipe. But a recording is brittle: replay the exact positions and the first time the cup sits somewhere new, the motion misses. What you want is for the robot to keep the character of the motion — the arc of the pour, the curl of the wipe — while retargeting it to wherever the cup actually is.
A Dynamic Movement Primitive is a stable spring-damper pulling the hand toward the goal, plus a learned forcing term that bends the straight pull into the demonstrated shape. The trick is that the forcing term is driven by a phase — a clock that runs once from 1 to 0 — and is multiplied by that phase, so it fades out on its own before the motion ends.
Draw a motion in the box below with your cursor — any squiggle — then release. The dashed gold curve is what you drew; the green curve is the primitive reproducing it. Or pick a preset.
drag the gold goal marker anywhere — the learned shape follows it and always arrives
Drag the goal to the far corner, somewhere the demonstration never went. The motion still lands on it. This is not luck and not the learning working well — it is structural. Because the forcing term is switched off by the phase clock, by the end of the motion only the spring-damper is left, and a spring-damper has exactly one destination: the goal.
| largest miss over three never-shown goals | … |
| verdict | … |
Drag the goal outward along the direction of the demonstration and the whole shape scales with it — twice as far, twice as big, same character. Drag it off to the side and the shape shears, because the primitive scales each axis by its own displacement; that shear is a real property, not a bug, and it is why a DMP is retargeted, not merely translated. The speed slider stretches the motion in time without touching its path at all — the phase clock, not the wall clock, drives the shape.
A single demonstration becomes a reusable, retargetable skill — one that generalizes to new goals and rescales in time, and whose safety-critical property, actually reaching the target, is guaranteed by the structure rather than trusted to the learning.
That split is why movement primitives endure. The learned part carries the style of the motion and can be as rough as a one-shot human demo; the guaranteed part carries the thing you cannot afford to get wrong. It is the same bargain as the safety filter two chapters back — put the hard guarantee in simple, provable structure and let the learned component be creative inside it — and it is a good bargain to make whenever a robot has to learn from people and still be relied on.
What you just drove: the Dmp from ferromotion-control — two of them, one per axis — compiled to WebAssembly, the same code the native tools link against. Weights are fit from your demonstration by locally weighted regression; every drag re-rolls the primitive live. Nothing is precomputed.
Verified in the library: it reproduces the demonstration it was shown · the goal is a structural attractor for any goal and even for scrambled weights · a rescaled goal reproduces the same shape · τ rescales duration without changing the path. Each is a test in cargo test, not a claim in prose. See also ch.1 · ch.2 · ch.3 · ch.4.
Institute for Physical AI · the Rust library · crates.io