¿Se puede transcribir voz con un modelo tipo Whisper dentro de un ESP32, sin internet y sin servidor? Hasta hace poco la respuesta era no: el modelo base de Whisper pesa unos 140 MB. Este proyecto usa Whistle, el modelo de voz a texto de Cactus Compute, recortado para que quepa en la flash de un ESP32-S3 con 16 MB de flash y 8 MB de PSRAM. Hablas a un micrófono I²S INMP441 mientras mantienes apretado un botón, sueltas, y en unos seis segundos el ESP32 entiende la orden y cambia el color del LED RGB que la placa trae soldado.
Al final vas a saber recortar el modelo, cargar el firmware con ESP IDF, escribir el modelo en su partición de flash y probarlo desde un monitor de terminal. También vas a entender por qué cada pin va donde va, que es lo que te permite después cambiar el LED por un relé o un servo.
El concepto: cuánto cabe en 16 MB
El modelo descargado pesa 16,9 MB, más que toda la flash del módulo. El repositorio trae un script que le saca capas al modelo y lo deja en 14,52 MB con cuatro capas. Ese número no es casual: el firmware vive en los primeros 2 MB de la flash y el modelo se escribe a partir de la dirección 0x210000, así que ocupa prácticamente todo lo que queda. Por eso este proyecto no funciona en una placa de 4 u 8 MB de flash: no es cuestión de optimizar, el archivo simplemente no entra. La PSRAM de 8 MB es la otra mitad del truco, porque ahí se guardan el audio grabado y los cálculos intermedios de la red mientras transcribe.
Comparado con las alternativas, el enfoque es distinto:
- Servicios en la nube (Wit.ai y similares): transcriben mejor y más rápido, pero necesitan WiFi, mandan tu voz a un servidor y dependen de una API que puede cambiar.
- Detección de palabras clave (Edge Impulse y parecidos): reconocen un puñado de palabras entrenadas, responden casi al instante y caben en placas pequeñas, pero no entienden frases libres.
- Whistle en el ESP32-S3: transcribe frases completas sin conexión, a cambio de unos seis segundos de espera y de exigir una placa con 16 MB de flash.
El hardware

Son solo tres piezas activas. La placa del autor es un módulo ESP32-S3 CAM (N16R8), pero la cámara no se usa: lo que importa es la combinación de 16 MB de flash, 8 MB de PSRAM y el LED RGB WS2812 en GPIO 48. El INMP441 es un micrófono MEMS que entrega el audio ya digitalizado por I²S, así que el ESP32 no tiene que lidiar con un conversor analógico ni con el ruido de un preamplificador. El pulsador marca el inicio y el fin de la grabación.

| Pin del componente | Pin del ESP32-S3 | Por qué |
|---|---|---|
| INMP441 VDD | 3V3 | El micrófono es de 3,3 V. Nunca a 5V. |
| INMP441 GND | GND | Tierra común |
| INMP441 L/R | GND | Con L/R a tierra el micrófono transmite en el canal izquierdo |
| INMP441 SCK | GPIO 4 | Reloj de bit I²S |
| INMP441 WS | GPIO 5 | Selección de palabra (izquierda o derecha) |
| INMP441 SD | GPIO 6 | Datos de audio |
| Pulsador, pata 1 | GPIO 7 | Usa el pull up interno |
| Pulsador, pata 2 | GND | Al apretar, GPIO 7 lee 0 |
| LED RGB WS2812 | GPIO 48 | Ya viene en la placa |
Dos detalles que suelen fallar. El pin L/R no se puede dejar al aire: si flota, el micrófono puede transmitir en el canal que el firmware no escucha y la grabación sale en silencio. Y SCK con WS invertidos es el error de cableado más común con el INMP441: la placa graba, pero lo que llega es ruido. Si el LED parpadea en rojo dos veces después de cada intento (es la señal de que no se detectó texto), revisa esas dos cosas antes que nada.
El software, paso a paso
El proyecto usa ESP IDF 5.5 o superior (el autor usó la 5.5.5) en Windows con PowerShell. Instálalo desde la página oficial de Espressif y ábrelo desde el menú Inicio.
1. Clonar el repositorio y preparar Python
Ubícate en la carpeta donde guardas tus proyectos y clona el repositorio:
cd $HOME\Documents\Projects
git clone https://github.com/andrisgauracs/whistle-esp32.git
cd whistle-esp32
Crea un entorno virtual para las herramientas del proyecto y actívalo:
python -m venv .venv
.\.venv\Scripts\Activate.ps1
Si PowerShell bloquea el script de activación, habilítalo solo para la sesión actual:
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope Process
Instala las dependencias:
pip install numpy rich pyserial huggingface_hub
pip install esptool
2. Descargar y recortar el modelo
Desde la raíz del repositorio, crea la carpeta del modelo, descárgalo desde Hugging Face y recórtalo a cuatro capas:
mkdir -Force model\whistle
python -c "from huggingface_hub import hf_hub_download; import shutil; shutil.copy(hf_hub_download('Cactus-Compute/whistle','whistle.cact'), 'model/whistle/whistle.cact')"
python tools\whistle_strip.py model\whistle\whistle.cact 4 model\whistle\whistle_d4.cact

3. Compilar y cargar el firmware
Entra a esp32\whistle_demo. Acá conviene desactivar el entorno virtual del proyecto, porque ESP IDF trae su propio entorno de Python y los dos chocan:
deactivate
En Windows, ESP IDF 5.5 suele instalarse en C:\Espressif o dentro de tu carpeta de usuario. Este comando encuentra el export.ps1:
Get-ChildItem -Path "C:\Espressif", "C:\Users\$env: USERNAME" -Filter "export.ps1" -Recurse -ErrorAction SilentlyContinue | Select-Object -ExpandProperty FullName
Ejecútalo con un punto delante, según dónde haya quedado. Por ejemplo:
. C:\Espressif\frameworks\esp-idf-v5.5.5\export.ps1
. C:\Users\Pavilion\esp\esp-idf\export.ps1
Ahora fija el chip, compila y carga. Cambia COMx por el puerto que muestra el Administrador de dispositivos:
idf.py set-target esp32s3
idf.py build
idf.py -p COMx flash
4. Escribir el modelo en la flash
Vuelve a la raíz, reactiva el entorno del proyecto y escribe el modelo en la dirección 0x210000:
cd ..\..
.\.venv\Scripts\Activate.ps1
esptool.py --chip esp32s3 -p COM6 -b 921600 write_flash 0x210000 model\whistle\whistle_d4.cact

El -b 921600 acelera la escritura: con 14 MB, a la velocidad por defecto te quedarías varios minutos mirando la barra.
5. Cambiar de puerto USB y abrir el monitor
Este paso es el que más confunde. Las placas ESP32-S3 de este tipo traen dos conectores USB-C: uno marcado UART, que pasa por un chip conversor (CP2102 o CH340) conectado a los pines TX0/RX0, y otro marcado USB OTG, que va directo al USB nativo del ESP32-S3. El firmware de Whistle se comunica por el USB nativo, así que para el monitor tienes que mover el cable al conector USB OTG. Si te quedas en el UART, el monitor abre pero nunca recibe nada.
python tools\needle_tui.py --whistle --serial COMx

Pruebas: qué pasa cuando hablas
Mientras mantienes el botón apretado, el monitor muestra "Recording" y el LED queda en blanco. Al soltar, cambia a "Transcribing" y el LED parpadea lento en blanco; esa etapa toma cerca de seis segundos.


Con la transcripción lista, el monitor muestra el texto y la acción, y el LED responde. Las órdenes que probó el autor (en inglés) son del tipo "Change colour to Red", "Flash green light for 5 seconds", "Blink violet every half second" o simplemente "Purple". Cualquier otra frase igual se transcribe y aparece en el monitor, aunque no dispare nada.

Si quieres resultados más estables:
- Habla a unos 10 a 20 cm del micrófono y sin ventilador ni música de fondo: el INMP441 es omnidireccional y capta todo.
- Aprieta el botón, espera medio segundo y recién habla. Las primeras sílabas que se cortan son la causa más común de transcripciones raras.
- Usa frases cortas y con verbo al inicio. El modelo recortado a cuatro capas pierde algo de precisión frente al completo; las órdenes simples sufren menos.
Variantes y mejoras
- Un relé en vez del LED. El LED de GPIO 48 es solo la salida de demostración. Conecta un módulo relé de 3,3 V a un GPIO libre (evita los usados por el micrófono y el botón) y, en la función que interpreta el texto, activa el relé cuando aparezca "encender" o "apagar". Así controlas una lámpara por voz sin depender de la nube.
- Órdenes en español. El autor probó en inglés, pero presenta el modelo como multilingüe. Antes de armar un sistema completo, graba unas cuantas frases en español y mira en el monitor qué transcribe; si las palabras clave salen bien, compara contra el texto con minúsculas y sin tildes para tolerar pequeñas diferencias.
- Respuesta hablada. Suma un amplificador I²S MAX98357A y un parlante para que el ESP32 confirme en voz alta lo que entendió, combinando este proyecto con un sistema de texto a voz offline.
Personalización para Chile
En Chile consigues casi todo lo necesario en MechatronicStore:
- Módulo Micrófono I2S INMP441 (SKU GL3-12): el micrófono digital que graba tu voz por I²S.
- Botón pulsador switch de 4 pines push button 12x12x8mm (SKU GA6-16): inicia y detiene la grabación.
- Breadboard / Protoboard 830 puntos MB102 (SKU C-302): para montar el circuito sin soldar.
- Cables macho macho 40 piezas 20cm (SKU C-411): las conexiones entre la placa, el micrófono y el botón.
- Cable USB Tipo C a USB Tipo A 1mt (SKU B-101): para cargar el firmware y conectar el puerto USB OTG.
La placa es el punto delicado: necesitas un ESP32-S3 con 16 MB de flash y 8 MB de PSRAM (variante N16R8), porque el modelo no entra en menos. El XIAO ESP32 S3 estándar trae 8 MB de flash, así que no sirve para este proyecto; revisa la flash de cualquier placa antes de comprarla.
Recursos
- Tutorial original (inglés): basado en How to Build an ESP32 Offline Speech Recognition, de Circuit Digest
- Repositorio GitHub: whistle esp32
- Archivos descargables: código del repositorio en .zip
- Documentación adicional: ESP IDF de Espressif y ficha del micrófono INMP441
Versión chilena con componentes en stock local en MechatronicStore.









