chore: remove Mamba F722S / STM32 / BlackPill legacy hw refs #716

Closed
sl-jetson wants to merge 2 commits from sl-android/cleanup-legacy-hw into main
Showing only changes of commit c52dc786a2 - Show all commits

View File

@ -5,17 +5,18 @@ You're working on **SaltyLab**, a self-balancing two-wheeled indoor robot. Read
## Project Overview ## Project Overview
A hoverboard-based balancing robot with two compute layers: A hoverboard-based balancing robot with two compute layers:
1. **FC (Flight Controller)** — MAMBA F722S (STM32F722RET6 + MPU6000 IMU). Runs a lean C balance loop at up to 8kHz. Talks UART to the hoverboard ESC. This is the safety-critical layer. 1. **ESP32-S3 BALANCE** — runs the PID balance loop. Safety-critical, operates independently of the Orin.
2. **Jetson Nano** — AI brain. ROS2, SLAM, person tracking. Sends velocity commands to FC via UART. Not safety-critical — FC operates independently. 2. **ESP32-S3 IO** — handles I/O: motor commands to VESCs, sensor polling, CAN/UART comms.
3. **Orin Nano Super** — AI brain. ROS2, SLAM, person tracking. Sends velocity commands to ESP32-S3 BALANCE via UART. Not safety-critical.
``` ```
Jetson (speed+steer via UART1) ←→ ELRS RC (UART3, kill switch) Orin Nano Super (speed+steer via UART) ←→ ELRS RC (kill switch)
MAMBA F722S (MPU6000 IMU, PID balance) ESP32-S3 BALANCE (IMU, PID balance loop)
▼ UART2 CAN / UART
Hoverboard ESC (FOC) → 2× 8" hub motors ESP32-S3 IO → VESC 68 (left) + VESC 56 (right)
``` ```
## ⚠️ SAFETY — READ THIS OR PEOPLE GET HURT ## ⚠️ SAFETY — READ THIS OR PEOPLE GET HURT
@ -26,7 +27,7 @@ This is not a toy. 8" hub motors + 36V battery can crush fingers, break toes, an
2. **Tilt cutoff at ±25°** — motors to zero, require manual re-arm. No retry, no recovery. 2. **Tilt cutoff at ±25°** — motors to zero, require manual re-arm. No retry, no recovery.
3. **Hardware watchdog (50ms)** — if firmware hangs, motors cut. 3. **Hardware watchdog (50ms)** — if firmware hangs, motors cut.
4. **RC kill switch** — dedicated ELRS channel, checked every loop iteration. Always overrides. 4. **RC kill switch** — dedicated ELRS channel, checked every loop iteration. Always overrides.
5. **Jetson UART timeout (200ms)** — if Jetson disconnects, motors cut. 5. **Orin UART timeout (200ms)** — if Orin disconnects, motors cut.
6. **Speed hard cap** — firmware limit, start at 10%. Increase only after proven stable. 6. **Speed hard cap** — firmware limit, start at 10%. Increase only after proven stable.
7. **Never test untethered** until PID is stable for 5+ minutes on a tether. 7. **Never test untethered** until PID is stable for 5+ minutes on a tether.
@ -35,31 +36,16 @@ This is not a toy. 8" hub motors + 36V battery can crush fingers, break toes, an
## Repository Layout ## Repository Layout
``` ```
firmware/ # STM32 HAL firmware (PlatformIO) esp32/ # ESP32-S3 firmware (ESP-IDF)
├── src/ ├── balance/ # ESP32-S3 BALANCE — PID loop, IMU, safety
│ ├── main.c # Entry point, clock config, main loop └── io/ # ESP32-S3 IO — VESC CAN, sensors, comms
│ ├── icm42688.c # ICM-42688-P SPI driver (backup IMU — currently broken)
│ ├── bmp280.c # Barometer driver (disabled)
│ └── status.c # LED + buzzer status patterns
├── include/
│ ├── config.h # Pin definitions, constants
│ ├── icm42688.h
│ ├── mpu6000.h # MPU6000 driver header (primary IMU)
│ ├── hoverboard.h # Hoverboard ESC UART protocol
│ ├── crsf.h # ELRS CRSF protocol
│ ├── bmp280.h
│ └── status.h
├── lib/USB_CDC/ # USB CDC stack (serial over USB)
│ ├── src/ # CDC implementation, USB descriptors, PCD config
│ └── include/
└── platformio.ini # Build config
cad/ # OpenSCAD parametric parts (16 files) cad/ # OpenSCAD parametric parts (16 files)
├── dimensions.scad # ALL measurements live here — single source of truth ├── dimensions.scad # ALL measurements live here — single source of truth
├── assembly.scad # Full robot assembly visualization ├── assembly.scad # Full robot assembly visualization
├── motor_mount_plate.scad ├── motor_mount_plate.scad
├── battery_shelf.scad ├── battery_shelf.scad
├── fc_mount.scad # Vibration-isolated FC mount ├── esp32_balance_mount.scad # Vibration-isolated ESP32-S3 BALANCE mount
├── jetson_shelf.scad ├── jetson_shelf.scad
├── esc_mount.scad ├── esc_mount.scad
├── sensor_tower_top.scad ├── sensor_tower_top.scad
@ -82,55 +68,55 @@ PLATFORM.md # Hardware platform reference
## Hardware Quick Reference ## Hardware Quick Reference
### MAMBA F722S Flight Controller ### ESP32-S3 BALANCE
| Spec | Value | | Spec | Value |
|------|-------| |------|-------|
| MCU | STM32F722RET6 (Cortex-M7, 216MHz, 512KB flash, 256KB RAM) | | MCU | ESP32-S3 (dual-core Xtensa LX7, 240MHz, 512KB SRAM, 8MB flash) |
| Primary IMU | MPU6000 (WHO_AM_I = 0x68) | | Primary IMU | MPU6000 (SPI) |
| IMU Bus | SPI1: PA5=SCK, PA6=MISO, PA7=MOSI, CS=PA4 | | Role | PID balance loop, tilt cutoff, arming |
| IMU EXTI | PC4 (data ready interrupt) | | Comms to Orin | UART (velocity commands in, telemetry out) |
| IMU Orientation | CW270 (Betaflight convention) | | Flash | `idf.py -p /dev/ttyUSB0 flash` |
| Secondary IMU | ICM-42688-P (on same SPI1, CS unknown — currently non-functional) |
| Betaflight Target | DIAT-MAMBAF722_2022B |
| USB | OTG FS (PA11/PA12), enumerates as /dev/cu.usbmodemSALTY0011 |
| VID/PID | 0x0483/0x5740 |
| LEDs | PC15 (LED1), PC14 (LED2), active low |
| Buzzer | PB2 (inverted push-pull) |
| Battery ADC | PC1=VBAT, PC3=CURR (ADC3) |
| DFU | Hold yellow BOOT button + plug USB (or send 'R' over CDC) |
### UART Assignments ### ESP32-S3 IO
| UART | Pins | Connected To | Baud | | Spec | Value |
|------|------|-------------|------| |------|-------|
| USART1 | PA9/PA10 | Jetson Nano | 115200 | | MCU | ESP32-S3 |
| USART2 | PA2/PA3 | Hoverboard ESC | 115200 | | Role | VESC CAN driver, sensor polling, peripheral I/O |
| USART3 | PB10/PB11 | ELRS Receiver | 420000 (CRSF) | | VESC IDs | 68 (left), 56 (right) |
| UART4 | — | Spare | — | | Motor bus | CAN 1Mbit/s |
| UART5 | — | Spare | — | | Flash | `idf.py -p /dev/ttyUSB1 flash` |
### UART Assignments (ESP32-S3 BALANCE)
| UART | Connected To | Baud |
|------|-------------|------|
| UART0 | Orin Nano Super | 115200 |
| UART1 | ESP32-S3 IO | 115200 |
| UART2 | ELRS Receiver | 420000 (CRSF) |
### Motor/ESC ### Motor/ESC
- 2× 8" pneumatic hub motors (36V, hoverboard type) - 2× 8" pneumatic hub motors (36V, hoverboard type)
- Hoverboard ESC with FOC firmware - 2× VESC motor controllers (CAN IDs 68, 56)
- UART protocol: `{0xABCD, int16 speed, int16 steer, uint16 checksum}` at 115200 - VESC CAN protocol: standard SET_DUTY / SET_CURRENT / SET_RPM
- Speed range: -1000 to +1000 - Speed range: -1.0 to +1.0 (duty cycle)
### Physical Dimensions (from `cad/dimensions.scad`) ### Physical Dimensions (from `cad/dimensions.scad`)
| Part | Key Measurement | | Part | Key Measurement |
|------|----------------| |------|----------------|
| FC mounting holes | 25.5mm spacing (NOT standard 30.5mm!) | | ESP32-S3 BALANCE board | ~55×28mm (DevKit form factor) |
| FC board size | ~36mm square | | ESP32-S3 IO board | ~55×28mm (DevKit form factor) |
| Hub motor body | Ø200mm (~8") | | Hub motor body | Ø200mm (~8") |
| Motor axle | Ø12mm, 45mm long | | Motor axle | Ø12mm, 45mm long |
| Jetson Nano | 100×80×29mm, M2.5 holes at 86×58mm | | Orin Nano Super | 100×79mm, M2.5 holes at 86×58mm |
| RealSense D435i | 90×25×25mm, 1/4-20 tripod mount | | RealSense D435i | 90×25×25mm, 1/4-20 tripod mount |
| RPLIDAR A1 | Ø70×41mm, 4× M2.5 on Ø67mm circle | | RPLIDAR A1 | Ø70×41mm, 4× M2.5 on Ø67mm circle |
| Kill switch hole | Ø22mm panel mount | | Kill switch hole | Ø22mm panel mount |
| Battery pack | ~180×80×40mm | | Battery pack | ~180×80×40mm |
| Hoverboard ESC | ~80×50×15mm | | VESC (each) | ~70×50×15mm |
| 2020 extrusion | 20mm square, M5 center bore | | 2020 extrusion | 20mm square, M5 center bore |
| Frame width | ~350mm (axle to axle) | | Frame width | ~350mm (axle to axle) |
| Frame height | ~500-550mm total | | Frame height | ~500-550mm total |
@ -147,7 +133,7 @@ PLATFORM.md # Hardware platform reference
| sensor_tower_top | ASA | 80% | | sensor_tower_top | ASA | 80% |
| lidar_standoff (Ø80×80mm) | ASA | 40% | | lidar_standoff (Ø80×80mm) | ASA | 40% |
| realsense_bracket | PETG | 60% | | realsense_bracket | PETG | 60% |
| fc_mount (vibration isolated) | TPU+PETG | — | | esp32_balance_mount (vibration isolated) | TPU+PETG | — |
| bumper front + rear (350×50×30mm) | TPU | 30% | | bumper front + rear (350×50×30mm) | TPU | 30% |
| handle | PETG | 80% | | handle | PETG | 80% |
| kill_switch_mount | PETG | 80% | | kill_switch_mount | PETG | 80% |
@ -159,99 +145,75 @@ PLATFORM.md # Hardware platform reference
### Critical Lessons Learned (DON'T REPEAT THESE) ### Critical Lessons Learned (DON'T REPEAT THESE)
1. **SysTick_Handler with HAL_IncTick() is MANDATORY** — without it, HAL_Delay() and every HAL timeout hangs forever. This bricked us multiple times. 1. **NEVER auto-run untested code on_boot** — we bricked the NSPanel 3x doing this. Test manually first.
2. **DCache breaks SPI on STM32F7** — disable DCache or use cache-aligned DMA buffers with clean/invalidate. We disable it. 2. **`-(int)0 == 0`** — checking `if (-result)` to detect errors doesn't work when result is 0. Always use explicit error codes.
3. **`-(int)0 == 0`** — checking `if (-result)` to detect errors doesn't work when result is 0 (success and failure look the same). Always use explicit error codes. 3. **USB CDC needs RX primed in init** — without it, the OUT endpoint never starts listening.
4. **NEVER auto-run untested code on_boot** — we bricked the NSPanel 3x doing this. Test manually first. 4. **Watchdog must be fed every loop iteration** — if balance loop stalls, motors must cut within 50ms.
5. **USB CDC needs ReceivePacket() primed in CDC_Init** — without it, the OUT endpoint never starts listening. No data reception. 5. **Never change PID and speed limit in the same test** — one variable at a time.
### DFU Reboot (Betaflight Method) ### Build & Flash (ESP32-S3)
The firmware supports reboot-to-DFU via USB command:
1. Send `R` byte over USB CDC
2. Firmware writes `0xDEADBEEF` to RTC backup register 0
3. `NVIC_SystemReset()` — clean hardware reset
4. On boot, `checkForBootloader()` (called after `HAL_Init()`) reads the magic
5. If magic found: clears it, remaps system memory, jumps to STM32 bootloader at `0x1FF00000`
6. Board appears as DFU device, ready for `dfu-util` flash
### Build & Flash
```bash ```bash
cd firmware/ # Balance board
python3 -m platformio run # Build cd esp32/balance/
dfu-util -a 0 -s 0x08000000:leave -D .pio/build/f722/firmware.bin # Flash idf.py build && idf.py -p /dev/ttyUSB0 flash monitor
# IO board
cd esp32/io/
idf.py build && idf.py -p /dev/ttyUSB1 flash monitor
``` ```
Dev machine: mbpm4 (seb@192.168.87.40), PlatformIO project at `~/Projects/saltylab-firmware/` Dev machine: mbpm4 (seb@192.168.87.40)
### Clock Configuration
```
HSE 8MHz → PLL (M=8, N=432, P=2, Q=9) → SYSCLK 216MHz
PLLSAI (N=384, P=8) → CLK48 48MHz (USB)
APB1 = HCLK/4 = 54MHz
APB2 = HCLK/2 = 108MHz
Fallback: HSI 16MHz if HSE fails (PLL M=16)
```
## Current Status & Known Issues ## Current Status & Known Issues
### Working ### Working
- USB CDC serial streaming (50Hz JSON: `{"ax":...,"ay":...,"az":...,"gx":...,"gy":...,"gz":...}`) - IMU streaming (50Hz JSON: `{"ax":...,"ay":...,"az":...,"gx":...,"gy":...,"gz":...}`)
- Clock config with HSE + HSI fallback - VESC CAN communication (IDs 68, 56)
- Reboot-to-DFU via USB 'R' command - LED status patterns
- LED status patterns (status.c)
- Web UI with WebSerial + Three.js 3D visualization - Web UI with WebSerial + Three.js 3D visualization
### Broken / In Progress ### In Progress
- **ICM-42688-P SPI reads return all zeros** — was the original IMU target, but SPI communication completely non-functional despite correct pin config. May be dead silicon. Switched to MPU6000 as primary. - PID balance loop tuning
- **MPU6000 driver** — header exists but implementation needs completion - ELRS CRSF receiver integration
- **PID balance loop** — not yet implemented - Orin UART integration
- **Hoverboard ESC UART** — protocol defined, driver not written
- **ELRS CRSF receiver** — protocol defined, driver not written
- **Barometer (BMP280)** — I2C init hangs, disabled
### TODO (Priority Order) ### TODO (Priority Order)
1. Get MPU6000 streaming accel+gyro data 1. Tune PID balance loop on ESP32-S3 BALANCE
2. Implement complementary filter (pitch angle) 2. Implement complementary filter (pitch angle)
3. Write hoverboard ESC UART driver 3. Wire ELRS receiver, implement CRSF parser
4. Write PID balance loop with safety checks 4. Bench test (VESCs disconnected, verify PID output)
5. Wire ELRS receiver, implement CRSF parser 5. First tethered balance test at 10% speed
6. Bench test (ESC disconnected, verify PID output) 6. Orin UART integration
7. First tethered balance test at 10% speed 7. LED subsystem (ESP32-S3 IO)
8. Jetson UART integration
9. LED subsystem (ESP32-C3)
## Communication Protocols ## Communication Protocols
### Jetson → FC (UART1, 50Hz) ### Orin → ESP32-S3 BALANCE (UART0, 50Hz)
```c ```c
struct { uint8_t header=0xAA; int16_t speed; int16_t steer; uint8_t mode; uint8_t checksum; }; struct { uint8_t header=0xAA; int16_t speed; int16_t steer; uint8_t mode; uint8_t checksum; };
// mode: 0=idle, 1=balance, 2=follow, 3=RC // mode: 0=idle, 1=balance, 2=follow, 3=RC
``` ```
### FC → Hoverboard ESC (UART2, loop rate) ### ESP32-S3 IO → VESC (CAN, loop rate)
```c - Standard VESC CAN protocol (SET_DUTY / SET_CURRENT / SET_RPM)
struct { uint16_t start=0xABCD; int16_t speed; int16_t steer; uint16_t checksum; }; - Node IDs: VESC 68 (left), VESC 56 (right)
// speed/steer: -1000 to +1000
```
### FC → Jetson Telemetry (UART1 TX, 50Hz) ### ESP32-S3 BALANCE → Orin Telemetry (UART0 TX, 50Hz)
``` ```
T:12.3,P:45,L:100,R:-80,S:3\n T:12.3,P:45,L:100,R:-80,S:3\n
// T=tilt°, P=PID output, L/R=motor commands, S=state (0-3) // T=tilt°, P=PID output, L/R=motor commands, S=state (0-3)
``` ```
### FC → USB CDC (50Hz JSON) ### ESP32-S3 → USB (50Hz JSON, debug/tuning)
```json ```json
{"ax":123,"ay":-456,"az":16384,"gx":10,"gy":-5,"gz":3,"t":250,"p":0,"bt":0} {"ax":123,"ay":-456,"az":16384,"gx":10,"gy":-5,"gz":3,"t":250,"p":0}
// Raw IMU values (int16), t=temp×10, p=pressure, bt=baro temp // Raw IMU values (int16), t=temp×10, p=PID output
``` ```
## LED Subsystem (ESP32-C3) ## LED Subsystem (ESP32-S3 IO)
ESP32-C3 eavesdrops on FC→Jetson telemetry (listen-only tap on UART1 TX). No extra FC UART needed. ESP32-S3 IO eavesdrops on BALANCE→Orin telemetry (listen-only). No extra UART needed.
| State | Pattern | Color | | State | Pattern | Color |
|-------|---------|-------| |-------|---------|-------|
@ -275,7 +237,7 @@ ESP32-C3 eavesdrops on FC→Jetson telemetry (listen-only tap on UART1 TX). No e
1. **Read SALTYLAB.md fully** before making any design decisions 1. **Read SALTYLAB.md fully** before making any design decisions
2. **Never remove safety checks** from firmware — add more if needed 2. **Never remove safety checks** from firmware — add more if needed
3. **All measurements go in `cad/dimensions.scad`** — single source of truth 3. **All measurements go in `cad/dimensions.scad`** — single source of truth
4. **Test firmware on bench before any motor test** — ESC disconnected, verify outputs on serial 4. **Test firmware on bench before any motor test**VESCs disconnected, verify outputs on serial
5. **One variable at a time** — don't change PID and speed limit in the same test 5. **One variable at a time** — don't change PID and speed limit in the same test
6. **Document what you change** — update this file if you add pins, change protocols, or discover hardware quirks 6. **Document what you change** — update this file if you add pins, change protocols, or discover hardware quirks
7. **Ask before wiring changes** — wrong connections can fry the FC ($50+ board) 7. **Ask before wiring changes** — wrong connections can fry an ESP32 or VESC