saltylab-firmware/docs/SAUL-TEE-SYSTEM-REFERENCE.md

217 lines
6.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# SAUL-TEE System Reference — SaltyLab ESP32 Architecture
*Source of truth for all hardware, pin, protocol, and CAN assignments.*
*Generated 2026-04-04 from hal@Orin spec.*
---
## Overview
| Board | Role | MCU | USB |
|-------|------|-----|-----|
| **ESP32-S3 BALANCE** | PID balance loop, CAN to VESCs, LCD UI | ESP32-S3 | CH343 USB-serial |
| **ESP32-S3 IO** | RC input, motor drivers, sensors, LEDs, peripherals | ESP32-S3 | JTAG USB |
**Robot form factor:** 4-wheel wagon — 870 × 510 × 550 mm, ~23 kg
**Power:** 36 V battery, DC-DC to 5 V / 12 V
**Orin connection:** CANable2 USB → CAN bus (same bus as VESCs)
---
## ESP32-S3 BALANCE
### Board
Waveshare ESP32-S3 Touch LCD 1.28 (GC9A01 round 240×240 LCD, CST816 touch, QMI8658 IMU)
### Pin Assignments
| Function | GPIO | Notes |
|----------|------|-------|
| **QMI8658 IMU** | | |
| SPI SCK | IO39 | |
| SPI MOSI | IO38 | |
| SPI MISO | IO40 | |
| IMU CS | IO41 | |
| IMU INT1 | IO42 | data-ready interrupt |
| **GC9A01 LCD** | | |
| SPI (shared) | IO39/38 | same SPI bus |
| LCD CS | IO12 | |
| LCD DC | IO11 | |
| LCD RST | IO10 | |
| LCD BL | IO9 | PWM backlight |
| **CST816 Touch** | | |
| I2C SDA | IO4 | |
| I2C SCL | IO5 | |
| Touch INT | IO6 | |
| Touch RST | IO7 | |
| **CAN (SN65HVD230)** | | 500 kbps |
| CAN TX | IO43 | to SN65HVD230 TXD |
| CAN RX | IO44 | from SN65HVD230 RXD |
| **Inter-board UART** | | 460800 baud |
| UART TX → IO | IO17 | |
| UART RX ← IO | IO18 | |
### Software Responsibilities
- Read QMI8658 @ 1 kHz (SPI)
- Run PID balance loop (configurable Kp/Ki/Kd, target pitch)
- Send VESC speed commands via CAN (IDs 68 left, 56 right)
- Receive Orin velocity commands via CAN (0x3000x303)
- Receive IO board status (arming, RC, faults) via UART
- Drive LCD status display (pitch, speed, battery, state)
- Enforce tilt cutoff at ±25°, hardware watchdog 50 ms
- Send telemetry CAN frames 0x4000x401 at 10 Hz
---
## ESP32-S3 IO
### Board
Bare ESP32-S3 devkit (JTAG USB)
### Pin Assignments
| Function | GPIO | Notes |
|----------|------|-------|
| **TBS Crossfire RC** | | UART0, primary RC |
| CRSF RX | IO44 | UART0 RX |
| CRSF TX | IO43 | UART0 TX |
| **ELRS RC failover** | | UART2 |
| ELRS RX | IO16 | UART2 RX |
| ELRS TX | IO17 | UART2 TX |
| **BTS7960 Motor Drivers** | | 2× drivers (left/right) |
| Left RPWM | IO1 | forward PWM |
| Left LPWM | IO2 | reverse PWM |
| Left R_EN | IO3 | enable |
| Left L_EN | IO4 | enable |
| Right RPWM | IO5 | forward PWM |
| Right LPWM | IO6 | reverse PWM |
| Right R_EN | IO7 | enable |
| Right L_EN | IO8 | enable |
| **I2C bus** | | sensors |
| SDA | IO11 | |
| SCL | IO12 | |
| NFC reader | I2C | PN532 or similar |
| Barometer | I2C | BMP280 / BMP388 |
| ToF sensor | I2C | VL53L0X / VL53L1X |
| **WS2812B LEDs** | | |
| LED data | IO13 | |
| **Outputs** | | |
| Horn / buzzer | IO14 | PWM |
| Headlight | IO15 | PWM or digital |
| Fan | IO16 | (shared if ELRS not fitted) |
| Arming button | IO9 | active-low, hold 3 s |
| Kill switch in | IO10 | hardware estop sense |
| **Inter-board UART** | | 460800 baud |
| UART TX → BAL | IO18 | |
| UART RX ← BAL | IO21 | |
### Software Responsibilities
- Parse CRSF frames (TBS Crossfire primary)
- Parse ELRS frames (failover if CRSF absent)
- Drive BTS7960 motor drivers (PWM + enable)
- Read NFC, barometer, ToF via I2C
- Drive WS2812B LEDs (status patterns)
- Control horn, headlight, fan, buzzer
- Manage arming sequence (hold button 3 s while upright)
- Monitor hardware kill switch
- Forward RC + sensor data to BALANCE board via UART
- Report faults, RC loss, sensor health upstream
---
## Inter-Board Protocol (UART 460800 baud)
```
Frame: [0xAA][LEN][TYPE][PAYLOAD...][CRC8]
0xAA — start byte
LEN — payload length (1 byte)
TYPE — message type (1 byte)
PAYLOAD — LEN bytes
CRC8 — CRC-8/MAXIM over TYPE+PAYLOAD
```
### Message Types (IO → BALANCE)
| TYPE | Name | Payload |
|------|------|---------|
| 0x01 | RC_CMD | int16 throttle, int16 steer, uint8 flags (armed, kill) |
| 0x02 | SENSOR | uint16 tof_mm, int16 baro_pa_delta, uint8 nfc_present |
| 0x03 | FAULT | uint8 fault_flags (rc_loss, motor_fault, estop) |
### Message Types (BALANCE → IO)
| TYPE | Name | Payload |
|------|------|---------|
| 0x10 | STATE | int16 pitch_x100, int16 pid_out, uint8 error_state |
| 0x11 | LED_CMD | uint8 pattern, uint8 r, uint8 g, uint8 b |
| 0x12 | BUZZER | uint8 tone_hz, uint16 duration_ms |
---
## CAN Bus — 500 kbps
### Node IDs
| Node | CAN ID | Description |
|------|--------|-------------|
| VESC Left motor | 68 | Speed/duty commands via VESC protocol |
| VESC Right motor | 56 | Speed/duty commands via VESC protocol |
| ESP32 BALANCE | — | Initiates VESC commands; sends telemetry |
| Jetson Orin | — | Via CANable2 USB adapter |
### CAN Frame Assignments
| ID | Direction | Description | Rate |
|----|-----------|-------------|------|
| 0x300 | Orin → BALANCE | Velocity cmd: int16 speed_mmps, int16 steer_mrad | 20 Hz |
| 0x301 | Orin → BALANCE | PID override: float Kp, Ki, Kd (IEEE 754, 4B each) | on demand |
| 0x302 | Orin → BALANCE | Mode: uint8 (0=off,1=balance,2=manual,3=estop) | on demand |
| 0x303 | Orin → BALANCE | Config: uint16 tilt_limit_x100, uint16 max_speed | on demand |
| 0x400 | BALANCE → Orin | Telemetry A: int16 pitch_x100, int16 pid_out, int16 speed_mmps, uint8 state | 10 Hz |
| 0x401 | BALANCE → Orin | Telemetry B: int16 vesc_l_rpm, int16 vesc_r_rpm, uint16 battery_mv, uint8 faults | 10 Hz |
---
## RC Channel Mapping (CRSF / ELRS)
| Channel | Function | Range | Notes |
|---------|----------|-------|-------|
| CH1 | Roll (steer) | 9882012 µs | ±100% = ±max steer |
| CH2 | Pitch (throttle) | 9882012 µs | forward/back speed |
| CH3 | Throttle | 9882012 µs | unused / spare |
| CH4 | Yaw | 9882012 µs | unused |
| CH5 | ARM switch | <1500=disarm, >1500=arm | SB on TX |
| CH6 | ESTOP | <1500=normal, >1500=kill | SC on TX, always checked |
| CH7 | Speed limit | 9882012 µs | 10100% speed cap |
| CH8 | Spare | | |
RC loss (CRSF failsafe or no frame >100 ms): immediate motor cutoff, fault 0x03.
---
## Safety Invariants (unchanged from STM32 era)
1. Motors NEVER spin on power-on — 3 s arm hold required
2. Tilt cutoff ±25° — immediate motor zero, manual re-arm
3. Hardware watchdog 50 ms — firmware hang → motors cut
4. RC ESTOP channel checked every loop iteration
5. Orin CAN timeout 500 ms — revert to RC-only mode
6. Speed hard cap in firmware — start at 10%, increase in 10% steps
7. Never test untethered until stable for 5+ min tethered
---
## Serial Commands (USB debug, both boards)
```
help — list commands
status — print state, pitch, PID, CAN stats
pid <Kp> <Ki> <Kd> — set PID gains
arm — arm (if upright)
disarm — disarm immediately
estop — emergency stop
tilt_limit <deg> — set tilt cutoff (default 25)
speed_limit <pct> — set speed cap (default 10)
can_stats — CAN bus stats (tx/rx/errors)
reboot — soft reboot
```