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.
This commit is contained in:
2026-08-22 11:41:00 +00:00
commit 3905647b7f
26 changed files with 22414 additions and 0 deletions
+233
View File
@@ -0,0 +1,233 @@
---
name: proxi-control
description: Steuert den Proxi-Roboter. Nutze diesen Skill, wenn jemand will, dass Proxi etwas tut — laufen, tanzen, sich umschauen, ein Gesicht zeigen, etwas sagen, Hindernisse suchen.
---
# Proxi steuern
Proxi ist ein kleiner zweibeiniger Roboter mit einem micro:bit als Kopf. Du
schickst ihm Textbefehle über die Brücke und übersetzt damit, was der Mensch
in Alltagssprache will.
## Befehle senden
Du brauchst **keine Dateien und kein Python**. Die Brücke läuft als Dienst auf
dem Raspberry Pi und ist über HTTP erreichbar — `curl` genügt.
Die Adresse der Brücke steht in der Umgebungsvariablen `PROXI_URL`:
```bash
PROXI="${PROXI_URL:?PROXI_URL ist nicht gesetzt — Adresse der Proxi-Brücke, z.B. http://proxi.local:8080}"
```
Ist sie nicht gesetzt, sag das dem Menschen, statt eine Adresse zu raten. Sie
hängt davon ab, wo die Brücke läuft — typisch ist der Hostname des
Raspberry Pi plus Port 8080, notfalls dessen IP-Adresse.
Ein einzelner Befehl:
```bash
curl -sX POST $PROXI/command \
-H 'Content-Type: application/json' \
-d '{"command":"MOVE:FWD:1000"}'
```
Mehrere am Stück — die Brücke arbeitet sie der Reihe nach ab, inklusive der
`WAIT`-Pausen. **So schickst du Choreografien:**
```bash
curl -sX POST $PROXI/commands \
-H 'Content-Type: application/json' \
-d '{"commands":["FACE:HAPPY","MELODY:FUNK","TURN:LEFT:400","WAIT:450","TURN:RIGHT:400","WAIT:450","STOP"]}'
```
Nachsehen, ob Proxi überhaupt da ist:
```bash
curl -s $PROXI/status # {"connected": true, ...}
```
Steht dort `"connected": false`, ist Proxi ausgeschaltet oder außer Reichweite.
Sag das dem Menschen, statt Befehle ins Leere zu schicken — die Brücke
verbindet sich von selbst, sobald er eingeschaltet wird.
### Nicht selbst starten
`proxi_bridge.py` brauchst du nicht und sollst du **nicht** aufrufen. Das Skript
liegt auf dem Pi und läuft dort bereits als Dienst. Eine zweite Instanz würde
scheitern: Bluetooth LE erlaubt nur **eine** Verbindung zum Roboter, und die
hält der Dienst. Alles läuft über HTTP.
## Was Proxi kann
| Befehl | Wirkung |
|---|---|
| `MOVE:FWD[:ms]` / `MOVE:BWD[:ms]` / `MOVE:STOP` | laufen |
| `TURN:LEFT[:ms]` / `TURN:RIGHT[:ms]` / `TURN:STOP` | Oberkörper drehen |
| `DANCE[:n]` / `STAMP[:n]` / `SHAKE[:n]` | tanzen, aufstampfen, Kopf schütteln |
| `FACE:<name>` / `FACE:RAW:z0:z1:z2:z3:z4` | Gesicht zeigen |
| `TEXT:<text>` | Text über das Display laufen lassen |
| `MELODY:<name>` / `TONE:<hz>[:ms]` | Musik und Töne |
| `SENSOR:ALL` / `SENSOR:IR_L` / `SENSOR:IR_R` | Sensoren lesen |
| `CLEAR` / `STOP` / `PING` / `STATUS` | System |
Die vollständige Liste aller Namen für `FACE` und `MELODY` steht in
[`docs/PROTOCOL.md`](../docs/PROTOCOL.md). Rate keine Namen — nimm einen aus
der Liste oder frag nach.
## Regeln
**Es gibt keine Geschwindigkeit.** Die Motoren können nur an oder aus. Alles,
was du steuerst, ist die *Dauer*. "Langsam" gibt es nicht — "kurz" schon.
Erfinde keinen Speed-Parameter.
**Realistische Zeiten.** Grobe Anhaltspunkte, jeder Untergrund ist anders:
| Was | Dauer |
|---|---|
| ein, zwei Schritte | 8001500 ms |
| durchs Zimmer | 40006000 ms |
| Vierteldrehung | ~700 ms |
| halbe Drehung | ~1400 ms |
**Zwischen Bewegungen `WAIT:<ms>` setzen.** Bewegungsbefehle kommen sofort mit
`OK` zurück und laufen dann weiter — ohne Pause überschreibt der nächste
Befehl die noch laufende Bewegung, und Proxi zuckt nur. `WAIT` ist eine Pause in
der Brücke, kein Befehl an den Roboter. Immer etwas länger als die Bewegung
davor:
```
MOVE:FWD:1200
WAIT:1400
TURN:LEFT:700
WAIT:900
```
**Immer mit `STOP` enden**, wenn eine Bewegungsfolge fertig ist.
**Ohne Dauer stoppt eine Bewegung nach 10 Sekunden von selbst.** Nutze `:0` nur,
wenn wirklich bis auf Weiteres gefahren werden soll — und dann mit einem klaren
`STOP` danach.
**Lauf- und Drehmotor sind unabhängig.** Beide zusammen ergibt eine Kurve:
`MOVE:FWD:0` plus `TURN:LEFT:800`.
**Für Choreografien: `MOVE` und `TURN` laufen parallel zur Musik, `DANCE`,
`STAMP` und `SHAKE` nicht.** Die drei Figuren teilen sich mit `MELODY` und
`TEXT` denselben Arbeiter und kommen deshalb erst dran, wenn die Melodie
fertig ist — bei `MELODY:NYAN` also 16 Sekunden später.
Soll zur Musik getanzt werden, bau die Schritte aus `MOVE` und `TURN`:
Wackeln ist `TURN:LEFT:220` / `TURN:RIGHT:220` im Wechsel, Stampfen
`MOVE:FWD:200` / `MOVE:BWD:200`, eine Kurve `MOVE:FWD:0` plus `TURN`.
`DANCE` und Co. gehören vor oder nach die Melodie, nicht mittenrein.
Ein fertiges Beispiel liegt in `bridge/nyan-dance.txt`.
**Aber immer nur ein Klang.** Ein neues `MELODY` oder `TONE` bricht das ab, was
gerade läuft. Soll eine Melodie ausklingen, gib ihr mit `WAIT` Zeit, bevor der
nächste Ton kommt.
## Kleine Choreografie
Auf "Proxi, freu dich!":
```json
{"commands": [
"FACE:FABULOUS",
"MELODY:POWERUP",
"STAMP:2", "WAIT:1200",
"TURN:LEFT:600", "WAIT:800",
"TURN:RIGHT:1200", "WAIT:1400",
"TURN:LEFT:600", "WAIT:800",
"DANCE:2", "WAIT:1500",
"FACE:HEART",
"STOP"
]}
```
## Eine Choreografie zur Musik bauen
Das ist die Königsdisziplin — und es gibt ein paar Regeln, ohne die es
auseinanderfällt. Geschickt wird eine Choreografie als eine einzige Liste an
`POST /commands`, mit `WAIT` als Taktgeber dazwischen.
**Getanzt wird mit `MOVE` und `TURN`, nicht mit `DANCE`.** Nur die beiden
laufen wirklich parallel zur Musik.
**Melodien reihen sich von selbst aneinander.** Schickst du `MELODY:B`,
während A noch läuft, startet B nahtlos danach. So baust du mehrteilige
Stücke.
**Rechne mit den Laufzeiten.** So lange spielt jede Melodie:
| | |
|---|---|
| ~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` |
**`WAIT` ist rund 150 ms kürzer als die Bewegung davor** — so lange braucht
die Brücke selbst zwischen zwei Befehlen. Ohne diesen Abzug läuft der Tanz
der Musik davon.
**Tanzschritte bestehen aus drei Bausteinen:**
```
Wackeln TURN:LEFT:220 / TURN:RIGHT:220 im Wechsel
Stampfen MOVE:FWD:200 / MOVE:BWD:200 im Wechsel
Kurve MOVE:FWD:0 + TURN währenddessen, danach MOVE:STOP
```
Kurze Zeiten wirken hektisch, lange gemütlich. Genau daraus entsteht Rhythmus.
**Ein vollständiges Beispiel** (vier Teile, 30 Sekunden) steht kommentiert in
`bridge/bigdance.txt` im Repo. Die Zeilen dort sind genau die Liste, die an
`POST /commands` geht — Zeilen mit `#` sind Kommentare und werden weggelassen.
**Jeder Abschnitt bekommt ein eigenes Gesicht** — das macht aus einer
Bewegungsfolge eine Aufführung.
**Gleich viel vorwärts wie rückwärts**, dann bleibt Proxi ungefähr da, wo
er losgetanzt ist. Und am Ende immer `STOP`.
## Sensoren nutzen
`SENSOR:IR_L` und `SENSOR:IR_R` liefern 01023, **höher heißt näher**.
Am Gerät gemessen: freie Sicht 515, Hand in etwa 10 cm 200600, direkt davor
bis ~980. Ab 400 steht etwas im Weg — das entspricht ungefähr einer Handbreit.
**Proxi kann kein Licht messen.** Der Helligkeitssensor sitzt hinter einer
getönten Scheibe und ist deshalb nicht angeschlossen. Sag nicht, Proxi könne
sehen, ob es hell oder dunkel ist — er kann es nicht.
Soll Proxi einem Hindernis ausweichen, fahr in kurzen Etappen und miss dazwischen,
statt blind eine lange Strecke zu setzen:
```
SENSOR:ALL -> SENSOR:ALL:IR_L=12,IR_R=640,...
rechts ist was -> nach links ausweichen
TURN:LEFT:700
WAIT:900
MOVE:FWD:1200
WAIT:1400
SENSOR:ALL
```
## Wenn nichts passiert
Kommt `OK` zurück, aber Proxi bewegt sich nicht: `SENSOR:PWR` abfragen. Steht da
`0`, ist Proxis Schalter aus (der micro:bit hängt dann nur am USB-Strom). Sag
das dem Menschen, statt weiter Fahrbefehle zu schicken.
## Sicherheit
Proxi fährt auf dem Boden herum, oft mit einem Kind daneben.
* Keine Dauerfahrten ohne Zeitlimit
* Nach jeder Folge `STOP`
* Taste A am Roboter ist der Not-Stopp und geht immer, auch ohne Verbindung
* Wenn jemand "Stopp" sagt: sofort `STOP` schicken, Nachfragen kommen danach