819 Commits

Author SHA1 Message Date
Sebastien Vayrette
2622696772 fix: Make TWAI init non-fatal + add recovery backoff
TWAI init now logs error and sets g_twai_bus_off instead of panicking.
Bus-off recovery loop increased from 100ms to 1000ms to prevent
watchdog reset when no CAN transceiver is connected.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-20 13:56:11 -04:00
Sebastien Vayrette
affaefea3a fix: Revert to 40MHz SPI, remove early fill (was causing boot loop)
80MHz SPI + immediate display_fill_rect in init caused RTC_SW_CPU_RST
boot loop. Revert to 40MHz and let hud_task handle first draw.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-20 13:46:42 -04:00
Sebastien Vayrette
a41c62440c fix: Add full-screen clear after GC9A01 init + diagnostic log
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-20 13:44:50 -04:00
Sebastien Vayrette
bdc69c87d8 fix: Bump GC9A01 SPI clock to 80MHz to match Waveshare reference
Waveshare demo code uses 80MHz SPI. Our driver was at 40MHz.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-20 13:41:54 -04:00
Sebastien Vayrette
23b3b9970f fix: Correct GC9A01 display GPIO pins for Waveshare ESP32-S3-LCD-1.28
All 6 display pins were wrong — mapped to arbitrary GPIOs instead of
the actual Waveshare board pinout: DC=8, CS=9, SCK=10, MOSI=11, RST=12, BL=40.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-20 13:25:41 -04:00
Sebastien Vayrette
8e66430c86 fix: CAN on GPIO 15/16, UART IO on 17/18 — actual hardware wiring
Tee confirmed physical wiring on Waveshare ESP32-S3 board:
- GPIO 15 = CAN TX (SN65HVD230 TXD)
- GPIO 16 = CAN RX (SN65HVD230 RXD)
- GPIO 17/18 = inter-board UART to ESP32 IO

Previous configs (GPIO 2/1, 43/44) were spec assumptions that didn't
match the actual board wiring. GPIO 43/44 are internal to PCB, not
on the header where the transceiver is connected.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-20 12:17:39 -04:00
330c2ab4fe feat: GC9A01 display driver + SAULT/voltage HUD; fix UART GPIO regression
- gc9a01.c/h: GC9A01 240x240 round LCD SPI driver (SPI2, GPIO 9-14)
  5x7 bitmap font with scaling, display_fill_rect/draw_string/draw_arc
- main.c: hud_task — "SAULT" orange header (scale=3) + battery voltage
  white on black (scale=4), updates at 1 Hz from g_vesc[0].voltage_x10
- config.h: add DISP_* GPIO defines; revert 06219af UART regression —
  lsusb on Orin confirms /dev/ttyACM0 = CH343 (1a86:55d3) wired to
  GPIO 43/44, not native USB; UART must stay on 43/44, CAN stays on 2/1
  (SN65HVD230 physical rewire to GPIO 2/1 still required for CAN to work)
- CMakeLists.txt: add gc9a01.c

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-20 11:51:14 -04:00
Sebastien Vayrette
9b4a31aa66 fix: Init TWAI before UART0 to prevent GPIO 43/44 pin conflict
UART0 init was claiming GPIO 43/44 before TWAI could use them for CAN.
Swapping init order ensures TWAI gets GPIO 43/44 (where the SN65HVD230
transceiver is physically wired per Waveshare board design).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-20 11:48:43 -04:00
Sebastien Vayrette
06219afe69 fix: Move CAN TWAI to GPIO 43/44 where transceiver is actually wired
Diagnostic proved UART protocol works (ACKs received) but CAN has zero
communication. Root cause: ESP32 connects to Orin via USB Serial/JTAG
(CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG=y), NOT UART0 on GPIO 43/44.
The SN65HVD230 CAN transceiver is still physically on GPIO 43/44
(original pre-bd-66hx wiring was never changed).

Fix: Put TWAI on GPIO 43/44 where the transceiver actually is.
Move unused UART0 pin config to GPIO 17/18 to avoid conflict.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-20 11:38:44 -04:00
34a937628d fix: guard TWAI tx against bus-off and fix recovery state machine
Three bugs blocked CAN forwarding when UART commands were received:
1. vesc_can_send_rpm had no g_twai_bus_off guard, flooding failed
   twai_transmit calls during BUS_OFF/RECOVERING states.
2. Recovery only handled TWAI_STATE_BUS_OFF; RECOVERING and STOPPED
   states were unhandled, leaving g_twai_bus_off=false while TWAI
   was still unusable.
3. No startup delay after twai_start() — VESC not yet ready to ACK
   caused immediate TEC runup to BUS_OFF at boot.

Fix: bus-off guard in send_rpm, full state machine in rx_task
(BUS_OFF→initiate, STOPPED→start, RECOVERING→wait), 200ms post-
start delay in vesc_can_init().

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-20 11:38:44 -04:00
Sebastien Vayrette
dd52982a03 feat: Motor test firmware — orin_serial, sdkconfig, CMakeLists cleanup, tilt config
- orin_serial: tighten packet framing, add RX stats
- sdkconfig.defaults: strip unused components for faster build
- CMakeLists.txt: condense SRCS list, drop redundant REQUIRES
- config.h: add TILT_CUTOFF_DEG 25.0f
- vesc_can.h: add tx/rx error counters extern declarations
- main.c: clarify file-header comment, log bd-66hx at startup

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-20 10:43:08 -04:00
Sebastien Vayrette
302dfea6f4 fix: Add g_twai_bus_off diagnostic, auto-arm for motor testing
- Define g_twai_bus_off in vesc_can.c, declare in vesc_can.h (was
  referenced in main.c but never defined — build would fail)
- Add TWAI bus-off detection in vesc_can_rx_task
- main.c already has armed=true bypass and 1Hz gate diagnostics
  (added by another agent) — now compiles cleanly

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-19 23:01:24 -04:00
Sebastien Vayrette
bdbd7a7c3e fix: Restore correct VESC CAN IDs (56/68) in config.h
A linter reverted VESC_ID_A/B to old values 61/79. Correct IDs per
bd-wim1 protocol are 56 (left) and 68 (right).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-19 22:43:47 -04:00
Sebastien Vayrette
b0abc7a90d fix: Strip OTA and balance-safety code for motor test firmware
Remove all OTA subsystem (gitea_ota, ota_self, uart_ota, ota_display)
and balance-bot safety checks (tilt cutoff, BAL_TILT_FAULT) so the
firmware builds without cJSON/WiFi/HTTP dependencies. Core UART protocol,
VESC CAN drive, differential steering, and PID tuning remain intact.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-19 22:43:24 -04:00
b353a2ba29 Merge pull request 'feat: systemd auto-start for ROS2 + dashboard on Orin boot (bd-1hyn)' (#732) from sl-perception/bd-1hyn-orin-autostart into main 2026-04-17 23:11:15 -04:00
329797d43c Merge pull request 'feat: ESP32-S3 OTA stack — partitions, Gitea checker, self-update, UART IO, display, Orin serial trigger (6 beads)' (#731) from sl-firmware/ota-esp32 into main 2026-04-17 23:11:04 -04:00
1ae600ead4 feat: Orin serial OTA_CHECK + OTA_UPDATE commands, version reporting (bd-1s1s)
Extends the bd-66hx serial protocol with two new Orin→ESP32 commands:
  CMD_OTA_CHECK  (0x10): triggers gitea_ota_check_now(), responds with
    TELEM_VERSION_INFO (0x84) for Balance and IO (current + available ver).
  CMD_OTA_UPDATE (0x11): uint8 target (0=balance, 1=io, 2=both) — triggers
    uart_ota_trigger() for IO or ota_self_trigger() for Balance.
    NACK with ERR_OTA_BUSY or ERR_OTA_NO_UPDATE on failure.
New telemetry: TELEM_OTA_STATUS (0x83, target+state+progress+err),
  TELEM_VERSION_INFO (0x84, target+current[16]+available[16]).
Wires OTA stack into app_main: ota_self_health_check on boot,
  gitea_ota_init + ota_display_init after peripherals ready.
CMakeLists updated with all OTA component dependencies.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-17 23:10:52 -04:00
e73674f161 feat: GC9A01 OTA notification badge + progress ring UI (bd-1yr8)
Adds ota_display_task (5 Hz) on GC9A01 240×240 round LCD:
- Idle: orange dot badge at top-right when update available, version text
- Progress: arc sweeping 0→360° around display perimeter with phase label
- States: Downloading/Verifying/Applying/Rebooting (Balance) and
  Downloading/Sending/Done (IO via UART)
- Error: red arc + "FAILED RETRY?" prompt
Display primitives (fill_rect, draw_string, draw_arc) are stubs called
from the GC9A01 SPI driver layer (separate driver bead).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-17 23:10:52 -04:00
972db16635 feat: UART OTA protocol Balance→IO board, 1 KB chunk + ACK (bd-21hv)
Balance side (uart_ota.c): downloads io-firmware.bin from Gitea to RAM,
computes SHA256, then streams to IO over UART1 (GPIO17/18, 460800 baud)
as OTA_BEGIN/OTA_DATA/OTA_END frames with CRC8 + per-chunk ACK/retry (×3).
IO side (uart_ota_recv.c): receives frames, writes to inactive OTA partition
via esp_ota_write, verifies SHA256 on OTA_END, sets boot partition, reboots.
IO board main.c + CMakeLists.txt scaffold included.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-17 23:10:52 -04:00
5250ce67ad feat: Balance self-OTA download, SHA256 verify, rollback (bd-18nb)
Downloads balance-firmware.bin from Gitea release URL to inactive OTA
partition, streams SHA256 verification via mbedTLS, sets boot partition
and reboots. Auto-rollback via CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE if
ota_self_health_check() not called within 30 s of boot. Progress 0-100%
in g_ota_self_progress for display task.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-17 23:10:52 -04:00
d2175bf7d0 feat: Gitea release version checker with WiFi (bd-3hte)
Adds gitea_ota_check_task on Balance board: fetches Gitea releases API
every 30 min and on boot, filters by esp32-balance/ and esp32-io/ tag
prefixes, compares semver against embedded FW version, stores update info
(version string, download URL, SHA256) in g_balance_update / g_io_update.
WiFi credentials read from NVS namespace "wifi"; falls back to compile-time
DEFAULT_WIFI_SSID/PASS if NVS is empty.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-17 23:10:52 -04:00
2a13c3e18b feat: partition tables + OTA setup for Balance and IO boards (bd-3gwo)
Add dual OTA partitions (ota_0/ota_1 × 1.75 MB each) and otadata to
both esp32s3/balance/ and esp32s3/io/ on 4 MB flash layouts.
Enable CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE and OTA HTTP on Balance.
Create esp32s3/io/ project scaffold with config.h pin assignments.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-17 23:10:51 -04:00
3f0508815d Merge pull request 'ci: OTA release pipeline — build + attach firmware binaries (bd-9kod)' (#730) from sl-jetson/bd-9kod-ota-ci into main 2026-04-17 23:10:26 -04:00
d9e7acfa0d Merge pull request 'feat: ESP32 Balance UART/USB protocol for Orin + VESC proxy (bd-66hx)' (#729) from sl-firmware/bd-66hx-esp32-uart-orin into main 2026-04-17 23:10:15 -04:00
c02faf3ac2 Merge pull request 'feat: Here4 GPS DroneCAN on Orin via CANable2 (bd-p47c)' (#728) from sl-perception/bd-p47c-here4-can-gps into main 2026-04-17 23:10:05 -04:00
61f241ae1d Merge pull request 'feat: Orin UART/USB serial comms with ESP32 Balance (bd-wim1)' (#727) from sl-perception/bd-wim1-orin-uart-esp32 into main 2026-04-17 23:09:53 -04:00
26e71d7a14 feat: systemd auto-start for ROS2 + dashboard on Orin boot (bd-1hyn)
Implements full boot-time auto-start for the SaltyBot ROS2 stack on
Jetson Orin. Everything comes up automatically after power-on with
correct dependency ordering and restart-on-failure for each service.

New systemd services:
  saltybot-ros2.service         full_stack.launch.py (perception + SLAM + Nav2)
  saltybot-esp32-serial.service ESP32-S3 BALANCE UART bridge (bd-wim1, PR #727)
  saltybot-here4.service        Here4 DroneCAN GPS bridge (bd-p47c, PR #728)
  saltybot-dashboard.service    Web dashboard on port 8080

Updated:
  saltybot.target               now Wants all four new services with
                                boot-order comments
  can-bringup.service           bitrate 500 kbps → 1 Mbps (DroneCAN for Here4)
  70-canable.rules              remove bitrate from udev RUN+=; let service
                                own the bitrate, add TAG+=systemd for device unit
  install_systemd.sh            installs all services + udev rules, colcon
                                build, enables mosquitto, usermod dialout
  full_stack.launch.py          resolve 8 merge conflict markers (ESP32-S3
                                rename) and fix missing indent on
                                enable_mission_logging_arg — file was
                                un-launchable with SyntaxError

New:
  scripts/ros2-launch.sh        sources ROS2 Humble + workspace overlay,
                                then exec ros2 launch — used by all
                                ROS2 service units via ExecStart=
  udev/80-esp32.rules           /dev/esp32-balance (CH343) and
                                /dev/esp32-io (ESP32-S3 native USB CDC)

Resolves bd-1hyn

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-17 22:20:40 -04:00
2fa097e3d6 ci: OTA release pipeline — build + attach firmware binaries (bd-9kod)
Adds .gitea/workflows/ota-release.yml: triggered on esp32-balance/vX.Y.Z
or esp32-io/vX.Y.Z tags, builds the corresponding ESP32-S3 project with
espressif/idf:v5.2.2, and attaches <app>_<version>.bin + .sha256 to the
Gitea release for OTA download.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-17 22:11:33 -04:00
b830420efc feat: add UART/USB serial protocol for Orin comms, proxy VESC CAN (bd-66hx)
Replaces Orin↔ESP32-S3 BALANCE CAN comms (0x300-0x303 / 0x400-0x401)
with binary serial framing over CH343 USB-CDC at 460800 baud.

Protocol matches bd-wim1 (sl-perception) exactly:
  Frame: [0xAA][LEN][TYPE][PAYLOAD][CRC8-SMBUS]
  CRC covers LEN+TYPE+PAYLOAD, big-endian multi-byte fields.

Commands (Orin→ESP32): HEARTBEAT/DRIVE/ESTOP/ARM/PID
Telemetry (ESP32→Orin): TELEM_STATUS, TELEM_VESC_LEFT (ID 56),
                         TELEM_VESC_RIGHT (ID 68), ACK/NACK

VESC CAN TWAI kept for motor control; drive commands from Orin
forwarded to VESCs via SET_RPM. Hardware note: SN65HVD230
rewired from IO43/44 to IO2/IO1 to free IO43/44 for CH343.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-17 22:09:12 -04:00
9d6c72bd24 feat: Here4 GPS DroneCAN integration via CANable2 (bd-p47c)
Implements saltybot_dronecan_gps ROS2 package — DroneCAN/UAVCAN v0
bridge that publishes Here4 GPS, IMU, magnetometer, and barometer data
to ROS2. CANable2 freed from ESP32 BALANCE comms (bd-wim1) now runs
Here4 at 1 Mbps DroneCAN.

Key features:
- dronecan_parser.py: pure-Python DSDL converters (Fix2, RawIMU, Mag,
  StaticPressure, StaticTemperature, NodeStatus, RTCMStream chunks),
  testable without dronecan library or CAN hardware
- here4_node.py: ROS2 node, auto-discovers Here4 node ID on first Fix2,
  publishes /gps/fix + /gps/velocity for navsat_transform EKF fusion,
  HDOP-based NavSatStatus upgrade (RTK/SBAS), RTCM injection via
  /rtcm (ByteMultiArray) or /rtcm_hex (String hex fallback)
- 39 unit tests, all passing
- bring_up_can:=true parameter to configure SocketCAN at launch

Resolves bd-p47c

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-17 21:49:00 -04:00
9b460e34db feat: Orin UART/USB serial interface for ESP32 Balance (bd-wim1)
New package saltybot_esp32_serial replaces saltybot_can_bridge
(CANable2/python-can) with direct USB-CDC serial to ESP32-S3 BALANCE
(CH343 chip, 1a86:55d3, /dev/esp32-balance @ 460800 baud).

Framing: [0xAA][LEN][TYPE][PAYLOAD][CRC8-SMBUS] matching bd-66hx spec.

esp32_balance_protocol.py — codec + streaming FrameParser (state-machine)
  - Commands: HEARTBEAT(0x01), DRIVE(0x02), ESTOP(0x03), ARM(0x04), PID(0x05)
  - Telemetry: STATUS(0x80), VESC_LEFT(0x81), VESC_RIGHT(0x82), ACK/NACK

esp32_balance_node.py — ROS2 node
  - Subs: /cmd_vel, /estop, /saltybot/arm, /saltybot/pid_update
  - Pubs: /saltybot/attitude, /saltybot/balance_state, /can/battery,
          /can/vesc/{left,right}/state, /can/connection_status
  - 500ms /cmd_vel watchdog → CMD_DRIVE(0,0)
  - 200ms CMD_HEARTBEAT keepalive timer
  - Auto-reconnect on serial disconnect

Proxied VESC telemetry: erpm, voltage, current, temp for IDs 56(L)/68(R).
Frees CANable2 for bd-p47c (Here4 GPS).
33 unit tests — all pass.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-17 19:38:38 -04:00
c297d24a48 Merge pull request 'fix: Rename sultee-tracker → saul-tee-tracker' (#724) from sl-webui/fix-tracker-rename into main 2026-04-04 11:23:02 -04:00
885a66f24b Merge pull request 'feat: MQTT bridge for iOS GPS on /saltybot/ios/gps (Issue #681)' (#723) from sl-jetson/issue-681-ios-gps-bridge into main 2026-04-04 11:21:14 -04:00
fbc88f5c2a fix: correct rclpy logger calls to use f-strings (pre-existing bugs)
rclpy RcutilsLogger.info/warning/debug() do not accept printf-style
positional format args. Also fix p["use_phone_timestamp"] → p["use_phone_ts"]
key mismatch in __init__ log line.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-04 11:20:58 -04:00
0122957b6b feat: Add iOS phone GPS MQTT-to-ROS2 bridge topic (Issue #681)
- Add _TOPIC_IOS_GPS = 'saltybot/ios/gps' constant
- Subscribe to saltybot/ios/gps in _on_mqtt_connect
- Dispatch to _handle_ios_gps() in _dispatch()
- _handle_ios_gps(): same logic as _handle_gps(), frame_id='ios_gps',
  publishes to /saltybot/ios/gps via self._ios_gps_pub
- Add rx/pub/err/last_rx_ts counters for the new topic
- Add /saltybot/ios/gps to rosbridge_params.yaml topics_glob

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-04 11:20:58 -04:00
759277a7e0 fix: Rename sultee-tracker to saul-tee-tracker (typo fix) 2026-04-04 11:19:35 -04:00
b1e8da4403 Merge pull request 'feat: iOS phone GPS via rosbridge topic /saltybot/ios/gps (Issue #681)' (#722) from sl-webui/issue-681-ios-gps-rosbridge into main 2026-04-04 11:15:13 -04:00
dd8afb480f Merge pull request 'fix: add phone bridge and GPS topics to rosbridge whitelist (Issue #681)' (#721) from sl-webui/issue-681-fix-gps-topics into main 2026-04-04 11:15:12 -04:00
43fb3f1147 feat: Route iOS phone GPS through rosbridge instead of raw WebSocket (Issue #681) 2026-04-04 11:11:15 -04:00
416a393134 fix: correct delay_between_messages type to float in rosbridge_params
rclpy expects DOUBLE for this param; integer 0 raises InvalidParameterTypeException.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-04 10:58:09 -04:00
60f500c206 fix: add phone bridge and GPS topics to rosbridge whitelist (Issue #681)
Add /saltybot/phone/gps, /saltybot/phone/imu, /saltybot/phone/battery,
/saltybot/phone/bridge/status, /gps/fix, /gps/vel to topics_glob so
the browser GPS dashboard can receive phone-bridged GPS data.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-04 10:56:06 -04:00
b1cd15327f Merge pull request 'fix: GPS tracker subscribes to correct phone bridge topic (Issue #681)' (#720) from sl-webui/issue-681-fix-gps-topics into main 2026-04-04 10:07:10 -04:00
b72e435bf3 fix: Update tracker GPS topic to match phone bridge (Issue #681) 2026-04-04 10:01:57 -04:00
9cf98830c6 Merge pull request 'feat: remove all STM32/Mamba/BlackPill references — ESP32-S3 only' (#715) from sl-firmware/cleanup-legacy-hw into main 2026-04-04 09:00:55 -04:00
a1233dbd04 fix: scrub remaining Mamba references in can_bridge and e2e test protocol files
- balance_protocol.py: Mamba→Orin / Mamba→VESC comments → ESP32-S3 BALANCE
- can_bridge_node.py: docstring and inline comments
- __init__.py: package description
- protocol_defs.py: all Mamba references in docstring and comments
- test_fc_vesc_broadcast.py, test_drive_command.py: test comments

Zero Mamba/STM32F722/BlackPill/stm32_protocol/mamba_protocol references
now exist outside legacy/stm32/.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-04 09:00:44 -04:00
fa75c442a7 feat: remove all STM32/Mamba/BlackPill references — ESP32-S3 only
Archive STM32 firmware to legacy/stm32/:
- src/, include/, lib/USB_CDC/, platformio.ini, test stubs, flash_firmware.py
- test/test_battery_adc.c, test_hw_button.c, test_pid_schedule.c, test_vesc_can.c, test_can_watchdog.c
- USB_CDC_BUG.md

Rename: stm32_protocol → esp32_protocol, mamba_protocol → balance_protocol,
  stm32_cmd_node → esp32_cmd_node, stm32_cmd_params → esp32_cmd_params,
  stm32_cmd.launch.py → esp32_cmd.launch.py,
  test_stm32_protocol → test_esp32_protocol, test_stm32_cmd_node → test_esp32_cmd_node

Content cleanup across all files:
- Mamba F722S → ESP32-S3 BALANCE
- BlackPill → ESP32-S3 IO
- STM32F722/F7xx → ESP32-S3
- stm32Mode/Version/Port → esp32Mode/Version/Port
- STM32 State/Mode labels → ESP32 State/Mode
- Jetson Nano → Jetson Orin Nano Super
- /dev/stm32 → /dev/esp32
- stm32_bridge → esp32_bridge
- STM32 HAL → ESP-IDF

docs/SALTYLAB.md:
- Update "Drone FC Details" to describe ESP32-S3 BALANCE board (Waveshare ESP32-S3 Touch LCD 1.28)
- Replace verbose "Self-Balancing Control" STM32 section with brief note pointing to SAUL-TEE-SYSTEM-REFERENCE.md

TEAM.md: Update Embedded Firmware Engineer role to ESP32-S3 / ESP-IDF

No new functionality — cleanup only.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-04 09:00:38 -04:00
fe84ff6039 Merge pull request 'feat(arch): CAN/UART bridge update for SAUL-TEE ESP32 architecture' (#714) from sl-controls/esp32-can-bridge-update into main 2026-04-04 09:00:10 -04:00
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
308be74330 feat(arch): implement SAUL-TEE ESP32 protocol specs from hal reference doc
Spec source: docs/SAUL-TEE-SYSTEM-REFERENCE.md (hal, 2026-04-04)

stm32_protocol.py — rewritten for inter-board UART protocol (ESP32 BALANCE ↔ IO):
- Frame: [0xAA][LEN][TYPE][PAYLOAD][CRC8] @ 460800 baud (was STX/ETX/CRC16)
- CRC-8 poly 0x07 over LEN+TYPE+PAYLOAD
- New message types: RC_CHANNELS(0x01), SENSORS(0x02), LED_CMD(0x10),
  OUTPUT_CMD(0x11), MOTOR_CMD(0x12), HEARTBEAT(0x20)

mamba_protocol.py — updated CAN IDs and frame formats:
- Orin→BALANCE: DRIVE(0x300) f32×2 LE, MODE(0x301), ESTOP(0x302), LED(0x303)
- BALANCE→Orin: FC_STATUS(0x400) pitch/vbat/state, FC_VESC(0x401) rpm/current
- VESC node IDs: Left=56, Right=68 (authoritative per §8)
- VESC extended frames: STATUS1(cmd=9), STATUS4(cmd=16), STATUS5(cmd=27)
- Replaced old MAMBA_CMD_*/MAMBA_TELEM_* constants

can_bridge_node.py — updated to use new IDs:
- ORIN_CMD_DRIVE/MODE/ESTOP replace MAMBA_CMD_VELOCITY/MODE/ESTOP
- FC_STATUS handler: publishes pitch→/can/imu, vbat_mv→/can/battery
- FC_VESC handler: publishes rpm/cur→/can/vesc/left|right/state
- VESC STATUS1 extended frames decoded per node ID (56/68)
- Removed PID CAN command (not in new spec)

CLAUDE.md — updated with ESP32-S3 BALANCE/IO hardware summary + key protocols

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-04 08:59:28 -04:00
19be6bbe11 Merge pull request 'docs: SAUL-TEE full ESP32-S3 system reference (arch migration)' (#712) from sl-firmware/arch-esp32-migration into main 2026-04-04 08:57:11 -04:00