Binary Protocol¶
Single source of truth: host/protocol.py (Python) and
firmware/shared/packet_protocol.h (C). Both must stay in sync.
KB2040 → STM32F405 (70 bytes, UART 921600 baud)¶
| Offset | Size | Field |
|---|---|---|
| 0 | 2 | Magic 0xBB 0x55 |
| 2 | 4 | Sequence number (uint32 LE) |
| 6 | 4 | Timestamp µs (uint32 LE) |
| 10 | 28 | IMU #4 chest: quat w,x,y,z + lin accel x,y,z (float32 LE × 7) |
| 38 | 28 | IMU #5 thigh: same layout |
| 66 | 4 | CRC32 (Ethernet polynomial 0xEDB88320) over bytes 0–65 |
IMU payload layout (28 bytes, both IMUs)¶
| Offset within IMU | Field |
|---|---|
| +0 | quaternion w |
| +4 | quaternion x |
| +8 | quaternion y |
| +12 | quaternion z |
| +16 | linear acceleration x |
| +20 | linear acceleration y |
| +24 | linear acceleration z |
STM32F405 → PC (214 bytes, USB CDC)¶
| Offset | Size | Field |
|---|---|---|
| 0 | 2 | Magic 0xAA 0x55 |
| 2 | 4 | Sequence number (uint32 LE) |
| 6 | 4 | Timestamp µs (uint32 LE) |
| 10 | 168 | 6 × BNO055 payload (28 bytes each, same layout as above) |
| 178 | 8 | MyoWare forearm + back (float32 LE, 0.0–1.0) |
| 186 | 16 | FSR: L heel, L toe, R heel, R toe (float32 LE, 0.0–1.0) |
| 202 | 4 | BMP390 pressure hPa (float32 LE, 0.0 until sensor arrives) |
| 206 | 4 | BMP390 altitude m (float32 LE, 0.0 until sensor arrives) |
| 210 | 4 | CRC32 over bytes 0–209 |
BNO055 order in the 168-byte block¶
| # | IMU location | Offset in packet |
|---|---|---|
| 0 | Left wrist | 10 |
| 1 | Right wrist | 38 |
| 2 | Left upper arm | 66 |
| 3 | Right upper arm | 94 |
| 4 | Chest | 122 |
| 5 | Thigh | 150 |
CRC32¶
Ethernet polynomial: 0xEDB88320 (reflected form). Computed over all bytes
before the CRC field. Verify with the standard test vector:
from host.protocol import crc32
assert crc32(b'123456789') == 0xCBF43926
Magic sync¶
The host reader scans for magic bytes and resyncs on mismatch:
# host/serial_reader.py
if byte0 == 0xAA and byte1 == 0x55:
read 212 more bytes
validate CRC32
parse frame
else:
shift window by 1 byte, repeat
False-magic probability: ~1/65536 per random byte pair. CRC32 catches any false-positive sync within the next frame.
Example parsed frame¶
seq=1234 ts=56789012
IMU[0] quat=(0.999,-0.001,0.002,-0.003) acc=(0.01,0.02,-9.80)
IMU[1] quat=(0.998,0.001,-0.003,0.004) acc=(0.00,-0.01,-9.81)
IMU[2] quat=(0.997,-0.002,0.001,-0.005) acc=(0.02,0.01,-9.79)
IMU[3] quat=(0.996,0.003,-0.002,0.006) acc=(-0.01,0.00,-9.80)
IMU[4] quat=(0.995,-0.001,0.004,-0.002) acc=(0.00,0.03,-9.78)
IMU[5] quat=(0.994,0.002,-0.001,0.007) acc=(0.01,-0.02,-9.80)
EMG fg=0.12 bk=0.34
FSR lh=0.45 lt=0.12 rh=0.55 rt=0.18
BMP p=0.00 alt=0.00 (placeholder)
CRC ok