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
+168
View File
@@ -0,0 +1,168 @@
# Proxi — Hardware
Wie der Roboter wirklich verdrahtet ist, und woher diese Angaben stammen.
## Herkunft
Kosmos dokumentiert die Pin-Belegung nirgends: die Anleitung richtet sich an
Kinder, programmiert wird ausschließlich mit den fertigen Blöcken von
[kosmos.de/proxi](https://kosmos.de/proxi). Die Angaben hier sind also nicht
abgeschrieben, sondern rekonstruiert.
Möglich ist das, weil MakeCode jedes Projekt komprimiert an die kompilierte
Firmware anhängt. Die `.hex`-Dateien der Kosmos-Beispielprogramme (Download
über [kosmos.de/proxi](https://kosmos.de/proxi)) enthalten damit ihren eigenen
Quelltext. Herausholen lässt er sich mit dem Werkzeug in diesem Repo:
```bash
python3 tools/hex_source.py 00_Funktionstest.hex -o ./quellen
```
Die interessante Datei darin ist `custom.ts`: die Kosmos-Extension mit allen
Hardware-Zugriffen. Sie liegt hier unverändert als
[`firmware/proxi.ts`](../firmware/proxi.ts) — wer wissen will,
wie sich eine Funktion in Grenzfällen verhält, liest am besten dort nach.
Sie ist eine eingedeutschte Fassung der MIT-lizenzierten Extension
[`kaku111/20190209`](https://github.com/kaku111/20190209) für den **Tobbie II**.
Proxi ist derselbe Roboter unter anderem Namen — Kosmos' eigenes Programm
`12_APP_Fernbedienung` hängt noch direkt an dieser Extension:
```json
"TobbieII": "github:kaku111/20190209#9c728847d1a08815275108ec42009211d57c2f0d"
```
Herkunft und Lizenzen im Detail: [LICENSES.md](LICENSES.md).
## Pin-Belegung
| Pin | Richtung | Funktion |
|---|---|---|
| **P13** | Ausgang | Laufmotor vorwärts |
| **P14** | Ausgang | Laufmotor rückwärts |
| **P15** | Ausgang | Drehmotor links (Oberkörper/Kopf) |
| **P16** | Ausgang | Drehmotor rechts |
| **P12** | Ausgang | IR-Sendediode (Messpuls) |
| **P1** | Analog-Eingang | IR-Empfänger links |
| **P2** | Analog-Eingang | IR-Empfänger rechts |
| **P8** | Digital-Eingang | Enable — wird vor jeder Bewegung geprüft |
| **P0** | Ausgang | Summer (Standard-Audiopin des micro:bit) |
### Motoren
Zwei Motoren, beide an einer H-Brücke mit **zwei digitalen Leitungen**
eine je Drehrichtung:
```
P13=1, P14=0 -> vorwärts
P13=0, P14=1 -> rückwärts
P13=0, P14=0 -> aus
P15=1, P16=0 -> Drehung nach links
P15=0, P16=1 -> Drehung nach rechts
P15=0, P16=0 -> aus
```
**Es gibt keine Geschwindigkeitsregelung.** Kein PWM, kein Servo, keine
Zwischenstufen — ein Motor läuft oder er läuft nicht. Gesteuert wird
ausschließlich über die Dauer, deshalb hat kein Befehl im
[Protokoll](PROTOCOL.md) einen Speed-Parameter.
Der Laufmotor bewegt die Beine, der Drehmotor den Oberkörper. Laufen beide
gleichzeitig, geht Proxi eine Kurve.
### IR-Sensoren
Gemessen wird als Differenz, damit Umgebungslicht herausfällt:
1. Empfänger analog lesen (Grundhelligkeit)
2. Sendediode P12 einschalten
3. 250 µs warten
4. Empfänger erneut lesen
5. Sendediode aus — Messwert ist die Differenz beider Messungen
Hoher Wert = Hindernis nah. Am Gerät gemessen: freie Sicht 5-15, Hand in etwa
10 cm 200-600, Hand direkt davor bis ~980. Beide Seiten erreichen den vollen
Bereich. Die Schwellen 400-600 aus Kosmos' eigenen Programmen entsprechen damit
ungefähr einer Handbreit Abstand.
### Helligkeitssensor: durch die Scheibe blockiert
Den gibt es hier nicht, und zwar aus einem Grund, den keine Software behebt.
`input.lightLevel()` misst über die LED-Matrix — und die sitzt bei Proxi
hinter einer **getönten Scheibe**. Nimmt man die weg, misst der Sensor
einwandfrei. Eingebaut liefert er konstant 0, auch mit einer Taschenlampe
direkt davor.
Deshalb kennt das Protokoll kein `SENSOR:LIGHT`. Wer den Sensor braucht, muss
an der Mechanik ansetzen, nicht am Code.
Die 0 sah lange nach einem Softwarefehler aus: Kosmos' eigenes Programm
`04_Licht-Tracker` benutzt denselben Sensor erfolgreich (mit Schwellen von 1
bis 10 — die Werte sind klein). Widerlegt wurde die Softwarespur erst, als
jemand die Scheibe abgenommen hat.
### P8
`custom.ts` prüft `P8 == 1` vor jeder Motorbewegung, beim Abbremsen der Drehung
und bei der rechten IR-Auswertung. Was genau daran hängt, ist nicht
dokumentiert — plausibel ist der Batterieschalter beziehungsweise eine
Power-Good-Leitung, denn der micro:bit läuft auch dann weiter, wenn Proxis
Schalter auf OFF steht und nur USB-Strom anliegt.
Diese Firmware rät nicht daran herum: alle Motorzugriffe laufen über die
unveränderten Extension-Funktionen, und `SENSOR:PWR` gibt den Rohwert von P8
zurück. **Reagiert Proxi auf Fahrbefehle mit `OK`, bewegt sich aber nicht,
lohnt zuerst ein Blick auf `SENSOR:PWR`** — steht da `0`, ist der Schalter aus.
## micro:bit V1 oder V2
Die Firmware wird als **Universal Hex** gebaut und läuft auf beiden.
Knapp ist es beim V1 trotzdem: der Bluetooth-Stack frisst dort den Großteil des
Flash. Erste Fassungen dieser Firmware passten nicht hinein — Platz geschaffen
hat erst der Verzicht auf den eingebauten Melodie-Player von MakeCode (siehe
`playMelodyBuffer` in [`main.ts`](../firmware/main.ts), der Grund dafür
war allerdings ein anderer). Wer die Firmware erweitert, sollte die V1-Variante
im Blick behalten: `pxt build` bricht ab, sobald sie nicht mehr passt.
V2 erkennt man am goldenen Logo-Taster oben mittig und dem Mikrofon oben rechts.
## Ton: keine Kommazahlen
Die Frequenz für `music.playTone()` **muss** eine Ganzzahl sein.
Sie wurde hier anfangs mit `Math.pow()` gerechnet. Der Wert war korrekt — eine
Diagnoseabfrage lieferte für MIDI 79 sauber 784 —, kam als Kommazahl im
Tonausgang aber falsch an. Der micro:bit machte daraus eine unsinnige
Schwingungsdauer, krachte laut, blieb hängen und bediente den Funk nicht mehr;
nach ein paar Sekunden starb die BLE-Verbindung an `Connection Timeout (0x08)`.
Ein Fehler, drei Symptome, die wie drei verschiedene Probleme aussahen. Gefunden
wurde er durch den direkten Vergleich zweier Aufrufe, die sich nur in diesem
einen Punkt unterschieden:
```
gerechnete 784 Hz -> Krachen, hängt, Verbindung weg
übergebene 784 -> sauberer Ton
```
`midiToFreq()` in `main.ts` rechnet deshalb rein ganzzahlig über eine Tabelle.
`tools/check_melodies.py` prüft das bei jedem Build mit.
Zwei Dinge, die dabei **nicht** die Ursache waren, obwohl sie lange danach
aussahen: der eingebaute Melodie-Player von MakeCode und der interne
Lautsprecher des micro:bit V2. Beides wurde gegengeprüft und entlastet.
## Nicht vorhanden
Damit niemand erneut danach sucht — Proxi hat **keine** Touch-Sensoren, **keinen**
Servo und **keine** regelbaren Motoren. Früher lagen in diesem Repo
`Source/*.py`-Dateien, die genau das behaupteten. Sie waren KI-generiert und
frei erfunden; ihre Pin-Belegung (P0P3 als PWM-Motoren, P4/P10 als IR, P6/P7 als
Touch, P8 als Servo) stimmt an keiner Stelle mit der Hardware überein. Sie sind
durch die echten, aus den `.hex`-Dateien extrahierten Quellen ersetzt.
Nebenbei: MicroPython auf dem micro:bit hat überhaupt kein Bluetooth. Wer BLE
will, muss über MakeCode gehen — daher TypeScript statt Python.