refactor: rename stm32_protocol.py→esp32_protocol.py, mamba_protocol.py→balance_protocol.py

Remove all legacy STM32/Mamba names from source files. Update all imports,
comments, and docstring references across the codebase.

- stm32_protocol.py → esp32_protocol.py (inter-board UART codec)
- mamba_protocol.py → balance_protocol.py (Orin↔ESP32 BALANCE CAN codec)
- Updated: stm32_cmd_node.py, can_bridge_node.py, all test files,
  conftest.py, protocol_defs.py, jlink_gimbal.py

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
sl-webui 2026-04-04 08:38:59 -04:00
parent 7db6158ada
commit b25f41ef1c
15 changed files with 34 additions and 34 deletions

View File

@ -1,4 +1,4 @@
"""stm32_protocol.py — Binary frame codec for Jetson↔STM32 communication.
"""esp32_protocol.py — Binary frame codec for Jetson↔STM32 communication.
Issue #119: defines the binary serial protocol between the Jetson Nano and the
STM32F722 flight controller over USB CDC @ 921600 baud.

View File

@ -55,7 +55,7 @@ from sensor_msgs.msg import Imu
from std_msgs.msg import String
from std_srvs.srv import SetBool, Trigger
from .stm32_protocol import (
from .esp32_protocol import (
FrameParser,
ImuFrame, BatteryFrame, MotorRpmFrame, ArmStateFrame, ErrorFrame,
encode_heartbeat, encode_speed_steer, encode_arm, encode_set_mode,

View File

@ -29,7 +29,7 @@ import pytest
sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))
from saltybot_bridge.stm32_protocol import (
from saltybot_bridge.esp32_protocol import (
STX, ETX, CmdType, TelType,
encode_speed_steer, encode_heartbeat, encode_arm, encode_pid_update,
_build_frame, _crc16_ccitt,
@ -219,10 +219,10 @@ class TestMockSerialTX:
class TestMockSerialRX:
"""Test RX parsing path using MockSerial with pre-loaded telemetry data."""
from saltybot_bridge.stm32_protocol import FrameParser
from saltybot_bridge.esp32_protocol import FrameParser
def test_rx_imu_frame(self):
from saltybot_bridge.stm32_protocol import FrameParser, ImuFrame
from saltybot_bridge.esp32_protocol import FrameParser, ImuFrame
raw = _imu_frame_bytes(pitch=500, roll=-200, yaw=100, ax=0, ay=0, az=981)
ms = MockSerial(rx_data=raw)
parser = FrameParser()
@ -241,7 +241,7 @@ class TestMockSerialRX:
assert f.accel_z == pytest.approx(9.81)
def test_rx_battery_frame(self):
from saltybot_bridge.stm32_protocol import FrameParser, BatteryFrame
from saltybot_bridge.esp32_protocol import FrameParser, BatteryFrame
raw = _battery_frame_bytes(v_mv=10500, i_ma=1200, soc=45)
ms = MockSerial(rx_data=raw)
parser = FrameParser()
@ -257,7 +257,7 @@ class TestMockSerialRX:
assert f.soc_pct == 45
def test_rx_multiple_frames_in_one_read(self):
from saltybot_bridge.stm32_protocol import FrameParser
from saltybot_bridge.esp32_protocol import FrameParser
raw = (_imu_frame_bytes() + _arm_state_frame_bytes() + _battery_frame_bytes())
ms = MockSerial(rx_data=raw)
parser = FrameParser()
@ -271,7 +271,7 @@ class TestMockSerialRX:
assert parser.frames_error == 0
def test_rx_bad_crc_counted_as_error(self):
from saltybot_bridge.stm32_protocol import FrameParser
from saltybot_bridge.esp32_protocol import FrameParser
raw = bytearray(_arm_state_frame_bytes(state=1))
raw[-3] ^= 0xFF # corrupt CRC
ms = MockSerial(rx_data=bytes(raw))
@ -282,7 +282,7 @@ class TestMockSerialRX:
assert parser.frames_error == 1
def test_rx_resync_after_corrupt_byte(self):
from saltybot_bridge.stm32_protocol import FrameParser, ArmStateFrame
from saltybot_bridge.esp32_protocol import FrameParser, ArmStateFrame
garbage = b"\xDE\xAD\x00\x00"
valid = _arm_state_frame_bytes(state=1)
ms = MockSerial(rx_data=garbage + valid)

View File

@ -1,4 +1,4 @@
"""test_stm32_protocol.py — Unit tests for binary STM32 frame codec.
"""test_esp32_protocol.py — Unit tests for binary STM32 frame codec.
Tests:
- CRC16-CCITT correctness
@ -12,7 +12,7 @@ Tests:
- Speed/steer clamping in encode_speed_steer
- Round-trip encode decode for all known telemetry types
Run with: pytest test/test_stm32_protocol.py -v
Run with: pytest test/test_esp32_protocol.py -v
"""
from __future__ import annotations
@ -25,7 +25,7 @@ import os
# ── Path setup (no ROS2 install needed) ──────────────────────────────────────
sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))
from saltybot_bridge.stm32_protocol import (
from saltybot_bridge.esp32_protocol import (
STX, ETX,
CmdType, TelType,
ImuFrame, BatteryFrame, MotorRpmFrame, ArmStateFrame, ErrorFrame,

View File

@ -1,6 +1,6 @@
#!/usr/bin/env python3
"""
mamba_protocol.py CAN message encoding/decoding for the Mamba motor controller
balance_protocol.py CAN message encoding/decoding for the Mamba motor controller
and VESC telemetry.
CAN message layout

View File

@ -1,6 +1,6 @@
#!/usr/bin/env python3
"""
can_bridge_node.py ROS2 node bridging the SaltyBot Orin to the Mamba motor
can_bridge_node.py ROS2 node bridging the SaltyBot Orin to the ESP32-S3 BALANCE
controller and VESC motor controllers over CAN bus.
The node opens the SocketCAN interface (slcan0 by default), spawns a background
@ -34,7 +34,7 @@ from rcl_interfaces.msg import SetParametersResult
from sensor_msgs.msg import BatteryState, Imu
from std_msgs.msg import Bool, Float32MultiArray, String
from saltybot_can_bridge.mamba_protocol import (
from saltybot_can_bridge.balance_protocol import (
MAMBA_CMD_ESTOP,
MAMBA_CMD_MODE,
MAMBA_CMD_VELOCITY,

View File

@ -1,6 +1,6 @@
#!/usr/bin/env python3
"""
Unit tests for saltybot_can_bridge.mamba_protocol.
Unit tests for saltybot_can_bridge.balance_protocol.
No ROS2 or CAN hardware required tests exercise encode/decode round-trips
and boundary conditions entirely in Python.
@ -11,7 +11,7 @@ Run with: pytest test/test_can_bridge.py -v
import struct
import unittest
from saltybot_can_bridge.mamba_protocol import (
from saltybot_can_bridge.balance_protocol import (
MAMBA_CMD_ESTOP,
MAMBA_CMD_MODE,
MAMBA_CMD_VELOCITY,

View File

@ -6,7 +6,7 @@ Orin↔Mamba↔VESC integration test suite.
All IDs and payload formats are derived from:
include/orin_can.h OrinFC (Mamba) protocol
include/vesc_can.h VESC CAN protocol
saltybot_can_bridge/mamba_protocol.py existing bridge constants
saltybot_can_bridge/balance_protocol.py existing bridge constants
CAN IDs used in tests
---------------------
@ -22,7 +22,7 @@ FC (Mamba) → Orin telemetry (standard 11-bit, matching orin_can.h):
FC_IMU 0x402 8 bytes
FC_BARO 0x403 8 bytes
Mamba VESC internal commands (matching mamba_protocol.py):
Mamba VESC internal commands (matching balance_protocol.py):
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_ESTOP 0x102 1 byte 0x01=stop
@ -54,7 +54,7 @@ FC_IMU: int = 0x402
FC_BARO: int = 0x403
# ---------------------------------------------------------------------------
# Mamba → VESC internal command IDs (from mamba_protocol.py)
# Mamba → VESC internal command IDs (from balance_protocol.py)
# ---------------------------------------------------------------------------
MAMBA_CMD_VELOCITY: int = 0x100
@ -136,14 +136,14 @@ def build_estop_cmd(action: int = 1) -> bytes:
# ---------------------------------------------------------------------------
# Frame builders — Mamba velocity commands (mamba_protocol.py encoding)
# Frame builders — Mamba velocity commands (balance_protocol.py encoding)
# ---------------------------------------------------------------------------
def build_velocity_cmd(left_mps: float, right_mps: float) -> bytes:
"""
Build a MAMBA_CMD_VELOCITY payload (8 bytes, 2 × float32 big-endian).
Matches encode_velocity_cmd() in mamba_protocol.py.
Matches encode_velocity_cmd() in balance_protocol.py.
"""
return struct.pack(">ff", float(left_mps), float(right_mps))

View File

@ -14,7 +14,7 @@ _pkg_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
if _pkg_root not in sys.path:
sys.path.insert(0, _pkg_root)
# Also add the saltybot_can_bridge package so we can import mamba_protocol.
# Also add the saltybot_can_bridge package so we can import balance_protocol.
_bridge_pkg = os.path.join(
os.path.dirname(_pkg_root), "saltybot_can_bridge"
)
@ -60,7 +60,7 @@ def loopback_can_bus():
@pytest.fixture(scope="function")
def bridge_components():
"""
Return the mamba_protocol encode/decode callables and a fresh mock bus.
Return the balance_protocol encode/decode callables and a fresh mock bus.
Yields a dict with keys:
bus MockCANBus instance
@ -69,7 +69,7 @@ def bridge_components():
encode_estop encode_estop_cmd(stop) bytes
decode_vesc decode_vesc_state(data) VescStateTelemetry
"""
from saltybot_can_bridge.mamba_protocol import (
from saltybot_can_bridge.balance_protocol import (
encode_velocity_cmd,
encode_mode_cmd,
encode_estop_cmd,

View File

@ -28,7 +28,7 @@ from saltybot_can_e2e_test.protocol_defs import (
parse_velocity_cmd,
parse_fc_vesc,
)
from saltybot_can_bridge.mamba_protocol import (
from saltybot_can_bridge.balance_protocol import (
encode_velocity_cmd,
encode_mode_cmd,
)

View File

@ -32,7 +32,7 @@ from saltybot_can_e2e_test.protocol_defs import (
parse_velocity_cmd,
parse_fc_status,
)
from saltybot_can_bridge.mamba_protocol import (
from saltybot_can_bridge.balance_protocol import (
encode_velocity_cmd,
encode_mode_cmd,
encode_estop_cmd,

View File

@ -30,7 +30,7 @@ from saltybot_can_e2e_test.protocol_defs import (
parse_fc_vesc,
parse_vesc_status,
)
from saltybot_can_bridge.mamba_protocol import (
from saltybot_can_bridge.balance_protocol import (
VESC_TELEM_STATE as BRIDGE_VESC_TELEM_STATE,
decode_vesc_state,
)

View File

@ -33,7 +33,7 @@ from saltybot_can_e2e_test.protocol_defs import (
build_velocity_cmd,
parse_velocity_cmd,
)
from saltybot_can_bridge.mamba_protocol import (
from saltybot_can_bridge.balance_protocol import (
encode_velocity_cmd,
encode_mode_cmd,
encode_estop_cmd,

View File

@ -27,7 +27,7 @@ from saltybot_can_e2e_test.protocol_defs import (
build_velocity_cmd,
parse_velocity_cmd,
)
from saltybot_can_bridge.mamba_protocol import (
from saltybot_can_bridge.balance_protocol import (
encode_velocity_cmd,
encode_mode_cmd,
encode_estop_cmd,
@ -189,7 +189,7 @@ class TestModeCommandEncoding:
"""build_mode_cmd in protocol_defs must produce identical bytes."""
for mode in (MODE_IDLE, MODE_DRIVE, MODE_ESTOP):
assert build_mode_cmd(mode) == encode_mode_cmd(mode), \
f"protocol_defs.build_mode_cmd({mode}) != mamba_protocol.encode_mode_cmd({mode})"
f"protocol_defs.build_mode_cmd({mode}) != balance_protocol.encode_mode_cmd({mode})"
class TestInvalidMode:
@ -218,8 +218,8 @@ class TestInvalidMode:
accepted = sm.set_mode(-1)
assert accepted is False
def test_mamba_protocol_invalid_mode_raises(self):
"""mamba_protocol.encode_mode_cmd must raise on invalid mode."""
def test_balance_protocol_invalid_mode_raises(self):
"""balance_protocol.encode_mode_cmd must raise on invalid mode."""
with pytest.raises(ValueError):
encode_mode_cmd(99)
with pytest.raises(ValueError):

View File

@ -13,7 +13,7 @@ Telemetry type (STM32 → Jetson):
uint16 pan_speed_raw + uint16 tilt_speed_raw +
uint8 torque_en + uint8 rx_err_pct (10 bytes)
Frame format (shared with stm32_protocol.py):
Frame format (shared with esp32_protocol.py):
[STX=0x02][CMD][LEN][PAYLOAD...][CRC16_hi][CRC16_lo][ETX=0x03]
CRC16-CCITT: poly=0x1021, init=0xFFFF, covers CMD+LEN+PAYLOAD bytes.
"""