The PID Loop
Write a proportional heading controller in Python control(obs) that eases the rover onto a goal pad within a tight 0.12 m tolerance, with no overshoot or weave.
Try this first — before any explanation.
Steer the rover to the green pad on real MuJoCo physics. The starter is the block's reflex: 'is the goal left or right? turn that way, full tilt.' That is bang-bang — it always commands a hard turn, so the nose slews past the goal heading, snaps back, and the rover weaves down the field. On a wide pad it might luck in; on this tight 0.12 m pad it skates right past. The weave is the whole motivation for proportional control.
Write control(obs) to ease the rover onto the green pad — real MuJoCo physics, tight 0.12 m tolerance. The starter is bang-bang and weaves; make it proportional.
The PID Loop
Write control(obs) to ease the rover onto the green pad — real MuJoCo physics, tight 0.12 m tolerance. The starter is bang-bang and weaves; make it proportional.
The idea, built visually.
Your control(obs) only ever asks which way — left or right — and then turns as hard as it can. A turning body can't stop on a dime, so it sails past the heading it wanted, then slams back the other way, forever.
The fix is to also ask how much. Make the turn proportional to the error: turn = Kp * goal_bearing. Far off heading, big bearing, hard turn; nearly aligned, tiny bearing, gentle turn that glides in instead of snapping. That single multiply is the P in PID — react in proportion to how wrong you are, not just to the sign of it.
One more ease: as goal_dist shrinks, bleed off forward speed, so you arrive slow enough to actually settle inside the small pad instead of shooting through it.
▣ Stage animation: The CHALLENGE's weaving trail labeled 'bang-bang: always full turn'; the fixed +/- turn command morphs into turn = Kp * goal_bearing with an arrow that shrinks as the bearing closes; the trail straightens and the wheel mix (forward - turn, forward + turn) is annotated; forward speed fades as a goal_dist bar empties, and the rover kisses the 0.12 m pad and stops.
Build it up, step by step.
Step A (read it): the starter computes only the SIGN of obs['goal_bearing'] and turns full tilt — that is bang-bang, the source of the weave. Step B (make it proportional): replace the hard turn with turn = Kp * obs['goal_bearing'] (a known-good neighborhood for this pad is Kp around 1.2), then mix into wheels as (forward - turn, forward + turn). Step C (ease the throttle): set forward proportional to obs['goal_dist'], capped (e.g. forward = min(0.7, 0.9 * obs['goal_dist'])), so you slow into the tight pad instead of overshooting. Remember + goal_bearing means the goal is to your LEFT, so a positive turn must steer left.
How the Bench grades your run.
PASS WHEN On real MuJoCo physics, control(obs) eases the rover onto the goal pad and reaches within 0.12 m: the turn is proportional to goal_bearing (no weave) and forward speed bleeds off as goal_dist shrinks (no overshoot).
- FAIL: closest approach never neared the pad — your steering sign is backwards. Positive goal_bearing means the goal is to your LEFT, so a positive turn must steer left; mix it as (forward - turn, forward + turn).
- FAIL: you weave across the pad and skate past — that is bang-bang. Replace the fixed +/-1 turn with turn = Kp * obs['goal_bearing'] (try Kp around 1.2) so the turn eases as the bearing closes.
- FAIL: closest approach is over 0.12 m — you arrive too fast and overshoot the tight pad. Ease the throttle: make forward proportional to obs['goal_dist'] (e.g. min(0.7, 0.9 * goal_dist)) so you slow into the pad.
Bring back what you've already mastered.
- From 2.1: your read_state feeds heading and goal_dist into this loop — if its estimate jitters, which term of a proportional turn gets noisy first? (The turn itself, since turn scales directly with the bearing error.)
- From 1.2: mark the line in the bang-bang starter that is purely reactive (sign-only) and rewrite it proportionally as turn = Kp * goal_bearing.
- Given a run that weaves across the pad with no steady offset, name the single change and direction. (It is bang-bang / Kp effectively infinite — make the turn proportional, lower the gain.)
What you must demonstrate to advance.
Drive the rover onto the goal pad within 0.12 m on real MuJoCo physics using a proportional control(obs): turn proportional to goal_bearing (no weave) and forward eased by goal_dist (no overshoot) — the P core of the DECIDE/ACT loop (L2).
How this feeds your build.
This proportional control(obs) is the DECIDE/ACT core of the capstone autonomy stack; the 2.3 FSM calls it per mode as a black box, Module 4 re-implements the same law in C on a timer interrupt, and Module 5 profiles it toward the metal.