This document defines the Interface Control Document (ICD) for the binary communication protocol used by the Tracked Robot (tracked_bot).
The protocol connects high-level telemetry/control clients (e.g. Python CLI, Web GUI, autonomous navigators) to the onboard ATmega328P microcontroller running at 16 MHz via UART (115200 baud, 8-N-1) or transparent ESP8266 WiFi bridges.
0x07).RESP_ACK), structured error feedback (RESP_NACK), or dedicated response frames (RESP_STATUS, RESP_DIAG, RESP_PONG).Every packet transmitted across the communication medium follows a uniform 4-part structure:
+--------+--------+--------+--------------------------+--------+
| SYNC | MSG_ID | LEN | PAYLOAD | CRC8 |
| 1 Byte | 1 Byte | 1 Byte | 0..16 Bytes | 1 Byte |
+--------+--------+--------+--------------------------+--------+
| Field | Length | Value / Range | Description |
|---|---|---|---|
| SYNC | 1 Byte | 0xAA (170 dec) |
Frame synchronization delimiter indicating start of a new packet. |
| MSG_ID | 1 Byte | 0x01 .. 0xFF |
Unique Message Identifier defining command or telemetry type. |
| LEN | 1 Byte | 0x00 .. 0x10 |
Payload length in bytes ($0 \le N \le 16$). |
| PAYLOAD | $N$ Bytes | Variable | Command parameters or telemetry payload ($N$ bytes). Empty if LEN = 0. |
| CRC8 | 1 Byte | 0x00 .. 0xFF |
CRC-8 checksum computed over [MSG_ID, LEN, PAYLOAD...]. |
[!NOTE] The
SYNCbyte (0xAA) is excluded from the CRC-8 computation to allow stream-oriented synchronization recovery without recursive checksum dependency.
The CRC-8 checksum is calculated using the ATM / SMBus polynomial standard:
MSG_ID, LEN, followed by each byte of PAYLOAD.uint8_t crc8_calculate(const uint8_t *data, uint8_t length) {
uint8_t crc = 0x00;
for (uint8_t i = 0; i < length; ++i) {
crc ^= data[i];
for (uint8_t bit = 0; bit < 8; ++bit) {
if (crc & 0x80) {
crc = (uint8_t)((crc << 1) ^ 0x07);
} else {
crc = (uint8_t)(crc << 1);
}
}
}
return crc;
}
Inbound commands use the range 0x01 .. 0x7F.
| MSG_ID | Name | LEN | Payload Format | Description |
|---|---|---|---|---|
0x01 |
CMD_MOTION |
1 | [motion_cmd_t: 1B] |
Drive robot tracks (Forward, Reverse, Turn, Spin). |
0x02 |
CMD_SET_SPEED |
1 | [speed: 1B] |
Set target PWM drive speed ($0 \dots 255$). |
0x03 |
CMD_STOP |
0 | None | Immediate kinematics deceleration / emergency stop. |
0x04 |
CMD_PING |
0 | None | Heartbeat request (expects RESP_PONG). |
0x10 |
CMD_GET_STATUS |
0 | None | Query standard operating telemetry status. |
0x11 |
CMD_GET_DIAG |
0 | None | Query extended hardware and failsafe diagnostic data. |
0x12 |
CMD_ERR_CLEAR |
0 | None | Clear error logs and restore normal operating mode. |
Outbound responses use the high-bit range 0x80 .. 0xFF.
| MSG_ID | Name | LEN | Payload Format | Description |
|---|---|---|---|---|
0x80 |
RESP_ACK |
1 | [cmd_id: 1B] |
Acknowledgment of successful command execution. |
0x81 |
RESP_NACK |
2 | [cmd_id: 1B] [err_code: 1B] |
Negative acknowledgment indicating command rejection or fault. |
0x84 |
RESP_PONG |
0 | None | Heartbeat response confirming communication link alive. |
0x90 |
RESP_STATUS |
7 | 7-byte telemetry struct | Consolidated status (mode, error, counts, kinematics, speed). |
0x91 |
RESP_DIAG |
9 | 9-byte diagnostic struct | Full telemetry + failsafe status + motor lock state. |
motion_cmd_t)Used in CMD_MOTION (payload byte 0) and reported in RESP_STATUS (payload byte 5):
| Value | Identifier | Action |
|---|---|---|
0x00 |
MOTION_STOP |
Tracks stopped / idle |
0x01 |
MOTION_FORWARD |
Both tracks drive forward |
0x02 |
MOTION_BACKWARD |
Both tracks drive reverse |
0x03 |
MOTION_TURN_LEFT |
Pivot left (right track forward, left idle) |
0x04 |
MOTION_TURN_RIGHT |
Pivot right (left track forward, right idle) |
0x05 |
MOTION_SPIN_LEFT |
Counter-rotate left (left reverse, right forward) |
0x06 |
MOTION_SPIN_RIGHT |
Counter-rotate right (left forward, right reverse) |
motion_state_t)Reported in RESP_STATUS (payload byte 4):
| Value | Identifier | Meaning |
|---|---|---|
0x00 |
MOTION_STATE_IDLE |
Kinematics at rest (speed = 0) |
0x01 |
MOTION_STATE_MOVING |
Motors active or slewing towards target |
0x02 |
MOTION_STATE_FAILSAFE |
Emergency deceleration triggered |
system_mode_t)Reported in RESP_STATUS (payload byte 0):
| Value | Identifier | Operating Condition |
|---|---|---|
0x00 |
SYSTEM_MODE_NORMAL |
Nominal operations, motor drive enabled |
0x01 |
SYSTEM_MODE_DEGRADED |
Subsystem error occurred; motor drive locked |
0x02 |
SYSTEM_MODE_PANIC |
Critical hardware fault; safety shutdown |
error_code_t)Reported in RESP_NACK (payload byte 1) and RESP_STATUS (payload byte 1):
| Value | Identifier | Root Cause |
|---|---|---|
0x00 |
ERR_CODE_NONE |
No error active |
0x01 |
ERR_CODE_INIT_UART |
UART driver failed initialization |
0x02 |
ERR_CODE_INIT_MOTORS |
L293D shield driver failed initialization |
0x03 |
ERR_CODE_INIT_TIMER |
Millisecond timer failed initialization |
0x04 |
ERR_CODE_INIT_PARSER |
Parser / dispatcher failed initialization |
0x05 |
ERR_CODE_INIT_FAILSAFE |
Failsafe watchdog failed initialization |
0x06 |
ERR_CODE_COMM_RX_OVERFLOW |
Serial receive ring buffer overrun |
0x07 |
ERR_CODE_COMM_TX_OVERFLOW |
Serial transmit buffer overrun |
0x08 |
ERR_CODE_CMD_SYNTAX_ERROR |
Malformed length or invalid parameter value |
0x09 |
ERR_CODE_CMD_UNKNOWN |
Unknown / unhandled MSG_ID |
0x0A |
ERR_CODE_FAILSAFE_TRIGGERED |
Watchdog timeout expired (loss of communication) |
0x0B |
ERR_CODE_HARDWARE_FAULT |
Critical driver or peripheral malfunction |
0x0C |
ERR_CODE_COMM_CRC |
Checksum mismatch on received frame |
RESP_STATUS Payload Layout (7 Bytes)Byte 0: system_mode_t (0=NORMAL, 1=DEGRADED, 2=PANIC)
Byte 1: error_code_t (Last active error code)
Byte 2: error_count (MSB - High byte of 16-bit cumulative error count)
Byte 3: error_count (LSB - Low byte of 16-bit cumulative error count)
Byte 4: motion_state (0=IDLE, 1=MOVING, 2=FAILSAFE)
Byte 5: motion_cmd (0..6 active motion direction)
Byte 6: current_speed (0..255 active slew PWM speed)
RESP_DIAG Payload Layout (9 Bytes)Bytes 0..6: Standard RESP_STATUS payload (same as above)
Byte 7: failsafe_flags (Bitfield):
- Bit 0 (0x01): Failsafe watchdog enabled
- Bit 1 (0x02): Failsafe watchdog currently triggered
Byte 8: motion_lock (0x00 = Motion Allowed, 0x01 = Motion Locked)
Below are concrete, byte-by-byte verified transmission packets for all supported operations.
CMD_PINGLEN = 0)[0x04, 0x00] $\rightarrow$ 0x54TX: 0xAA 0x04 0x00 0x54
RESP_PONGLEN = 0)[0x84, 0x00] $\rightarrow$ 0xE2RX: 0xAA 0x84 0x00 0xE2
CMD_MOTION FWD (Forward)MOTION_FORWARD (0x01)[0x01, 0x01, 0x01] $\rightarrow$ 0x79TX: 0xAA 0x01 0x01 0x01 0x79
RESP_ACK (for 0x01)[0x01][0x80, 0x01, 0x01] $\rightarrow$ 0x19RX: 0xAA 0x80 0x01 0x01 0x19
| Command | Action | Payload | Complete Packet (HEX) | CRC-8 |
| :— | :— | :—: | :— | :—: |
| CMD_MOTION BWD | Drive Reverse | 0x02 | 0xAA 0x01 0x01 0x02 0x70 | 0x70 |
| CMD_MOTION LEFT | Pivot Left | 0x03 | 0xAA 0x01 0x01 0x03 0x77 | 0x77 |
| CMD_MOTION RIGHT | Pivot Right | 0x04 | 0xAA 0x01 0x01 0x04 0x62 | 0x62 |
| CMD_MOTION SPINL | Counter-Rotate Left | 0x05 | 0xAA 0x01 0x01 0x05 0x65 | 0x65 |
| CMD_MOTION SPINR | Counter-Rotate Right | 0x06 | 0xAA 0x01 0x01 0x06 0x6C | 0x6C |
| CMD_STOP | Decelerate to Stop | None | 0xAA 0x03 0x00 0x3F | 0x3F |
CMD_SET_SPEED 150 (0x96)150 (0x96)[0x02, 0x01, 0x96] $\rightarrow$ 0x28TX: 0xAA 0x02 0x01 0x96 0x28
RESP_ACK (for 0x02)[0x80, 0x01, 0x02] $\rightarrow$ 0x10RX: 0xAA 0x80 0x01 0x02 0x10
CMD_SET_SPEED 255 (0xFF - Max Speed)255 (0xFF)[0x02, 0x01, 0xFF] $\rightarrow$ 0x30TX: 0xAA 0x02 0x01 0xFF 0x30
CMD_GET_STATUSLEN = 0)[0x10, 0x00] $\rightarrow$ 0x57TX: 0xAA 0x10 0x00 0x57
RESP_STATUS (Example: Normal Mode, Idle, No Errors, Speed 150)[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x96][0x90, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x96] $\rightarrow$ 0x23RX: 0xAA 0x90 0x07 0x00 0x00 0x00 0x00 0x00 0x00 0x96 0x23
RESP_STATUS (Example: Normal Mode, Moving Forward, Speed 200)[0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0xC8][0x90, 0x07, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0xC8] $\rightarrow$ 0xC0RX: 0xAA 0x90 0x07 0x00 0x00 0x00 0x00 0x01 0x01 0xC8 0xC0
CMD_GET_DIAGLEN = 0)[0x11, 0x00] $\rightarrow$ 0x42TX: 0xAA 0x11 0x00 0x42
RESP_DIAG (Example: Normal, Idle, Failsafe Enabled, Lock Off)[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x96, 0x01, 0x00][0x91, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x96, 0x01, 0x00] $\rightarrow$ 0xA5RX: 0xAA 0x91 0x09 0x00 0x00 0x00 0x00 0x00 0x00 0x96 0x01 0x00 0xA5
CMD_ERR_CLEARLEN = 0)[0x12, 0x00] $\rightarrow$ 0x7DTX: 0xAA 0x12 0x00 0x7D
RESP_ACK (for 0x12)[0x12][0x80, 0x01, 0x12] $\rightarrow$ 0x60RX: 0xAA 0x80 0x01 0x12 0x60
RESP_NACK (Example: Syntax Error on 0x01)0x010x08 (ERR_CODE_CMD_SYNTAX_ERROR)[0x81, 0x02, 0x01, 0x08] $\rightarrow$ 0xD2RX: 0xAA 0x81 0x02 0x01 0x08 0xD2
RESP_NACK (Example: CRC Error on Received Frame)0x02)0x0C (ERR_CODE_COMM_CRC)[0x81, 0x02, 0x02, 0x0C] $\rightarrow$ 0xFFRX: 0xAA 0x81 0x02 0x02 0x0C 0xFF
The firmware implements a non-blocking 5-state parser inside command_parser_process():
stateDiagram-v2
[*] --> WAIT_SYNC
WAIT_SYNC --> READ_ID: Byte == 0xAA
WAIT_SYNC --> WAIT_SYNC: Byte != 0xAA (Discard noise)
READ_ID --> READ_LEN: Store MSG_ID
READ_LEN --> READ_PAYLOAD: LEN <= 16 && LEN > 0
READ_LEN --> CHECK_CRC: LEN == 0
READ_LEN --> WAIT_SYNC: LEN > 16 (Frame Error / NACK)
READ_PAYLOAD --> READ_PAYLOAD: Read until payload_index == LEN
READ_PAYLOAD --> CHECK_CRC: All payload bytes read
CHECK_CRC --> EXECUTE: Computed CRC == Received CRC
CHECK_CRC --> CRC_FAULT: Computed CRC != Received CRC
EXECUTE --> WAIT_SYNC: Dispatch command & send ACK / Telemetry
CRC_FAULT --> WAIT_SYNC: Report ERR_CODE_COMM_CRC & send NACK
0xAA is ignored in the WAIT_SYNC state.WAIT_SYNC to avoid buffer overflow.error_handler_t subsystem.