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.
234 lines
8.1 KiB
Markdown
234 lines
8.1 KiB
Markdown
---
|
||
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
|