Dominando Reconhecimento e Síntese de Fala no Arduino Due
Componentes e Materiais
| Componente | Quantidade |
|---|---|
| Arduino Due | 1 |
| SparkFun Electret Microphone Breakout | 1 |
| SparkFun Mono Audio Amp Breakout | 1 |
| Alto-falante: 0.25W, 8 ohms | 1 |
| Protoboard (genérica) | 1 |
| LED 5mm Vermelho | 3 |
| Resistor 330 Ω | 3 |
| Jumpers (genéricos) | 1 |
Ferramentas Necessárias
- Ferro de solda (genérico)
Aplicativos e Serviços Online
- BitVoicer Server 1.0
Sobre o Projeto
No meu projeto anterior, mostrei como controlar alguns LEDs usando Arduino e BitVoicer Server. Neste, complico um pouco mais: também vou sintetizar fala usando o conversor digital-analógico (DAC) do Arduino Due. Se não tiver um Due, pode usar outras placas, mas precisará de um DAC externo e código adicional (a biblioteca BVSSpeaker não ajudará com isso).
No vídeo, o Arduino toca uma musiquinha e pisca os LEDs como teclas de piano. Peço desculpas pelas habilidades de piano, mas é o melhor que consigo :) Os LEDs piscam na mesma sequência e tempo das teclas C, D e E reais; se tiver um piano, pode seguir os LEDs e tocar a mesma música. É um jingle de um antigo varejista (Mappin) que nem existe mais.
Procedimentos para Transformar Comandos de Voz em Atividade de LEDs e Fala Sintetizada
- Ondas de áudio capturadas e amplificadas pelo SparkFun Electret Breakout.
- Sinal amplificado digitalizado e bufferizado no Arduino via ADC.
- Amostras de áudio transmitidas ao BitVoicer Server pela porta serial.
- BitVoicer Server processa o stream e reconhece a fala.
- Fala reconhecida mapeada a comandos pré-definidos, enviados de volta ao Arduino. Se o comando for síntese de fala, o servidor prepara o stream de áudio e envia ao Arduino.
- Arduino identifica comandos e executa ações. Se recebe stream de áudio, enfileira na classe BVSSpeaker e reproduz usando DAC e DMA do Due.
- SparkFun Mono Audio Amp amplifica o sinal do DAC para驱动 alto-falante de 8 Ohms.
Lista de Materiais (Preços Aproximados)
- Arduino Due: ~US$ 50,00
- SparkFun Electret Microphone Breakout: US$ 7,95
- SparkFun Mono Audio Amp Breakout: US$ 7,95
- BitVoicer Server 1.0: US$ 9,90
- Alto-falante 8 Ohms: ~US$ 2,00
- Protoboard: ~US$ 10,00
- 3x LEDs: ~US$ 1,00
- 3x Resistores 330 Ω: ~US$ 0,75
- Jumpers: ~US$ 0,50
Passo 1: Fiação
Monte o Arduino e a protoboard com os componentes conforme as imagens. Coloquei uma pequena borracha sob o alto-falante porque vibra muito e sem ela a qualidade de áudio fica consideravelmente afetada.




Diferença importante: A maioria dos Arduinos opera a 5V, mas o Due roda a 3.3V. Obtive melhores resultados rodando o SparkFun Electret Breakout a 3.3V. Se usar placas Arduino 5V, recomendo jumper entre pino 3.3V e AREF. O Due já usa referência analógica 3.3V, então não precisa jumper no AREF. Na verdade, o pino AREF do Due é conectado ao microcontrolador através de ponte de resistores; para usar AREF, o resistor BR1 deve ser dessoldado da PCB.
Passo 2: Carregando o Código no Arduino
Carregue o sketch abaixo (também disponível em anexos). Antes, instale corretamente as bibliotecas do BitVoicer Server na Arduino IDE (Importar Biblioteca .zip).
Sketch Arduino: BVS_Demo2.ino
O sketch tem sete partes principais:
- Referências de bibliotecas e declaração de variáveis: Inclui
BVSP.h,BVSMic.h,BVSSpeaker.h,DAC.h. Bibliotecas fornecidas pela BitSophia na pasta de instalação do BitVoicer Server. A biblioteca DAC é incluída automaticamente ao referenciar BVSSpeaker. Declara constantes e variáveis. Classes: BVSP (comunicação), BVSMic (captura/armazenamento de amostras), BVSSpeaker (reprodução via DAC do Due). - Função setup(): Configura modos de pinos e estado inicial; inicia comunicação serial; inicializa classes BVSP, BVSMic, BVSSpeaker. Define "event handlers" (ponteiros de função) para eventos
frameReceived,modeChanged,streamReceivedda classe BVSP. - Função loop(): Cinco ações: solicita status ao servidor (
keepAlive()); verifica dados recebidos e processa (receive()); controla gravação e envio de streams de áudio (isSREAvailable(),startRecording(),stopRecording(),sendStream()); reproduz amostras enfileiradas no BVSSpeaker (play()); chamaplayNextLEDNote()que controla piscar dos LEDs após comandoplayLEDNotes. - BVSP_frameReceived(): Chamada quando
receive()identifica frame completo. Executa comandos do servidor. Comandos de LEDs contêm 2 bytes: pino e valor. UsaanalogWrite(). Verifica se comandoplayLEDNotes(tipo Byte) foi recebido; se sim, defineplayLEDNotes=truee marca tempo atual para sincronização. - BVSP_modeChanged(): Chamada quando
receive()detecta mudança de modo na direção outbound (Servidor → Arduino). BitVoicer Server pode enviar dados enquadrados ou streams de áudio. Antes de mudar modo, envia sinal. Classe BVSP identifica e dispara evento. Se comunicação muda de stream para framed, sabe que áudio acabou e manda BVSSpeaker parar quando buffer esvaziar. - BVSP_streamReceived(): Chamada quando amostras de áudio recebidas. Recupera amostras e enfileira no BVSSpeaker para reprodução via
play(). - playNextLEDNote(): Executa apenas se
BVSP_frameReceivedidentificar comandoplayLEDNotes. Controla e sincroniza LEDs com áudio enviado do servidor. Para sincronizar, usei Sonic Visualizer (software livre) para ver ondas de áudio e identificar quando tecla de piano era pressionada. Também mostra timeline, de onde obtive os milissegundos usados. Parece truque bobo, mas funciona. Analisar stream de áudio e acender LED correspondente seria possível, mas foge do escopo.
Passo 3: Importando Objetos da Solução BitVoicer Server
Configure o BitVoicer Server para trabalhar com o Arduino. Quatro objetos principais: Locations, Devices, BinaryData, Voice Schemas.
- Locations: Local físico do dispositivo. Criei "Home".
- Devices: Clientes do BitVoicer Server. Criei dispositivo "Mixed" chamado
ArduinoDUEcom configurações de comunicação. IMPORTANTE: O Due tem pouca memória para armazenar todas as amostras de áudio que o servidor fará stream. Se não limitar largura de banda, precisaria de buffer enorme. Tive estouros de buffer, então limitei Data Rate nas configurações de comunicação para 8000 amostras/segundo. - BinaryData: Tipo de comando que o servidor envia ao dispositivo. São arrays de bytes vinculados a comandos. Quando o servidor reconhece fala relacionada, envia o array ao dispositivo alvo. Criei um objeto BinaryData para cada valor de pino:
ArduinoDUEGreenLedOn,ArduinoDUEGreenLedOff, etc. Total de 18 objetos. Sugiro baixar e importar do arquivoVoiceSchema.sof. - Voice Schemas: Onde tudo se junta. Definem frases a reconhecer e comandos a executar. Para cada frase, pode definir vários comandos e ordem. Também pode definir atrasos entre comandos. Assim gerenciei a sequência de ações do vídeo.
Uma das frases no Voice Schema é "play a little song". Contém dois comandos: primeiro envia byte indicando que o próximo comando será stream de áudio; Arduino inicia "tocada" dos LEDs enquanto áudio é transmitido. O áudio é um jingle de piano que gravei e defini como fonte do segundo comando. BitVoicer Server suporta apenas áudio PCM mono 8-bit (8000 amostras/seg). Para converter arquivos, recomendo: audio.online-convert.com.
Importe todos os objetos da solução usados neste projeto nos arquivos abaixo:
Device.sof(Dispositivo Due)VoiceSchema.sof(Voice Schema e Comandos)
Passo 4: Conclusão
Pronto! Ligue tudo e faça as mesmas coisas do vídeo.
Como no projeto anterior, iniciei o reconhecimento de fala habilitando o dispositivo Arduino no BitVoicer Server Manager. Assim que habilitado, o Arduino identifica um Speech Recognition Engine disponível e começa a transmitir áudio ao servidor. Agora há muito mais atividade no LED RX do Arduino enquanto áudio é transmitido do servidor para o Arduino.
No próximo projeto, serei mais ambicioso: adicionarei comunicação WiFi a um Arduino e controlarei outros dois Arduinos todos juntos por voz. Estou pensando em algum tipo de jogo entre eles. Sugestões são bem-vindas!
Código
Sketch Arduino (Arduino)
#include <BVSP.h>
#include <BVSMic.h>
#include <BVSSpeaker.h>
#include <DAC.h>
#define BVSM_AUDIO_INPUT 7
#define RED_LED_PIN 6
#define YELLOW_LED_PIN 9
#define GREEN_LED_PIN 10
const unsigned long STATUS_REQUEST_TIMEOUT = 3000;
const unsigned long STATUS_REQUEST_INTERVAL = 4000;
const int MIC_BUFFER_SIZE = 64;
const int SPEAKER_BUFFER_SIZE = 128;
const int RECEIVE_BUFFER_SIZE = 2;
BVSP bvsp = BVSP();
BVSMic bvsm = BVSMic();
BVSSpeaker bvss = BVSSpeaker();
byte micBuffer[MIC_BUFFER_SIZE];
byte speakerBuffer[SPEAKER_BUFFER_SIZE];
byte receiveBuffer[RECEIVE_BUFFER_SIZE];
bool playLEDNotes = false;
unsigned int playStartTime = 0;
void setup() {
pinMode(RED_LED_PIN, OUTPUT);
pinMode(YELLOW_LED_PIN, OUTPUT);
pinMode(GREEN_LED_PIN, OUTPUT);
digitalWrite(RED_LED_PIN, LOW);
digitalWrite(YELLOW_LED_PIN, LOW);
digitalWrite(GREEN_LED_PIN, LOW);
Serial.begin(115200);
bvsp.begin(Serial, STATUS_REQUEST_TIMEOUT, STATUS_REQUEST_INTERVAL);
bvsp.frameReceived = BVSP_frameReceived;
bvsp.modeChanged = BVSP_modeChanged;
bvsp.streamReceived = BVSP_streamReceived;
bvsm.begin();
bvss.begin(DAC);
}
void loop() {
bvsp.keepAlive();
bvsp.receive();
if (bvsp.isSREAvailable()) {
if (!bvsm.isRecording) {
bvsm.setAudioInput(BVSM_AUDIO_INPUT, DEFAULT);
bvsm.startRecording();
}
if (bvsm.available) {
if (bvsp.inboundMode == FRAMED_MODE) bvsp.setInboundMode(STREAM_MODE);
int bytesRead = bvsm.read(micBuffer, MIC_BUFFER_SIZE);
bvsp.sendStream(micBuffer, bytesRead);
}
} else {
if (bvsm.isRecording) bvsm.stopRecording();
}
bvss.play();
if (playLEDNotes) playNextLEDNote();
}
void BVSP_frameReceived(byte dataType, int payloadSize) {
if (dataType == DATA_TYPE_BINARY) {
if (bvsp.getReceivedBytes(receiveBuffer, RECEIVE_BUFFER_SIZE) == RECEIVE_BUFFER_SIZE) {
analogWrite(receiveBuffer[0], receiveBuffer[1]);
}
} else if (dataType == DATA_TYPE_BYTE) {
if (bvsp.getReceivedByte() == 255) {
playLEDNotes = true;
playStartTime = millis();
}
}
}
void BVSP_modeChanged() {
if (bvsp.outboundMode == FRAMED_MODE) bvss.finishPlaying();
}
void BVSP_streamReceived(int size) {
int bytesRead = bvsp.getReceivedStream(speakerBuffer, SPEAKER_BUFFER_SIZE);
bvss.enqueue(speakerBuffer, bytesRead);
}
void playNextLEDNote() {
unsigned long elapsed = millis() - playStartTime;
allLEDsOff();
if (elapsed >= 11500) { analogWrite(RED_LED_PIN, 0); playLEDNotes = false; }
else if (elapsed >= 9900) analogWrite(RED_LED_PIN, 255);
else if (elapsed >= 9370) analogWrite(RED_LED_PIN, 255);
else if (elapsed >= 8900) analogWrite(YELLOW_LED_PIN, 255);
else if (elapsed >= 8610) analogWrite(RED_LED_PIN, 255);
else if (elapsed >= 8230) analogWrite(YELLOW_LED_PIN, 255);
else if (elapsed >= 7970) analogWrite(YELLOW_LED_PIN, 255);
else if (elapsed >= 7470) analogWrite(RED_LED_PIN, 255);
else if (elapsed >= 6760) analogWrite(GREEN_LED_PIN, 255);
else if (elapsed >= 6350) analogWrite(RED_LED_PIN, 255);
else if (elapsed >= 5880) analogWrite(YELLOW_LED_PIN, 255);
else if (elapsed >= 5560) analogWrite(RED_LED_PIN, 255);
else if (elapsed >= 5180) analogWrite(YELLOW_LED_PIN, 255);
else if (elapsed >= 4890) analogWrite(YELLOW_LED_PIN, 255);
else if (elapsed >= 4420) analogWrite(RED_LED_PIN, 255);
else if (elapsed >= 3810) analogWrite(GREEN_LED_PIN, 255);
else if (elapsed >= 3420) analogWrite(RED_LED_PIN, 255);
else if (elapsed >= 2930) analogWrite(YELLOW_LED_PIN, 255);
else if (elapsed >= 2560) analogWrite(RED_LED_PIN, 255);
else if (elapsed >= 2200) analogWrite(YELLOW_LED_PIN, 255);
else if (elapsed >= 1930) analogWrite(YELLOW_LED_PIN, 255);
else if (elapsed >= 1470) analogWrite(RED_LED_PIN, 255);
else if (elapsed >= 1000) analogWrite(GREEN_LED_PIN, 255);
}
void allLEDsOff() {
analogWrite(RED_LED_PIN, 0);
analogWrite(YELLOW_LED_PIN, 0);
analogWrite(GREEN_LED_PIN, 0);
}
Esquemático

Processo de manufatura
- Sistema de Presença RFID Confiável com Arduino e Python
- Projeto DHT11: Sensor Temperatura/Umidade com LEDs Indicadores e Buzzer
- Display Interativo de Giroscópio com Anel NeoPixel e Arduino
- Monitor de Temperatura e Relógio Tempo Real com Arduino Due e Display TFT 3.2"
- Controlar Roomba Create 2 com Arduino e Android: Guia Passo a Passo
- Construa um Voltímetro DIY com Arduino e Display Nokia 5110 – Guia Passo a Passo
- Arduino e MPU6050: Controle Preciso de Servomotores SG90 e MG996R
- Módulo GPS u-blox LEA‑6H 02: Guia de Integração com Arduino e Python
- Leitura de Temperatura e Umidade com DHT11 no Blynk – Tutorial Arduino Passo a Passo
- Construa um Cubo de LED 4x4x4 com Arduino Uno e 1Sheeld – Projeto Interativo de LED