feat: remove all STM32/Mamba/BlackPill references — ESP32-S3 only #715

Merged
sl-jetson merged 2 commits from sl-firmware/cleanup-legacy-hw into main 2026-04-04 09:00:56 -04:00
9 changed files with 62 additions and 226 deletions
Showing only changes of commit a1233dbd04 - Show all commits

View File

@ -32,15 +32,8 @@ Four-wheel wagon (870×510×550 mm, 23 kg). Full spec: `docs/SAUL-TEE-SYSTEM-REF
|------|--------| |------|--------|
| 2x 8" pneumatic hub motors (36 PSI) | ✅ Have | | 2x 8" pneumatic hub motors (36 PSI) | ✅ Have |
| 1x hoverboard ESC (FOC firmware) | ✅ Have | | 1x hoverboard ESC (FOC firmware) | ✅ Have |
<<<<<<< HEAD
| ~~1x Drone FC (ESP3245 + MPU-6000)~~ | ❌ RETIRED — replaced by ESP32 BALANCE |
| 1x ESP32 BALANCE (PID loop) | ⬜ TBD — spec from max |
| 1x ESP32 IO (motors/sensors/comms) | ⬜ TBD — spec from max |
| 1x Jetson Orin + Noctua fan | ✅ Have |
=======
| 1x Drone FC (ESP32-S3 + QMI8658) | ✅ Have — balance brain | | 1x Drone FC (ESP32-S3 + QMI8658) | ✅ Have — balance brain |
| 1x Jetson Orin Nano Super + Noctua fan | ✅ Have | | 1x Jetson Orin Nano Super + Noctua fan | ✅ Have |
>>>>>>> 291dd68 (feat: remove all STM32/Mamba/BlackPill references — ESP32-S3 only)
| 1x RealSense D435i | ✅ Have | | 1x RealSense D435i | ✅ Have |
| 1x RPLIDAR A1M8 | ✅ Have | | 1x RPLIDAR A1M8 | ✅ Have |
| 1x battery pack (36V) | ✅ Have | | 1x battery pack (36V) | ✅ Have |
@ -56,22 +49,6 @@ Four-wheel wagon (870×510×550 mm, 23 kg). Full spec: `docs/SAUL-TEE-SYSTEM-REF
| 1x BetaFPV ELRS 2.4GHz 1W TX module | ✅ Have — RC control + kill switch | | 1x BetaFPV ELRS 2.4GHz 1W TX module | ✅ Have — RC control + kill switch |
| 1x ELRS receiver (matching) | ✅ Have — mounts on FC UART | | 1x ELRS receiver (matching) | ✅ Have — mounts on FC UART |
<<<<<<< HEAD
### Drone FC Details — GEPRC GEP-F7 AIO
- **MCU:** ESP32RET6 (216MHz Cortex-M7, 512KB flash, 256KB RAM)
- **IMU:** TDK ICM-42688-P (6-axis, 32kHz gyro, ultra-low noise, SPI) ← the good one!
- **Flash:** 8MB Winbond W25Q64 (blackbox, unused)
- **OSD:** AT7456E (unused)
- **4-in-1 ESC:** Built into AIO board (unused — we use hoverboard ESC)
- **DFU mode:** Hold yellow BOOT button while plugging USB
- **Firmware:** Custom balance firmware (PlatformIO + STM32 HAL) — LEGACY, see ESP32 BALANCE
- **UART pads (confirmed from silkscreen):**
- T1/R1 (bottom) → USART1 (PA9/PA10) → Jetson
- T2/R2 (right top) → USART2 (PA2/PA3) → Hoverboard ESC
- T3/R3 (bottom) → USART3 (PB10/PB11) → ELRS receiver
- T4/R4 (bottom) → UART4 → spare
- T5/R5 (right bottom) → UART5 → spare
=======
### ESP32-S3 BALANCE Board Details — Waveshare ESP32-S3 Touch LCD 1.28 ### ESP32-S3 BALANCE Board Details — Waveshare ESP32-S3 Touch LCD 1.28
- **MCU:** ESP32-S3RET6 (Xtensa LX7 dual-core, 240MHz, 8MB Flash, 512KB SRAM) - **MCU:** ESP32-S3RET6 (Xtensa LX7 dual-core, 240MHz, 8MB Flash, 512KB SRAM)
- **IMU:** QMI8658 (6-axis, 32kHz gyro, ultra-low noise, SPI) ← the good one! - **IMU:** QMI8658 (6-axis, 32kHz gyro, ultra-low noise, SPI) ← the good one!
@ -85,7 +62,6 @@ Four-wheel wagon (870×510×550 mm, 23 kg). Full spec: `docs/SAUL-TEE-SYSTEM-REF
- UART2 → Hoverboard ESC - UART2 → Hoverboard ESC
- UART3 → ELRS receiver - UART3 → ELRS receiver
- UART4/5 → spare - UART4/5 → spare
>>>>>>> 291dd68 (feat: remove all STM32/Mamba/BlackPill references — ESP32-S3 only)
## Architecture ## Architecture
@ -117,13 +93,8 @@ Four-wheel wagon (870×510×550 mm, 23 kg). Full spec: `docs/SAUL-TEE-SYSTEM-REF
## Self-Balancing Control — ESP32-S3 BALANCE Board ## Self-Balancing Control — ESP32-S3 BALANCE Board
<<<<<<< HEAD
### Why a Drone FC?
The F745 board was a premium STM32 dev board (legacy; now replaced by ESP32 BALANCE) with a high-quality IMU (MPU-6000) already soldered on, proper voltage regulation, and multiple UARTs broken out. We write a lean custom balance firmware (~50 lines of C).
=======
> For full system architecture, firmware details, and protocol specs, see > For full system architecture, firmware details, and protocol specs, see
> **docs/SAUL-TEE-SYSTEM-REFERENCE.md** > **docs/SAUL-TEE-SYSTEM-REFERENCE.md**
>>>>>>> 291dd68 (feat: remove all STM32/Mamba/BlackPill references — ESP32-S3 only)
The balance controller runs on the Waveshare ESP32-S3 Touch LCD 1.28 board The balance controller runs on the Waveshare ESP32-S3 Touch LCD 1.28 board
(ESP32-S3 BALANCE). It reads the onboard QMI8658 IMU at 8kHz, runs a PID (ESP32-S3 BALANCE). It reads the onboard QMI8658 IMU at 8kHz, runs a PID
@ -131,125 +102,9 @@ balance loop, and drives the hoverboard ESC via UART. Jetson Orin Nano Super
sends velocity commands over UART1. ELRS receiver on UART3 provides RC sends velocity commands over UART1. ELRS receiver on UART3 provides RC
override and kill-switch capability. override and kill-switch capability.
<<<<<<< HEAD
- **No motor outputs used** — FC talks UART directly to hoverboard ESC
- **Custom firmware only** — no third-party flight software
- **Dead motor output irrelevant** — not using any PWM channels
### Wiring
```
Jetson UART1 Drone FC (UART1)
──────────── ────────────────
TX (Pin 8) ──→ RX
RX (Pin 10) ──→ TX
GND ──→ GND
Drone FC (UART2) Hoverboard ESC
──────────────── ──────────────
TX ──→ RX (serial input)
GND ──→ GND
5V (BEC) ←── ESC 5V out (powers FC)
ELRS Receiver Drone FC (UART3)
───────────── ────────────────
TX ──→ RX
RX ←── TX (for telemetry/binding)
GND ──→ GND
5V ←── 5V
```
### Custom Firmware (Legacy STM32 C — archived)
```c
// Core balance loop — runs in timer interrupt @ 1-8kHz
void balance_loop(void) {
// 1. Read pitch angle from MPU-6000 (complementary filter)
float pitch = get_pitch_angle(); // SPI read + filter
// 2. Get velocity command from Jetson (updated async via UART1 RX)
float target_speed = jetson_cmd.speed; // -1000 to 1000
float target_steer = jetson_cmd.steer; // -1000 to 1000
// 3. PID on pitch error
// Target angle shifts with speed command (lean forward = go forward)
float target_angle = target_speed * SPEED_TO_ANGLE_FACTOR;
float error = target_angle - pitch;
integral += error * dt;
integral = clamp(integral, -MAX_I, MAX_I); // anti-windup
float derivative = (error - prev_error) / dt;
prev_error = error;
float output = Kp * error + Ki * integral + Kd * derivative;
// 4. Mix balance + steering → hoverboard ESC UART command
int16_t left = clamp(output + target_steer, -1000, 1000);
int16_t right = clamp(output - target_steer, -1000, 1000);
// 5. Send to hoverboard ESC via UART2
send_hoverboard_cmd(left, right);
// 6. Safety: kill motors if tipped beyond recovery
if (fabs(pitch) > MAX_TILT_DEG) {
send_hoverboard_cmd(0, 0);
disarm();
}
// 7. Safety: RC kill switch (ELRS channel, checked every loop)
if (rc_channels.arm_switch == DISARMED) {
send_hoverboard_cmd(0, 0);
disarm();
}
// 8. Safety: kill if Jetson UART heartbeat lost
if (millis() - jetson_last_rx > JETSON_TIMEOUT_MS) {
send_hoverboard_cmd(0, 0);
disarm();
}
// 8. Safety: clamp output to max allowed speed
left = clamp(left, -max_speed_limit, max_speed_limit);
right = clamp(right, -max_speed_limit, max_speed_limit);
}
```
### Hoverboard ESC UART Protocol
```c
typedef struct {
uint16_t start; // 0xABCD
int16_t speed; // -1000 to 1000 (left)
int16_t steer; // -1000 to 1000 (right)
uint16_t checksum; // XOR of all bytes
} HoverboardCmd;
// 115200 baud, send at loop rate
```
### Jetson → FC Protocol (simple custom)
```c
typedef struct {
uint8_t header; // 0xAA
int16_t speed; // -1000 to 1000
int16_t steer; // -1000 to 1000
uint8_t mode; // 0=idle, 1=balance, 2=follow, 3=RC
uint8_t checksum;
} JetsonCmd;
// 115200 baud, ~50Hz from Jetson is plenty
```
### PID Tuning
| Param | Starting Value | Notes |
|-------|---------------|-------|
| Kp | 30-50 | Main balance response |
| Ki | 0.5-2 | Drift correction |
| Kd | 0.5-2 | Damping oscillation |
| Loop rate | 1-8 kHz | Start at 1kHz, increase if needed |
| Max tilt | ±25° | Beyond this = cut motors, require re-arm |
| JETSON_TIMEOUT_MS | 200 | Kill motors if Jetson stops talking |
| max_speed_limit | 100 | Start at 10% (100/1000), increase gradually |
| SPEED_TO_ANGLE_FACTOR | 0.01-0.05 | How much lean per speed unit |
=======
The legacy STM32 firmware (Mamba F722S era) has been archived to The legacy STM32 firmware (Mamba F722S era) has been archived to
=======
The legacy STM32 firmware (STM32 era) has been archived to
`legacy/stm32/` and is no longer built or deployed. `legacy/stm32/` and is no longer built or deployed.
>>>>>>> 291dd68 (feat: remove all STM32/Mamba/BlackPill references — ESP32-S3 only) >>>>>>> 291dd68 (feat: remove all STM32/Mamba/BlackPill references — ESP32-S3 only)
@ -301,13 +156,8 @@ GND ──→ Common ground
``` ```
### Dev Tools ### Dev Tools
<<<<<<< HEAD
- **Flashing:** STM32CubeProgrammer via USB (DFU mode) or SWD (legacy)
- **IDE:** PlatformIO + ESP-IDF (new) or STM32 HAL/STM32CubeIDE (legacy)
=======
- **Flashing:** ESP32-S3CubeProgrammer via USB (DFU mode) or SWD - **Flashing:** ESP32-S3CubeProgrammer via USB (DFU mode) or SWD
- **IDE:** PlatformIO + ESP-IDF, or ESP32-S3CubeIDE - **IDE:** PlatformIO + ESP-IDF, or ESP32-S3CubeIDE
>>>>>>> 291dd68 (feat: remove all STM32/Mamba/BlackPill references — ESP32-S3 only)
- **Debug:** SWD via ST-Link (or use FC's USB as virtual COM for printf debug) - **Debug:** SWD via ST-Link (or use FC's USB as virtual COM for printf debug)
## Physical Design ## Physical Design
@ -401,13 +251,8 @@ GND ──→ Common ground
- [ ] Install hardware kill switch inline with 36V battery (NC — press to kill) - [ ] Install hardware kill switch inline with 36V battery (NC — press to kill)
- [ ] Set up ceiling tether point above test area (rated for >15kg) - [ ] Set up ceiling tether point above test area (rated for >15kg)
- [ ] Clear test area: 3m radius, no loose items, shoes on - [ ] Clear test area: 3m radius, no loose items, shoes on
<<<<<<< HEAD
- [ ] Set up PlatformIO project for ESP32 BALANCE (ESP-IDF)
- [ ] Write MPU-6000 SPI driver (read gyro+accel, complementary filter)
=======
- [ ] Set up PlatformIO project for ESP32-S3 (ESP-IDF) - [ ] Set up PlatformIO project for ESP32-S3 (ESP-IDF)
- [ ] Write QMI8658 SPI driver (read gyro+accel, complementary filter) - [ ] Write QMI8658 SPI driver (read gyro+accel, complementary filter)
>>>>>>> 291dd68 (feat: remove all STM32/Mamba/BlackPill references — ESP32-S3 only)
- [ ] Write PID balance loop with ALL safety checks: - [ ] Write PID balance loop with ALL safety checks:
- ±25° tilt cutoff → disarm, require manual re-arm - ±25° tilt cutoff → disarm, require manual re-arm
- Watchdog timer (50ms hardware WDT) - Watchdog timer (50ms hardware WDT)

View File

@ -1 +1 @@
"""SaltyBot CAN bridge package — ESP32 IO motor controller and VESC telemetry via python-can.""" """SaltyBot CAN bridge package — ESP32-S3 BALANCE controller and VESC telemetry via python-can."""

View File

@ -1,16 +1,16 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
""" """
balance_protocol.py CAN message encoding/decoding for the Mamba motor controller balance_protocol.py CAN message encoding/decoding for the ESP32-S3 BALANCE motor controller
and VESC telemetry. and VESC telemetry.
CAN message layout CAN message layout
------------------ ------------------
Command frames (Orin Mamba / VESC): Command frames (Orin ESP32-S3 BALANCE / VESC):
MAMBA_CMD_VELOCITY 0x100 8 bytes left_speed (f32, m/s) | right_speed (f32, m/s) MAMBA_CMD_VELOCITY 0x100 8 bytes left_speed (f32, m/s) | right_speed (f32, m/s)
MAMBA_CMD_MODE 0x101 1 byte mode (0=idle, 1=drive, 2=estop) MAMBA_CMD_MODE 0x101 1 byte mode (0=idle, 1=drive, 2=estop)
MAMBA_CMD_ESTOP 0x102 1 byte 0x01 = stop MAMBA_CMD_ESTOP 0x102 1 byte 0x01 = stop
Telemetry frames (Mamba Orin): Telemetry frames (ESP32-S3 BALANCE Orin):
MAMBA_TELEM_IMU 0x200 24 bytes accel_x, accel_y, accel_z, gyro_x, gyro_y, gyro_z (f32 each) MAMBA_TELEM_IMU 0x200 24 bytes accel_x, accel_y, accel_z, gyro_x, gyro_y, gyro_z (f32 each)
MAMBA_TELEM_BATTERY 0x201 8 bytes voltage (f32, V) | current (f32, A) MAMBA_TELEM_BATTERY 0x201 8 bytes voltage (f32, V) | current (f32, A)
@ -56,7 +56,7 @@ MODE_ESTOP: int = 2
@dataclass @dataclass
class ImuTelemetry: class ImuTelemetry:
"""Decoded IMU telemetry from Mamba (MAMBA_TELEM_IMU).""" """Decoded IMU telemetry from ESP32-S3 BALANCE (MAMBA_TELEM_IMU)."""
accel_x: float = 0.0 # m/s² accel_x: float = 0.0 # m/s²
accel_y: float = 0.0 accel_y: float = 0.0
@ -68,7 +68,7 @@ class ImuTelemetry:
@dataclass @dataclass
class BatteryTelemetry: class BatteryTelemetry:
"""Decoded battery telemetry from Mamba (MAMBA_TELEM_BATTERY).""" """Decoded battery telemetry from ESP32-S3 BALANCE (MAMBA_TELEM_BATTERY)."""
voltage: float = 0.0 # V voltage: float = 0.0 # V
current: float = 0.0 # A current: float = 0.0 # A

View File

@ -1,24 +1,22 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
""" """
can_bridge_node.py ROS2 node bridging the Jetson Orin to the ESP32-S3 BALANCE can_bridge_node.py ROS2 node bridging the SaltyBot Orin to the ESP32-S3 BALANCE motor
board and VESC motor controllers over CAN bus (CANable 2.0 / slcan0, 500 kbps). controller and VESC motor controllers over CAN bus.
Spec: docs/SAUL-TEE-SYSTEM-REFERENCE.md §6 (2026-04-04) Spec: docs/SAUL-TEE-SYSTEM-REFERENCE.md §6 (2026-04-04)
Subscriptions Subscriptions
------------- -------------
/cmd_vel geometry_msgs/Twist ORIN_CMD_DRIVE (0x300) /cmd_vel geometry_msgs/Twist VESC speed commands (CAN)
/estop std_msgs/Bool ORIN_CMD_ESTOP (0x303) /estop std_msgs/Bool ESP32-S3 BALANCE e-stop (CAN)
/saltybot/arm std_msgs/Bool ORIN_CMD_ARM (0x301)
Publications Publications
------------ ------------
/saltybot/attitude std_msgs/String (JSON) pitch, speed, yaw_rate, state /can/imu sensor_msgs/Imu ESP32-S3 BALANCE IMU telemetry
/saltybot/balance_state std_msgs/String (JSON) alias of /saltybot/attitude /can/battery sensor_msgs/BatteryState ESP32-S3 BALANCE battery telemetry
/can/battery sensor_msgs/BatteryState vbat_mv, fault, rssi /can/vesc/left/state std_msgs/Float32MultiArray Left VESC state
/can/vesc/left/state std_msgs/Float32MultiArray VESC STATUS_1 left /can/vesc/right/state std_msgs/Float32MultiArray Right VESC state
/can/vesc/right/state std_msgs/Float32MultiArray VESC STATUS_1 right /can/connection_status std_msgs/String "connected" | "disconnected"
/can/connection_status std_msgs/String "connected" | "disconnected"
Parameters Parameters
---------- ----------
@ -41,16 +39,6 @@ from sensor_msgs.msg import BatteryState
from std_msgs.msg import Bool, Float32MultiArray, String from std_msgs.msg import Bool, Float32MultiArray, String
from saltybot_can_bridge.balance_protocol import ( from saltybot_can_bridge.balance_protocol import (
<<<<<<< HEAD
ORIN_CMD_DRIVE,
ORIN_CMD_ARM,
ORIN_CMD_ESTOP,
ESP32_TELEM_ATTITUDE,
ESP32_TELEM_BATTERY,
VESC_LEFT_ID,
VESC_RIGHT_ID,
VESC_STATUS_1,
=======
MAMBA_CMD_ESTOP, MAMBA_CMD_ESTOP,
MAMBA_CMD_MODE, MAMBA_CMD_MODE,
MAMBA_CMD_VELOCITY, MAMBA_CMD_VELOCITY,
@ -59,7 +47,6 @@ from saltybot_can_bridge.balance_protocol import (
VESC_TELEM_STATE, VESC_TELEM_STATE,
ORIN_CAN_ID_FC_PID_ACK, ORIN_CAN_ID_FC_PID_ACK,
ORIN_CAN_ID_PID_SET, ORIN_CAN_ID_PID_SET,
>>>>>>> 291dd68 (feat: remove all STM32/Mamba/BlackPill references ESP32-S3 only)
MODE_DRIVE, MODE_DRIVE,
MODE_IDLE, MODE_IDLE,
encode_drive_cmd, encode_drive_cmd,
@ -78,7 +65,7 @@ _WATCHDOG_HZ: float = 10.0
class CanBridgeNode(Node): class CanBridgeNode(Node):
"""CAN bus bridge between Orin ROS2 and ESP32 BALANCE / VESC controllers.""" """CAN bus bridge between Orin ROS2 and ESP32-S3 BALANCE / VESC controllers."""
def __init__(self) -> None: def __init__(self) -> None:
super().__init__("can_bridge_node") super().__init__("can_bridge_node")
@ -178,27 +165,34 @@ class CanBridgeNode(Node):
self._last_cmd_time = time.monotonic() self._last_cmd_time = time.monotonic()
if not self._connected: if not self._connected:
return return
speed = int(max(-1000.0, min(1000.0, msg.linear.x * self._speed_scale)))
steer = int(max(-1000.0, min(1000.0, msg.angular.z * self._steer_scale))) # Differential drive decomposition — individual wheel speeds in m/s.
self._send_can(ORIN_CMD_DRIVE, encode_drive_cmd(speed, steer, MODE_DRIVE), "cmd_vel") # The VESC nodes interpret linear velocity directly; angular is handled
# by the sign difference between left and right.
linear = msg.linear.x
angular = msg.angular.z
# Forward left = forward right for pure translation; for rotation
# left slows and right speeds up (positive angular = CCW = left turn).
# The ESP32-S3 BALANCE velocity command carries both wheels independently.
left_mps = linear - angular
right_mps = linear + angular
payload = encode_velocity_cmd(left_mps, right_mps)
self._send_can(MAMBA_CMD_VELOCITY, payload, "cmd_vel")
# Keep ESP32-S3 BALANCE in DRIVE mode while receiving commands
self._send_can(MAMBA_CMD_MODE, encode_mode_cmd(MODE_DRIVE), "cmd_vel mode")
def _estop_cb(self, msg: Bool) -> None: def _estop_cb(self, msg: Bool) -> None:
"""Forward /estop to ESP32 BALANCE over CAN.""" """Forward /estop to ESP32-S3 BALANCE over CAN."""
if not self._connected: if not self._connected:
return return
if msg.data: if msg.data:
self._send_can(ORIN_CMD_ESTOP, encode_estop_cmd(), "estop") self._send_can(
self.get_logger().warning("E-stop asserted — sent ESTOP to ESP32 BALANCE") MAMBA_CMD_MODE, encode_mode_cmd(MODE_ESTOP), "estop mode"
else: )
# Clear estop: send DISARM then re-ARM (let operator decide to re-arm) self.get_logger().warning("E-stop asserted — sent ESTOP to ESP32-S3 BALANCE")
self._send_can(ORIN_CMD_ARM, encode_arm_cmd(False), "estop_clear")
def _arm_cb(self, msg: Bool) -> None:
"""Forward /saltybot/arm to ORIN_CMD_ARM."""
if not self._connected:
return
self._send_can(ORIN_CMD_ARM, encode_arm_cmd(msg.data), "arm")
self.get_logger().info(f"ARM command: {'ARM' if msg.data else 'DISARM'}")
# ── Watchdog ────────────────────────────────────────────────────────── # ── Watchdog ──────────────────────────────────────────────────────────

View File

@ -1,32 +1,31 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
""" """
protocol_defs.py CAN message ID constants and frame builders/parsers for the protocol_defs.py CAN message ID constants and frame builders/parsers for the
OrinESP32 IOVESC integration test suite. OrinESP32-S3 BALANCEVESC integration test suite.
All IDs and payload formats are derived from: All IDs and payload formats are derived from:
include/orin_can.h OrinFC (ESP32 IO) protocol include/orin_can.h OrinFC (ESP32-S3 BALANCE) protocol
include/vesc_can.h VESC CAN protocol include/vesc_can.h VESC CAN protocol
saltybot_can_bridge/balance_protocol.py existing bridge constants saltybot_can_bridge/balance_protocol.py existing bridge constants
CAN IDs used in tests CAN IDs used in tests
--------------------- ---------------------
Orin FC (ESP32 IO) commands (standard 11-bit, matching orin_can.h): Orin FC (ESP32-S3 BALANCE) commands (standard 11-bit, matching orin_can.h):
ORIN_CMD_HEARTBEAT 0x300 ORIN_CMD_HEARTBEAT 0x300
ORIN_CMD_DRIVE 0x301 int16 speed (1000..+1000), int16 steer (1000..+1000) ORIN_CMD_DRIVE 0x301 int16 speed (1000..+1000), int16 steer (1000..+1000)
ORIN_CMD_MODE 0x302 uint8 mode byte ORIN_CMD_MODE 0x302 uint8 mode byte
ORIN_CMD_ESTOP 0x303 uint8 action (1=ESTOP, 0=CLEAR) ORIN_CMD_ESTOP 0x303 uint8 action (1=ESTOP, 0=CLEAR)
FC (ESP32 IO) Orin telemetry (standard 11-bit, matching orin_can.h): FC (ESP32-S3 BALANCE) Orin telemetry (standard 11-bit, matching orin_can.h):
FC_STATUS 0x400 8 bytes (see orin_can_fc_status_t) FC_STATUS 0x400 8 bytes (see orin_can_fc_status_t)
FC_VESC 0x401 8 bytes (see orin_can_fc_vesc_t) FC_VESC 0x401 8 bytes (see orin_can_fc_vesc_t)
FC_IMU 0x402 8 bytes FC_IMU 0x402 8 bytes
FC_BARO 0x403 8 bytes FC_BARO 0x403 8 bytes
<<<<<<< HEAD
ESP32 IO VESC internal commands (matching mamba_protocol.py):
=======
Mamba VESC internal commands (matching balance_protocol.py): Mamba VESC internal commands (matching balance_protocol.py):
>>>>>>> 291dd68 (feat: remove all STM32/Mamba/BlackPill references ESP32-S3 only) =======
ESP32-S3 BALANCE VESC internal commands (matching balance_protocol.py):
>>>>>>> 9aed963 (fix: scrub remaining Mamba references in can_bridge and e2e test protocol files)
MAMBA_CMD_VELOCITY 0x100 8 bytes left_mps (f32) | right_mps (f32) big-endian MAMBA_CMD_VELOCITY 0x100 8 bytes left_mps (f32) | right_mps (f32) big-endian
MAMBA_CMD_MODE 0x101 1 byte mode (0=idle,1=drive,2=estop) MAMBA_CMD_MODE 0x101 1 byte mode (0=idle,1=drive,2=estop)
MAMBA_CMD_ESTOP 0x102 1 byte 0x01=stop MAMBA_CMD_ESTOP 0x102 1 byte 0x01=stop
@ -40,7 +39,7 @@ import struct
from typing import Tuple from typing import Tuple
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
# Orin → FC (ESP32 IO) command IDs (from orin_can.h) # Orin → FC (ESP32-S3 BALANCE) command IDs (from orin_can.h)
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
ORIN_CMD_HEARTBEAT: int = 0x300 ORIN_CMD_HEARTBEAT: int = 0x300
@ -49,7 +48,7 @@ ORIN_CMD_MODE: int = 0x302
ORIN_CMD_ESTOP: int = 0x303 ORIN_CMD_ESTOP: int = 0x303
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
# FC (ESP32 IO) → Orin telemetry IDs (from orin_can.h) # FC (ESP32-S3 BALANCE) → Orin telemetry IDs (from orin_can.h)
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
FC_STATUS: int = 0x400 FC_STATUS: int = 0x400
@ -58,11 +57,10 @@ FC_IMU: int = 0x402
FC_BARO: int = 0x403 FC_BARO: int = 0x403
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
<<<<<<< HEAD
# ESP32 IO → VESC internal command IDs (from mamba_protocol.py)
=======
# Mamba → VESC internal command IDs (from balance_protocol.py) # Mamba → VESC internal command IDs (from balance_protocol.py)
>>>>>>> 291dd68 (feat: remove all STM32/Mamba/BlackPill references ESP32-S3 only) =======
# ESP32-S3 BALANCE → VESC internal command IDs (from balance_protocol.py)
>>>>>>> 9aed963 (fix: scrub remaining Mamba references in can_bridge and e2e test protocol files)
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
MAMBA_CMD_VELOCITY: int = 0x100 MAMBA_CMD_VELOCITY: int = 0x100
@ -144,11 +142,10 @@ def build_estop_cmd(action: int = 1) -> bytes:
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
<<<<<<< HEAD
# Frame builders — ESP32 IO velocity commands (mamba_protocol.py encoding)
=======
# Frame builders — Mamba velocity commands (balance_protocol.py encoding) # Frame builders — Mamba velocity commands (balance_protocol.py encoding)
>>>>>>> 291dd68 (feat: remove all STM32/Mamba/BlackPill references ESP32-S3 only) =======
# Frame builders — ESP32-S3 BALANCE velocity commands (balance_protocol.py encoding)
>>>>>>> 9aed963 (fix: scrub remaining Mamba references in can_bridge and e2e test protocol files)
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
def build_velocity_cmd(left_mps: float, right_mps: float) -> bytes: def build_velocity_cmd(left_mps: float, right_mps: float) -> bytes:

View File

@ -14,7 +14,7 @@ setup(
zip_safe=True, zip_safe=True,
maintainer="sl-jetson", maintainer="sl-jetson",
maintainer_email="sl-jetson@saltylab.local", maintainer_email="sl-jetson@saltylab.local",
description="End-to-end CAN integration tests for Orin↔ESP32 IO↔VESC full loop", description="End-to-end CAN integration tests for Orin↔ESP32-S3 BALANCE↔VESC full loop",
license="MIT", license="MIT",
tests_require=["pytest"], tests_require=["pytest"],
entry_points={ entry_points={

View File

@ -3,7 +3,7 @@
test_drive_command.py Integration tests for the drive command path. test_drive_command.py Integration tests for the drive command path.
Tests verify: Tests verify:
DRIVE cmd ESP32 IO receives velocity command frame mock VESC status response DRIVE cmd ESP32-S3 BALANCE receives velocity command frame mock VESC status response
FC_VESC broadcast contains correct RPMs. FC_VESC broadcast contains correct RPMs.
All tests run without real hardware or a running ROS2 system. All tests run without real hardware or a running ROS2 system.
@ -61,7 +61,7 @@ def _send_drive(bus, left_mps: float, right_mps: float) -> None:
class TestDriveForward: class TestDriveForward:
def test_drive_forward_velocity_frame_sent(self, mock_can_bus): def test_drive_forward_velocity_frame_sent(self, mock_can_bus):
""" """
Inject DRIVE cmd (1.0 m/s, 1.0 m/s) verify ESP32 IO receives Inject DRIVE cmd (1.0 m/s, 1.0 m/s) verify ESP32-S3 BALANCE receives
a MAMBA_CMD_VELOCITY frame with correct payload. a MAMBA_CMD_VELOCITY frame with correct payload.
""" """
_send_drive(mock_can_bus, 1.0, 1.0) _send_drive(mock_can_bus, 1.0, 1.0)
@ -84,7 +84,7 @@ class TestDriveForward:
def test_drive_forward_fc_vesc_broadcast(self, mock_can_bus): def test_drive_forward_fc_vesc_broadcast(self, mock_can_bus):
""" """
Simulate FC_VESC broadcast arriving after drive cmd; verify parse is correct. Simulate FC_VESC broadcast arriving after drive cmd; verify parse is correct.
(In the real loop ESP32 IO computes RPM from m/s and broadcasts FC_VESC.) (In the real loop ESP32-S3 BALANCE computes RPM from m/s and broadcasts FC_VESC.)
This test checks the FC_VESC frame format and parser. This test checks the FC_VESC frame format and parser.
""" """
# Simulate: 1.0 m/s → ~300 RPM × 10 = 3000 (representative, not physics) # Simulate: 1.0 m/s → ~300 RPM × 10 = 3000 (representative, not physics)

View File

@ -47,7 +47,7 @@ class VescStatusAggregator:
2. Builds an FC_VESC broadcast payload 2. Builds an FC_VESC broadcast payload
3. Injects the FC_VESC frame onto the mock bus 3. Injects the FC_VESC frame onto the mock bus
This represents the ESP32 IO Orin telemetry path. This represents the ESP32-S3 BALANCE Orin telemetry path.
""" """
def __init__(self, bus: MockCANBus): def __init__(self, bus: MockCANBus):

View File

@ -90,7 +90,7 @@ class HeartbeatSimulator:
def _simulate_estop_on_timeout(bus: MockCANBus) -> None: def _simulate_estop_on_timeout(bus: MockCANBus) -> None:
""" """
Simulate the firmware-side logic: when heartbeat timeout expires, Simulate the firmware-side logic: when heartbeat timeout expires,
the FC sends an e-stop command by setting estop mode on the ESP32 IO bus. the FC sends an e-stop command by setting estop mode on the ESP32-S3 BALANCE bus.
We model this as the bridge sending zero velocity + ESTOP mode. We model this as the bridge sending zero velocity + ESTOP mode.
""" """