Zurück

Cute Desktop Robot: ein Gesicht, das auf dem ESP-VoCat zuhört, mit seinem Emulator im Browser

Die meisten Schreibtisch-Gadgets zeigen Informationen. Ich wollte eines, das auf Menschen reagiert: einen Roboter, der dich ansieht, wenn du sprichst, dir antwortet und etwas Amüsantes tut, wenn niemand da ist. Der Espressif ESP-VoCat v1.2 hat die Hardware dafür. Er vereint einen ESP32-S3-SoC, einen runden 360×360-Touchscreen, zwei Mikrofone, einen Lautsprecher und einen Akku in einem Gehäuse mit Katzenohren.

VoCat Eyes ist das Gesicht, das ich dafür geschrieben habe, und der erste Roboter einer Reihe namens Cute Desktop Robot. Seine Hauptmerkmale sind:

Die Firmware, der Emulator und die Werkzeuge sind Open Source im cute-desktop-robot-Repository.

Der VoCat-Eyes-Roboter in der 3D-Ansicht des Emulators: das katzenohrige ESP-VoCat-Gehäuse in Blau, mit dem Gesicht des Roboters auf seinem runden Bildschirm

Das Bild oben ist die 3D-Ansicht des Emulators: das Gehäusemodell, das Espressif veröffentlicht hat, mit dem Live-Bildschirm des emulierten Roboters darin.

Und das ist der echte Roboter auf einem Schreibtisch, der dieselbe Firmware ausführt:

Der Roboter auf der echten Hardware: schau ihn dir auf YouTube an.

Probiere den Roboter in deinem Browser aus

Der Emulator unten führt den C++-Code des Roboters aus, kompiliert zu WebAssembly: dieselbe Face-Engine, Zustandsmaschine und dieselben Bildschirme, die auf dem ESP32-S3 laufen. Nur die Hardwareschicht ist durch simulierte Teile ersetzt. Er braucht kein Konto und keine Installation. Nur das Sprachgespräch braucht den echten Roboter, denn der Emulator hat kein Netzwerk.

Wenn der Rahmen zu klein ist, öffne den Emulator in einem vollständigen Fenster.

Das Fenster hat drei Teile. Links ist der Roboter in 3D, darunter die Zustandsmaschine, und rechts ein Panel mit dem Emotionsgraphen und den Sensoren. So probierst du es aus:

  1. Tippe auf den Bildschirm des Roboters. Klicke einmal auf den runden Bildschirm des 3D-Roboters. Der Roboter spielt seine nächste Animation ab.
  2. Öffne die Einstellungen. Klicke und halte den Bildschirm gedrückt, bis Uhr und Akku erscheinen, dann klicke einmal auf die Uhr. Ein Einstellungsmenü öffnet sich. Klicke auf die linke Hälfte einer Zeile, um einen Wert zu verringern, und auf die rechte Hälfte, um ihn zu erhöhen. Klicke und halte gedrückt, um das Menü zu schließen.
  3. Sprich von einer Seite. Ziehe im rechten Panel unter SENSORS den Schieberegler neben from auf einen Winkel und klicke dann auf talk [V]. Ein violetter Punkt auf dem Boden zeigt, woher die simulierte Stimme kommt, und die Augen des Roboters drehen sich dorthin.
  4. Beobachte die Zustandsmaschine. Jedes Mal, wenn der Roboter seine Aktivität ändert, leuchtet das passende Kästchen in der Zustandsmaschine auf, und die Balken unten zeigen die Timer, die sie als Nächstes ändern können.
  5. Drehe den Roboter. Ziehe irgendwo außerhalb des Bildschirms, um die 3D-Ansicht zu drehen, und benutze das Mausrad zum Zoomen. Drücke M, um zu einer flachen Ansicht des Bildschirms zu wechseln.

Die Tastatur funktioniert ebenfalls, sobald du in den Emulator klickst: 1 bis 9 zeigen Gesichtsausdrücke, Y nickt, U schüttelt den Kopf und H zeigt eine Sprechblase. Das Tippen und die Einstellungen funktionieren auf dem echten Roboter genauso.

Der nächste Screenshot zeigt das gesamte Emulatorfenster, wie es auf einem Desktop-PC aussieht:

Der vollständige Desktop-Emulator: der Roboter in 3D, der Emotionsgraph, die Sensoren mit ihren Schiebereglern und die Zustandsmaschine mit ihren Timern

Die Hardware

Der ESP-VoCat kommt zusammengebaut, mit Gehäuse, Akku und Bildschirm an Ort und Stelle. Der ESP-VoCat-Benutzerleitfaden beschreibt das Board im Detail. Ein ESP32-S3-Modul erledigt die ganze Arbeit. Es hat 16 MB Flash-Speicher und 16 MB PSRAM (externen RAM). Das PSRAM macht ein 360×360-Gesicht möglich: Ein vollständiges Bild in 16-Bit-Farbe belegt 253 KB, mehr, als der interne RAM des SoC fassen kann.

Das folgende Diagramm zeigt die Teile, die die Firmware verwendet, und den Bus, der jedes davon mit dem ESP32-S3 verbindet:

Blockdiagramm: Der ESP32-S3 steuert das runde ST77916-LCD über QSPI an, liest den CST816S-Touch und den BQ27220-Akkumesser über I2C, bekommt die Mikrofone über den ES7210 und gibt über den ES8311 und seinen Verstärker über I2S TDM wieder, und spricht über Wi-Fi mit Gemini Live

Zwei Teile brauchten zusätzliche Arbeit:

Wie der Roboter sein Gesicht zeichnet

Der Roboter zeichnet sein Gesicht alle 33 ms neu, etwa 30 Mal pro Sekunde. Das folgende Diagramm verfolgt eines dieser Frames von den Sensoren bis zum Bildschirm:

Die Frame-Pipeline: Die Sensoren erzeugen einen SensorState für das Brain, das Brain wählt einen Gesichtsausdruck für die FaceEngine, die FaceEngine zeichnet Formen in den Canvas, der Canvas findet die geänderten 24-Pixel-Kacheln und VocatLcd sendet nur diese über QSPI. Die Listener-Task speist Sprache, Geräusche und das Weckwort in die Sensoren, und das Gespräch speist set_face und play_act in das Brain

Jeder Block im Diagramm ist ein Modul der Firmware:

Alle Ausdrücke und Animationen

Der Emulator enthält ein Kommandozeilen-Tool, facetool, das den Bildschirm des Roboters rendert, ohne ein Fenster zu öffnen. Die Videos unten stammen davon. Jedes spielt alle Gesichter einer Gruppe gleichzeitig ab: zuerst den Übergang in jedes Gesicht, dann das Gesicht selbst.

Ausdrücke

Ruhig und nachdenklich (16): normal, neugierig, konzentriert, skeptisch, gelangweilt, verwirrt und zuhörend, unter anderem.

Fröhlich (15): von einem kleinen Lächeln bis zum Lachen, Liebe und Sternenstaunen.

Traurig (8): besorgt, flehend, weinend, einsam und schuldbewusst, unter anderem.

Wütend (6): von genervt bis wütend, und Ekel.

Überrascht und alarmiert (7): überrascht, verängstigt, schwindelig, bewusstlos und hypnotisiert, unter anderem.

Schläfrig (4): schläfrig, gähnend, schlafend und müde.

Animationen

Animationen, im Code Acts genannt, sind kurze Szenen, viele mit einem Objekt, das neben den Augen gezeichnet wird: eine Regenwolke, eine Kaffeetasse, ein Radarschirm. Das Brain spielt sie ab, wenn der Roboter im Leerlauf ist, und ein Tippen auf den Bildschirm spielt die nächste ab.

Körpersprache (9): nicken, den Kopf schütteln, die Augen rollen, niesen.

Bildschirmeffekte (5): ein Glitch, ein Neustart, eine Scannerlinie, fallender Code.

Mit Objekten (18): Herzen, Regen, Feuerwerk, Blasen, ein Ball, Tanzen.

Alltagsdinge (9): ein Buch, Kopfhörer, Kaffee, eine Rakete, Schnee.

Spiele und Rundbildschirm-Effekte (6): Pac-Man, Pong, ein Regenbogen, ein Radar, ein Aquarium.

Dieselben Raster, als animierte GIFs, findest du in der README des Repositories.

Wie der Roboter spricht

Das Gespräch nutzt die Gemini Live API, die einen Audiostream empfängt und über eine einzige WebSocket-Verbindung mit einem Audiostream antwortet. Zum Zeitpunkt des Schreibens verwendet der Roboter das Modell gemini-2.5-flash-native-audio. Das folgende Diagramm zeigt den Weg des Audios:

Die Sprachpipeline: Die ES7210-Mikrofone speisen den Listener-Task mit 16 kHz, der GeminiLive-Task sendet 100-ms-Chunks an die Gemini Live API und empfängt 24-kHz-Audio, das für den Player und den Lautsprecher neu abgetastet wird. Tool-Aufrufe gehen an Talk, das das Gesicht ändert. Der Player schaltet den Listener während der Wiedergabe stumm

Der Roboter sendet den Klang eines Mikrofons als 16-kHz-PCM-Audio in Chunks von 100 ms. Gemini antwortet mit 24-kHz-Sprache, die der Roboter in 16 kHz umwandelt und abspielt.

Das Gespräch ist halbduplex: Der Roboter hört entweder zu oder spricht, nie beides gleichzeitig. Der Lautsprecher sitzt nur wenige Zentimeter von den Mikrofonen entfernt, daher schaltet der Roboter den Mikrofonstream stumm, während er eine Antwort abspielt. Andernfalls würde Gemini seine eigene Stimme hören. Gemini entscheidet auf seiner Seite, wann die Person mit dem Sprechen fertig ist.

Gemini erhält außerdem vier Tools, also Funktionen, die es während des Gesprächs aufrufen kann: set_face, play_act, look und show_text. Wenn das Gespräch traurig wird, kann Gemini set_face("sad") aufrufen. Wenn du den Roboter bittest, zuzustimmen, kann er play_act("yes") aufrufen und der Roboter nickt. Jede Sitzung beginnt mit einer kurzen Textnachricht, die die lokale Uhrzeit und das Datum enthält, damit Gemini Fragen dazu beantworten kann.

Drei Probleme nahmen den größten Teil der Entwicklungszeit in Anspruch:

  1. Die sichere Verbindung. Der Roboter verbindet sich über TLS mit Gemini. Die Funktion setInsecure() der ArduinoWebsockets-Bibliothek hat auf dem ESP32-S3 keine Wirkung, daher schlug der TLS-Handshake fehl. Die Firmware enthält nun Googles zwei Root-Zertifikate (GTS Root R1 und R4, gültig bis 2036). Sie wartet außerdem darauf, dass die Uhr über NTP synchronisiert wird, denn die Prüfung eines Zertifikats benötigt das aktuelle Datum.
  2. Interner RAM. Das Weckwort „Hi ESP” läuft auf ESP-SR, der Spracherkennungsbibliothek von Espressif, die etwa 100 KB internen RAM belegt. Die TLS-Bibliothek benötigt internen RAM für den Handshake, und die ersten Versuche scheiterten mit SSL - Memory allocation failed. Der Roboter stoppt ESP-SR nun, wenn ein Gespräch beginnt, was 107 KB freigibt, und lädt es wieder, wenn das Gespräch endet. Das Laden von ESP-SR dauert etwa 1,2 Sekunden.
  3. Der fehlende Mikrofonstream. Einen Tag lang begrüßte der Roboter den Benutzer und ignorierte dann alles, was folgte. Seine Augen folgten weiterhin meiner Stimme, die Mikrofone funktionierten also eindeutig. Die Ursache war, dass die Firmware den Audiostream zu Gemini nie aktivierte. Die serielle Konsole gibt nun Geminis Transkription des Gehörten aus, sodass dasselbe Problem sofort sichtbar wäre.

Die Nutzung von Gemini erfordert einen API-Schlüssel aus dem Google AI Studio, und die API wird gemäß Googles Gemini-API-Preisen pro Nutzung abgerechnet. Der Schlüssel bleibt in einer lokalen Datei secrets.h, die niemals ins Repository eingecheckt wird.

Einstellungen auf dem Bildschirm des Roboters

Der Roboter benötigt nach der Einrichtung keinen Computer mehr. Ein langer Druck auf den Bildschirm zeigt die Uhr, den Batteriestand und den Wi-Fi-Status. Ein Tippen auf die Uhr öffnet die Einstellungen, in denen du ändern kannst:

Die Wi-Fi-Zeile öffnet eine Liste der Netzwerke in Reichweite und eine Bildschirmtastatur mit Großbuchstaben, Zahlen und Symbolen. Der ESP32-S3 kann nicht nach Netzwerken suchen, während er sich mit einem verbindet, daher pausiert die Firmware die Verbindungsversuche während der Suche und setzt sie danach fort. Wenn das Passwort falsch ist, zeigt der Uhrbildschirm dies als Grund an. Der ESP32-S3 unterstützt nur 2,4-GHz-Netzwerke.

Eine Codebasis für den Roboter, den PC und den Browser

Der Code des Roboters ruft die Display-, Touch- oder Audio-Treiber nicht direkt auf. Das Gesicht, das Brain und die Bildschirme laufen über eine dünne Hardwareschicht in src/hw und src/audio. Der Emulator ersetzt diese Schicht, sodass der restliche Code unverändert für drei Ziele gebaut wird:

Der gemeinsame C++-Code in src/ wird auf drei Arten kompiliert: arduino-cli erzeugt die ESP32-S3-Firmware, g++ mit gemockten Arduino-Headern erzeugt den raylib-Desktop-Emulator, und em++ erzeugt denselben Emulator für den Browser

Im Emulator schreiben kleine Ersatzversionen von Arduino.h, Wire.h und SPI.h in eine Struktur, die die Hardware repräsentiert. Sie enthält den Displayspeicher, die Register des Touch-Controllers und die Batteriewerte. Das Emulatorfenster, geschrieben mit der Grafikbibliothek raylib, zeichnet diese Struktur und lässt dich die Sensorwerte ändern.

Die Browserversion ist dasselbe Emulatorprogramm, kompiliert mit Emscripten, das C++ in WebAssembly umwandelt. Drei Änderungen machten das möglich:

  1. raylib für das Web. raylib baut mit Emscripten zu einer statischen Bibliothek, die über WebGL zeichnet.
  2. Ein Frame pro Aufruf. Die Desktop-Version lief in einer Endlosschleife. Diese Schleife wurde zu einer Funktion, die einen Frame zeichnet. Die Desktop-Version ruft sie in einer Schleife auf, und der Browser ruft sie einmal pro Bildschirmaktualisierung auf.
  3. Eine feste Fenstergröße. Im Browser zeichnet der Emulator in ein 1380×900-Canvas, und die Seite skaliert das Canvas passend. Ein größenveränderbares Canvas brach die Zuordnung zwischen Maus- und Canvas-Koordinaten.

Das 3D-Gehäuse stammt von Espressif. ESP-College veröffentlichte das ESP-VoCat-(EchoEar-)Gehäuse als STL-Dateien auf OSHWHub unter der GPL-3.0-Lizenz. Ein kurzes Python-Skript wandelt die STL-Dateien in eine einzige 3D-Modelldatei um und reduziert deren Detailgrad, damit der Browser sie schnell lädt. Der Emulator zeichnet den Live-Bildschirm auf eine Scheibe im runden Fenster des Gehäuses. Wenn du auf den 3D-Bildschirm klickst, findet der Emulator den angeklickten Punkt auf dieser Scheibe und wandelt ihn in einen Touch am passenden Pixel um.

Baue deinen eigenen

Um VoCat Eyes zu bauen, benötigst du ein ESP-VoCat-v1.2-Board und zum Zeitpunkt des Schreibens Version 3.3 des Arduino-Cores für ESP32. Die VoCat-Eyes-README listet die Bibliotheken und die genauen Befehle auf. Kurz gesagt:

  1. Kopiere secrets.example.h nach secrets.h und füge deinen Gemini-API-Schlüssel hinzu. Du kannst dort auch das Wi-Fi-Netzwerk eingeben oder es später am Roboter einstellen.
  2. Kompiliere den Sketch mit dem Partitionsschema esp_sr_16 und der Datei partitions.csv im Sketch-Ordner. Dieses Layout gibt der Anwendung 6 MB Flash.
  3. Lade die Firmware zusammen mit srmodels.bin hoch, der Modelldatei für das Weckwort „Hi ESP”.
  4. Drücke am Roboter lange auf den Bildschirm, tippe auf die Uhr, wähle Wi-Fi, wähle dein Netzwerk und gib dessen Passwort ein.
  5. Sage „Hi ESP” oder tippe auf das kleine Mikrofon unten am Bildschirm und beginne zu sprechen.

Wenn du Firmware für den ESP32-S3 oder andere Boards entwickelst, kann Velxio sie im Browser simulieren, bevor du irgendeine Hardware flashst.


Teilen auf:
David Montero

Geschrieben von

David Montero

Creator of Velxio, the open-source circuit and Arduino simulator.

GitHub velxio.dev

Ähnliche Artikel


Vorheriger Artikel
Sieben Halloween-Projekte, die du im Browser bauen und ausführen kannst
Nächster Artikel
Ein Claude-Nutzungsdashboard auf dem M5Stack Basic: Planlimits und API-Ausgaben auf dem Schreibtisch