Skip to content

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