Files
proxi-ai/agent/proxi-control.md
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

234 lines
8.1 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
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