Dobot Magician: Kommunikation per USB-Serial
Ausgangsfrage
Es ging um die Frage, wie Anfragen an den Dobot Magician über den USB-to-Serial-Port gesendet werden.
Als Beispiel diente der Befehl:
GetDeviceSN
Quelle der Information war das offizielle Kommunikationsprotokoll:
Dobot Communication Protocol V1.1.5
Grundprinzip
Der Dobot Magician erwartet über die serielle Schnittstelle keine Klartextbefehle.
Man sendet also nicht:
GetDeviceSN
sondern ein binäres Datenpaket.
Der Befehlsname GetDeviceSN ist nur die lesbare Bezeichnung aus der Dokumentation.
Serielle Verbindung
Typische Einstellungen für die Verbindung:
Baudrate: 115200
Datenbits: 8
Stoppbits: 1
Parität: keine
Allgemeiner Paketaufbau
Ein Befehlspaket hat folgenden Aufbau:
AA AA LEN ID CTRL PARAMS... CHECKSUM
| Teil | Bedeutung |
|---|---|
AA AA |
Header / Startkennung |
LEN |
Länge des Payloads |
ID |
Befehls-ID |
CTRL |
Steuerbyte |
PARAMS |
Parameter, falls vorhanden |
CHECKSUM |
Prüfsumme |
Beispiel: GetDeviceSN
Für den Befehl GetDeviceSN gilt:
| Teil | Wert | Bedeutung |
|---|---|---|
| Header | AA AA |
Startkennung |
| LEN | 02 |
Payload besteht aus ID und CTRL |
| ID | 00 |
Befehls-ID für GetDeviceSN |
| CTRL | 00 |
Lesen, nicht queued |
| PARAMS | keine | Der Befehl benötigt keine Parameter |
| CHECKSUM | 00 |
Prüfsumme |
Das vollständige Paket lautet:
AA AA 02 00 00 00
Bedeutung des Control-Bytes
Das Control-Byte enthält unter anderem Informationen darüber, ob ein Befehl gelesen oder geschrieben wird und ob er in die Queue gestellt werden soll.
Für GetDeviceSN:
CTRL = 00
Bedeutung:
rw = 0
isQueued = 0
Das heißt:
- Es handelt sich um eine Leseanfrage.
- Der Befehl wird nicht in die Bewegungs-Queue gestellt.
Berechnung der Checksumme
Die Checksumme wird über den Payload berechnet.
Beim Beispiel GetDeviceSN ist der Payload:
00 00
Also:
ID = 00
CTRL = 00
Die Summe ist:
00 + 00 = 00
Die Checksumme ist das Zweierkomplement dieser Summe:
checksum = (-sum(payload)) & 0xFF
Für dieses Beispiel ergibt sich:
CHECKSUM = 00
Einfachstes Python-Beispiel
import serial
PORT = "COM5"
BAUDRATE = 115200
with serial.Serial(PORT, BAUDRATE, bytesize=8, parity="N", stopbits=1, timeout=1) as ser:
ser.write(bytes.fromhex("AA AA 02 00 00 00"))
answer = ser.read(100)
print(answer.hex(" "))
Besseres Python-Beispiel mit Paketfunktion
import serial
PORT = "COM5"
BAUDRATE = 115200
def checksum(payload: bytes) -> int:
return (-sum(payload)) & 0xFF
def make_packet(cmd_id: int, rw: int = 0, is_queued: int = 0, params: bytes = b"") -> bytes:
ctrl = (rw & 0x01) | ((is_queued & 0x01) << 1)
payload = bytes([cmd_id, ctrl]) + params
length = len(payload)
return bytes([0xAA, 0xAA, length]) + payload + bytes([checksum(payload)])
packet = make_packet(cmd_id=0, rw=0, is_queued=0)
print("Sende:", packet.hex(" "))
with serial.Serial(PORT, BAUDRATE, bytesize=8, parity="N", stopbits=1, timeout=1) as ser:
ser.write(packet)
answer = ser.read(100)
print("Antwort:", answer.hex(" "))
Merksatz
Der Befehl GetDeviceSN wird nicht als Text gesendet.
Stattdessen wird dieses Bytepaket gesendet:
AA AA 02 00 00 00
In Python:
ser.write(bytes.fromhex("AA AA 02 00 00 00"))
Didaktischer Hinweis
Dieses Beispiel eignet sich gut, um Schülern den Unterschied zwischen folgenden zwei Ebenen zu zeigen:
- Befehlsname in der Dokumentation
GetDeviceSN - Tatsächlich gesendete Bytes auf der seriellen Schnittstelle
AA AA 02 00 00 00
Bei der Kommunikation mit dem Dobot Magician werden binäre Telegramme gesendet, keine Klartextbefehle.