# Next Session: Battery Recalibration (12→4 Batteries)

## What
Robot batteries reduced from 12 to 4 (~67% mass reduction). All motor calibration needs recalibrating — 30° turn at speed=40 produced 88° (3x overshoot due to less friction → more coast). Plan applies speed reduction (40→25), makes open-loop rate speed-proportional, resets motor trim, adjusts homing nudge parameters, and recalibrates panda-nav forward/turn constants.

## Plan
`~/.claude/plans/agile-riding-stream.md`

Read the plan FIRST — it has the full adversarial-reviewed implementation with all design decisions explained.

## Key Design Decisions (from adversarial review — DO NOT REVERT THESE)

1. **Open-loop rate MUST be speed-proportional** — rename `DEGREES_PER_SECOND_OPEN_LOOP` to `OPEN_LOOP_DPS_AT_40`, compute `rate * speed / 40`. Without this, open-loop turns are wrong at speed≠40.
2. **`max_time` MUST be speed-aware** — `(angle_deg / max(speed * 0.5, 10.0)) + 2.0`. Old formula would timeout IMU turns at low speeds.
3. **`_align_180` tolerance increased to 20°** — lighter robot can't reach 165° threshold; 160° (=180-20) is reachable.
4. **Forward durations reduced LESS aggressively** than initial plan — `FWD_SMALL=0.8` (not 0.6) to avoid requiring 3x more nav cycles.
5. **Nudge pulse right minimum is 0.08s** (not 0.07s) — below motor controller minimum response time.
6. **Calibration script runs at speed 25** (not 50) — must match operating speed.
7. **Drift check is Step 3.1** (before turn calibration) — trim issues mask turn results.
8. **Escape sequence uses PI_DRIVE_SPEED** — speed 40 at lighter mass causes 3x turn overshoot in escape turns too.

---

## Implementation Strategy: 3 Parallel Agents

The 5 commits touch 3 independent file groups. **Dispatch 3 agents in parallel**, then run tests, then commit sequentially.

### Agent 1: turbopi-server motor control (Commits 1+2)

**Files**: `services/turbopi-server/main.py`, `services/turbopi-server/tests/test_drive_turn.py`, `services/turbopi-server/turbopi-server.service`

**Instructions for agent prompt:**
```
Read ~/.claude/plans/agile-riding-stream.md first.

Implement Commits 1 and 2 from the plan in services/turbopi-server/.

COMMIT 1 — Turn speed + max_time (main.py + test):
1. After line 109, add: DEFAULT_TURN_SPEED = 25
2. Line 190: TurnRequest speed default=40 → default=DEFAULT_TURN_SPEED
3. Line 908: _imu_turn speed: int = 40 → speed: int = DEFAULT_TURN_SPEED
4. Line 949: max_time = (angle_deg / 20.0) + 2.0
   → max_time = (angle_deg / max(speed * 0.5, 10.0)) + 2.0
5. In tests/test_drive_turn.py, add a new test that calls POST /drive/turn
   WITHOUT a speed field and asserts the response has speed == DEFAULT_TURN_SPEED.

COMMIT 2 — Open-loop rate + motor trim (main.py + service file):
1. Line 109: Replace DEGREES_PER_SECOND_OPEN_LOOP = 50.0 with:
   OPEN_LOOP_DPS_AT_40 = float(os.getenv("OPEN_LOOP_DPS_AT_40", "85.0"))
2. Line 923: Replace duration = angle_deg / DEGREES_PER_SECOND_OPEN_LOOP with:
   effective_dps = OPEN_LOOP_DPS_AT_40 * speed / 40
   duration = angle_deg / effective_dps
3. Lines 101-102: Change MOTOR_TRIM_FL/RL defaults from "1.15" to "1.0"
4. In turbopi-server.service, add two Environment lines:
   Environment=MOTOR_TRIM_FL=1.0
   Environment=MOTOR_TRIM_RL=1.0

CRITICAL: Update ALL references to DEGREES_PER_SECOND_OPEN_LOOP in tests too
(grep for the old name — it may appear in test_drive_turn.py).

Do NOT commit — just make the edits. Tests will be run after all agents finish.
```

### Agent 2: homing recalibration (Commit 3)

**Files**: `services/turbopi-server/homing.py`

**Instructions for agent prompt:**
```
Read ~/.claude/plans/agile-riding-stream.md first (Commit 3 section).

Implement Commit 3 in services/turbopi-server/homing.py:

1. Line 25: DRIVE_SPEED = 40 → 25
2. Line 258: NUDGE_SPEED = 50 → 30
3. Line 259: NUDGE_PULSE = {"left": 0.15, "right": 0.10}
   → {"left": 0.10, "right": 0.08}
4. Find _align_180 method — locate the call to main._imu_turn with
   tolerance_deg=15.0 and change to tolerance_deg=20.0
5. Above the _pulse_no_trim function (around line 279), add this comment:
   # NOTE: When MOTOR_TRIM defaults are 1.0, this save/restore is a no-op.
   # Pattern preserved intentionally — if trim is later re-tuned above 1.0
   # (e.g., via env var for drift compensation), nudge symmetry is restored.

Do NOT commit — just make the edits.
```

### Agent 3: panda-nav + calibration script (Commits 4+5)

**Files**: `services/panda_nav/server.py`, `services/panda_nav/tests/test_nav_controller.py`, `scripts/calibrate_odometry.py`

**Instructions for agent prompt:**
```
Read ~/.claude/plans/agile-riding-stream.md first (Commits 4+5 sections).

COMMIT 4 — Panda-nav recalibration:
1. In server.py, after line 68 (SEARCH_ANGLE_DEG = 15), add:
   PI_DRIVE_SPEED = int(os.getenv("PI_DRIVE_SPEED", "25"))
2. Replace ALL 5 occurrences of "speed": 40 with "speed": PI_DRIVE_SPEED
   at lines 779, 787, 793, 810, 821. Use replace_all or edit each.
3. Lines 97-99: ANGLE_SMALL = 12 → 10, ANGLE_MEDIUM = 8 → 6, ANGLE_LARGE = 5 → 4
4. Lines 103-105: FWD_SMALL = 1.0 → 0.8, FWD_MEDIUM = 0.3 → 0.25, FWD_NUDGE = 0.2 → 0.15
5. In tests/test_nav_controller.py line 483:
   "speed": 40 → "speed": server.PI_DRIVE_SPEED
   Ensure 'server' is imported (check existing imports — likely already has
   'from panda_nav import server' or 'from panda_nav.server import ...').
   If not, add the import needed to reference server.PI_DRIVE_SPEED.

COMMIT 5 — Calibration script:
1. In scripts/calibrate_odometry.py line 26: SPEED = 50 → SPEED = 25

Do NOT commit — just make the edits.
```

---

## Post-Agent Steps (sequential, do NOT parallelize)

### Step 1: Verify agent work
Read each modified file to confirm changes match the plan. Watch for:
- Old constant names left behind (grep for `DEGREES_PER_SECOND_OPEN_LOOP` — should be gone)
- Missing import for `server.PI_DRIVE_SPEED` in test file
- Wrong line numbers (agents may have shifted lines)

### Step 2: Run tests
```bash
cd services/turbopi-server && python -m pytest tests/ -v
cd services/panda_nav && python -m pytest tests/ -v
```
All must pass. If failures, fix before committing.

### Step 3: Commit sequentially (5 commits)
```bash
# Commit 1
git add services/turbopi-server/main.py services/turbopi-server/tests/test_drive_turn.py
git commit -m "fix(nav): reduce DEFAULT_TURN_SPEED to 25 for 4-battery weight, speed-aware max_time"

# Commit 2
git add services/turbopi-server/main.py services/turbopi-server/turbopi-server.service
git commit -m "fix(nav): speed-proportional open-loop rate, reset motor trim to neutral"

# Commit 3
git add services/turbopi-server/homing.py
git commit -m "fix(nav): recalibrate homing for 4-battery weight — speed, nudge, tolerance"

# Commit 4
git add services/panda_nav/server.py services/panda_nav/tests/test_nav_controller.py
git commit -m "fix(nav): extract PI_DRIVE_SPEED, recalibrate panda-nav angles and durations"

# Commit 5
git add scripts/calibrate_odometry.py
git commit -m "fix(nav): calibrate odometry at speed 25 to match operating speed"
```

### Step 4: Deploy
```bash
# On Pi, Panda, Titan:
git pull
sudo systemctl daemon-reload   # REQUIRED for service file changes
./stop.sh annie && ./start.sh annie
```

### Step 5: On-robot calibration (8 steps, sequential)
1. **Drift check** — POST /drive forward 3s at speed 25. Observe drift. Adjust MOTOR_TRIM if needed.
2. **Turn precision** — POST /drive/turn left 30° at speed 25. Target: 27-33° achieved.
3. **Stall check** — POST /drive/turn both directions at speed 20. Must move.
4. **Open-loop fallback** — Disconnect IMU, test turn. Measure actual vs expected.
5. **Odometry calibration** — Run `python3 scripts/calibrate_odometry.py --host 192.168.68.61`
6. **ArUco homing** — POST /homing/start. Watch nudge + align_180 + approach.
7. **Escape sequence** — Place obstacle close, trigger escape. Verify backup + turn.
8. **Full nav E2E** — Ask Annie to navigate. Confirm turns, forward, stuck detection.

### Step 6: Update nav grid documentation
After calibration, update the 9-cell VLM→command grid with final tuned values.

## Rollback
- **Fast**: `git stash` on Pi. `./stop.sh annie && ./start.sh annie`.
- **Env-var tuning** (no redeploy): `MOTOR_TRIM_FL`, `MOTOR_TRIM_RL`, `PI_DRIVE_SPEED`, `OPEN_LOOP_DPS_AT_40` in turbopi-server.service.
