# Autonomous Arming (Issue #512)

## Overview
The robot can now be armed and operated autonomously from the Jetson without requiring an RC transmitter. The RC receiver (ELRS) is now optional and serves as an override/kill-switch rather than a requirement.

## Arming Sources

### Jetson Autonomous Arming
- Command: `A\n` (single byte 'A' followed by newline)
<<<<<<< HEAD
- Sent via USB CDC to the ESP32 BALANCE firmware
=======
- Sent via USB Serial (CH343) to the ESP32-S3 firmware
>>>>>>> 291dd68 (feat: remove all STM32/Mamba/BlackPill references — ESP32-S3 only)
- Robot arms after ARMING_HOLD_MS (~500ms) safety hold period
- Works even when RC is not connected or not armed

### RC Arming (Optional Override)
- Command: CH5 switch on ELRS transmitter
- When RC is connected and armed, robot can be armed via RC
- RC and Jetson can both request arming independently

## Safety Features

### Maintained from Original Design
1. **Arming Hold Timer** — 500ms hold before motors enable (prevents accidental arming)
2. **Tilt Safety** — Robot must be within ±10° level to arm
3. **IMU Calibration** — Gyro must be calibrated before arming
4. **Remote E-Stop Override** — `safety_remote_estop_active()` blocks all arming

### New for Autonomous Operation
1. **RC Kill Switch** (CH5 OFF when RC connected)
   - Triggers emergency stop (motor cutoff) instead of disarm
   - Allows Jetson-armed robots to remain armed when RC disconnects
   - Maintains safety of kill switch for emergency situations

2. **RC Failsafe**
   - If RC signal is lost after being established, robot disarms (500ms timeout)
   - Prevents runaway if RC connection drops during flight
   - USB-only mode (no RC ever connected) is unaffected

3. **Jetson Timeout** (200ms heartbeat)
   - Jetson must send heartbeat (H command) every 500ms
   - Prevents autonomous runaway if Jetson crashes/loses connection
   - Handled by `jetson_cmd_is_active()` checks

## Command Protocol

<<<<<<< HEAD
### From Jetson to ESP32 BALANCE (USB CDC)
=======
### From Jetson to ESP32-S3 (USB Serial (CH343))
>>>>>>> 291dd68 (feat: remove all STM32/Mamba/BlackPill references — ESP32-S3 only)
```
A           — Request arm (triggers safety hold, then motors enable)
D           — Request disarm (immediate motor stop)
E           — Emergency stop (immediate motor cutoff, latched)
Z           — Clear emergency stop latch
H           — Heartbeat (refresh timeout timer, every 500ms)
C<spd>,<str> — Drive command: speed, steer (also refreshes heartbeat)
```

<<<<<<< HEAD
### From ESP32 BALANCE to Jetson (USB CDC)
=======
### From ESP32-S3 to Jetson (USB Serial (CH343))
>>>>>>> 291dd68 (feat: remove all STM32/Mamba/BlackPill references — ESP32-S3 only)
Motor commands are gated by `bal.state == BALANCE_ARMED`:
- When ARMED: Motor commands sent every 20ms (50 Hz)
- When DISARMED: Zero sent every 20ms (prevents ESC timeout)

## Arming State Machine

```
DISARMED
  ↓
  +-- Jetson sends 'A' OR RC CH5 rises (with conditions met)
      ↓
      safety_arm_start() called
      (arm hold timer starts)
      ↓
      Wait ARMING_HOLD_MS
      ↓
      safety_arm_ready() returns true
      ↓
      balance_arm() called
      ARMED ← (motors now respond to commands)

ARMED
  ↓
  +-- Jetson sends 'D' → balance_disarm()
  +-- RC CH5 falls AND RC still alive → balance_disarm()
  +-- RC signal lost (failsafe) → balance_disarm()
  +-- Tilt fault detected → immediate motor stop
  +-- RC kill switch (CH5 OFF) → emergency stop (not disarm)
```

## RC Override Priority

When RC is connected and active:
- **Steer channel**: Blended with Jetson via `mode_manager` (per active mode)
- **Kill switch**: RC CH5 OFF triggers emergency stop (overrides everything)
- **Failsafe**: RC signal loss triggers disarm (prevents runaway)

When RC is disconnected:
- Robot operates under Jetson commands alone
- Emergency stop remains available via 'E' command from Jetson
- No automatic mode change; mission continues autonomously

## Testing Checklist

- [ ] Jetson can arm robot without RC (send 'A' command)
- [ ] Robot motors respond to Jetson drive commands when armed
- [ ] Robot disarms on Jetson 'D' command
- [ ] RC kill switch (CH5 OFF) triggers emergency stop without disarming
- [ ] Robot can be re-armed after RC kill switch via Jetson 'A' command
- [ ] RC failsafe still works (500ms signal loss = disarm)
- [ ] Jetson heartbeat timeout works (500ms without H/C = motors zero)
- [ ] Tilt fault still triggers immediate stop
- [ ] IMU calibration required before arm
- [ ] Arming hold timer (500ms) enforced

## Migration from RC-Only

### Old Workflow (ELRS-Required)
1. Power on robot
2. Arm via RC CH5
3. Send speed/steer commands via RC
4. Disarm via RC CH5

### New Workflow (Autonomous)
1. Power on robot
2. Send heartbeat 'H' every 500ms from Jetson
3. When ready to move, send 'A' command (wait 500ms)
4. Send drive commands 'C<spd>,<str>' every ≤200ms
5. When done, send 'D' command to disarm

### New Workflow (RC + Autonomous Mixed)
1. Power on robot, bring up RC
2. Jetson sends heartbeat 'H'
3. Arm via RC CH5 OR Jetson 'A' (both valid)
4. Control via RC sticks OR Jetson drive commands (blended)
5. Emergency kill: RC CH5 OFF (emergency stop) OR Jetson 'E'
6. Disarm: RC CH5 OFF then ON, OR Jetson 'D'

## References
- Issue #512: Remove ELRS arm requirement
- Files: `/src/main.c` (arming logic), `/lib/USB_CDC/src/usbd_cdc_if.c` (CDC commands)
