Protocol Reference (Python)¶
The Python-side protocol definitions live in host/protocol.py. This page
documents every exported symbol.
Constants¶
PKT_STM32_SIZE = 214 # full frame: STM32 → PC
PKT_KB2040_SIZE = 70 # relay frame: KB2040 → STM32
EXPECTED_FEATURE_DIM = 328 # FeatureExtractor output size
NUM_CLASSES = 11 # activity labels count
MAGIC_STM32 = 0xAA55 # big-endian view of [0xAA, 0x55]
MAGIC_KB2040 = 0xBB55 # big-endian view of [0xBB, 0x55]
Byte offsets¶
STM32 frame (214 bytes)¶
OFF_MAGIC = 0
OFF_SEQ = 2
OFF_TIMESTAMP = 6
OFF_IMU0 = 10 # IMU #0: L wrist (0x28, I2C1)
OFF_IMU1 = 38 # IMU #1: R wrist (0x29, I2C1)
OFF_IMU2 = 66 # IMU #2: L arm (0x28, I2C2)
OFF_IMU3 = 94 # IMU #3: R arm (0x29, I2C2)
OFF_IMU4 = 122 # IMU #4: chest (0x28, KB2040 I2C0)
OFF_IMU5 = 150 # IMU #5: thigh (0x28, KB2040 I2C1)
OFF_EMG = 178 # 2× float32
OFF_FSR = 186 # 4× float32
OFF_BMP = 202 # 2× float32 (placeholder)
OFF_CRC = 210
KB2040 frame (70 bytes)¶
KB2040_OFF_MAGIC = 0
KB2040_OFF_SEQ = 2
KB2040_OFF_TS = 6
KB2040_OFF_IMU4 = 10 # quat + acc (28 bytes)
KB2040_OFF_IMU5 = 38 # quat + acc (28 bytes)
KB2040_OFF_CRC = 66
Activity labels¶
ACTIVITY_LABELS = [
"standing", # 0
"walking", # 1
"walking-carrying", # 2
"climbing_ladder", # 3
"hammering", # 4
"sawing", # 5
"drilling", # 6
"lifting", # 7
"bending", # 8
"crouching", # 9
"troweling", # 10
]
Feature names¶
EXTRACTED_FEATURE_NAMES is a list of 328 strings naming every feature
produced by FeatureExtractor. Format:
imu{N}_{metric}_{stat}
emg{N}_{stat}
fsr{N}_{stat}
fsr_ratio_{side}
Examples: imu0_quat_w_mean, imu3_linacc_z_std, emg0_zcr,
fsr2_min, fsr_ratio_left.
CRC32¶
def crc32(data: bytes) -> int:
"""CRC32 using Ethernet polynomial (0xEDB88320)."""
...
Verification: crc32(b'123456789') == 0xCBF43926
IMUData¶
@dataclass
class IMUData:
q_w: float = 0.0
q_x: float = 0.0
q_y: float = 0.0
q_z: float = 0.0
ax: float = 0.0
ay: float = 0.0
az: float = 0.0
SensorFrame¶
@dataclass
class SensorFrame:
seq: int = 0
timestamp_us: int = 0
imus: list[IMUData] = field(default_factory=lambda: [IMUData() for _ in range(6)])
emg_forearm: float = 0.0
emg_back: float = 0.0
fsr: list[float] = field(default_factory=lambda: [0.0] * 4)
bmp_pressure: float = 0.0
bmp_altitude: float = 0.0
Parsing¶
from host.protocol import parse_frame
frame: SensorFrame = parse_frame(raw_bytes: bytes) # 214-byte STM32 frame
# raises ValueError on bad magic or CRC