Communication Protocol¶
This document describes the CAN bus communication protocol used by DaMiao motors.
Overview¶
DaMiao motors communicate over CAN bus using a custom protocol. The protocol supports:
- Command messages: Send control commands to motors
- Feedback messages: Receive motor state information
- Register operations: Read/write motor configuration registers
Message Types¶
1. Control Commands
Control commands send motion commands to motors. All frames are standard CAN (STD) with 8-byte data payload (D[0]..D[7]).
MIT command frame (MIT mode)
| Arbitration ID | Attribute | D[0] | D[1] | D[2] | D[3] | D[4] | D[5] | D[6] | D[7] |
|---|---|---|---|---|---|---|---|---|---|
motor_id |
STD |
pos_u[15:8] |
pos_u[7:0] |
vel_u[11:4] |
vel_u[3:0] / kp_u[11:8] |
kp_u[7:0] |
kd_u[11:4] |
kd_u[3:0] / torq_u[11:8] |
torq_u[7:0] |
POS_VEL command frame (POS_VEL mode, little-endian)
| Arbitration ID | Attribute | D[0] | D[1] | D[2] | D[3] | D[4] | D[5] | D[6] | D[7] |
|---|---|---|---|---|---|---|---|---|---|
0x100 + motor_id |
STD |
position_b0 |
position_b1 |
position_b2 |
position_b3 |
vel_limit_b0 |
vel_limit_b1 |
vel_limit_b2 |
vel_limit_b3 |
VEL command frame (VEL mode, little-endian)
| Arbitration ID | Attribute | D[0] | D[1] | D[2] | D[3] | D[4] | D[5] | D[6] | D[7] |
|---|---|---|---|---|---|---|---|---|---|
0x200 + motor_id |
STD |
velocity_b0 |
velocity_b1 |
velocity_b2 |
velocity_b3 |
0x00 |
0x00 |
0x00 |
0x00 |
FORCE_POS command frame (FORCE_POS mode, little-endian)
| Arbitration ID | Attribute | D[0] | D[1] | D[2] | D[3] | D[4] | D[5] | D[6] | D[7] |
|---|---|---|---|---|---|---|---|---|---|
0x300 + motor_id |
STD |
position_b0 |
position_b1 |
position_b2 |
position_b3 |
vel_limit_b0 |
vel_limit_b1 |
torque_ratio_b0 |
torque_ratio_b1 |
b0 is the least significant byte (LSB), b3 is the most significant byte (MSB).
2. System Commands
System commands also use arbitration_id = motor_id and STD frames:
| Command | Arbitration ID | Attribute | D[0] | D[1] | D[2] | D[3] | D[4] | D[5] | D[6] | D[7] |
|---|---|---|---|---|---|---|---|---|---|---|
| Enable motor | motor_id |
STD |
0xFF |
0xFF |
0xFF |
0xFF |
0xFF |
0xFF |
0xFF |
0xFC |
| Disable motor | motor_id |
STD |
0xFF |
0xFF |
0xFF |
0xFF |
0xFF |
0xFF |
0xFF |
0xFD |
| Set zero position | motor_id |
STD |
0xFF |
0xFF |
0xFF |
0xFF |
0xFF |
0xFF |
0xFF |
0xFE |
| Clear error | motor_id |
STD |
0xFF |
0xFF |
0xFF |
0xFF |
0xFF |
0xFF |
0xFF |
0xFB |
3. Register Operations
Register command requests use arbitration ID 0x7FF and STD frames:
For register semantics and persistence behavior:
- See Registers: How it works? for write (RAM/runtime) vs store (flash persistence) behavior (
write_register(...)vsstore_parameters()). - See Register Table for valid
RID, access type (RW/RO), value range, and data type. - Terminology used in this documentation: write = runtime RAM update, store = persist to flash.
Read register request (D[2] = 0x33)
| Arbitration ID | Attribute | D[0] | D[1] | D[2] | D[3] | D[4] | D[5] | D[6] | D[7] |
|---|---|---|---|---|---|---|---|---|---|
0x7FF |
STD |
CANID_L |
CANID_H |
0x33 |
RID |
0x00 |
0x00 |
0x00 |
0x00 |
Write register request (D[2] = 0x55)
| Arbitration ID | Attribute | D[0] | D[1] | D[2] | D[3] | D[4] | D[5] | D[6] | D[7] |
|---|---|---|---|---|---|---|---|---|---|
0x7FF |
STD |
CANID_L |
CANID_H |
0x55 |
RID |
data_b0 |
data_b1 |
data_b2 |
data_b3 |
Store parameters request (D[2] = 0xAA)
| Arbitration ID | Attribute | D[0] | D[1] | D[2] | D[3] | D[4] | D[5] | D[6] | D[7] |
|---|---|---|---|---|---|---|---|---|---|
0x7FF |
STD |
CANID_L |
CANID_H |
0xAA |
RID (driver uses 0x01) |
0x00 |
0x00 |
0x00 |
0x00 |
4. Feedback Messages
Motors continuously send feedback as STD frames:
| Arbitration ID | Attribute | D[0] | D[1] | D[2] | D[3] | D[4] | D[5] | D[6] | D[7] |
|---|---|---|---|---|---|---|---|---|---|
feedback_id (MST_ID, reg 7) |
STD |
status[7:4] / motor_id[3:0] |
pos_u[15:8] |
pos_u[7:0] |
vel_u[11:4] |
vel_u[3:0] / torq_u[11:8] |
torq_u[7:0] |
T_mos |
T_rotor |
Status Codes¶
| Group | Code | Name | Description |
|---|---|---|---|
| Normal | 0x0 |
DISABLED | Motor is disabled |
| Normal | 0x1 |
ENABLED | Motor is enabled and ready |
| Fault | 0x8 |
OVER_VOLTAGE | Over-voltage protection triggered (threshold: OV_Value reg 29) |
| Fault | 0x9 |
UNDER_VOLTAGE | Under-voltage protection triggered (threshold: UV_Value reg 0) |
| Fault | 0xA |
OVER_CURRENT | Over-current protection triggered (threshold: OC_Value reg 3) |
| Fault | 0xB |
MOS_OVER_TEMP | MOSFET over-temperature protection triggered (threshold: OT_Value reg 2) |
| Fault | 0xC |
ROTOR_OVER_TEMP | Rotor over-temperature protection triggered (threshold: OT_Value reg 2) |
| Fault | 0xD |
LOST_COMM | Communication timeout/loss detected (related: TIMEOUT reg 9, where 1 register unit = 50 microseconds) |
| Fault | 0xE |
OVERLOAD | Motor overload detected |
5. Register Reply Messages
Register read replies are STD frames:
| Arbitration ID | Attribute | D[0] | D[1] | D[2] | D[3] | D[4] | D[5] | D[6] | D[7] |
|---|---|---|---|---|---|---|---|---|---|
feedback_id (MST_ID, reg 7) |
STD |
CANID_L |
CANID_H |
0x33 |
RID |
data_b0 |
data_b1 |
data_b2 |
data_b3 |
Data Encoding¶
Position/Velocity/Torque Encoding
Position, velocity, and torque values are encoded using a mapping function:
Where:
- x_{\min} and x_{\max} are motor-specific limits (from motor type presets; see PMAX / VMAX / TMAX defaults)
- N is the bit width (16 for position, 12 for velocity/torque)
- u is the encoded unsigned integer value
Decoding reverses this process:
Stiffness/Damping Encoding
Stiffness (kp) and damping (kd) use fixed ranges:
- Stiffness: 0-500 (12-bit encoding)
- Damping: 0-5 (12-bit encoding)
Multi-Motor Communication¶
Multiple motors can share the same CAN bus:
- Each motor has a unique
motor_id(ESC_ID, register 8) - Each motor has a
feedback_id(MST_ID, register 7); unique assignment is recommended - Commands are addressed to specific
motor_id - Feedback is identified by
feedback_id
@remarks
Each motor has a unique feedback_id (MST_ID, register 7) that identifies the motor in feedback messages.
While the feedback_id does not strictly need to be unique for each motor (since the motor ID is included in the data frame),
it is recommended to assign unique feedback_ids to avoid confusion and simplify message routing.
@see Message frame structure for details on motor ID encoding in feedback messages.
Example: Three Motors
Motor ID assignment:
| Motor | motor_id (ESC_ID, reg 8) |
feedback_id (MST_ID, reg 7) |
|---|---|---|
| Motor 1 | 0x01 |
0x11 |
| Motor 2 | 0x02 |
0x12 |
| Motor 3 | 0x03 |
0x13 |
MIT mode command arbitration IDs (arbitration_id = motor_id):
| Motor | Arbitration ID |
|---|---|
| Motor 1 | 0x001 |
| Motor 2 | 0x002 |
| Motor 3 | 0x003 |
Feedback arbitration IDs (arbitration_id = feedback_id):
| Motor | Arbitration ID |
|---|---|
| Motor 1 | 0x011 |
| Motor 2 | 0x012 |
| Motor 3 | 0x013 |
Error Handling¶
Timeout Protection
- Register operations have timeout protection
- If no reply received within timeout, operation fails
- Motor has CAN timeout alarm (TIMEOUT register 9); Register 9 stores timeout in units of 50 microseconds (1 register unit = 50 microseconds), and motor disables if no commands are received
- Timeout-related status is reported as LOST_COMM (
0xD)
Error States
- Motor enters error state on various conditions (overcurrent, overtemperature, etc.)
- Error state is reported in feedback status byte
- Use clear error command to reset error state
Protocol Limitations¶
- Message size: Fixed 8 bytes (CAN limitation)
- Arbitration ID range: 0x000-0x7FF (11-bit standard CAN)
- Bitrate: Must match across all devices
- Real-time: No guaranteed delivery time (best-effort)
Further Reading¶
- See Motor Control Modes for control mode details
- See CAN Bus Fundamentals for CAN bus basics
- For interactive understanding of control modes, use
damiao gui - See API Reference for implementation details