saltylab-firmware/docs/wiring-diagram.md
sl-controls fda6ab99ff feat(arch): align CAN/UART bridges with SAUL-TEE-SYSTEM-REFERENCE.md spec
Update CAN and serial bridge code to match authoritative protocol spec
from docs/SAUL-TEE-SYSTEM-REFERENCE.md §5-6 (hal, 2026-04-04).

mamba_protocol.py (CAN, Orin ↔ ESP32 BALANCE):
- 0x300 DRIVE: [speed:i16][steer:i16][mode:u8][flags:u8][_:u16] — combined frame
- 0x301 ARM:   [arm:u8]
- 0x302 PID:   [kp:f16][ki:f16][kd:f16][_:u16]  — half-float gains
- 0x303 ESTOP: [0xE5] — magic byte cut
- 0x400 ATTITUDE: [pitch:f16][speed:f16][yaw_rate:f16][state:u8][flags:u8]
- 0x401 BATTERY:  [vbat_mv:u16][fault_code:u8][rssi:i8]
- Add VESC STATUS1/4/5 decode helpers; VESC IDs 56 (left) / 68 (right)

can_bridge_node.py:
- /cmd_vel → encode_drive_cmd (speed/steer int16, MODE_DRIVE)
- /estop → encode_estop_cmd (magic 0xE5); clear → DISARM
- /saltybot/arm → encode_arm_cmd (new subscription)
- Watchdog sends DRIVE(0,0,MODE_IDLE) when /cmd_vel silent
- ATTITUDE (0x400) → /saltybot/attitude + /saltybot/balance_state JSON
- BATTERY  (0x401) → /can/battery BatteryState
- VESC STATUS1 frames → /can/vesc/left|right/state

stm32_cmd_node.py — rewritten for inter-board protocol API:
- Imports from updated stm32_protocol (BAUD_RATE=460800, new frame types)
- RX: RcChannels → /saltybot/rc_channels, SensorData → /saltybot/sensors
- TX: encode_led_cmd, encode_output_cmd from /saltybot/leds + /saltybot/outputs
- HEARTBEAT (0x20) timer replaces old SPEED_STEER/ARM logic

stm32_cmd_params.yaml: serial_port=/dev/esp32-io, baud=460800
stm32_cmd.launch.py: updated defaults and description

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-04 08:59:45 -04:00

15 KiB

SaltyLab / SAUL-TEE Wiring Reference

⚠️ ARCHITECTURE CHANGE (2026-04-03): Mamba F722S / STM32 retired. New stack: ESP32-S3 BALANCE + ESP32-S3 IO + VESCs on 500 kbps CAN. Authoritative reference: docs/SAUL-TEE-SYSTEM-REFERENCE.md Historical STM32/Mamba wiring below is obsolete — retained for reference only.


System Overview (OBSOLETE — see SAUL-TEE-SYSTEM-REFERENCE.md)

┌─────────────────────────────────────────────────────────────────────┐
│                        ORIN NANO SUPER                              │
│                     (Top Plate — 25W)                               │
│                                                                     │
│  USB-A ──── CANable2 USB-CAN adapter (slcan0, 500 kbps)           │
│  USB-A ──── ESP32-S3 IO (/dev/esp32-io, 460800 baud)              │
│  USB-A1 ─── RealSense D435i (USB 3.1)                             │
│  USB-A2 ─── RPLIDAR A1M8 (via CP2102 adapter, 115200)             │
│  USB-C* ─── SIM7600A 4G/LTE modem (ttyUSB0-2, AT cmds + PPP)     │
│  USB ─────── Leap Motion Controller (hand/gesture tracking)        │
│  CSI-A ──── ArduCam adapter → 2x IMX219 (front + left)            │
│  CSI-B ──── ArduCam adapter → 2x IMX219 (rear + right)            │
│  M.2 ───── 1TB NVMe SSD                                            │
│  40-pin ─── ReSpeaker 2-Mic HAT (I2S + I2C, WM8960 codec)         │
│  Pin 8 ──┐                                                         │
│  Pin 10 ─┤ UART fallback to ESP32-S3 BALANCE (ttyTHS0, 460800)    │
│  Pin 6 ──┘ GND                                                     │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘
         │ USB-A (CANable2)               │ UART fallback (3 wires)
         │ SocketCAN slcan0               │ 460800 baud, 3.3V
         │ 500 kbps                       │
         ▼                                ▼
┌─────────────────────────────────────────────────────────────────────┐
│                  ESP32-S3 BALANCE                                    │
│          (Waveshare Touch LCD 1.28, Middle Plate)                   │
│                                                                     │
│  CAN bus ──── CANable2 → Orin (primary link, ISO 11898)            │
│  UART0 ──── Orin UART fallback (460800 baud, 3.3V)                │
│  UART1 ──── VESC Left  (CAN ID 56) via UART/CAN bridge            │
│  UART2 ──── VESC Right (CAN ID 68) via UART/CAN bridge            │
│  I2C   ──── QMI8658 IMU (onboard, 6-DOF accel+gyro)               │
│  SPI   ──── GC9A01 LCD (onboard, 240x240 round display)           │
│  GPIO  ──── WS2812B LED strip                                      │
│  GPIO  ──── Buzzer                                                  │
│  ADC   ──── Battery voltage divider                                │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘
         │ CAN bus (ISO 11898)            │ UART (460800 baud)
         │ 500 kbps                       │
         ▼                                ▼
┌────────────────────────┐    ┌──────────────────────────┐
│   VESC Left (ID 56)    │    │   VESC Right (ID 68)     │
│   (Bottom Plate)       │    │   (Bottom Plate)          │
│                        │    │                            │
│  BLDC hub motor        │    │  BLDC hub motor            │
│  CAN 500 kbps          │    │  CAN 500 kbps             │
│  FOC current control   │    │  FOC current control      │
│  VESC Status 1 (0x900) │    │  VESC Status 1 (0x910)   │
│                        │    │                            │
└────────────────────────┘    └──────────────────────────┘
         │                              │
    LEFT MOTOR                    RIGHT MOTOR

Wire-by-Wire Connections

1. Orin <-> ESP32-S3 BALANCE (Primary: CAN Bus via CANable2)

From To Wire Notes
Orin USB-A CANable2 USB USB cable SocketCAN slcan0 @ 500 kbps
CANable2 CAN-H ESP32-S3 BALANCE CAN-H twisted pair ISO 11898 differential
CANable2 CAN-L ESP32-S3 BALANCE CAN-L twisted pair ISO 11898 differential
  • Interface: SocketCAN slcan0, 500 kbps
  • Device node: /dev/canable2 (via udev, symlink to ttyUSBx)
  • Protocol: CAN frames --- ORIN_CMD_DRIVE (0x300), ORIN_CMD_MODE (0x301), ORIN_CMD_ESTOP (0x302)
  • Telemetry: BALANCE_STATUS (0x400), BALANCE_VESC (0x401), BALANCE_IMU (0x402), BALANCE_BATTERY (0x403)

2. Orin <-> ESP32-S3 BALANCE (Fallback: Hardware UART)

Orin Pin Signal ESP32-S3 Pin Notes
Pin 8 TXD0 GPIO17 (UART0 RX) Orin TX -> BALANCE RX
Pin 10 RXD0 GPIO18 (UART0 TX) Orin RX <- BALANCE TX
Pin 6 GND GND Common ground
  • Jetson device: /dev/ttyTHS0
  • Baud: 460800, 8N1
  • Voltage: 3.3V both sides (no level shifter needed)
  • Cross-connect: Orin TX -> BALANCE RX, Orin RX <- BALANCE TX

3. Orin <-> ESP32-S3 IO (USB Serial)

From To Notes
Orin USB-A ESP32-S3 IO USB-C USB cable, /dev/esp32-io
  • Device node: /dev/esp32-io (udev symlink)
  • Baud: 460800, 8N1
  • Protocol: Binary frames [0xAA][LEN][TYPE][PAYLOAD][CRC8]
  • Use: IO expansion, GPIO control, sensor polling

4. ESP32-S3 BALANCE <-> VESC Motors (CAN Bus)

BALANCE Pin Signal VESC Pin Notes
GPIO21 CAN-H CAN-H ISO 11898 differential pair
GPIO22 CAN-L CAN-L ISO 11898 differential pair
GND GND GND Common ground
  • Baud: 500 kbps CAN
  • VESC Left: CAN ID 56, VESC Right: CAN ID 68
  • Commands: COMM_SET_RPM, COMM_SET_CURRENT, COMM_SET_DUTY
  • Telemetry: VESC Status 1 at 50 Hz (RPM, current, duty)

5. Power Distribution

BATTERY (36V) ──┬── VESC Left  (36V direct -> BLDC left motor)
                ├── VESC Right (36V direct -> BLDC right motor)
                │
                ├── 5V BEC/regulator ──┬── Orin (USB-C PD or barrel jack)
                │                      ├── ESP32-S3 BALANCE (5V via USB-C)
                │                      ├── ESP32-S3 IO (5V via USB-C)
                │                      ├── WS2812B LEDs (5V)
                │                      └── RPLIDAR (5V via USB)
                │
                └── Battery monitor ──── ESP32-S3 BALANCE ADC (voltage divider)

6. Sensors on Orin (USB/CSI)

Device Interface Orin Port Device Node
RealSense D435i USB 3.1 USB-A (blue) /dev/bus/usb/...
RPLIDAR A1M8 USB-UART USB-A /dev/rplidar
IMX219 front+left MIPI CSI-2 CSI-A (J5) /dev/video0,2
IMX219 rear+right MIPI CSI-2 CSI-B (J8) /dev/video4,6
1TB NVMe PCIe Gen3 x4 M.2 Key M /dev/nvme0n1
CANable2 USB-CAN USB-A /dev/canable2 -> slcan0

FC UART Summary (MAMBA F722S — OBSOLETE)

Interface Pins Baud/Rate Assignment Notes
UART0 GPIO17=RX, GPIO18=TX 460800 Orin UART fallback 3.3V, cross-connect
UART1 GPIO19=RX, GPIO20=TX 115200 Debug serial Optional
CAN (TWAI) GPIO21=H, GPIO22=L 500 kbps CAN bus (VESCs + Orin) SN65HVD230 transceiver
I2C GPIO4=SDA, GPIO5=SCL 400 kHz QMI8658 IMU (addr 0x6B) Onboard
SPI GPIO36=MOSI, GPIO37=SCLK, GPIO35=CS 40 MHz GC9A01 LCD (onboard) 240x240 round
USB CDC USB-C 460800 Orin USB fallback /dev/esp32-balance

CAN Frame ID Map

CAN ID Direction Name Contents
0x300 Orin -> BALANCE ORIN_CMD_DRIVE left_rpm_f32, right_rpm_f32 (8 bytes LE)
0x301 Orin -> BALANCE ORIN_CMD_MODE mode byte (0=IDLE, 1=DRIVE, 2=ESTOP)
0x302 Orin -> BALANCE ORIN_CMD_ESTOP flags byte (bit0=stop, bit1=clear)
0x400 BALANCE -> Orin BALANCE_STATUS pitch x10:i16, motor_cmd:u16, vbat_mv:u16, state:u8, flags:u8
0x401 BALANCE -> Orin BALANCE_VESC l_rpm x10:i16, r_rpm x10:i16, l_cur x10:i16, r_cur x10:i16
0x402 BALANCE -> Orin BALANCE_IMU pitch x100:i16, roll x100:i16, yaw x100:i16, ax x100:i16, ay x100:i16, az x100:i16
0x403 BALANCE -> Orin BALANCE_BATTERY vbat_mv:u16, current_ma:i16, soc_pct:u8
0x900+ID VESC Left -> VESC_STATUS_1 erpm:i32, current x10:i16, duty x1000:i16
0x910+ID VESC Right -> VESC_STATUS_1 erpm:i32, current x10:i16, duty x1000:i16

VESC Left CAN ID = 56 (0x38), VESC Right CAN ID = 68 (0x44).

7. ReSpeaker 2-Mic HAT (on Orin 40-pin header)

Orin Pin Signal Function
Pin 12 (GPIO 18) I2S BCLK Audio bit clock
Pin 35 (GPIO 19) I2S LRCLK Audio left/right clock
Pin 38 (GPIO 20) I2S DIN Audio data in (from mics)
Pin 40 (GPIO 21) I2S DOUT Audio data out (to speaker)
Pin 3 (GPIO 2) I2C SDA WM8960 codec control (i2c-7)
Pin 5 (GPIO 3) I2C SCL WM8960 codec control (i2c-7)
Pin 32 (GPIO 12) GPIO Button input
Pin 11 (GPIO 17) GPIO RGB LED (APA102 data)
Pin 2, 4 5V Power
Pin 6, 9 GND Ground
  • Codec: Wolfson WM8960 (I2C addr 0x1A)
  • Mics: 2x MEMS (left + right) --- basic stereo / sound localization
  • Speaker: 3W class-D amp output (JST connector)
  • Headset: 3.5mm TRRS jack
  • Requires: WM8960 device tree overlay for Jetson (community port)
  • Use: Voice commands (faster-whisper), wake word (openWakeWord), audio feedback, status announcements

8. SIM7600A 4G/LTE HAT (via USB)

Connection Detail
Interface USB (micro-B on HAT -> USB-A/C on Orin)
Device nodes /dev/ttyUSB0 (AT), /dev/ttyUSB1 (PPP/data), /dev/ttyUSB2 (GPS NMEA)
Power 5V from USB or separate 5V supply (peak 2A during TX)
SIM Nano-SIM slot on HAT
Antenna 4G LTE + GPS/GNSS (external SMA antennas --- mount high on chassis)
  • Data: PPP or QMI for internet connectivity
  • GPS/GNSS: Built-in receiver, NMEA sentences on ttyUSB2 --- outdoor positioning
  • AT commands: AT+CGPS=1 (enable GPS), AT+CGPSINFO (get fix)
  • Connected via USB (not 40-pin) --- avoids UART conflict with BALANCE fallback, flexible antenna placement
  • Use: Remote telemetry, 4G connectivity outdoors, GPS positioning, remote SSH/control

9. Leap Motion Controller (USB)

Connection Detail
Interface USB 3.0 (micro-B on controller -> USB-A on Orin)
Power ~0.5W
Range ~80cm, 150 deg FOV
SDK Ultraleap Gemini V5+ (Linux ARM64 support)
ROS2 leap_motion_ros2 wrapper available
  • 2x IR cameras + 3x IR LEDs --- tracks all 10 fingers in 3D, sub-mm precision
  • Mount: Forward-facing on sensor tower or upward on Orin plate
  • Use: Gesture control (palm=stop, point=go, fist=arm), hand-following mode, demos
  • Combined with ReSpeaker: Voice + gesture control with zero hardware in hand

10. Power Budget (USB)

Device Interface Power Draw
CANable2 USB-CAN USB-A ~0.5W
ESP32-S3 BALANCE USB-C ~0.8W (WiFi off)
ESP32-S3 IO USB-C ~0.5W
RealSense D435i USB-A ~1.5W (3.5W peak)
RPLIDAR A1M8 USB-A ~2.6W (motor on)
SIM7600A USB ~1W idle, 3W TX peak
Leap Motion USB-A ~0.5W
ReSpeaker HAT 40-pin ~0.5W
Total USB ~7.9W typical, ~11W peak

Orin Nano Super delivers up to 25W --- USB peripherals are well within budget.


Data Flow

                    ┌──────────────┐
                    │  RC TX       │ (in your hand)
                    │  (2.4GHz)    │
                    └──────┬───────┘
                           │ radio
                    ┌──────▼───────┐
                    │  RC RX       │ CRSF 420kbaud (future)
                    └──────┬───────┘
                           │ UART
              ┌────────────▼────────────┐
              │   ESP32-S3 BALANCE      │
              │  (Waveshare LCD 1.28)   │
              │                         │
              │  QMI8658 -> Balance PID │
              │  RC -> Mode Manager     │
              │  Safety Monitor         │
              │                         │
              └──┬──────────┬───────────┘
    CAN 500kbps─┘          └───── CAN bus / UART fallback
         │                              │
    ┌────┴────────────┐                 ▼
    │ CAN bus (500k)  │        ┌───────────────────┐
    ├─ VESC Left  56  │        │   Orin Nano Super  │
    └─ VESC Right 68  │        │                     │
         │    │                │  SLAM / Nav2 / AI  │
         ▼    ▼                │  Person following   │
       LEFT  RIGHT             │  Voice commands     │
       MOTOR MOTOR             │  4G telemetry       │
                               └──┬──────────┬───────┘
                                  │          │
                       ┌──────────▼─┐   ┌────▼──────────┐
                       │ ReSpeaker  │   │  SIM7600A     │
                       │ 2-Mic HAT  │   │  4G/LTE + GPS │
                       └────────────┘   └───────────────┘