Manufaturação industrial
Internet das coisas industrial | Materiais industriais | Manutenção e reparo de equipamentos | Programação industrial |
home  MfgRobots >> Manufaturação industrial >  >> Manufacturing Technology >> Processo de manufatura

Construa um Robô de 2 Rodas Controlado por Voz com Arduino e BitVoicer Server

Componentes e Materiais

Arduino UNO 1
Shield Driver de Motor Duplo MC33926 Pololu 1
Shield XBee SparkFun 1
Módulo Microchip RN171VX 1
Breakout Microfone Electret SparkFun 1
Chassi Carro Robô 2WD 1
Regulador de Tensão Texas Instruments LM1117 (TO-220) 1
Capacitor 10 µF 1
LED (genérico) 4
Resistor 330 ohm 4
Pilhas AA 4
Bateria 9V (genérica) 1
Adaptador 9V para Jack Barril 1
Fios Jumper (genéricos) 17
Fio de Cobre Comum 1
Parafusos e braçadeira plástica flexível para fixação 1

Ferramentas e Máquinas Necessárias

Aplicativos e Serviços Online

Sobre o Projeto

Neste tutorial, vou mostrar como construir um robô 2WD controlado por voz. Embora eu esteja controlando apenas motores DC para mover o robô, a mesma abordagem pode ser usada para controlar por voz motores de passo e servomotores, então se você está planejando construir qualquer robô controlado por voz que realize movimentos mecânicos, este tutorial pode servir como referência para seu projeto.

Construa um Robô de 2 Rodas Controlado por Voz com Arduino e BitVoicer Server

Para construir este robô, você basicamente precisará de um chassi 2 rodas, uma placa Arduino, um shield driver de motor DC, uma licença do BitVoicer Server, um módulo WiFi e um microfone pré-amplificado. Quanto aos componentes, há uma enorme variedade no mercado e você pode obter os mesmos resultados usando diferentes combinações. No Passo 1, dou alguns detalhes sobre alguns componentes usados no robô, então se você precisar trocar alguns deles, apenas procure componentes com características semelhantes.

Os seguintes procedimentos serão executados para transformar comandos de voz em movimentos do robô:

  1. Ondas de áudio serão capturadas e amplificadas pela placa Sparkfun Electret Breakout;
  2. O sinal amplificado será digitalizado e bufferizado no Arduino usando seu conversor analógico-digital (ADC);
  3. As amostras de áudio serão transmitidas para o BitVoicer Server usando o módulo WiFi Microchip;
  4. O BitVoicer Server processará o fluxo de áudio e reconhecerá a fala que ele contém;
  5. A fala reconhecida será mapeada para comandos predefinidos que serão enviados ao Arduino;
  6. O Arduino identificará o comando e definirá quais motores DC serão usados, por quanto tempo e em que velocidade;
  7. O driver de motor será ativado para fornecer a tensão e corrente necessárias para mover os motores.

Lista de Materiais:

PASSO 1: Conhecendo os Componentes

Neste passo, dou algumas informações importantes sobre os componentes do robô e como prepará-los para montagem.

Em primeiro lugar, o coração do robô: um Arduino UNO R3. Embora eu esteja usando um Arduino UNO, você pode usar outras placas Arduino para montar seu robô. Decidi usar um Arduino UNO porque é, de longe, a placa Arduino mais popular e mais pessoas poderiam reconstruir este robô. Se você tem um Arduino DUE, também pode adicionar respostas de voz ao seu robô como fiz neste tutorial.

Para mover os motores DC, usei este shield da Pololu. É um driver de motor duplo capaz de controlar motores DC de 5 a 28V e entregar até 3A de corrente contínua por motor. Embora eu ache que este é um shield muito bom, o que mais me impressionou nos produtos da Pololu é a documentação clara e detalhada. Além disso, a Pololu fornece uma biblioteca Arduino que torna realmente simples controlar os motores. Você só precisa passar a velocidade e a direção (valores negativos ou positivos) para a função setSpeeds. Se você optar por usar outro driver de motor DC, preste atenção aos pinos usados pelo driver porque eles não podem conflitar com qualquer outro pino usado pelo robô. O shield Pololu usa os seguintes pinos do Arduino: digital 4, 7, 8, 9, 10 e 12; analógico 0 e 1; terra; e 5V. O aspecto mais importante aqui é que apenas os pinos 9 e 10 são usados como pinos PWM e o timer usado para gerar pulsos nesses pinos não é o mesmo timer (timer 2 no UNO) usado pela classe BVSMic do BitSophia.

Construa um Robô de 2 Rodas Controlado por Voz com Arduino e BitVoicer Server

Para estabelecer comunicação com o servidor e acessar os serviços do BitVoicer Server, uso o módulo WiFi Microchip RN171VX. Duas características principais se destacam neste módulo: toda a comunicação pode ser feita através da porta serial de maneira simples; e o módulo tem o mesmo fator de forma da maioria dos módulos XBee populares. Em outras palavras, se você já tem um shield XBee, provavelmente não precisará comprar o shield Sparkfun que uso neste robô.

Usar o shield XBee com o módulo WiFi Microchip tornou a montagem do robô bem fácil. No entanto, identifiquei um problema nesta combinação. Sabe-se que trabalhar com rádio é extremamente complexo e considerado por alguns como "mágica vodu". Bem, percebi que enquanto o adaptador WiFi está ligado e transmitindo dados, ocorre uma forte interferência no sinal de áudio medido pelo ADC do Arduino. Não consegui identificar precisamente a fonte desta interferência, mas tenho duas fontes possíveis: os picos de consumo de corrente do módulo (até 240mA) não estão sendo desacoplados adequadamente e comprometem a tensão de referência fornecida ao ADC do Arduino; ou o sinal emitido pela antena está sendo captado por alguns pinos expostos logo abaixo do módulo. Geralmente, fabricantes de módulos WiFi instruem designers a evitar colocar qualquer coisa (até mesmo planos de terra) perto da antena precisamente para prevenir este tipo de problema.

Para corrigir o problema descrito acima, soldei um regulador de tensão 3,3V e um capacitor eletrolítico de 10μF no shield Sparkfun para que eles pudessem fornecer a tensão de referência ao ADC do Arduino. A mesma fonte de alimentação é usada pelo microfone electret Sparkfun. Resolveu os problemas de pico de volume que eu via no Gerenciador do BitVoicer Server. Mesmo durante períodos de silêncio, o nível de áudio chegava a 35 (0-100) no Monitor do Servidor. Se você vir a mesma coisa acontecendo no seu projeto, investigue o que está acontecendo com o sinal de áudio medido pelo ADC do Arduino.

Decidi também usar o espaço de prototipagem disponível no shield Sparkfun para soldar alguns LEDs que indicam o status de algumas funcionalidades do BitVoicer Server. Na imagem abaixo, da esquerda para a direita, as seguintes informações são expostas pelos LEDs:

Construa um Robô de 2 Rodas Controlado por Voz com Arduino e BitVoicer Server
Construa um Robô de 2 Rodas Controlado por Voz com Arduino e BitVoicer Server

Quanto ao microfone electret pré-amplificado, há muitas opções disponíveis no mercado: Sparkfun, Adafruit, RoboCore, Hackerstore e provavelmente muitos outros. Para usar o código que estou postando neste tutorial, certifique-se de que o microfone que você está comprando é analógico, a tensão necessária está disponível na sua placa Arduino, e a amplificação é alta o suficiente (geralmente 100x para microfones electret) para o ADC do Arduino.

O chassi 2WD usado no robô é um dos mais baratos e populares no eBay. O kit completo contém uma plataforma de acrílico, duas rodas de plástico/borracha, uma roda 360º, dois motores DC com engrenagem (proporção 1:48), um suporte para 4 pilhas AA, dois discos codificadores de velocidade e um conjunto de parafusos.

PASSO 2: Montagem

Mãos à obra! Neste passo você deve montar todos os componentes no chassi como mostrado nas imagens abaixo.

Construa um Robô de 2 Rodas Controlado por Voz com Arduino e BitVoicer Server
Construa um Robô de 2 Rodas Controlado por Voz com Arduino e BitVoicer Server
Construa um Robô de 2 Rodas Controlado por Voz com Arduino e BitVoicer Server
Construa um Robô de 2 Rodas Controlado por Voz com Arduino e BitVoicer Server
Construa um Robô de 2 Rodas Controlado por Voz com Arduino e BitVoicer Server
Construa um Robô de 2 Rodas Controlado por Voz com Arduino e BitVoicer Server
Construa um Robô de 2 Rodas Controlado por Voz com Arduino e BitVoicer Server
Construa um Robô de 2 Rodas Controlado por Voz com Arduino e BitVoicer Server
Construa um Robô de 2 Rodas Controlado por Voz com Arduino e BitVoicer Server
Construa um Robô de 2 Rodas Controlado por Voz com Arduino e BitVoicer Server
Construa um Robô de 2 Rodas Controlado por Voz com Arduino e BitVoicer Server
Construa um Robô de 2 Rodas Controlado por Voz com Arduino e BitVoicer Server

Se você não quiser soldar os LEDs e o regulador de tensão no shield XBee, pode montá-los em uma pequena protoboard como mostrado na imagem abaixo. Neste caso, escolha uma protoboard de tamanho reduzido para poder fixá-la em algum lugar no chassi sem mais problemas.

Construa um Robô de 2 Rodas Controlado por Voz com Arduino e BitVoicer Server

Nas imagens acima, você pode notar que fiz um suporte de arame de ferro para segurar o microfone. Você também pode ver que colei uma tira de tecido felpudo ao redor da roda 360º. Tomei estas duas medidas para tentar reduzir o ruído gerado pelo robô e captado pelo microfone quando o robô está se movendo. Até cortei um pequeno pedaço de esponja para isolar os fios do microfone do suporte. Claro que não foi 100% eficaz, mas reduziu um pouco o ruído e melhorou a precisão do reconhecimento de fala.

PASSO 3: Configurando o Módulo WiFi

Como disse no Passo 1, o módulo WiFi Microchip RN171VX pode ser totalmente operado através da porta serial. Isso torna extremamente fácil configurar o módulo porque todos os comandos são strings simples enviadas através da porta serial do Arduino. Você só precisa enviar uma string contendo "$$$" para entrar no modo de comando, enviar os comandos e então enviar uma string contendo "exit" para retornar ao modo de dados.

O código chamado Configuração do Módulo WiFi no final deste tutorial é o código que usei para configurar o módulo WiFi na minha rede doméstica. Você terá que alterar as partes do código marcadas como "XXXXXX" com informações da sua rede WiFi. Três comandos terão que ser alterados:

Na minha rede WiFi, o método de autenticação é WPA2-PSK. Se sua rede usa um método de autenticação diferente, você também terá que alterar o comando set wlan auth. Consulte a documentação do módulo WiFi (seção 4.3 Set Commands) para descobrir qual valor é o correto para sua rede.

Há um detalhe importante sobre o shield Sparkfun e sua pequena chave (imagem abaixo). Para enviar código para o Arduino usando sua interface USB, a chave deve estar na posição DLINE. Para o Arduino enviar/receber dados através do módulo WiFi usando sua porta serial, a chave deve estar na posição UART. Isso é necessário porque o módulo WiFi e o chip USB no Arduino UNO usam a mesma porta serial no microcontrolador ATmega. Se a chave estiver definida para UART e você tentar enviar código para o Arduino, uma mensagem de erro será exibida no Arduino IDE.

Construa um Robô de 2 Rodas Controlado por Voz com Arduino e BitVoicer Server

Para enviar o código Configuração do Módulo WiFi para o Arduino e permitir que o Arduino configure o módulo WiFi, siga os passos abaixo:

  1. Defina a chave para a posição DLINE;
  2. Abra o Arduino IDE, cole e envie o código para o Arduino;
  3. Assim que o envio terminar, você terá 5 segundos (delay no início do código) para mudar a chave para a posição UART antes que os comandos sejam enviados ao módulo WiFi. Se o primeiro comando for perdido, nenhum dos outros funcionará. Neste caso, simplesmente reinicie o Arduino para que o sketch possa rodar novamente desde o início.

Durante a configuração do módulo, que leva cerca de 25 segundos, os LEDs do módulo piscarão de forma diferente do seu padrão padrão. Neste momento você saberá que o módulo WiFi está sendo configurado.

Após o módulo ser configurado, tente fazer ping (Prompt de Comando --> "ping [Endereço IP]" --> pressione Enter) no módulo usando o endereço IP especificado no comando set ip address. Se você não obtiver resposta do módulo, algo deu errado nos passos anteriores.

PASSO 4: Planejando os Movimentos do Robô

Embora o robô tenha apenas dois motores DC, ele é capaz de realizar uma série de movimentos complexos. Para manter este tutorial o mais simples possível, escolhi definir apenas cerca de três dezenas de movimentos uniformes básicos e alguns movimentos complexos formados pela combinação dos movimentos básicos.

Como você pode ver nas imagens do Passo 2, não uso sensores de rotação nas rodas, sensores ultrassônicos ou qualquer outro tipo de sensor para medir a distância de objetos ou a distância percorrida. Isso impede o robô de realizar movimentos de alta precisão. No entanto, controlando apenas a direção e a velocidade dos motores, você pode atingir um nível de precisão bom o suficiente para mover o robô por aí.

A primeira coisa que você precisa saber para calcular o tempo de execução necessário para cada movimento é a velocidade média do robô. Para fazer isso, coloque uma fita métrica paralela ao robô e ative ambos os motores simultaneamente por um ou dois segundos, meça a distância percorrida e deduza a velocidade. Na minha configuração, obtive 13,7 centímetros por segundo empregando 62,5% da velocidade máxima do motor (250/400, veja biblioteca Arduino Pololu). Em outras palavras, para mover o robô 1 metro (100 cm) à frente, os motores tiveram que ser ativados simultaneamente por 7,299270... segundos. Escolhi manter a contagem de tempo na resolução de milissegundos, mas se você quiser atingir maior precisão de movimento, considere elevar a resolução para microssegundos. Resumindo, para mover o robô 1 metro, tenho que ativar ambos os motores simultaneamente por 7299 milissegundos. A partir deste número, tudo se torna regra de três para outras distâncias. Para realizar movimentos de arco ou circulares, uma roda tem que se mover mais rápido que a outra. Para virar o robô para os lados, apenas uma roda tem que ser ativada ou ambas em direções opostas (para virar no próprio eixo). Aqui você terá que usar um pouco de trigonometria para descobrir a distância percorrida por cada roda e por quanto tempo cada motor deve ser ativado. Um bom ponto de partida para esses conceitos pode ser encontrado nos seguintes links (não pretendo ir além aqui): https://rossum.sourceforge.net/papers/CalculationsForRobotics/CirclePath.htm e https://math.stackexchange.com/questions/60176/move-two-wheeled-robot-from-one-point-to-another.

Construa um Robô de 2 Rodas Controlado por Voz com Arduino e BitVoicer Server

Como você pode ver no final do vídeo abaixo, também faço o robô "desenhar" algumas formas geométricas básicas (quadrado, triângulo e círculo) no chão. Esses movimentos são alcançados pela combinação de movimentos básicos (ex: ir para frente, virar, ir para frente, virar, etc.). A combinação desses movimentos é feita no Esquema de Voz do BitVoicer Server e você não os verá no sketch do Arduino apresentado no próximo passo.

PASSO 5: Enviando o Código para o Arduino

Neste passo você terá que enviar o sketch chamado Código Fonte do Robô, localizado no final deste tutorial, para o Arduino. Você também pode baixar o sketch do Arduino no link abaixo. Lembre-se que para enviar código para o Arduino você deve definir a chave no shield Sparkfun para a posição DLINE como descrito no Passo 3. Antes de enviar o código, você deve instalar corretamente as bibliotecas do BitVoicer Server e do driver de motor Pololu na Arduino IDE (Importando uma Biblioteca .zip).

Código Fonte do Robô: BVS_Demo3.ino

Algumas partes deste sketch são semelhantes a partes que usei em um dos meus tutoriais anteriores e lidam com a comunicação com o BitVoicer Server (classes BVSP e BVSMic). Neste tutorial, vou me ater à explicação das novas partes do sketch. Se você quiser obter mais informações sobre como usar as classes BVSP e BVSMic, sugiro que consulte o tutorial mencionado acima.

PASSO 6: Configurando o BitVoicer Server

Neste passo você deve construir o Esquema de Voz do BitVoicer Server com as frases a serem reconhecidas e os comandos que serão enviados ao Arduino. No final deste passo, há dois links para arquivos contendo todos os Objetos de Solução do BitVoicer Server usados neste tutorial. Se você não quiser criar todos os objetos de solução um a um, pode importá-los (Importando Objetos de Solução) usando esses arquivos.

Antes de começar a construir o Esquema de Voz, você deve criar um dispositivo que representará o Arduino no BitVoicer Server. Crie um dispositivo misto e nomeie-o ArduinoUnoWiFi. Na aba Comunicação, selecione TCP/IP e insira o endereço IP atribuído ao módulo WiFi no Passo 3. Na aba Cues, habilite as cues Start of Activated Period e End of Activated Period. Selecione comandos Int16 SendData para ambas as cues e selecione o dispositivo ArduinoUnoWiFi como alvo dos comandos. No campo Data, insira 1 para a cue Start of Activated Period e 0 para a cue End of Activated Period. Estas cues farão o Arduino acender um LED toda vez que a palavra de ativação for reconhecida. Quando o período ativado (definido no Esquema de Voz) expirar, este LED se apagará.

Agora vamos construir o Esquema de Voz. Embora o robô tenha apenas 40 comandos básicos, você pode querer criar muitas combinações de palavras que acionem o mesmo comando. Como exemplo, você pode querer que as frases "mova para frente um metro" e "vá para frente um metro" acionem o mesmo comando. Além disso, você pode querer criar comandos complexos como "faça um quadrado" que acionarão uma série de comandos temporizados em sequência. Por causa disso, seu Esquema de Voz pode crescer muito e ter muitos mais que 40 comandos básicos. O BitVoicer Server suporta frases ilimitadas, então você pode definir quantas frases precisar (o meu acabou com mais de 80 frases). Aqui gostaria de dar duas dicas: crie um comando padrão nas Opções do Gerenciador do BitVoicer Server; e copie e cole comandos duplicados de uma frase para as outras.

Construa um Robô de 2 Rodas Controlado por Voz com Arduino e BitVoicer Server

Comandos de frase enviarão tipos de dados byte para o Arduino. Use as constantes definidas no início do sketch para saber qual valor deve ser enviado para cada comando. Comandos complexos enviarão muitos valores em sequência e você terá que controlar o intervalo (delay) entre eles para que nenhum valor seja enviado enquanto o comando anterior estiver em execução. Use o campo delay para definir o intervalo entre comandos.

Arquivos de Objetos de Solução:

PASSO 7: Conclusão

Agora tudo que você tem a fazer é colocar as pilhas AA e conectar a bateria de 9V na entrada de energia do Arduino para seu robô ganhar vida! Após enviar o código para o Arduino, não se esqueça de virar a chave montada no shield Sparkfun para a posição UART. Caso contrário, o módulo WiFi não receberá nenhum dado enviado da porta serial do Arduino.

Após ligar o robô, os LEDs de status levarão um tempinho antes de acender. Você verá o módulo WiFi iniciando a comunicação e quando a conexão TCP/IP for estabelecida, um dos LEDs do módulo ficará solidamente aceso. Após alguns instantes, três dos quatro LEDs de status acenderão também. Isso significa que um motor de reconhecimento de fala foi atribuído ao Arduino. A partir de agora, o robô está pronto para receber comandos.

Após alguns testes com o robô, fiquei bastante satisfeito com o reconhecimento de fala, embora não reconhecesse 100% dos comandos o tempo todo. Neste aspecto, o BitVoicer Server realmente me surpreendeu. No entanto, não fiquei tão satisfeito com a precisão dos movimentos do robô. Para corrigir esse problema, teria que adicionar sensores de rotação nas rodas. O kit de chassi que usei no robô já vem com discos decodificadores que podem ser acoplados à engrenagem. Aplicar sensores a esses discos me permitiria mover o robô com base na distância real percorrida, de modo que seu movimento seria mais preciso. Também poderia adicionar sensores ultrassônicos para evitar bater nos móveis. Provavelmente farei isso algum dia, mas por enquanto, deixo isso a você.

Até a próxima!

Código

Configuração do Módulo WiFi (Arduino)

Configura o módulo WiFi Microchip RN171VX usando a porta serial do Arduino.

void setup() {
  Serial.begin(115200);
  pinMode(13, OUTPUT);
  delay(5000);
  Serial.print("$$$");
  delay(1000);
  Serial.println("set wlan auth 4");
  delay(1000);
  Serial.println("set wlan phrase XXXXXX");
  delay(1000);
  Serial.println("set wlan ssid XXXXXX");
  delay(1000);
  Serial.println("set wlan channel 0");
  delay(1000);
  Serial.println("set wlan join 1");
  delay(1000);
  Serial.println("set wlan tx 0");
  delay(1000);
  Serial.println("set ip dhcp 0");
  delay(1000);
  Serial.println("set ip address XXXXXX");
  delay(1000);
  Serial.println("set comm remote 0");
  delay(1000);
  Serial.println("set comm close 0");
  delay(1000);
  Serial.println("set comm open 0");
  delay(1000);
  Serial.println("set comm size 500");
  delay(1000);
  Serial.println("set comm time 50");
  delay(1000);
  Serial.println("set uart baud 115200");
  delay(1000);
  Serial.println("set uart flow 0");
  delay(1000);
  Serial.println("save");
  delay(1000);
  Serial.println("exit");
  delay(1000);
  digitalWrite(13, LOW);
}
void loop() {
}

Código Fonte do Robô (Arduino)

Controla os movimentos do robô, captura áudio, gerencia a conexão TCP/IP e comunica com o BitVoicer Server.

#include <BVSP.h>
#include <BVSMic.h>
#include <DualMC33926MotorShield.h>

// Define os pinos do Arduino que serão usados para
// controlar LEDs e capturar áudio
#define BVS_RUNNING 2
#define BVS_SRE 5
#define BVS_DATA_FWD 3
#define BVS_ACT_PERIOD 6
#define BVSM_AUDIO_INPUT 3

// Define as constantes que serão passadas como parâmetros para
// a função BVSP.begin
const unsigned long STATUS_REQUEST_INTERVAL = 2000;
const unsigned long STATUS_REQUEST_TIMEOUT = 1000;

// Define o tamanho do buffer do microfone
const int MIC_BUFFER_SIZE = 64;

// Inicializa uma nova instância global da classe BVSP
BVSP bvsp = BVSP();

// Inicializa uma nova instância global da classe BVSMic
BVSMic bvsm = BVSMic();

// Inicializa uma nova instância global da
// classe DualMC33926MotorShield
DualMC33926MotorShield ms = DualMC33926MotorShield();

// Cria um buffer que será usado para ler amostras gravadas
// da classe BVSMic
byte micBuffer[MIC_BUFFER_SIZE];

// Cria uma variável global que indica se o
// Arduino está conectado ao BitVoicer Server
boolean connected = false;

// Define algumas constantes para as configurações do motor
const int SPEED_STOP = 0;
const int SPEED_SLOW = 100;
const int SPEED_NORMAL = 250;
const int SPEED_FAST = 400;
const int DIRECTION_FRONT = -1;
const int DIRECTION_BACK = 1;

// Declara uma variável global para manter a velocidade atual do motor.
// O padrão é SPEED_NORMAL, mas há comandos de voz
// que alteram esta configuração.
int motorSpeed = SPEED_NORMAL;

// Armazena a duração do comando em milissegundos
unsigned long cmdDuration = 0;

// Armazena o tempo que o comando começou a rodar
unsigned long cmdStartTime = 0;

// Armazena se um comando está rodando ou não
bool cmdRunning = false;

// Armazena o último comando MOVE_FORWARD. Esta variável
// é usada apenas para o comando COME_BACK.
byte lastFwdCmd = 0;

// Define algumas constantes para nomes/valores de comandos
// Apenas para tornar o código mais legível
const byte CMD_STOP = 0;
const byte CMD_MOVE_FORWARD = 1;
const byte CMD_MOVE_FORWARD_1_CM = 2;
const byte CMD_MOVE_FORWARD_2_CM = 3;
const byte CMD_MOVE_FORWARD_5_CM = 4;
const byte CMD_MOVE_FORWARD_10_CM = 5;
const byte CMD_MOVE_FORWARD_25_CM = 6;
const byte CMD_MOVE_FORWARD_50_CM = 7;
const byte CMD_MOVE_FORWARD_1_M = 8;
const byte CMD_MOVE_BACKWARD = 9;
const byte CMD_MOVE_BACKWARD_1_CM = 10;
const byte CMD_MOVE_BACKWARD_2_CM = 11;
const byte CMD_MOVE_BACKWARD_5_CM = 12;
const byte CMD_MOVE_BACKWARD_10_CM = 13;
const byte CMD_MOVE_BACKWARD_25_CM = 14;
const byte CMD_MOVE_BACKWARD_50_CM = 15;
const byte CMD_MOVE_BACKWARD_1_M = 16;
const byte CMD_TURN_AROUND = 17;
const byte CMD_TURN_AROUND_RIGHT = 18;
const byte CMD_TURN_AROUND_LEFT = 19;
const byte CMD_DO_360 = 20;
const byte CMD_TURN_RIGHT = 21;
const byte CMD_TURN_RIGHT_10 = 22;
const byte CMD_TURN_RIGHT_25 = 23;
const byte CMD_TURN_RIGHT_45 = 24;
const byte CMD_TURN_LEFT = 25;
const byte CMD_TURN_LEFT_10 = 26;
const byte CMD_TURN_LEFT_25 = 27;
const byte CMD_TURN_LEFT_45 = 28;
const byte CMD_DO_CIRCLE = 29;
const byte CMD_COME_BACK = 30;
const byte CMD_MOVE_FORWARD_2_M = 31;
const byte CMD_MOVE_FORWARD_3_M = 32;
const byte CMD_MOVE_BACKWARD_2_M = 33;
const byte CMD_MOVE_BACKWARD_3_M = 34;
const byte CMD_SET_SPEED_SLOW = 35;
const byte CMD_SET_SPEED_NORMAL = 36;
const byte CMD_SET_SPEED_FAST = 37;
const byte CMD_TURN_LEFT_45_BACKWARD = 38;
const byte CMD_TURN_RIGHT_45_BACKWARD = 39;

void setup() {
  // Inicia comunicação serial a 115200 bps
  Serial.begin(115200);
  // Define os modos dos pinos do Arduino
  pinMode(BVS_RUNNING, OUTPUT);
  pinMode(BVS_SRE, OUTPUT);
  pinMode(BVS_DATA_FWD, OUTPUT);
  pinMode(BVS_ACT_PERIOD, OUTPUT);
  AllLEDsOff();
  // Define a porta serial do Arduino que será usada para
  // comunicação, quanto tempo levará antes que uma solicitação de status
  // expire e com que frequência solicitações de status devem ser enviadas
  // ao BitVoicer Server
  bvsp.begin(Serial, STATUS_REQUEST_TIMEOUT, STATUS_REQUEST_INTERVAL);
  // Define a função que manipulará o evento
  // frameReceived
  bvsp.frameReceived = BVSP_frameReceived;
  // Prepara o timer da classe BVSMic
  bvsm.begin();
  // Prepara a classe do shield de motor (pinos e timer1)
  ms.init();
}

void loop() {
  // Se não estiver conectado ao servidor, abre uma conexão
  // TCP/IP, define connected como true e reseta a classe BVSP
  if (!connected) {
    Connect(Serial);
    connected = true;
    bvsp.reset();
  }
  // Verifica se o intervalo de solicitação de status decorreu e se
  // sim, envia uma solicitação de status ao BitVoicer Server
  bvsp.keepAlive();
  // Verifica se há dados disponíveis no buffer da porta serial
  // e processa seu conteúdo de acordo com as especificações
  // do Protocolo BitVoicer Server
  bvsp.receive();
  // Obtém o respectivo status da classe BVSP e define
  // os LEDs ligados ou desligados
  digitalWrite(BVS_RUNNING, bvsp.isBVSRunning());
  digitalWrite(BVS_DATA_FWD, bvsp.isDataFwdRunning());
  // Verifica se há um SRE atribuído ao Arduino
  if (bvsp.isSREAvailable()) {
    // Liga o LED SRE disponível
    digitalWrite(BVS_SRE, HIGH);
    // Se a classe BVSMic não está gravando, configura a
    // entrada de áudio e inicia a gravação
    if (!bvsm.isRecording) {
      bvsm.setAudioInput(BVSM_AUDIO_INPUT, EXTERNAL);
      bvsm.startRecording();
    }
    // Verifica se a classe BVSMic tem amostras disponíveis
    if (bvsm.available) {
      // Garante que o modo de entrada seja STREAM_MODE antes
      // de transmitir o stream
      if (bvsp.inboundMode == FRAMED_MODE)
        bvsp.setInboundMode(STREAM_MODE);
      // Lê as amostras de áudio da classe BVSMic
      int bytesRead = bvsm.read(micBuffer, MIC_BUFFER_SIZE);
      // Envia o stream de áudio para o BitVoicer Server
      bvsp.sendStream(micBuffer, bytesRead);
    }
  } else {
    // Não há SRE disponível
    // Desliga os LEDs SRE e ACT_PERIOD
    digitalWrite(BVS_SRE, LOW);
    digitalWrite(BVS_ACT_PERIOD, LOW);
    // Se a classe BVSMic está gravando, para
    if (bvsm.isRecording)
      bvsm.stopRecording();
  }
  // Se o status expirou, a conexão é considerada
  // perdida
  if (bvsp.hasStatusTimedOut()) {
    // Se o BVSMic está gravando, para
    if (bvsm.isRecording)
      bvsm.stopRecording();
    // Fecha a conexão TCP/IP
    Disconnect(Serial);
    AllLEDsOff();
    connected = false;
  }
  // Se um comando está rodando, verifica se sua duração
  // expirou. Se expirou, para os motores.
  if (cmdRunning)
    if (millis() - cmdStartTime >= cmdDuration)
      RunCommand(CMD_STOP);
}

// Manipula o evento frameReceived
void BVSP_frameReceived(byte dataType, int payloadSize) {
  // Executa as ações apropriadas baseadas no tipo de dado
  // do frame. Se o tipo de dado for byte, é um comando.
  // Se o tipo de dado for int, muda o LED do período
  // ativado.
  switch (dataType) {
    case DATA_TYPE_BYTE:
      RunCommand(bvsp.getReceivedByte());
      break;
    case DATA_TYPE_INT16:
      digitalWrite(BVS_ACT_PERIOD, bvsp.getReceivedInt16());
      break;
  }
}

// Executa o comando recebido do servidor
void RunCommand(byte cmd) {
  switch (cmd) {
    case CMD_STOP:
      ms.setSpeeds(SPEED_STOP, SPEED_STOP);
      cmdRunning = false;
      return;
    case CMD_MOVE_FORWARD:
      lastFwdCmd = cmd;
      ms.setSpeeds(
        motorSpeed * DIRECTION_FRONT,
        motorSpeed * DIRECTION_FRONT);
      cmdDuration = 60000;
      break;
    case CMD_MOVE_FORWARD_1_CM:
      lastFwdCmd = cmd;
      ms.setSpeeds(
        motorSpeed * DIRECTION_FRONT,
        motorSpeed * DIRECTION_FRONT);
      cmdDuration = 23;
      break;
    case CMD_MOVE_FORWARD_2_CM:
      lastFwdCmd = cmd;
      ms.setSpeeds(
        motorSpeed * DIRECTION_FRONT,
        motorSpeed * DIRECTION_FRONT);
      cmdDuration = 47;
      break;
    case CMD_MOVE_FORWARD_5_CM:
      lastFwdCmd = cmd;
      ms.setSpeeds(
        motorSpeed * DIRECTION_FRONT,
        motorSpeed * DIRECTION_FRONT);
      cmdDuration = 117;
      break;
    case CMD_MOVE_FORWARD_10_CM:
      lastFwdCmd = cmd;
      ms.setSpeeds(
        motorSpeed * DIRECTION_FRONT,
        motorSpeed * DIRECTION_FRONT);
      cmdDuration = 234;
      break;
    case CMD_MOVE_FORWARD_25_CM:
      lastFwdCmd = cmd;
      ms.setSpeeds(
        motorSpeed * DIRECTION_FRONT,
        motorSpeed * DIRECTION_FRONT);
      cmdDuration = 468;
      break;
    case CMD_MOVE_FORWARD_50_CM:
      lastFwdCmd = cmd;
      ms.setSpeeds(
        motorSpeed * DIRECTION_FRONT,
        motorSpeed * DIRECTION_FRONT);
      cmdDuration = 1170;
      break;
    case CMD_MOVE_FORWARD_1_M:
      lastFwdCmd = cmd;
      ms.setSpeeds(
        motorSpeed * DIRECTION_FRONT,
        motorSpeed * DIRECTION_FRONT);
      cmdDuration = 2339;
      break;
    case CMD_MOVE_FORWARD_2_M:
      lastFwdCmd = cmd;
      ms.setSpeeds(
        motorSpeed * DIRECTION_FRONT,
        motorSpeed * DIRECTION_FRONT);
      cmdDuration = 4678;
      break;
    case CMD_MOVE_FORWARD_3_M:
      lastFwdCmd = cmd;
      ms.setSpeeds(
        motorSpeed * DIRECTION_FRONT,
        motorSpeed * DIRECTION_FRONT);
      cmdDuration = 7018;
      break;
    case CMD_MOVE_BACKWARD:
      ms.setSpeeds(
        motorSpeed * DIRECTION_BACK,
        motorSpeed * DIRECTION_BACK);
      cmdDuration = 60000;
      break;
    case CMD_MOVE_BACKWARD_1_CM:
      ms.setSpeeds(
        motorSpeed * DIRECTION_BACK,
        motorSpeed * DIRECTION_BACK);
      cmdDuration = 23;
      break;
    case CMD_MOVE_BACKWARD_2_CM:
      ms.setSpeeds(
        motorSpeed * DIRECTION_BACK,
        motorSpeed * DIRECTION_BACK);
      cmdDuration = 47;
      break;
    case CMD_MOVE_BACKWARD_5_CM:
      ms.setSpeeds(
        motorSpeed * DIRECTION_BACK,
        motorSpeed * DIRECTION_BACK);
      cmdDuration = 117;
      break;
    case CMD_MOVE_BACKWARD_10_CM:
      ms.setSpeeds(
        motorSpeed * DIRECTION_BACK,
        motorSpeed * DIRECTION_BACK);
      cmdDuration = 234;
      break;
    case CMD_MOVE_BACKWARD_25_CM:
      ms.setSpeeds(
        motorSpeed * DIRECTION_BACK,
        motorSpeed * DIRECTION_BACK);
      cmdDuration = 468;
      break;
    case CMD_MOVE_BACKWARD_50_CM:
      ms.setSpeeds(
        motorSpeed * DIRECTION_BACK,
        motorSpeed * DIRECTION_BACK);
      cmdDuration = 1170;
      break;
    case CMD_MOVE_BACKWARD_1_M:
      ms.setSpeeds(
        motorSpeed * DIRECTION_BACK,
        motorSpeed * DIRECTION_BACK);
      cmdDuration = 2339;
      break;
    case CMD_MOVE_BACKWARD_2_M:
      ms.setSpeeds(
        motorSpeed * DIRECTION_BACK,
        motorSpeed * DIRECTION_BACK);
      cmdDuration = 4678;
      break;
    case CMD_MOVE_BACKWARD_3_M:
      ms.setSpeeds(
        motorSpeed * DIRECTION_BACK,
        motorSpeed * DIRECTION_BACK);
      cmdDuration = 7017;
      break;
    case CMD_TURN_AROUND:
      ms.setSpeeds(
        motorSpeed * DIRECTION_FRONT,
        motorSpeed * DIRECTION_BACK);
      cmdDuration = 540;
      break;
    case CMD_TURN_AROUND_RIGHT:
      ms.setSpeeds(
        motorSpeed * DIRECTION_FRONT,
        motorSpeed * DIRECTION_BACK);
      cmdDuration = 540;
      break;
    case CMD_TURN_AROUND_LEFT:
      ms.setSpeeds(
        motorSpeed * DIRECTION_BACK,
        motorSpeed * DIRECTION_FRONT);
      cmdDuration = 540;
      break;
    case CMD_DO_360:
      ms.setSpeeds(
        motorSpeed * DIRECTION_FRONT,
        motorSpeed * DIRECTION_BACK);
      cmdDuration = 1065;
      break;
    case CMD_TURN_RIGHT:
      ms.setSpeeds(motorSpeed * DIRECTION_FRONT, 0);
      cmdDuration = 503;
      break;
    case CMD_TURN_RIGHT_10:
      ms.setSpeeds(motorSpeed * DIRECTION_FRONT, 0);
      cmdDuration = 56;
      break;
    case CMD_TURN_RIGHT_25:
      ms.setSpeeds(motorSpeed * DIRECTION_FRONT, 0);
      cmdDuration = 140;
      break;
    case CMD_TURN_RIGHT_45:
      ms.setSpeeds(motorSpeed * DIRECTION_FRONT, 0);
      cmdDuration = 252;
      break;
    case CMD_TURN_LEFT:
      ms.setSpeeds(0, motorSpeed * DIRECTION_FRONT);
      cmdDuration = 503;
      break;
    case CMD_TURN_LEFT_10:
      ms.setSpeeds(0, motorSpeed * DIRECTION_FRONT);
      cmdDuration = 56;
      break;
    case CMD_TURN_LEFT_25:
      ms.setSpeeds(0, motorSpeed * DIRECTION_FRONT);
      cmdDuration = 140;
      break;
    case CMD_TURN_LEFT_45:
      ms.setSpeeds(0, motorSpeed * DIRECTION_FRONT);
      cmdDuration = 252;
      break;
    case CMD_DO_CIRCLE:
      ms.setSpeeds(
        SPEED_NORMAL * DIRECTION_FRONT,
        SPEED_NORMAL * DIRECTION_FRONT * 0.60);
      cmdDuration = 4587;
      break;
    case CMD_COME_BACK:
      RunCommand(lastFwdCmd);
      return;
    case CMD_SET_SPEED_SLOW:
      motorSpeed = SPEED_SLOW;
      return;
    case CMD_SET_SPEED_NORMAL:
      motorSpeed = SPEED_NORMAL;
      return;
    case CMD_SET_SPEED_FAST:
      motorSpeed = SPEED_FAST;
      return;
    case CMD_TURN_LEFT_45_BACKWARD:
      ms.setSpeeds(motorSpeed * DIRECTION_BACK, 0);
      cmdDuration = 252;
      break;
    case CMD_TURN_RIGHT_45_BACKWARD:
      ms.setSpeeds(0, motorSpeed * DIRECTION_BACK);
      cmdDuration = 252;
      break;
  }
  // Define o tempo de início do comando
  cmdStartTime = millis();
  // Define cmdRunning como true
  cmdRunning = true;
}

// Abre uma conexão TCP/IP com o BitVoicer Server
void Connect(HardwareSerial &serialPort) {
  serialPort.print("$$$");
  delay(500);
  // Use o endereço IP do servidor e a porta TCP definida
  // nas propriedades do servidor
  serialPort.println("open 192.168.0.11 4194");
  delay(1000);
  serialPort.println("exit");
  delay(500);
}

// Fecha a conexão TCP/IP com o BitVoicer Server
void Disconnect(HardwareSerial &serialPort) {
  serialPort.print("$$$");
  delay(500);
  serialPort.println("close");
  delay(1000);
  serialPort.println("exit");
  delay(500);
}

// Desliga todos os LEDs
void AllLEDsOff() {
  digitalWrite(BVS_RUNNING, LOW);
  digitalWrite(BVS_SRE, LOW);
  digitalWrite(BVS_DATA_FWD, LOW);
  digitalWrite(BVS_ACT_PERIOD, LOW);
}

Esquemáticos

Construa um Robô de 2 Rodas Controlado por Voz com Arduino e BitVoicer Server

Processo de manufatura

  1. Construa um Robô Raspberry Pi Controlado por Bluetooth com Feedback de Áudio
  2. Construa um Robô de Streaming de Vídeo Controlado por Internet com Arduino e Raspberry Pi
  3. Sistema de Presença RFID Confiável com Arduino e Python
  4. Display Interativo de Giroscópio com Anel NeoPixel e Arduino
  5. Veículo Remoto Controlado por Android com Raspberry Pi e Motor Shield
  6. Robô Desviador de Obstáculos com Servo: Construa com Arduino e HC-SR04
  7. Controlar Roomba Create 2 com Arduino e Android: Guia Passo a Passo
  8. Braço Robótico 6 GDL Controlado por Nunchuk com Arduino Mega
  9. Construa um Robô Controlado por Voz com Arduino Nano
  10. Eletrodomésticos Ativados por Voz: Controle Bluetooth com Google Assistant