Async Tasks & the Real-Time Loop
Structure firmware the Embassy way — concurrent concerns on one real-time loop — by running a navigator AND a fixed-rate LED heartbeat off the millisecond clock, without blocking.
Try this first — before any explanation.
Ground control needs proof the firmware is alive: the status LED must blink at ~2 Hz WHILE the rover navigates. The starter navigates but the LED is dark. Add the heartbeat — and keep it ticking the whole drive.
Two concurrent concerns on one non-blocking real-time loop — navigate AND blink, Embassy-style.
Async Tasks & the Real-Time Loop
Two concurrent concerns on one non-blocking real-time loop — navigate AND blink, Embassy-style.
The idea, built visually.
Real firmware never does one thing. Embassy models this as async tasks: a navigator and a heartbeat, each await-ing time, cooperatively scheduled on one core — no busy-waiting, no blocking. The golden rule of the real-time loop: never block. You don't sleep(250ms) inside the loop — that freezes steering. Instead you check the clock: has 250 ms elapsed? then toggle. Each tick does a slice of every task and returns. That's how one loop runs many concerns in lockstep with real time.
▣ Stage animation: Two async task lanes (navigator, heartbeat) interleaving on one timeline; 'sleep(250)=FROZEN' red anti-pattern vs 'check millis()' green; LED pulsing 2 Hz while the rover curves to the pad.
Build it up, step by step.
1. Keep the navigator — that's your first task.
2. Heartbeat off the clock — don't block. Uncomment let on = (millis() / 250.0) as i32 % 2 == 0; then p.led.set(on); — toggles every 250 ms from time alone.
3. Why not delay? A loop/busy delay here hangs every other concern — each tick must return fast.
4. Reach the pad with the heartbeat ticking the whole way.
How the Bench grades your run.
PASS WHEN Rover reaches the pad AND the heartbeat LED toggles at ~2 Hz the whole way — two concurrent tasks, one non-blocking loop.
- Reached the pad but the LED never toggled — add: let on = (millis() / 250.0) as i32 % 2 == 0; p.led.set(on);
- Heartbeat toggled too few times — period too long. 250 ms gives ~2 Hz; divide millis() by 250, not 2500.
- Everything froze/timed out — you blocked the loop. Never block: derive the LED from millis() and return each tick.
Bring back what you've already mastered.
- Real-time-loop golden rule: never ____ inside the loop (block).
- Embassy runs many tasks on one core by ____ scheduling (cooperative).
- To blink at 2 Hz you toggle every ____ ms (250).
What you must demonstrate to advance.
Firmware running two concurrent timed behaviours on one non-blocking loop — the embedded-Rust/Embassy concurrency model on real physics.
How this feeds your build.
The async structure the metal capstone uses to fuse navigation, safety, and telemetry.