Timers, PWM & Proportional Drive
Use PWM motor channels and the millisecond clock to replace bang-bang control with a smooth proportional controller that settles in the pad without overshoot.
Try this first — before any explanation.
The starter slams the motors to full, then to zero — watch it overshoot and wobble and miss the tighter tolerance. Rebuild it so the rover eases in and stops clean.
PWM duty + a proportional law in real Rust — smooth the rover into the pad.
Timers, PWM & Proportional Drive
PWM duty + a proportional law in real Rust — smooth the rover into the pad.
The idea, built visually.
A motor pin is digital — on or off. So how do you get HALF speed? You blink it fast: on 60% of each tiny window. That's PWM — the duty cycle IS the average power, and p.motors.set(0.6, ..) is that duty. Bang-bang uses only 0% or 100%, so it overshoots. Proportional control scales the duty by how far you still are: lots of error → more power, near the goal → gentle. The timer gives the steady tick that makes 'per second' mean something.
▣ Stage animation: A square wave whose duty morphs 20->80% with 'PWM = average power'; bang-bang overshoot vs proportional easing into the pad; a timer ticking the loop.
Build it up, step by step.
1. PWM is duty. p.motors.set(d, d) drives at duty d ∈ [-1,1] — the average power.
2. Proportional forward. Replace bang-bang with let forward = (0.8 * dist).min(0.6).max(0.0);
3. Keep steering. let turn = 1.2 * bearing; then p.motors.set(forward - turn, forward + turn);
4. Timing. millis() returns the loop clock in ms if you want to rate-limit.
How the Bench grades your run.
PASS WHEN The rover settles within 0.12 m of the pad — proportional drive, no bang-bang overshoot.
- Still overshooting past 0.12 m — you're using a constant forward. Make it proportional: forward = (0.8 * dist).min(0.6).
- Rover crawls and times out — gain too low / clamp too small. Raise toward 0.8, cap at 0.6.
- Wobbles at the pad — reduce forward near zero so it can settle.
Bring back what you've already mastered.
- PWM: a duty of 0.6 means the pin is on ____ % of each window (60).
- From the Python PID lesson: a proportional term scales effort by the ____ (error/distance).
- Why .min(0.6).max(0.0) on forward? (keep duty in a safe, non-reversing range).
What you must demonstrate to advance.
Firmware that drives into a TIGHT tolerance using proportional PWM — the bare-metal version of the PID intuition.
How this feeds your build.
The smooth-drive primitive the capstone reuses; sets up timing for the async tier.