Files
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

186 lines
6.7 KiB
Markdown

# Einrichtung
Zwei Schritte: Firmware auf den micro:bit, Brücke auf irgendeinen Rechner mit
Bluetooth.
```
KI / LLM --HTTP--> proxi_bridge.py --BLE--> micro:bit im Proxi
(Pi Zero W, Laptop, ...)
```
## 1. Firmware flashen
Läuft auf micro:bit **V1 und V2** — die `.hex` ist ein Universal Hex und
enthält beides.
1. micro:bit per USB anschließen — er meldet sich als Laufwerk `MICROBIT`
2. [`firmware/proxi-ai.hex`](../firmware/proxi-ai.hex) darauf kopieren
3. Die gelbe LED blinkt, das Laufwerk verschwindet und kommt zurück — fertig
Danach zeigt Proxi ein schlafendes Gesicht: Firmware läuft, wartet auf
Bluetooth.
Ein Nachflashen ist nie nötig. Alles Weitere passiert über Befehle.
### Selbst bauen
Nur nötig, wenn du am Code etwas änderst.
```bash
cd firmware/proxi-ai
npm install pxt
./node_modules/.bin/pxt target microbit
./node_modules/.bin/pxt install
./build.sh # -> proxi-ai.hex
```
Der C++-Teil wird vom MakeCode-Build-Service kompiliert, dafür braucht der
erste Build Internet. `build.sh` prüft am Ende, ob die erzeugte `.hex`
tatsächlich den aktuellen `main.ts` enthält.
Auf dem V1 ist der Flash mit Bluetooth-Stack fast voll. Kommt beim Erweitern
`program too big by ... bytes`, betrifft das die V1-Variante.
Alternativ im Browser: [makecode.microbit.org](https://makecode.microbit.org)
öffnen, neues Projekt, in der JavaScript-Ansicht `main.ts` einfügen, über den
Explorer eine Datei `proxi.ts` anlegen und deren Inhalt einfügen. Die
Bluetooth-Extension muss hinzugefügt und in den Projekteinstellungen
`bluetooth.open` auf `1` gesetzt werden — sonst verlangt der micro:bit Pairing
und die Brücke kommt nicht rein.
## 2. Brücke einrichten
Läuft auf allem mit Linux und Bluetooth. Ein Pi Zero W reicht.
```bash
pip3 install bleak
cd bridge
python3 proxi_bridge.py --scan
```
Ausgabe etwa:
```
C4:1F:2B:AA:BB:CC BBC micro:bit [tuvig]
```
Testen:
```bash
python3 proxi_bridge.py --ping
python3 proxi_bridge.py "FACE:HEART" "MOVE:FWD:1000" "DANCE:2"
python3 proxi_bridge.py --script demo.txt
python3 proxi_bridge.py -i # interaktiv
```
Die Adresse lässt sich festnageln, das spart den Suchlauf:
```bash
export PROXI_ADDRESS=C4:1F:2B:AA:BB:CC
```
## 3. HTTP-API für die KI
```bash
python3 proxi_bridge.py --serve 8080
```
| Route | Zweck |
|---|---|
| `POST /command` | `{"command": "MOVE:FWD:1000"}` |
| `POST /commands` | `{"commands": ["FACE:HAPPY", "DANCE:2"]}` |
| `GET /status` | Verbindungszustand und die letzten Meldungen vom Roboter |
```bash
curl -X POST localhost:8080/command \
-H 'Content-Type: application/json' \
-d '{"command":"DANCE:3"}'
```
```json
{"command": "DANCE:3", "response": "OK:DANCE:3", "ok": true}
```
> ### ⚠️ Nur im eigenen Netz betreiben
>
> Die API hat **keine Authentifizierung**. Wer sie erreicht, fährt den Roboter —
> ohne Passwort, ohne Rückfrage.
>
> Im heimischen WLAN ist das unproblematisch und bewusst so gehalten: es soll
> ohne Hürden funktionieren. **Aber gib den Port nicht nach außen frei** und
> richte keine Portweiterleitung darauf ein. Sonst lässt sich ein Roboter, der
> im Kinderzimmer herumfährt, von jedem beliebigen Fremden steuern.
>
> Soll er über das Heimnetz hinaus erreichbar sein, gehört ein VPN davor —
> nicht eine Portfreigabe.
Im `--serve`-Modus startet der HTTP-Server **sofort** und sucht den Roboter
danach im Hintergrund, alle 10 Sekunden. Die API ist damit auch erreichbar,
wenn Proxi gerade aus ist — `GET /status` meldet dann `"connected": false`,
Befehle antworten mit `ERR:not_connected`. Sobald Proxi eingeschaltet wird,
verbindet sich die Brücke von selbst; niemand muss sich einloggen.
Das ist der Unterschied zu den interaktiven Modi: die brechen sofort ab, wenn
der Roboter nicht da ist, weil man dort auf eine Antwort wartet.
Als Autostart auf einem Pi:
```ini
# /etc/systemd/system/proxi-bridge.service
[Unit]
Description=Proxi BLE Bridge
After=bluetooth.target
[Service]
ExecStart=/usr/bin/python3 /home/pi/proxi/proxi_bridge.py --serve 8080
Environment=PROXI_ADDRESS=C4:1F:2B:AA:BB:CC
Restart=always
RestartSec=5
User=pi
[Install]
WantedBy=multi-user.target
```
## 4. KI anbinden
[`agent/proxi-control.md`](../agent/proxi-control.md) ist ein fertiger
Agent-Skill: er enthält das Protokoll und die Regeln, nach denen aus
"lass ihn tanzen" eine Befehlsfolge wird.
Der Skill enthält **keine feste Adresse** — er erwartet sie in der
Umgebungsvariablen `PROXI_URL`. Die muss in der Umgebung des Agenten gesetzt
sein:
```bash
export PROXI_URL=http://<hostname-des-pi>.local:8080
# oder, falls der Name nicht auflöst:
export PROXI_URL=http://<ip-des-pi>:8080
```
Absichtlich so: die Adresse hängt vom eigenen Netz ab und hat in einer Datei,
die weitergegeben wird, nichts verloren.
**mDNS-Namen (`*.local`) funktionieren nur im selben Netz.** Sitzt der Agent in
einem anderen VLAN als der Pi, nimm die IP-Adresse — oder aktiviere im Router
die mDNS-Weiterleitung.
Der Agent braucht **nur HTTP-Zugriff**, weder das Repo noch Python. Er soll
`proxi_bridge.py` ausdrücklich nicht selbst starten: Bluetooth LE erlaubt nur
eine Verbindung zum Roboter, und die hält der Dienst.
## Wenn etwas klemmt
| Symptom | Ursache |
|---|---|
| `--scan` findet nichts | Proxi aus, oder schon mit einem anderen Gerät verbunden — BLE erlaubt nur eine Verbindung |
| Verbindung bricht sofort ab | Firmware ohne `bluetooth.open=1` gebaut, der micro:bit verlangt dann Pairing |
| Befehle kommen mit `OK` zurück, Proxi bewegt sich nicht | `SENSOR:PWR` prüfen. `0` heißt: Enable-Leitung P8 ist low, meist der Batterieschalter |
| Antworten bleiben aus, Befehle wirken | Auf dem falschen Characteristic gelauscht. Host schreibt auf `…0003`, der micro:bit meldet sich auf `…0002` |
| Lange `TEXT:`-Zeilen abgeschnitten | BLE-Attribute sind 20 Byte, längere Zeilen müssen gestückelt werden — `proxi_bridge.py` macht das |
| Dienst startet immer wieder neu, Port nie offen | Alte Fassung: die Brücke verband sich zuerst und startete den Server danach. Ab Werk behoben — im `--serve`-Modus kommt der Server zuerst |
| Pi nach dem Abziehen des Kabels nicht mehr da | Er hat per WLAN eine **andere** Adresse als per Kabel. `avahi-daemon` installieren, dann geht `<hostname>.local`. mDNS bleibt aber im eigenen Netz — über VLAN-Grenzen hinweg braucht es einen mDNS-Repeater im Router |
| Display bleibt schwarz | Firmware ohne Bluetooth-Extension gebaut, `bluetooth.startUartService()` stirbt dann still beim Start |
| Ton kracht, Proxi hängt, Verbindung weg | Eine Frequenz kam als Kommazahl in `music.playTone()`. Siehe HARDWARE.md, "Ton: keine Kommazahlen" |
| Ein behobener Fehler tritt wieder auf | Vermutlich läuft noch die alte Firmware. `STATUS` schicken und die Build-Kennung dahinter mit der Ausgabe von `build.sh` vergleichen |