Der Roboter Dobot Magician - GetDeviceSN per USB-Serial.

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:

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:

  1. Befehlsname in der Dokumentation
    GetDeviceSN
  2. 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.