GPIO, Peripherals & the Control Loop
Write your first no_std Rust firmware: own the rover's peripherals, blink a GPIO LED, and drive the motors from the control loop to reach the goal.
Try this first — before any explanation.
The Bench opens on firmware whose control() only blinks the LED — the rover sits still. Press Compile & Run: it builds real Rust to WASM and the rover doesn't move. Your job: make this firmware drive to the green pad.
Write no_std embedded Rust against the rover HAL. It compiles to WASM and runs as the real control loop.
GPIO, Peripherals & the Control Loop
Write no_std embedded Rust against the rover HAL. It compiles to WASM and runs as the real control loop.
The idea, built visually.
On the Python tier you called set_motor(...). What ran underneath? A control loop on a chip, talking to motor and sensor peripherals it OWNS. In Rust that ownership is literal: you take() the Peripherals once, as a value — the compiler then guarantees no two parts of your code fight over the same motor. The loop runs every tick like a heartbeat: read sensors, decide, drive. The same embodied loop you've known since the blocks tier — now you're writing the metal that runs it.
▣ Stage animation: Peripherals fly out of a chip as labelled ownership tokens (motors, range, goal, led); a 'tick' heartbeat pulses; each beat shows sensor->compute->motor; a Rust 'one owner' overlay.
Build it up, step by step.
1. Take the peripherals. control_loop!(control) exports the tick; inside, p is your &mut Peripherals.
2. Read the goal beacon. p.goal.distance() (m) and p.goal.bearing() (rad, + = left).
3. Drive the motors. p.motors.set(left, right) in [-1, 1].
4. Steer + go. let turn = 1.2 * bearing; then let forward = if dist > 0.2 { 0.6 } else { 0.0 }; and p.motors.set(forward - turn, forward + turn);
5. GPIO. Keep p.led.set(dist > 0.2).
How the Bench grades your run.
PASS WHEN The firmware compiles as no_std and drives the rover within 0.2 m of the pad.
- Closest approach barely changed — your motors are still set(0.0, 0.0). Compute turn from bearing and a forward term, then p.motors.set(forward - turn, forward + turn).
- Rover spun/veered away — the steering sign is flipped. bearing is + when the goal is LEFT: set(forward - turn, forward + turn).
- rustc error 'cannot find value `bearing`' — you read it into `_bearing`; drop the underscore to use it.
Bring back what you've already mastered.
- Ownership: why does take() hand you the peripherals exactly once? (single guaranteed owner of each motor/pin).
- Units: p.goal.bearing() is in ____ and + means the goal is to your ____ (radians; left).
- What does control_loop!(control) generate? (a #[no_mangle] tick() the host calls each period).
What you must demonstrate to advance.
Compile-and-run firmware (no_std, no emulator) that owns the peripherals and drives the rover into the pad.
How this feeds your build.
Foundation of the metal capstone: every later firmware builds on this take → read → drive loop.