From ea71cefff5759c1918bda94e6c6c57da3eee7339 Mon Sep 17 00:00:00 2001 From: sl-jetson Date: Sat, 4 Apr 2026 08:19:14 -0400 Subject: [PATCH] =?UTF-8?q?docs:=20Add=20SAUL-TEE=20system=20reference=20?= =?UTF-8?q?=E2=80=94=20ESP32-S3=20architecture=20(Issue=20#695+)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/SAUL-TEE-SYSTEM-REFERENCE.md | 216 ++++++++++++++++++++++++++++++ 1 file changed, 216 insertions(+) create mode 100644 docs/SAUL-TEE-SYSTEM-REFERENCE.md diff --git a/docs/SAUL-TEE-SYSTEM-REFERENCE.md b/docs/SAUL-TEE-SYSTEM-REFERENCE.md new file mode 100644 index 0000000..e9340af --- /dev/null +++ b/docs/SAUL-TEE-SYSTEM-REFERENCE.md @@ -0,0 +1,216 @@ +# 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 (0x300–0x303) +- 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 0x400–0x401 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) | 988–2012 µs | ±100% = ±max steer | +| CH2 | Pitch (throttle) | 988–2012 µs | forward/back speed | +| CH3 | Throttle | 988–2012 µs | unused / spare | +| CH4 | Yaw | 988–2012 µ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 | 988–2012 µs | 10–100% 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 — set PID gains +arm — arm (if upright) +disarm — disarm immediately +estop — emergency stop +tilt_limit — set tilt cutoff (default 25) +speed_limit — set speed cap (default 10) +can_stats — CAN bus stats (tx/rx/errors) +reboot — soft reboot +```