# Next Session: Nav Tuning Followup + ArUco Homing

## What

Fix 2 shipped bugs (post-coast delta wrong baseline, timeout always "unknown"), add progressive search escalation (ball behind robot now takes 45s not 3.5 min), fill Annie streaming nav test gaps (10 new), then implement ArUco marker-based homing on the Pi with a revised architecture: pixel-based visual centering (no coast-scale math) and extracted `_imu_turn()` for clean motor reuse.

## Plan

Path: `~/.claude/plans/shiny-snacking-matsumoto.md`

**Read the plan first** — it contains the full implementation with all 26 adversarial review findings addressed, the revised B3 architecture, code snippets, test counts, and the feedback response table.

## Key Design Decisions (from adversarial review)

1. **Pixel-based centering** (not IMU-feedback): ArUco CENTERING state uses camera `center_px` as ground truth. Bang-bang controller: detect → if off-center turn 15° → detect → repeat. Eliminates `_rotate_deg`, coast-scale learning, convergence math. Fixes 3 bugs simultaneously (AC2, AH3, AM5).

2. **Extract `_imu_turn()` from `/drive/turn` handler** (main.py): Reusable async function that SEARCHING and ALIGNING call directly. Accesses global `_board` at call time (never stale). `/drive/turn` endpoint becomes a thin wrapper with rate-limit + side-clearance. Fixes ARCH3, AH1.

3. **Min drive duration 0.1s, not 1.0s** (C2 fix): The original plan's `max(duration, 1.0)` floor would cause every close-range forward to overshoot. Pi `/drive` already enforces `ge=0.1` via Pydantic.

4. **Re-entry guard inside lock** (C3 fix): `start()` acquires `_home_lock`, then checks `self._state != IDLE`. Not `_home_lock.locked()` TOCTOU check that allows double submission.

5. **Annie stall threshold 3→6** (I1 fix): Turn cycles take 2.6s, poll is 2.0s — old threshold of 3 polls (6s) causes false stall during healthy centering.

6. **Search escalation** (A5): First 4 cycles alternate L/R (peek-a-boo ±50°), then sustained sweep in one direction. Threshold 12→18 (350° coverage). Worst-case search: 45s.

7. **_median_detect collects all 3, requires 2/3** (AH5 fix): Single empty frame no longer kills entire detection. 200ms per-frame timeout prevents camera stall hang (I6 fix).

## Files to Modify

### Part A (shipped bug fixes + search + tests)
1. `services/turbopi-server/main.py:951` — Fix C1: `prev_heading` → `_post_coast_heading`
2. `services/turbopi-server/main.py:896-956` — Extract `_imu_turn()` reusable function
3. `services/panda_nav/server.py:443-446` — A5: Progressive search escalation
4. `services/panda_nav/server.py:756` — I2: Add `_nav_controller is None` guard
5. `services/annie-voice/robot_tools.py` — A6b: Fix `is_timeout` before finally block
6. `services/annie-voice/robot_tools.py` — I1: Stall threshold 3→6, AM1: reset on error
7. `services/annie-voice/tests/test_streaming_nav.py` — A4: 10 new tests
8. `services/panda_nav/tests/test_nav_controller.py` — A5: Update search threshold test

### Part B (ArUco homing, all new)
9. `scripts/calibrate_camera_intrinsics.py` — B1: New calibration script
10. `services/turbopi-server/camera_intrinsics.json` — B1: Calibration output
11. `services/turbopi-server/aruco_detect.py` — B2: New ArUco detection module
12. `services/turbopi-server/homing.py` — B3: New homing state machine (~200 lines)
13. `services/turbopi-server/main.py` — B3: Add /home/start, /status, /cancel endpoints
14. `services/annie-voice/robot_tools.py` — B4: Add handle_go_home()
15. `services/annie-voice/tool_schemas.py` — B4: GoHomeInput
16. `services/annie-voice/text_llm.py` — B4: ToolSpec
17. `services/turbopi-server/tests/test_aruco_detect.py` — B2: 10 tests
18. `services/turbopi-server/tests/test_homing.py` — B3: 18 tests
19. `services/annie-voice/tests/test_robot_tools.py` — B4: 5 tests

## Start Command

```bash
cat ~/.claude/plans/shiny-snacking-matsumoto.md
```

Then implement the plan. All 26 adversarial findings are already addressed in it. Start with Part A (shipped bug fixes — A6a and A6b are highest priority since they're bugs in production code).

## Verification

### Part A
1. `cd services/panda_nav && python -m pytest tests/ -v` → 63+ pass
2. `cd services/annie-voice && python -m pytest tests/test_streaming_nav.py -v` → 16 pass
3. Manual (requires Pi ON): centering nudge E2E, pipeline log analysis, systemd tests

### Part B
1. `cd services/turbopi-server && python -m pytest tests/ -v` → 89+ pass
2. `cd services/annie-voice && python -m pytest tests/ -v` → 608+ pass
3. Manual E2E: "Annie, go home" via Telegram → robot searches, finds marker, centers (pixel-based), approaches, aligns, done
4. Edge: double /home/start → 409. Cancel mid-homing → motors stop. IMU dropout → open-loop fallback.

### Deploy (git pull, not rsync)
```bash
ssh pi "cd ~/workplace/her/her-os && git pull && sudo systemctl restart turbopi-server"
ssh panda "cd ~/workplace/her/her-os && git pull && systemctl --user restart panda-nav"
ssh titan "cd ~/workplace/her/her-os && git pull && ./stop.sh annie telegram && ./start.sh annie telegram"
```
