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:
parent
7db6158ada
commit
b25f41ef1c
@ -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.
|
||||
@ -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,
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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
|
||||
@ -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,
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -6,7 +6,7 @@ Orin↔Mamba↔VESC integration test suite.
|
||||
All IDs and payload formats are derived from:
|
||||
include/orin_can.h — Orin↔FC (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))
|
||||
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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,
|
||||
)
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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,
|
||||
)
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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):
|
||||
|
||||
@ -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.
|
||||
"""
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user