Learn From Data
Train a simple classifier mapping sensor readings to a discrete action and run it on the rover, meeting held-out accuracy >= 0.85 and goal completion with zero collisions.
Try this first — before any explanation.
The rover sits at a short corridor. Sensors expose front_dist, goal_dist, heading_err; three discrete actions FORWARD/SLOW/TURN. A panel shows 40 expert-labeled points. Make the rover finish the course by deciding an action every tick — but you may NOT write more than 3 if statements. The trap: the labels overlap in the 0.18-0.35 m band depending on heading_err, so three thresholds can't separate SLOW from TURN.
Fit a small decision tree on the two informative features, then drive the rover with its predictions.
Learn From Data
Fit a small decision tree on the two informative features, then drive the rover with its predictions.
The idea, built visually.
Last module you told the rover every rule — a threshold here, an if there. That works until the right answer depends on two things at once. One straight cut can't separate these points: the amber and white overlap on a single axis, so no three ifs get it right.
A classifier doesn't take a rule from you — it takes examples and finds the boundary that separates them. Give it both features and the cut can tilt and wrap around the overlap; the rule emerges from the data. Every tick, the rover's live reading is just a new point, and which region it lands in is its decision.
▣ Stage animation: 40 expert points on a front_dist x heading_err plane, visibly interleaved; a vertical front_dist threshold sweeps but mislabels stay ~12/40; the line bends and tilts into a diagonal boundary carving three regions, mislabeled 14->5->2; live ticks drop new points whose region is the chosen action.
Build it up, step by step.
Step 1 (worked): plot the labeled set and see the interleave. Step 2 (worked): fit a small decision tree (max_depth=3) and read train accuracy. Step 3 (faded): write the 70/30 split, fit on train, score on test, tune max_depth (depth 8 just memorizes 28 points). Step 4 (independent): wire clf.predict into the live control loop.
How the Bench grades your run.
PASS WHEN Held-out action accuracy >= 0.85 on the 30% holdout, reaches the goal with zero collisions on C1, and also reaches goal on unseen seed 332.
- FAIL: test_acc below 0.85 — boundary mislabels SLOW<->TURN; the tree split on front_dist only, but heading_err is needed to separate the overlap.
- FAIL: collided — predicted FORWARD while front_dist was small; feature vector may be unscaled/misordered, print feat at the collision tick.
- FAIL: passed seed 331 but failed generalization seed 332 — you fit on all 40 points; refit on the train split only.
Bring back what you've already mastered.
- From 2.1: apply your EMA filter to heading_err before predict — does course completion get steadier? (Yes — noisy features jitter across a sharp boundary.)
- From 2.2: which of the three actions is really a continuous control problem in disguise? (TURN — classification suits the discrete mode choice.)
- From 1.3: how many `if` lines would a max_depth=3 tree compile to? A tree IS learned ifs.
What you must demonstrate to advance.
Trained classifier reaches held-out accuracy >= 0.85, drives to goal completion with zero collisions on C1, and generalizes to unseen seed 332 (L3: produce a generalizing decision rule from labeled data and deploy it).
How this feeds your build.
Feeds the capstone (5.1) as the rover's discrete mode selector; packaged as doorway_policy(state) -> Command(heading=...) so the learned discrete decision becomes a target heading the Module-2 PID can hold.