sl-mechanical a2c554c232 cleanup: remove all Mamba/F722S/STM32F722 refs — replace with ESP32-S3 BALANCE/IO
- docs/: rewrite AGENTS.md, wiring-diagram.md (SAUL-TEE arch); update
  SALTYLAB.md, FACE_LCD_ANIMATION.md, board-viz.html, SALTYLAB-DETAILED refs
- cad/: dimensions.scad FC params → ESP32-S3 BALANCE params
- chassis/: ASSEMBLY.md, BOM.md, ip54_BOM.md, *.scad — FC_MOUNT_SPACING/
  FC_PITCH → TBD ESP32-S3; Drone FC → MCU mount throughout
- CLAUDE.md, TEAM.md: project desc → SAUL-TEE; hardware table → ESP32-S3/VESC
- USB_CDC_BUG.md: marked ARCHIVED (legacy STM32 era)
- AUTONOMOUS_ARMING.md: USB CDC → inter-board UART (ESP32-S3 BALANCE)
- projects/saltybot/SLAM-SETUP-PLAN.md: FC/STM32F722 → BALANCE/CAN
- jetson/docs/pinout.md, power-budget.md, README.md: STM32 bridge → CAN bridge
- jetson/config/RECOVERY_BEHAVIORS.md: FC+Hoverboard → BALANCE+VESC
- jetson/ros2_ws: stm32_protocol.py → esp32_protocol.py,
  stm32_cmd_node.py → esp32_cmd_node.py,
  mamba_protocol.py → balance_protocol.py; can_bridge_node imports updated
- scripts/flash_firmware.py: DFU/STM32 → pio run -t upload
- src/ include/: ARCHIVED headers added (legacy code preserved)
- test/: ARCHIVED notices; STM32F722 comments marked LEGACY
- ui/diagnostics_panel.html: Board/STM32 → ESP32-S3

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-04 09:06:09 -04:00

7.7 KiB
Raw Permalink Blame History

AGENTS.md — SAUL-TEE Agent Onboarding

You're working on SAUL-TEE, a 4-wheel wagon robot. Read this entire file before touching anything.

Full system reference: docs/SAUL-TEE-SYSTEM-REFERENCE.md

Project Overview

A 4-wheel wagon robot (870×510×550 mm, 23 kg) with three compute layers:

  1. ESP32-S3 BALANCE (Waveshare Touch LCD 1.28) — QMI8658 IMU, PID drive / stability loop, CAN bus master for VESCs. Safety-critical layer. Firmware in esp32/balance/.
  2. ESP32-S3 IO (bare board) — RC input (TBS Crossfire + ELRS failover), BTS7960 motor drivers, I2C sensors (NFC/baro/ToF), WS2812 LEDs, accessories. Firmware in esp32/io/.
  3. Jetson Orin Nano Super — AI brain: ROS2, SLAM, Nav2, perception. Sends high-level velocity commands over CAN (0x3000x303). Receives telemetry on CAN (0x4000x401).
Orin (CAN 0x300-0x303)  ←→  TBS Crossfire / ELRS (CRSF @ 420000)
         │                              │
         ▼ CAN 500kbps                  │ inter-board UART 460800
 ESP32-S3 BALANCE ───────────────── ESP32-S3 IO
   QMI8658 IMU                         BTS7960 × 4 motor drivers
   PID loop                            NFC / baro / ToF (I2C)
   SN65HVD230 CAN                      WS2812 LEDs
         │                             Horn / headlight / fan / buzzer
         ▼ CAN 500kbps
  VESC left (ID 68)   VESC right (ID 56)
         │                    │
     Hub motors FL/RL     Hub motors FR/RR

⚠️ SAFETY — READ THIS OR PEOPLE GET HURT

This is not a toy. 4× hub motors + 36V × high-current VESCs can crush fingers, break toes, and throw the 23 kg frame. Every firmware change must preserve these invariants:

  1. Motors NEVER spin on power-on. Requires deliberate arming: deliberate ARM command.
  2. RC kill switch — dedicated ELRS/Crossfire channel, checked every loop iteration. Always overrides.
  3. CAN watchdog — if no Orin heartbeat for 500 ms, drop to RC-only mode.
  4. ESTOP CAN frame — 0x303 with magic byte 0xE5 cuts all motors instantly.
  5. Inter-board heartbeat — if IO board misses BALANCE heartbeat for 200 ms, IO disables all BTS7960 enables.
  6. Speed hard cap — firmware limit, start at 10%. Increase only after proven stable.
  7. Never test without RC transmitter in hand.

If you break any of these, you are removed from the project.

Repository Layout

esp32/
├── balance/          — ESP32-S3 BALANCE firmware (PlatformIO)
│   ├── src/
│   │   ├── main.cpp
│   │   ├── config.h      ← GPIO assignments — update here first
│   │   ├── imu_qmi8658.cpp/.h
│   │   ├── can_vesc.cpp/.h
│   │   └── protocol.cpp/.h
│   └── platformio.ini
├── io/               — ESP32-S3 IO firmware (PlatformIO)
│   ├── src/
│   │   ├── main.cpp
│   │   ├── config.h      ← GPIO assignments — update here first
│   │   ├── rc_crsf.cpp/.h
│   │   ├── motor_bts7960.cpp/.h
│   │   └── protocol.cpp/.h
│   └── platformio.ini
└── shared/
    └── protocol.h    ← inter-board frame types — authoritative

src/                  — LEGACY STM32 code (ARCHIVED — do not touch)
include/              — LEGACY STM32 headers (ARCHIVED — do not touch)

chassis/              — OpenSCAD mechanical parts
├── ASSEMBLY.md       — assembly instructions
├── BOM.md            — bill of materials
└── *.scad            — parametric parts

docs/
├── SAUL-TEE-SYSTEM-REFERENCE.md  ← MASTER REFERENCE — read this
├── AGENTS.md                     — this file
├── wiring-diagram.md             — wiring reference (see SAUL-TEE-SYSTEM-REFERENCE.md)
└── SALTYLAB.md                   — legacy design doc (historical)

Hardware Quick Reference

ESP32-S3 BALANCE (Waveshare Touch LCD 1.28)

Spec Value
MCU ESP32-S3, dual-core 240 MHz, 8MB flash, 8MB PSRAM
USB CH343G USB-UART bridge (UART0 / GPIO43 TX, GPIO44 RX)
Display 1.28" round GC9A01 240×240 (SPI, onboard)
IMU QMI8658 6-axis (I2C-0 SDA=GPIO6, SCL=GPIO7, INT=GPIO3)
CAN SN65HVD230 external transceiver (GPIO TBD — see esp32/balance/src/config.h)
Inter-board UART UART1 (GPIO TBD) ↔ ESP32-IO @ 460800 baud

ESP32-S3 IO (bare board)

Peripheral Interface GPIO
TBS Crossfire RX UART0 CRSF @ 420000 GPIO43 TX / GPIO44 RX
ELRS failover RX UART2 CRSF @ 420000 TBD
BTS7960 FL/FR/RL/RR PWM + GPIO TBD — see config.h
I2C bus (NFC/baro/ToF) I2C TBD
WS2812B LEDs RMT GPIO TBD
Horn / headlight / fan / buzzer GPIO/PWM TBD
Inter-board UART UART1 @ 460800 TBD

All TBD GPIO assignments are confirmed in esp32/io/src/config.h.

CAN Bus

Node CAN ID Notes
VESC left motor 68 (0x44) FSESC 6.7 Pro Mini Dual
VESC right motor 56 (0x38) FSESC 6.7 Pro Mini Dual
Orin → robot cmds 0x3000x303 drive / arm / PID / ESTOP
BALANCE → Orin telemetry 0x4000x401 attitude + battery + faults

Physical Dimensions

Parameter Value
Robot (SAUL-TEE) 870 × 510 × 550 mm, 23 kg
Hub motor axle base OD Ø16.11 mm (caliper-verified)
Hub motor axle D-cut OD Ø15.95 mm, 13.00 mm flat chord
Bearing seat collar Ø37.8 mm
Tire 10 × 2.125" pneumatic (Ø254 mm)
ESP32-S3 BALANCE PCB ~40×40 mm (TBD — caliper before machining)
Orin carrier hole pattern 58 × 49 mm M3

Inter-Board Protocol

UART @ 460800 baud, 8N1. Frame: [0xAA][LEN][TYPE][PAYLOAD…][CRC8]

CRC polynomial: CRC-8/MAXIM (poly 0x31, init 0x00, RefIn/RefOut true).

Authoritative message type definitions: esp32/shared/protocol.h

Build & Flash

# ESP32-S3 BALANCE
cd esp32/balance
pio run -t upload                  # Upload via USB (CH343 serial)

# ESP32-S3 IO
cd esp32/io
pio run -t upload                  # Upload via USB (JTAG/CDC)

Critical Lessons Learned

  1. -(int)0 == 0 — checking if (-result) doesn't detect a zero error result. Use explicit error codes.
  2. NEVER auto-run untested firmware on boot — we bricked hardware doing this. Test manually first.
  3. One variable at a time — never change PID gains and speed limit in the same test session.
  4. QMI8658 data ready — poll INT pin (GPIO3) or use interrupt; don't poll status register in a tight loop.
  5. CAN bus termination — 120 Ω at each physical end of the bus. Missing termination = unreliable comms.

LED States (WS2812B on ESP32-IO)

State Pattern Color
Disarmed Slow breathe White
Arming Fast blink Yellow
Armed Solid Green
Turning Sweep direction Orange
Braking Flash rear Red
Fault / ESTOP Triple flash Red
RC lost Alternating flash Red/Blue

Printing (Bambu Lab)

  • X1C (192.168.87.190) — structural PETG/ASA parts
  • A1 (192.168.86.161) — TPU bumpers, prototypes
  • STL export from OpenSCAD, slice in Bambu Studio

Rules for Agents

  1. Read docs/SAUL-TEE-SYSTEM-REFERENCE.md fully before any design or firmware decision
  2. Never remove safety checks — add more if needed
  3. All mechanical measurements go in cad/dimensions.scad — single source of truth
  4. Test firmware on bench first — VESCs/BTS7960 disconnected, verify outputs on serial
  5. GPIO assignments live in config.h — change there, not scattered in source
  6. Document hardware quirks here — if you find a gotcha, add a "Critical Lesson Learned"
  7. Ask before wiring changes — wrong connections can fry ESP32-S3 boards