Reconocimiento y síntesis de voz con Arduino
Componentes y suministros
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 3 | ||||
| × | 3 | ||||
| × | 1 |
Herramientas y máquinas necesarias
|
Aplicaciones y servicios en línea
|
Acerca de este proyecto
En mi proyecto anterior, mostré cómo controlar algunos LED usando una placa Arduino y BitVoicer Server. En este proyecto, voy a complicar un poco las cosas. También voy a sintetizar voz usando el convertidor de digital a analógico (DAC) Arduino DUE. Si no tiene un Arduino DUE, puede usar otras placas Arduino, pero necesitará un DAC externo y algún código adicional para operar el DAC (la biblioteca BVSSpeaker no lo ayudará con eso).
En el video a continuación, puede ver que también hago que el Arduino reproduzca una pequeña canción y haga parpadear los LED como si fueran teclas de piano. Perdón por mis habilidades con el piano, pero eso es lo mejor que puedo hacer :). Los LED parpadean en la misma secuencia y sincronización que las teclas C, D y E reales, por lo que si tiene un piano a su alrededor, puede seguir los LED y tocar la misma canción. Es un tintineo de un antiguo minorista (Mappin) que ya ni siquiera existe.
Se ejecutarán los siguientes procedimientos para transformar los comandos de voz en actividad LED y voz sintetizada:
- 1. Las ondas de audio serán capturadas y amplificadas por la placa Sparkfun Electret Breakout;
- 2. La señal amplificada se digitalizará y almacenará en búfer en el Arduino utilizando su convertidor analógico a digital (ADC);
- 3. Las muestras de audio se transmitirán al servidor BitVoicer utilizando el puerto serie Arduino;
- 4. BitVoicer Server procesará el flujo de audio y reconocerá el discurso que contiene;
- 5. El discurso reconocido se asignará a comandos predefinidos que se enviarán de vuelta al Arduino. Si uno de los comandos consiste en sintetizar voz, BitVoicer Server preparará el flujo de audio y lo enviará al Arduino;
- 6. El Arduino identificará los comandos y realizará la acción apropiada. Si se recibe una transmisión de audio, se pondrá en cola en la clase BVSSpeaker y se reproducirá usando DUE DAC y DMA.
- 7. El amplificador de audio mono SparkFun amplificará la señal DAC para que pueda manejar un altavoz de 8 ohmios.
Lista de materiales:
- Arduino DUE:~ U $ 50.00
- Desglose del micrófono Sparkfun Electret:U $ 7.95
- Salida de amplificador de audio mono SparkFun:U $ 7.95
- BitVoicer Server 1.0:U $ 9.90
- Altavoz de 8 ohmios:~ U $ 2.00
- Tablero de pruebas:~ U $ 10.00
- 3 x LED:~ U $ 1.00
- 3 resistencias de 330 ohmios:~ U $ 0,75
- Cables de puente:~ U $ 0.50
PASO 1:Cableado
El primer paso es conectar el Arduino y la placa con los componentes como se muestra en las imágenes a continuación. Tuve que colocar una pequeña goma debajo del altavoz porque vibra mucho y sin la goma la calidad del audio se ve considerablemente afectada.
Aquí tenemos una pequeña pero importante diferencia con mi proyecto anterior. La mayoría de las placas Arduino funcionan a 5 V, pero el DUE funciona a 3,3 V. Debido a que obtuve mejores resultados ejecutando Sparkfun Electret Breakout a 3.3V, le recomiendo que agregue un puente entre el pin de 3.3V y el pin AREF SI está utilizando placas Arduino de 5V. El DUE ya usa una referencia analógica de 3.3V, por lo que no necesita un puente al pin AREF. De hecho, el pin AREF en el DUE está conectado al microcontrolador a través de un puente de resistencia. Para usar el pin AREF, la resistencia BR1 debe desoldarse de la PCB.
PASO 2:Subiendo el código al Arduino
Ahora debe cargar el siguiente código en su Arduino. Para mayor comodidad, el boceto de Arduino también está disponible en la sección Adjuntos en la parte inferior de esta publicación. Antes de cargar el código, debe instalar correctamente las bibliotecas del servidor BitVoicer en el IDE de Arduino (Importar una biblioteca .zip).
Boceto de Arduino :BVS_Demo2.ino
Este boceto tiene siete partes principales:
- Referencias de biblioteca y declaración de variables :Las primeras cuatro líneas incluyen referencias a las bibliotecas BVSP, BVSMic, BVSSpeaker y DAC. Estas bibliotecas son proporcionadas por BitSophia y se pueden encontrar en la carpeta de instalación de BitVoicer Server. La biblioteca DAC se incluye automáticamente cuando agrega una referencia a la biblioteca BVSSpeaker. Las otras líneas declaran constantes y variables utilizadas a lo largo del boceto. La clase BVSP se usa para comunicarse con BitVoicer Server, la clase BVSMic se usa para capturar y almacenar muestras de audio y la clase BVSSpeaker se usa para reproducir audio usando DUE DAC.
- Función de configuración :Esta función realiza las siguientes acciones:configura los modos de pin y su estado inicial; inicializa la comunicación en serie; e inicializa las clases BVSP, BVSMic y BVSSpeaker. También establece "controladores de eventos" (en realidad son punteros de función) para los eventos frameReceived, modeChanged y streamReceived de la clase BVSP.
- Función de bucle :Esta función realiza cinco acciones importantes:solicita información de estado al servidor (función keepAlive ()); comprueba si el servidor ha enviado datos y procesa los datos recibidos (función recibir ()); controla la grabación y el envío de transmisiones de audio (funciones isSREAvailable (), startRecording (), stopRecording () y sendStream ()); reproduce las muestras de audio en cola en la clase BVSSpeaker (función play ()); y llama a la función playNextLEDNote () que controla cómo deben parpadear los LED después de recibir el comando playLEDNotes.
- Función BVSP_frameReceived :Esta función se llama cada vez que la función recibir () identifica que se ha recibido una trama completa. Aquí ejecuto los comandos enviados desde BitVoicer Server. Los comandos que controlan los LED contienen 2 bytes. El primer byte indica el pin y el segundo byte indica el valor del pin. Utilizo la función analogWrite () para establecer el valor apropiado para el pin. También verifico si se ha recibido el comando playLEDNotes, que es de tipo Byte. Si se ha recibido, configuro playLEDNotes en true y marque la hora actual. Este tiempo será utilizado por la función playNextLEDNote para sincronizar los LED con la canción.
- Función BVSP_modeChanged :Esta función se llama cada vez que la función recibir () identifica un cambio de modo en la dirección de salida (Servidor -> Arduino). ¡¡¡GUAU!!! ¡¿Que es eso?! BitVoicer Server puede enviar datos enmarcados o transmisiones de audio al Arduino. Antes de que la comunicación pase de un modo a otro, BitVoicer Server envía una señal. La clase BVSP identifica esta señal y genera el evento modeChanged. En la función BVSP_modeChanged, si detecto que la comunicación va del modo de transmisión al modo enmarcado, sé que el audio ha finalizado, por lo que puedo decirle a la clase BVSSpeaker que deje de reproducir muestras de audio.
- Función BVSP_streamReceived :Esta función se llama cada vez que la función recibir () identifica que se han recibido muestras de audio. Simplemente recupero las muestras y las pongo en cola en la clase BVSSpeaker para que la función play () pueda reproducirlas.
- función playNextLEDNote :Esta función solo se ejecuta si la función BVSP_frameReceived identifica el comando playLEDNotes. Controla y sincroniza los LED con el audio enviado desde BitVoicer Server. Para sincronizar los LED con el audio y conocer la sincronización correcta, utilicé Sonic Visualizer. Este software gratuito me permitió ver las ondas de audio para poder saber fácilmente cuándo se presionó una tecla de piano. También muestra una línea de tiempo y así es como obtuve los milisegundos usados en esta función. Suena como un truco tonto y lo es. Creo que sería posible analizar el flujo de audio y encender el LED correspondiente, pero eso está fuera de mi alcance.
PASO 3:Importación de objetos de la solución del servidor BitVoicer
Ahora tienes que configurar BitVoicer Server para que funcione con Arduino. BitVoicer Server tiene cuatro objetos de solución principales:ubicaciones, dispositivos, datos binarios y esquemas de voz.
Las ubicaciones representan la ubicación física donde se instala un dispositivo. En mi caso, creé una ubicación llamada Casa.
Los dispositivos son los clientes de BitVoicer Server. Creé un dispositivo mixto, lo llamé ArduinoDUE e ingresé la configuración de comunicación. IMPORTANTE :incluso el Arduino DUE tiene una pequeña cantidad de memoria para almacenar todas las muestras de audio que BitVoicer Server transmitirá. Si no limita el ancho de banda, necesitará un búfer mucho más grande para almacenar el audio. Obtuve algunos desbordamientos de búfer por esta razón, así que tuve que limitar la velocidad de datos en la configuración de comunicación a 8000 muestras por segundo.
BinaryData es un tipo de comando que BitVoicer Server puede enviar a los dispositivos cliente. En realidad, son matrices de bytes que puede vincular a comandos. Cuando BitVoicer Server reconoce la voz relacionada con ese comando, envía la matriz de bytes al dispositivo de destino. Creé un objeto BinaryData para cada valor de pin y los llamé ArduinoDUEGreenLedOn, ArduinoDUEGreenLedOff, etc. Terminé con 18 objetos BinaryData en mi solución, por lo que le sugiero que descargue e importe los objetos desde VoiceSchema.sof archivo a continuación.
Los esquemas de voz son donde todo se junta. Definen qué oraciones deben reconocerse y qué comandos ejecutar. Para cada oración, puede definir tantos comandos como necesite y el orden en que se ejecutarán. También puede definir retrasos entre comandos. Así es como logré realizar la secuencia de acciones que ves en el video.
Una de las frases de mi esquema de voz es "toca una pequeña canción". Esta oración contiene dos comandos. El primer comando envía un byte que indica que el siguiente comando será un flujo de audio. Luego, el Arduino comienza a "reproducir" los LED mientras se transmite el audio. El audio es un pequeño tintineo de piano que grabé yo mismo y lo configuré como la fuente de audio del segundo comando. BitVoicer Server solo admite audio PCM mono de 8 bits (8000 muestras por segundo), por lo que si necesita convertir un archivo de audio a este formato, le recomiendo la siguiente herramienta de conversión en línea:http://audio.online-convert.com/convert -a-wav.
Puede importar (Importar objetos de solución) todos los objetos de solución que utilicé en este proyecto desde los archivos a continuación. Uno contiene el dispositivo DUE y el otro contiene el esquema de voz y sus comandos.
Archivos de objeto de solución :
- Device.sof
- VoiceSchema.sof
PASO 4:Conclusión
¡Ahí tienes! Puedes encender todo y hacer las mismas cosas que se muestran en el video.
Como hice en mi proyecto anterior, comencé el reconocimiento de voz habilitando el dispositivo Arduino en BitVoicer Server Manager. Tan pronto como se habilita, Arduino identifica un motor de reconocimiento de voz disponible y comienza a transmitir audio al servidor BitVoicer. Sin embargo, ahora ve mucha más actividad en el LED Arduino RX mientras el audio se transmite desde BitVoicer Server al Arduino.
En mi próximo proyecto, seré un poco más ambicioso. Voy a agregar comunicación WiFi a un Arduino y controlaré otros dos Arduino todos juntos por voz. Estoy pensando en una especie de juego entre ellos. ¡Las sugerencias son bienvenidas!
Código
- Bosquejo de Arduino
Arduino Sketch Arduino
#include#include #include #include // Define el pin Arduino que se usará para capturar audio #define BVSM_AUDIO_INPUT 7 // Define los pines LED # define RED_LED_PIN 6 # define YELLOW_LED_PIN 9 # define GREEN_LED_PIN 10 // Define las constantes que se pasarán como parámetros a // la función BVSP.begin const unsigned long STATUS_REQUEST_TIMEOUT =3000; const unsigned long STATUS_REQUEST_INTERVAL =4000; // Define el tamaño del búfer de audio del micrófono const int MIC_BUFFER_SIZE =64; // Define el tamaño del búfer de audio del altavozconst int SPEAKER_BUFFER_SIZE =128; // Define el tamaño del búfer de recepciónconst int RECEIVE_BUFFER_SIZE =2; // Inicializa una nueva instancia global de la clase BVSP BVSP bvsp =BVSP (); // Inicializa una nueva instancia global de la clase BVSMic BVSMic bvsm =BVSMic (); // Inicializa una nueva instancia global de la clase BVSSpeaker BVSSpeaker bvss =BVSSpeaker (); // Crea un búfer que se utilizará para leer muestras grabadas // de t a clase BVSMic byte micBuffer [MIC_BUFFER_SIZE]; // Crea un búfer que se utilizará para escribir muestras de audio // en el byte de la clase BVSSpeaker speakerBuffer [SPEAKER_BUFFER_SIZE]; // Crea un búfer que se utilizará para leer los comandos enviados // desde BitVoicer Server.// Byte 0 =número de pin // Byte 1 =valor de pin byte receiveBuffer [RECEIVE_BUFFER_SIZE]; // Estas variables se utilizan para controlar cuándo reproducir // "Notas LED". Estas notas se reproducirán junto con // la canción transmitida desde BitVoicer Server.bool playLEDNotes =false; unsigned int playStartTime =0; void setup () {// Configura los modos pin pinMode (RED_LED_PIN, OUTPUT); pinMode (AMARILLO_LED_PIN, SALIDA); pinMode (GREEN_LED_PIN, SALIDA); // Establece el estado inicial de todos los LED digitalWrite (RED_LED_PIN, LOW); digitalWrite (AMARILLO_LED_PIN, BAJO); digitalWrite (GREEN_LED_PIN, BAJO); // Inicia la comunicación en serie a 115200 bps Serial.begin (115200); // Establece el puerto serie Arduino que se utilizará para // la comunicación, cuánto tiempo pasará antes de que se agote el // tiempo de espera de una solicitud de estado y con qué frecuencia se deben enviar las solicitudes de estado al // servidor BitVoicer. bvsp.begin (Serie, STATUS_REQUEST_TIMEOUT, STATUS_REQUEST_INTERVAL); // Define la función que manejará el evento frameReceived // bvsp.frameReceived =BVSP_frameReceived; // Establece la función que manejará el evento modeChanged // bvsp.modeChanged =BVSP_modeChanged; // Establece la función que manejará el evento streamReceived // bvsp.streamReceived =BVSP_streamReceived; // Prepara el temporizador de la clase BVSMic bvsm.begin (); // Establece el DAC que será utilizado por la clase BVSSpeaker bvss.begin (DAC);} void loop () {// Verifica si el intervalo de solicitud de estado ha transcurrido y si // lo ha hecho, envía una solicitud de estado al servidor BitVoicer bvsp.keepAlive (); // Comprueba si hay datos disponibles en el búfer del puerto serie // y procesa su contenido de acuerdo con las especificaciones // del BitVoicer Server Protocol bvsp.receive (); // Comprueba si hay un SRE disponible. Si hay uno, // comienza a grabar. if (bvsp.isSREAvailable ()) {// Si la clase BVSMic no está grabando, configura la entrada // de audio y comienza a grabar if (! bvsm.isRecording) {bvsm.setAudioInput (BVSM_AUDIO_INPUT, DEFAULT); bvsm.startRecording (); } // Comprueba si la clase BVSMic tiene muestras disponibles if (bvsm.available) {// Se asegura de que el modo de entrada sea STREAM_MODE antes de // transmitir el flujo if (bvsp.inboundMode ==FRAMED_MODE) bvsp.setInboundMode (STREAM_MODE); // Lee las muestras de audio de la clase BVSMic int bytesRead =bvsm.read (micBuffer, MIC_BUFFER_SIZE); // Envía el flujo de audio a BitVoicer Server bvsp.sendStream (micBuffer, bytesRead); }} else {// No hay SRE disponible. Si la clase BVSMic está grabando, // la detiene. if (bvsm.isRecording) bvsm.stopRecording (); } // Reproduce todas las muestras de audio disponibles en la clase BVSSpeaker // búfer interno. Estos ejemplos están escritos en el controlador de eventos // BVSP_streamReceived. Si no hay muestras // disponibles en el búfer interno, no se reproduce nada. bvss.play (); // Si playLEDNotes se ha establecido en true, // reproduce las "notas LED" junto con la música. if (playLEDNotes) playNextLEDNote ();} // Maneja el evento frameReceived void BVSP_frameReceived (byte dataType, int payloadSize) {// Comprueba si el frame recibido contiene datos binarios // 0x07 =Datos binarios (matriz de bytes) if (dataType ==DATA_TYPE_BINARY) {// Si se recibieron 2 bytes, procese el comando. if (bvsp.getReceivedBytes (recibirBuffer, RECEIVE_BUFFER_SIZE) ==RECEIVE_BUFFER_SIZE) {analogWrite (recibirBuffer [0], recibirBuffer [1]); }} // Comprueba si el marco recibido contiene un tipo de datos de byte // 0x01 =Tipo de datos de byte else if (dataType ==DATA_TYPE_BYTE) {// Si el valor del byte recibido es 255, establece playLEDNotes // y marca la hora actual. if (bvsp.getReceivedByte () ==255) {playLEDNotes =true; playStartTime =millis (); }}} // Maneja el evento modeChanged void BVSP_modeChanged () {// Si el outboundMode (Server -> Device) se ha convertido en // FRAMED_MODE, no se supone que se reciba ningún flujo de audio. // Le dice a la clase BVSSpeaker que termine de reproducir cuando su // búfer interno se vacíe. if (bvsp.outboundMode ==FRAMED_MODE) bvss.finishPlaying ();} // Maneja el evento streamReceived void BVSP_streamReceived (int size) {// Obtiene el flujo recibido de la clase BVSP int bytesRead =bvsp.getReceivedStream (speakerBuffer, SPEAKER_SIZEFF); // Pone en cola el flujo recibido para reproducir bvss.enqueue (speakerBuffer, bytesRead);} // Ilumina el LED correspondiente según la hora // se recibió el comando para comenzar a reproducir las notas del LED .// Los tiempos usados aquí están sincronizados con the music.void playNextLEDNote () {// Obtiene el tiempo transcurrido entre playStartTime y // la hora actual. unsigned long transcurrido =millis () - playStartTime; // Apaga todos los LED allLEDsOff (); // Se ha tocado la última nota. // Apaga el último LED y deja de tocar las notas del LED. si (transcurrido> =11500) {analogWrite (RED_LED_PIN, 0); playLEDNotes =falso; } else if (transcurrido> =9900) analogWrite (RED_LED_PIN, 255); // C note else if (transcurrido> =9370) analogWrite (RED_LED_PIN, 255); // C note else if (transcurrido> =8900) analogWrite (YELLOW_LED_PIN, 255); // D note else if (transcurrido> =8610) analogWrite (RED_LED_PIN, 255); // C note else if (transcurrido> =8230) analogWrite (YELLOW_LED_PIN, 255); // D note else if (transcurrido> =7970) analogWrite (YELLOW_LED_PIN, 255); // D note else if (transcurrido> =7470) analogWrite (RED_LED_PIN, 255); // C note else if (transcurrido> =6760) analogWrite (GREEN_LED_PIN, 255); // E note else if (transcurrido> =6350) analogWrite (RED_LED_PIN, 255); // C note else if (transcurrido> =5880) analogWrite (YELLOW_LED_PIN, 255); // D note else if (transcurrido> =5560) analogWrite (RED_LED_PIN, 255); // C note else if (transcurrido> =5180) analogWrite (YELLOW_LED_PIN, 255); // D note else if (transcurrido> =4890) analogWrite (YELLOW_LED_PIN, 255); // D note else if (transcurrido> =4420) analogWrite (RED_LED_PIN, 255); // C note else if (transcurrido> =3810) analogWrite (GREEN_LED_PIN, 255); // E note else if (transcurrido> =3420) analogWrite (RED_LED_PIN, 255); // C note else if (transcurrido> =2930) analogWrite (YELLOW_LED_PIN, 255); // D note else if (transcurrido> =2560) analogWrite (RED_LED_PIN, 255); // C note else if (transcurrido> =2200) analogWrite (YELLOW_LED_PIN, 255); // D note else if (transcurrido> =1930) analogWrite (YELLOW_LED_PIN, 255); // D note else if (transcurrido> =1470) analogWrite (RED_LED_PIN, 255); // C note else if (transcurrido> =1000) analogWrite (GREEN_LED_PIN, 255); // Nota E} // Apaga todos los LED.void allLEDsOff () {analogWrite (RED_LED_PIN, 0); analogWrite (YELLOW_LED_PIN, 0); analogWrite (GREEN_LED_PIN, 0);}
Esquemas
Proceso de manufactura
- Sistema de asistencia que usa Arduino y RFID con Python
- Sensor DHT11 con LED y altavoz piezoeléctrico
- Diversión con giroscopio con NeoPixel Ring
- Arduino Temp. Monitor y reloj en tiempo real con pantalla 3.2
- Controlar un robot Roomba con Arduino y un dispositivo Android
- Voltímetro de bricolaje con Arduino y una pantalla Nokia 5110
- Control del servomotor con Arduino y MPU6050
- Módulo GPS u-blox LEA-6H 02 con Arduino y Python
- Cómo leer la temperatura y la humedad en Blynk con DHT11
- Cubo LED 4x4x4 con Arduino Uno y 1sheeld
- Pantalla de ubicación GPS con protectores de pantalla GPS y TFT