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:
@@ -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 | 800–1500 ms |
|
||||
| durchs Zimmer | 4000–6000 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,5–1 s | `BADING` `JUMPUP` `JUMPDOWN` `POWERUP` `POWERDOWN` |
|
||||
| ~2,5–3,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 0–1023, **höher heißt näher**.
|
||||
Am Gerät gemessen: freie Sicht 5–15, Hand in etwa 10 cm 200–600, 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
|
||||
Reference in New Issue
Block a user