Files
proxi-ai/docs/PROTOCOL.md
T
christian 3905647b7f Proxi AI — Spielzeug-Roboter mit natürlicher Sprache steuern
Firmware, Bluetooth-Brücke und Agent-Skill für den KOSMOS-Proxi: einmal
flashen, danach hört der Roboter über Bluetooth LE auf Textbefehle. Was die
Befehle schickt, ist ihm egal — ein Skript, ein curl, oder ein KI-Agent, der
aus "mach mal was Lustiges" eine Choreografie baut.

  firmware/   MakeCode-Projekt (TypeScript) und fertige .hex für V1 und V2
  bridge/     BLE-Brücke und HTTP-API, einzige Abhängigkeit ist bleak
  agent/      Skill-Definition: Alltagssprache -> Befehle
  tools/      Quelltext aus .hex extrahieren, Musik-Tabellen prüfen
  docs/       Protokoll, Einrichtung, Hardware, Lizenzen

Zwei Dinge, die sonst nirgends stehen und in docs/HARDWARE.md dokumentiert
sind: die Pin-Belegung des Roboters ist nicht öffentlich, sie wurde aus den
mitgelieferten .hex-Dateien rekonstruiert (tools/hex_source.py holt sie
heraus). Und der Ton braucht zwingend eine ganzzahlige Frequenz sowie Pin P0
— sonst kracht der Lautsprecher, der Aufruf hängt und die Bluetooth-
Verbindung stirbt.

Am echten Roboter durchgetestet: Verbindung, Sensoren, Display, 41 Sekunden
Musik am Stück, alle Bewegungsrichtungen, Musik und Fahren gleichzeitig,
Tanzfiguren, Not-Stopp mitten in der Bewegung, Autostart nach Neustart.

MIT-Lizenz. Die Hardware-Extension stammt von kaku111 (TobbieII) und die
Notendaten aus pxt-microbit, beide ebenfalls MIT — siehe THIRD-PARTY-NOTICES.
2026-08-22 11:41:00 +00:00

7.5 KiB
Raw Blame History

Proxi Command Protocol 1.0

Textbefehle über Bluetooth-LE-UART. Ein Befehl pro Zeile, eine Antwortzeile zurück.

BEFEHL:PARAM:PARAM\n   ->   OK:...\n | ERR:...\n | <Wert>\n
  • Befehlsname und Schlüsselwörter sind nicht groß-/kleinschreibungsabhängig
  • Parameter trennt :
  • Jede Zeile endet mit \n
  • Fehlende Parameter fallen auf den Default zurück, unlesbare ebenso
  • Es gibt keinen Speed-Parameter — die Motoren können nur an oder aus, siehe HARDWARE.md

Dauer-Parameter

Alle Bewegungsbefehle nehmen als letzten Parameter eine Dauer in Millisekunden.

Angabe Wirkung
weggelassen fährt los und stoppt nach 10 s von selbst (Sicherheitsnetz)
1..60000 fährt genau so lange und stoppt
0 fährt weiter, bis ein Stopp-Befehl kommt

Die Firmware blockiert während der Fahrt nicht: der Befehl wird sofort mit OK quittiert, ein Watchdog schaltet die Motoren zur Deadline ab. STOP kommt deshalb auch mitten in einer laufenden Bewegung durch.

Bewegung

Befehl Wirkung
MOVE:FWD[:ms] vorwärts laufen
MOVE:BWD[:ms] rückwärts laufen
MOVE:STOP Laufmotor aus
TURN:LEFT[:ms] Oberkörper nach links drehen
TURN:RIGHT[:ms] nach rechts drehen
TURN:STOP Drehmotor aus
STOP alles aus: beide Motoren, Ton, Display, laufende Jobs

Lauf- und Drehmotor sind unabhängig. Beide gleichzeitig ergibt eine Kurve:

MOVE:FWD:0
TURN:LEFT:800

Bewegungsfiguren

Laufen im Hintergrund und melden sich mit DONE:<name>, wenn sie fertig sind — oder mit DONE:<name>:aborted, wenn STOP oder Taste A dazwischenkam.

Befehl Default Wirkung
DANCE[:n] 2 n Takte tanzen (vor/zurück + links/rechts)
STAMP[:n] 3 n mal aufstampfen
SHAKE[:n] 3 n mal den Kopf schütteln

n wird auf 1..20 begrenzt.

Sie laufen nicht parallel zur Musik. DANCE, STAMP, SHAKE, TEXT, TONE und MELODY teilen sich einen Arbeiter und werden nacheinander abgearbeitet — eine Figur startet also erst, wenn die Melodie durch ist. MOVE und TURN laufen dagegen sofort und damit echt gleichzeitig zur Musik. Für eine Choreografie zur Melodie deshalb MOVE/TURN verwenden; ein Beispiel liegt in bridge/nyan-dance.txt.

Display

Befehl Wirkung
FACE:<name> Symbol anzeigen (bleibt stehen)
FACE:RAW:z0:z1:z2:z3:z4 eigenes 5×5-Bild, je Zeile eine Bitmaske 031
TEXT:<text> Text durchlaufen lassen, danach Display leer
CLEAR Display löschen

Namen für FACE: HAPPY SAD ANGRY CONFUSED ASLEEP SURPRISED SILLY FABULOUS MEH YES NO HEART SMALLHEART SKULL GHOST DUCK HOUSE GIRAFFE COW RABBIT SNAKE BUTTERFLY TORTOISE STICKFIGURE TARGET DIAMOND SQUARE TRIANGLE UMBRELLA SWORD NORTH EAST SOUTH WEST

Bei FACE:RAW ist in jeder Zeilen-Bitmaske Bit 0 die linke LED:

FACE:RAW:0:10:0:17:14      # zwei Augen, lächelnder Mund

TEXT darf : enthalten — alles ab dem ersten Parameter gilt als Text.

Ton

Befehl Default Wirkung
TONE:<hz>[:ms] 440, 400 einzelner Ton (505000 Hz, 105000 ms)
MELODY:<name> eingebaute Melodie, spielt im Hintergrund

Namen für MELODY: DADADUM ENTERTAINER PRELUDE ODE NYAN RINGTONE FUNK BLUES BIRTHDAY WEDDING FUNERAL PUNCHLINE BADDY CHASE BADING WAWAWAWAA JUMPUP JUMPDOWN POWERUP POWERDOWN

Laufzeiten (für Choreografien):

~0,51 s BADING JUMPUP JUMPDOWN POWERUP POWERDOWN
~2,53,5 s WAWAWAWAA PUNCHLINE RINGTONE BADDY ENTERTAINER FUNERAL
~4 s DADADUM FUNK
~8 s CHASE WEDDING PRELUDE
~12 s BIRTHDAY BLUES
~16 s ODE NYAN

Mehrere MELODY hintereinander reihen sich in der Warteschlange und spielen nahtlos nacheinander.

Sensoren

Befehl Antwort
SENSOR:ALL SENSOR:ALL:IR_L=..,IR_R=..,TEMP=..,PWR=..
SENSOR:IR_L SENSOR:IR_L:<0..1023> — höher = Hindernis näher
SENSOR:IR_R SENSOR:IR_R:<0..1023>
SENSOR:TEMP SENSOR:TEMP:<°C> (Prozessortemperatur, träge)
SENSOR:PWR SENSOR:PWR:<0|1> — Zustand von P8, siehe HARDWARE.md

Ohne Parameter verhält sich SENSOR wie SENSOR:ALL.

IR-Werte, am Gerät gemessen:

Situation Wert
freie Sicht 515
Hand in ~20 cm 3090
Hand in ~10 cm 200600
Hand direkt davor bis ~980

Als Hindernis-Schwelle taugen die 400600, die auch Kosmos' eigene Programme verwenden — das entspricht etwa einer Handbreit Abstand. Beide Sensoren erreichen den vollen Bereich; ein dauerhaft niedriger Wert auf einer Seite ist also ein Defekt und keine Eigenart.

System

<build> ist eine siebenstellige Kennung des Quellstands, die build.sh aus main.ts, proxi.ts und pxt.json errechnet. Geflasht wird von Hand — daran sieht man, welcher Stand tatsächlich auf dem Roboter liegt. Gleicher Code ergibt immer dieselbe Kennung.

Befehl Antwort
PING PONG
STATUS STATUS:proxi-ai/1.0+<build>:PWR=<0|1>

WAIT:<ms> — Pause in der Brücke

WAIT ist kein Roboter-Befehl. Die Firmware kennt ihn nicht; proxi_bridge.py fängt ihn ab und legt die angegebene Pause ein, bevor der nächste Befehl rausgeht (maximal 60000 ms).

Er wird gebraucht, weil Bewegungsbefehle sofort mit OK quittieren und dann im Hintergrund weiterlaufen. Ohne Pause dazwischen überschreibt der nächste Befehl die noch laufende Bewegung — Proxi zuckt nur kurz:

MOVE:FWD:1200      # läuft 1,2 s ...
WAIT:1400          # ... so lange warten
TURN:LEFT:700
WAIT:900
STOP

Faustregel: WAIT etwas größer wählen als die Dauer davor.

Unaufgeforderte Meldungen

Diese Zeilen kommen ohne passenden Befehl und sind keine Antwort:

Zeile Bedeutung
READY:proxi-ai/1.0+<build> BLE verbunden, Firmware bereit — kommt oft nicht an, weil der Client die Indications meist erst kurz nach dem Verbindungsaufbau aktiviert. Verlass dich nicht darauf, nimm PING
DONE:<job> DANCE/STAMP/SHAKE/TEXT/TONE/MELODY fertig
DONE:<job>:aborted derselbe Job, aber vorzeitig gestoppt
EVENT:ESTOP Taste A gedrückt — Not-Stopp

proxi_bridge.py hält sie von den Befehlsantworten getrennt.

Fehler

Antwort Bedeutung
ERR:unknown:<CMD> Befehl gibt es nicht
ERR:MOVE:bad_dir erwartet FWD, BWD oder STOP
ERR:TURN:bad_dir erwartet LEFT, RIGHT oder STOP
ERR:FACE:unknown Symbolname unbekannt
ERR:MELODY:unknown Melodiename unbekannt
ERR:SENSOR:bad_type Sensorname unbekannt
ERR:TEXT:empty kein Text angegeben
ERR:<CMD>:busy Warteschlange voll (8 Aufträge). Betrifft TEXT, TONE, MELODY, DANCE, STAMP, SHAKE — mit WAIT entzerren

Tasten am Roboter

Funktionieren auch ohne Verbindung.

Taste Wirkung
A Not-Stopp — alles aus, sendet EVENT:ESTOP
B Status senden

Bricht die BLE-Verbindung ab, stoppen die Motoren sofort von selbst.

Beispiel

PING                          -> PONG
FACE:HAPPY                    -> OK:FACE:HAPPY
MOVE:FWD:1500                 -> OK:MOVE:FWD:1500
SENSOR:IR_L                   -> SENSOR:IR_L:612
TURN:RIGHT:700                -> OK:TURN:RIGHT:700
MELODY:POWERUP                -> OK:MELODY:POWERUP
DANCE:3                       -> OK:DANCE:3
                              -> DONE:DANCE      (später, unaufgefordert)
STOP                          -> OK:STOP