La mayoría de los gadgets de escritorio muestran información. Yo quería uno que reaccionara a las personas: un robot que te mire cuando hablas, te responda y haga algo divertido cuando no hay nadie cerca. La Espressif ESP-VoCat v1.2 tiene el hardware para ello. Combina un SoC ESP32-S3, una pantalla táctil redonda de 360×360, dos micrófonos, un altavoz y una batería en una carcasa con orejas de gato.
VoCat Eyes es la cara que escribí para él, y el primer robot de una serie llamada Cute Desktop Robot. Sus características principales son:
- 56 expresiones faciales y 47 animaciones cortas
- Una pequeña máquina de estados que decide qué hace el robot: jugar, reaccionar, aburrirse, dormirse
- Ojos que giran hacia la persona que está hablando
- Conversaciones habladas a través de la API Gemini Live, iniciadas con la palabra de activación “Hi ESP” o con un toque
- Ajustes de Wi-Fi, volumen, brillo y voz en la propia pantalla del robot
- Un emulador que ejecuta el mismo código en un PC y en esta página
El firmware, el emulador y las herramientas son de código abierto en el repositorio cute-desktop-robot.

La imagen de arriba es la vista 3D del emulador: el modelo de la carcasa que publicó Espressif, con la pantalla en vivo del robot emulado dentro.
Y este es el robot real sobre un escritorio, ejecutando el mismo firmware:
El robot en el hardware real: míralo en YouTube.
Prueba el robot en tu navegador
El emulador de abajo ejecuta el código C++ del robot compilado a WebAssembly: el mismo motor de cara, máquina de estados y pantallas que se ejecutan en el ESP32-S3. Solo la capa de hardware se sustituye por piezas simuladas. No necesita cuenta ni instalación. Solo la conversación por voz necesita el robot real, porque el emulador no tiene red.
Si el marco es demasiado pequeño, abre el emulador en una ventana completa.
La ventana tiene tres partes. A la izquierda está el robot en 3D, debajo está la máquina de estados, y a la derecha hay un panel con el grafo de emociones y los sensores. Para probarlo:
- Toca la pantalla del robot. Haz clic una vez en la pantalla redonda del robot en 3D. El robot reproduce su siguiente animación.
- Abre los ajustes. Haz clic y mantén pulsado en la pantalla hasta que aparezcan el reloj y la batería, luego haz clic una vez en el reloj. Se abre un menú de ajustes. Haz clic en la mitad izquierda de una fila para bajar un valor y en la mitad derecha para subirlo. Haz clic y mantén pulsado para cerrar el menú.
- Habla desde un lado. En el panel de la derecha, bajo SENSORS, arrastra el deslizador junto a from hasta un ángulo, luego haz clic en talk [V]. Un punto morado en el suelo muestra de dónde viene la voz simulada, y los ojos del robot giran hacia ella.
- Observa la máquina de estados. Cada vez que el robot cambia de actividad, la casilla correspondiente se ilumina en la máquina de estados, y las barras de abajo muestran los temporizadores que pueden cambiarla a continuación.
- Gira el robot. Arrastra en cualquier punto fuera de la pantalla para rotar la vista 3D, y usa la rueda del ratón para hacer zoom. Pulsa
Mpara cambiar a una vista plana de la pantalla.
El teclado también funciona una vez que haces clic en el emulador: 1 a 9 muestran expresiones, Y asiente, U niega con la cabeza, y H muestra un bocadillo de diálogo. El toque y los ajustes funcionan igual en el robot real.
La siguiente captura muestra toda la ventana del emulador tal como se ve en un PC de escritorio:

El hardware
El ESP-VoCat viene montado, con la carcasa, la batería y la pantalla en su sitio. La guía de usuario del ESP-VoCat describe la placa en detalle. Un único módulo ESP32-S3 hace todo el trabajo. Tiene 16 MB de memoria flash y 16 MB de PSRAM (RAM externa). La PSRAM hace posible una cara de 360×360: un fotograma completo en color de 16 bits ocupa 253 KB, más de lo que puede contener la RAM interna del SoC.
El siguiente diagrama muestra las piezas que usa el firmware y el bus que conecta cada una al ESP32-S3:
Dos piezas necesitaron trabajo extra:
- La pantalla encendía su retroiluminación pero se quedaba en negro. A la secuencia de inicialización que adapté del driver del fabricante le faltaban dos comandos finales: el formato de píxel (
0x3A) y encender la pantalla (0x29). - Los micrófonos devolvían solo ceros al principio. El ADC de los micrófonos (ES7210) y el DAC del altavoz (ES8311) comparten las mismas líneas de reloj I2S. Por lo tanto, el bus I2S tiene que usar el mismo formato de trama en ambas direcciones: TDM (multiplexación por división de tiempo) con cuatro ranuras de 16 bits. Con ese cambio, los dos micrófonos aparecen en las ranuras 0 y 2, y la ranura 1 lleva una copia de la señal del altavoz como referencia de eco.
Cómo dibuja el robot su cara
El robot redibuja su cara cada 33 ms, unas 30 veces por segundo. El diagrama de abajo sigue uno de esos fotogramas desde los sensores hasta la pantalla:
Cada bloque del diagrama es un módulo del firmware:
- Sensors recoge los toques, el nivel de batería, la hora y los eventos de sonido en una sola estructura.
- Brain es una máquina de estados con los estados awake, show, reacting, dozing, sleeping, info y manual. Cada estado sale con eventos concretos, como un toque, un ruido fuerte, la hora del día o mucho tiempo a solas. El Brain también sigue estados de ánimo lentos: un robot al que acarician a menudo tiende hacia caras felices, y uno al que pinchan demasiado a menudo se vuelve molesto.
- FaceEngine se mueve entre expresiones a lo largo de un grafo. Las 56 expresiones son sus nodos, y un cambio de cara sigue el camino más corto, así que el robot pasa de feliz a triste a través de caras intermedias. Cada ojo se describe con unos pocos parámetros, como tamaño, radio de las esquinas, inclinación, párpados y color, y el motor los interpola.
- Canvas dibuja el fotograma en PSRAM y registra qué mosaicos de 24×24 han cambiado. Un parpadeo cambia unos pocos mosaicos, así que el bus de la pantalla envía unos pocos kilobytes en lugar de los 253 KB completos.
- VocatLcd envía los mosaicos cambiados a la pantalla ST77916 por QSPI (un bus SPI de cuatro líneas).
Todas las expresiones y animaciones
El emulador incluye una herramienta de línea de comandos, facetool, que renderiza la pantalla del robot sin abrir una ventana. Los vídeos de abajo provienen de ella. Cada uno reproduce todas las caras de un grupo al mismo tiempo — primero el cambio a cada cara, luego la cara en sí.
Expresiones
Tranquilo y pensativo (16) — normal, curioso, concentrado, escéptico, aburrido, confundido y escuchando, entre otras.
Feliz (15) — desde una pequeña sonrisa hasta la risa, el amor y el flechazo.
Triste (8) — preocupado, suplicante, llorando, solitario y culpable, entre otras.
Enfadado (6) — desde molesto hasta furioso, y asco.
Sorprendido y alerta (7) — sorprendido, asustado, mareado, noqueado e hipnotizado, entre otras.
Somnoliento (4) — somnoliento, bostezando, dormido y cansado.
Animaciones
Las animaciones, llamadas acts en el código, son escenas cortas, muchas con un objeto dibujado junto a los ojos — una nube de lluvia, una taza de café, una pantalla de radar. El Brain las reproduce cuando el robot está inactivo, y un toque en la pantalla reproduce la siguiente.
Lenguaje corporal (9) — asentir, negar con la cabeza, poner los ojos en blanco, estornudar.
Efectos de pantalla (5) — un glitch, un reinicio, una línea de escáner, código cayendo.
Con objetos (18) — corazones, lluvia, fuegos artificiales, burbujas, una pelota, bailar.
Cosas del día a día (9) — un libro, auriculares, café, un cohete, nieve.
Juegos y efectos de pantalla redonda (6) — Pac-Man, Pong, un arcoíris, un radar, un acuario.
Las mismas cuadrículas, como GIF animados, están en el README del repositorio.
Cómo habla el robot
La conversación utiliza la API Gemini Live, que recibe un flujo de audio y responde con un flujo de audio a través de una única conexión WebSocket. En el momento de escribir esto, el robot usa el modelo gemini-2.5-flash-native-audio. El siguiente diagrama muestra el recorrido del audio:
El robot envía el sonido de un micrófono como audio PCM de 16 kHz, en fragmentos de 100 ms. Gemini responde con voz a 24 kHz, que el robot convierte a 16 kHz y reproduce.
La conversación es semidúplex: el robot o escucha o habla, nunca ambas cosas a la vez. El altavoz está a pocos centímetros de los micrófonos, así que el robot silencia el flujo del micrófono mientras reproduce una respuesta. De lo contrario, Gemini oiría su propia voz. Gemini decide por su parte cuándo la persona ha terminado de hablar.
Gemini también recibe cuatro herramientas, funciones que puede llamar durante la conversación: set_face, play_act, look y show_text. Cuando la conversación se vuelve triste, Gemini puede llamar a set_face("sad"). Cuando le pides al robot que asienta, puede llamar a play_act("yes") y el robot asiente. Cada sesión comienza con un breve mensaje de texto que contiene la hora y la fecha locales, para que Gemini pueda responder preguntas sobre ellas.
Tres problemas acapararon la mayor parte del tiempo de desarrollo:
- La conexión segura. El robot se conecta a Gemini mediante TLS. La función
setInsecure()de la biblioteca ArduinoWebsockets no tiene efecto en el ESP32-S3, así que el handshake TLS fallaba. El firmware ahora incluye los dos certificados raíz de Google (GTS Root R1 y R4, válidos hasta 2036). También espera a que el reloj se sincronice por NTP, porque verificar un certificado necesita la fecha actual. - La RAM interna. La palabra de activación “Hi ESP” se ejecuta en ESP-SR, la biblioteca de reconocimiento de voz de Espressif, que ocupa unos 100 KB de RAM interna. La biblioteca TLS necesita RAM interna para el handshake, y los primeros intentos fallaban con
SSL - Memory allocation failed. Ahora el robot detiene ESP-SR cuando empieza una conversación, lo que libera 107 KB, y lo vuelve a cargar cuando la conversación termina. Cargar ESP-SR tarda unos 1,2 segundos. - El flujo de micrófono ausente. Durante un día, el robot saludaba al usuario y luego ignoraba todo lo que venía después. Sus ojos seguían mi voz, así que los micrófonos claramente funcionaban. La causa era que el firmware nunca habilitaba el flujo de audio hacia Gemini. Ahora la consola serie imprime la transcripción de Gemini de lo que oyó, así que el mismo problema sería visible de inmediato.
Usar Gemini requiere una clave de API de Google AI Studio, y la API se factura por uso según los precios de la API Gemini de Google. La clave permanece en un archivo local secrets.h que nunca se sube al repositorio.
Ajustes en la pantalla del robot
El robot no necesita un ordenador una vez configurado. Una pulsación larga en la pantalla muestra el reloj, el nivel de batería y el estado del Wi-Fi. Un toque en el reloj abre los ajustes, donde puedes cambiar:
- El volumen y el brillo de la pantalla
- La voz de Gemini, entre ocho voces
- La palabra de activación “Hi ESP”, activada o desactivada
- Los sonidos que acompañan a las expresiones
- Si el robot reproduce y duerme por su cuenta
- Cuántos segundos de silencio terminan una conversación
La fila de Wi-Fi abre una lista de las redes disponibles y un teclado en pantalla con mayúsculas, números y símbolos. El ESP32-S3 no puede escanear redes mientras se conecta a una, así que el firmware pausa los intentos de conexión durante el escaneo y los reanuda después. Si la contraseña es incorrecta, la pantalla del reloj lo muestra como motivo. El ESP32-S3 solo admite redes de 2,4 GHz.
Un solo código base para el robot, el PC y el navegador
El código del robot no llama directamente a los controladores de pantalla, táctil o audio. La cara, el Brain y las pantallas pasan por una fina capa de hardware en src/hw y src/audio. El emulador sustituye esa capa, así que el resto del código se compila sin cambios para tres objetivos:
En el emulador, pequeñas versiones de reemplazo de Arduino.h, Wire.h y SPI.h escriben en una estructura que hace las veces de hardware. Contiene la memoria de la pantalla, los registros del controlador táctil y las lecturas de la batería. La ventana del emulador, escrita con la biblioteca gráfica raylib, dibuja esa estructura y te permite cambiar los valores de los sensores.
La versión para navegador es el mismo programa emulador compilado con Emscripten, que convierte C++ en WebAssembly. Tres cambios lo hicieron posible:
- raylib para la web. raylib se compila con Emscripten en una biblioteca estática que dibuja mediante WebGL.
- Un fotograma por llamada. La versión de escritorio se ejecutaba en un bucle infinito. Ese bucle se convirtió en una función que dibuja un fotograma. La versión de escritorio la llama en un bucle, y el navegador la llama una vez por cada refresco de pantalla.
- Un tamaño de ventana fijo. En el navegador, el emulador dibuja en un lienzo de 1380×900, y la página escala el lienzo para ajustarlo. Un lienzo redimensionable rompía la correspondencia entre las coordenadas del ratón y las del lienzo.
La carcasa 3D proviene de Espressif. ESP-College publicó la carcasa del ESP-VoCat (EchoEar) como archivos STL en OSHWHub bajo la licencia GPL-3.0. Un breve script de Python convierte los archivos STL en un único archivo de modelo 3D y reduce su detalle para que el navegador lo cargue rápido. El emulador dibuja la pantalla en vivo sobre un disco en la ventana redonda de la carcasa. Cuando haces clic en la pantalla 3D, el emulador encuentra el punto pulsado en ese disco y lo convierte en un toque en el píxel correspondiente.
Construye el tuyo
Para construir VoCat Eyes necesitas una placa ESP-VoCat v1.2 y, en el momento de escribir esto, la versión 3.3 del core de Arduino para ESP32. El README de VoCat Eyes enumera las bibliotecas y los comandos exactos. En resumen:
- Copia
secrets.example.hasecrets.hy añade tu clave de API de Gemini. También puedes introducir allí la red Wi-Fi, o configurarla más tarde en el robot. - Compila el sketch con el esquema de particiones
esp_sr_16y el archivopartitions.csvde la carpeta del sketch. Esta distribución da a la aplicación 6 MB de flash. - Sube el firmware junto con
srmodels.bin, el archivo de modelo para la palabra de activación “Hi ESP”. - En el robot, mantén pulsada la pantalla, toca el reloj, elige Wi-Fi, selecciona tu red y escribe su contraseña.
- Di “Hi ESP”, o toca el pequeño micrófono en la parte inferior de la pantalla, y empieza a hablar.
Si estás diseñando firmware para el ESP32-S3 u otras placas, Velxio puede simularlo en el navegador antes de que flashees ningún hardware.