A Weekend Teaching MentorPi to Read Traffic Signs

Saturday's first bounding box, Saturday afternoon's confidence-threshold headache, and the Sunday moment every piece finally clicked into place together.
MentorPi comes with a pretrained YOLOv5 model — traffic_signs_640s_7_1, recognizing go, right, park, red, green, and crosswalk — sitting there ready to use. This weekend was about actually turning it on, watching it get confidently wrong in a specific and fixable way, and then bolting it onto the line-follow behavior I'd already gotten working the week before.
Saturday Morning: The First Bounding Box
Two launch commands to get started: ros2 launch peripherals depth_camera.launch.py to bring the depth camera stream up, then ros2 launch yolov5_ros2 yolov5_ros2.launch.py model:="traffic_signs_640s_7_1" to load the pretrained sign-detection model against that stream. Printed out a handful of the six sign classes on plain paper — a "go" arrow, a "right" arrow, a rough "park" symbol, red and green circles, a crosswalk icon — and held the first one up in front of the camera with rqt open to actually watch what the model saw.
The first bounding box that appeared, snapping cleanly around the printed "go" sign with a confidence score sitting comfortably above 0.9, was a genuinely good little moment — a model I'd done absolutely nothing to train myself, correctly identifying a piece of paper I'd printed five minutes earlier, on hardware sitting on my kitchen table. Ran through the other five signs one at a time, all detecting cleanly under the morning light coming through the window. Suspiciously easy, in retrospect, given what Saturday afternoon had waiting for it.
Saturday Afternoon: The Confidence Threshold Fight

By afternoon, the window light had shifted to that warm, slightly yellow-toned late-day quality, and the "go" sign started getting misclassified as "right" a meaningful fraction of the time — not randomly wrong, consistently wrong, in exactly this lighting, on exactly this sign. Confidence scores for these misclassifications were sitting noticeably below where they'd been that morning, hovering right around the default threshold rather than confidently above it, which was the first clue about where to actually look.
Opened self_driving.launch.py and found the conf parameter — the confidence threshold below which a detection gets discarded entirely rather than acted on — sitting at its default of 0.75. My first instinct was to drop it, reasoning that if genuine "go" detections were scoring lower under this lighting, a lower threshold would stop the system from discarding them. Dropped it to somewhere around 0.5, reran the test.
That fixed the missed detections and immediately created a new, different problem: with the threshold that loose, the corner of a wall in the background, caught at a particular angle in the same warm afternoon light, started occasionally getting picked up as a low-confidence "park" detection — a false positive that simply hadn't been possible at the stricter default threshold, because whatever weak, coincidental resemblance the wall corner had to a sign pattern never used to clear 0.75, but cleared 0.5 easily. Spent a genuinely annoyed twenty minutes moving the threshold back and forth — 0.5 let too much through, 0.75 missed too much of the actual sign under this specific lighting, before settling around 0.62 as a compromise that caught the real "go" sign reliably in the afternoon light without picking up the wall corner. Not a clean, satisfying number, but the number that actually worked for the specific room and specific afternoon light I was actually testing in — which is, I'm realizing, most of what confidence threshold tuning actually is in practice.
Sunday Morning: Wiring Sign Detection Into Line-Follow

With Saturday's threshold settled, Sunday morning was about actually combining sign detection with the line-follow behavior from last week, using the kit's Integrated Application mode rather than running each feature in isolation. This is the point where the weekend started feeling like it was building toward something, rather than just being two separate feature tests.
First integrated run: MentorPi following the lane normally, encountering a printed "right" sign held up beside the track, and — genuinely satisfying to watch — smoothly initiating a right turn at the junction, rather than continuing straight through it. Followed that with a "crosswalk" sign placed near a marked crossing point on the mat, and watched the robot's speed visibly drop as it approached, exactly matching the "slow down for crosswalk" behavior the integrated application is supposed to produce. Neither of these worked perfectly on the very first attempt — the crosswalk slowdown triggered a beat later than felt ideal on the first pass, close enough to the sign that a slightly larger obstacle would have been a problem — but by the third or fourth run, with the sign placed slightly earlier along the track relative to the crossing point, the timing settled into something that looked genuinely deliberate rather than lucky.
Sunday Afternoon: The Last Piece, and Everything Clicking Together

The final test of the weekend, and the one I'd been saving for last on purpose: red light stop, followed by green light go. Set up a "red" sign at a crosswalk point on the track and watched MentorPi approach, correctly detect it, and come to a full, clean stop right at the crossing line — not sliding past it, not stopping awkwardly short, close enough that it was clearly reading the actual crosswalk line position rather than just reacting the moment the sign entered frame.
Then, sign swap — red paper card out, green paper card in — held up in the same spot, and the robot pulled away almost immediately, resuming the line-follow behavior it had paused a moment earlier, continuing on through the rest of the loop as if nothing had interrupted it.
That specific sequence — stop cleanly on red, resume cleanly on green, timed against an actual crosswalk line rather than just "sign visible equals stop" — was the moment the whole weekend's separate pieces actually became one coherent thing rather than a list of individually-working demos. Saturday morning's bounding box, Saturday afternoon's annoying but ultimately correct threshold compromise, and Sunday morning's turn-and-slow-down integration all had to be right, simultaneously, for this last test to work as cleanly as it did. It did. That's a genuinely good note to end a weekend on, and a much better feeling than Saturday morning's suspiciously easy first bounding box gave any real indication I'd earn by Sunday afternoon.