SPI to RS485
The following protocol applies to firmware V4.1 or later
Send the AT+VER serial command to check the firmware version; if no version is returned or it shows V33, please update to the latest firmware
The SANPO Motor Debug Tool can generate test code quickly and supports CAN/RS485 motors
Protocol Overview
Use Case |
Wiring |
TX Protocol (SPI->RS485) |
RX Protocol (RS485->SPI) |
|---|---|---|---|
RS485 motors (fixed 23-byte frames) |
CS1 controls RS485-1/RS485-2; CS2 controls RS485-3/RS485-4 |
Transparent, fixed length 23 bytes. Last 3 bytes reserved: last is CRC, second last is valid data length, third last is Channel. |
Transparent, fixed length 23 bytes. Last 3 bytes reserved: last is CRC, second last is valid data length, third last is Channel. |
The first two bytes of RS485 frames must not be the reserved headers 0x45 0x54, 0x41 0x54, or 0x53 0x54
Frame Examples
TX frame
RS485 data passthrough (pad to 20 bytes with 0x00) |
Channel |
Data length |
CRC (1 byte) |
|---|---|---|---|
0x22 0x33 0x00 0x53 0x54 0x00 0x53 0x54 0x00 0x53 0x54 0x00 0x53 0x54 0x00 0x53 0x54 0x00 0x00 0x00 |
0x00 |
0x17 |
0x0F |
RX frame
RS485 feedback passthrough |
Channel |
Data length |
CRC (1 byte) |
|---|---|---|---|
0x22 0x33 0x00 0x53 0x54 0x00 0x53 0x54 0x00 0x53 0x54 0x00 0x53 0x54 0x00 0x53 0x00 0x00 0x00 0x00 |
0x00 |
0x16 |
0x0F |
Code Snippet (SPI to RS485, Python)
Full example: spi_unitree_GO_M8010_demo_v4.py
# TX: motor command data (<=20 bytes, pad with 0x00) + Channel + Data length + CRC
def build_spi_rs485_frame(cmd: bytes, channel: int) -> bytes:
data_bytes = bytearray(cmd[:20])
data_len = len(data_bytes)
if data_len < 20:
data_bytes.extend([0x00] * (20 - data_len))
payload = bytes(data_bytes) + bytes([channel & 0xFF, data_len])
crc = crc8_calculator.calculate(payload)
return payload + bytes([crc]) # fixed length 23 bytes
tx = build_spi_rs485_frame(cmd, channel=0x00)
rx = spi.xfer2(list(tx)) # fixed length 23 bytes
# RX parse: CRC check + read valid data length
data_part = rx[:22]
crc_ok = crc8_calculator.calculate(data_part) == rx[22]
data_len = rx[21]
motor_data = rx[:data_len]
Examples
SPI to RS485 example (Python): Download
SPI uses fixed 23-byte frames by default