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