sexta-feira, 6 de abril de 2012

Arduino comando por voz


-->

Um dia desses fuçando o Ebay encontrei um módulo de comando por voz baseado no CI SPCE061A. Ele é capaz de armazenar até 15 comandos divididos em 3 bancos de 5 comandos. No projeto descrito aqui foram gravados cinco comandos no banco "1" com a finalidade de controlar o acendimento, apagamento e frequência de piscada de uma lâmpada comum ligada ao pino 13 do arduino através de um módulo de força baseado em um triac.

A comunicação com o módulo é  feita via interface serial. As mensagens de comando devem ser formadas pela chave 0xAA seguida do comando propriamente dito. Para gravar o banco um, por exemplo, basta envia via terminal o valor em 0xAA seguido do comando 0x11 (é sempre bom lembra que o "0x" informa que o número que o segue esta em hexadecimal) e, seguindo as mensagens de retorno no terminal ou observando os dois leds na placa,  pronunciar e repetir cada um dos cinco comandos desejados para o banco em questão.
 
Após a gravação é possível acessar o banco 1 através do comando 0xAA + 0x21 que serve para importar o banco 01. Importar, neste caso, é ativar um determinado grupo de comandos, pois apenas um dos grupos pode estar ativo por vês. Isso faz com que o módulo compare o comando falado com os cinco gravados naquele banco.


O manual do modulo pode ser encontrado aqui. Ele é bastante completo inclusive indica um programa gratuito para
-->comunicação serial, o AccessPort que pode ser baixado aqui.

-->
Resumidamente para fazer funcionar o módulo com o arduino deve-se:
1. Selecionar a velocidade de comunicação serial enviando, por exemplo, o comando "AA34" para 19200bps ou "AA33" para 9600bps. Por padrão a velocidade é 9600;

2. Selecionar o modo de comunicação: modo comum ou compacto. O modo determina se o módulo irá responder aos comandos com respostas longas (mensagens) ou curtas (hexadecimal);

3. Iniciar a gravação de um dos três bancos enviando o comando correspondente "AA11" para gravar o banco um "AA12" para o dois ou "AA13" para o banco três.

-->
Ao iniciar a gravação do banco um, por exemplo, o módulo irá solicitar os cinco comandos  de voz que deverão ser pronunciados e repetidos conforme mensagens de solicitação. Estes comandos de voz são associados a  números. No banco um os números 0x11, 0x12, 0x13, 0x14 e 0x15 são associados aos comandos de voz um a cinco respectivamente. Sendo que o comando de voz um é o primeiro que foi gravado no banco  e assim sucessivamente. Se um banco é ativado e o módulo recebe um comando de voz válido ele envia o valor correspondente via serial.

Quando um comando de gravação é enviado através do terminal, por exemplo, o modulo enviará um das seguintes respostas em hexadecimal ou em texto:


"ERROR! \ n" (0xe0) Erro de instrução
"START \ n" (0x40) Pronto para gravar
"No voice \ n" (0x41) Não detectada voz
"Again \ n" (0x42) Repita a instrução  ( após proximo "START")
"Too loud \ n" (0x43) Muito alto para gravar
"Different \ n" (0x44) Repetição da instrução diferente da primera aguarde o START para repetir o comando de voz
"Finish one \ n" (0x45) Uma instrução gravada com sucesso. O proximo START é para o comando de voz seguinte. Isso se repete até o quinto comando
"Group1 finished! \ n" (0x46) Fim da gravação do grupo 1

-->É possível também acompanhar as mensagens através dos dois leds existentes no módulo. O que torna possível, por exemplo, gravar um banco comunicando-se com o modulo através do arduino sem o auxilio de um computador. Os detalhes para isso estão no  manual.

-->
No programa, mostrado abaixo, o arduino inicializa o banco 1 e fica aguardando o comando enviado pelo modulo que por sua vez aguarda comandos de voz compatíveis com os gravados.


/*
 comandos de voz:
 
 1 - liga
 2 - desliga
 3 - pisca
 4 - mais
 5 - menos
 
 */

#include <Servo.h> 

long dist = 0;

int lampState = LOW;   

long previousMillis = 0;  
long intervalo = 1000; 
unsigned long currentMillis;

int lampada =13;
byte com = 0; 

void setup()
{
  

Serial.begin(9600);

pinMode(lampada, OUTPUT);

delay(2000);

// O modulo aceita comandos, em hexadecimal no seguinte formato:
// AA + comando 
Serial.write(0xAA); 
Serial.write(0x37); //configura o modulo para responder em modo compacto
delay(1000);        // no modo compacto as respostas são numeros em hexadecimal
Serial.write(0xAA);
Serial.write(0x21);//importa o grupo 1


}

void loop() // inicio do programa principal
{
  

while(Serial.available())
{
com = Serial.read();  //recebe o byte referente ao comando

if(com == 0x11) // ao recxeber o comando de voz "liga" o modulo envia o valor em hexadecimal: 11
digitalWrite(lampada, HIGH); // se receber 0x11 acende a lampada

if(com == 0x12) // ao recxeber o comando de voz "desiga" o modulo envia o valor em hexadecimal: 12
digitalWrite(lampada, LOW);// se receber 0x12 apaga a lampada

if(com == 0x13)// ao recxeber o comando de voz "pisca" o modulo envia o valor em hexadecimal: 13
{
 do  // se receber 0x13 entra neste laço que faz a lamada piscar. Aqui existem tres possibilidades:
     // Receber 0x14 "mais" e aumentar o intervalo entre as piscadas
     // Receber 0x15 "menos" e diminuir o intervalo entre as piscadas
     // Receber 0x11 (liga) 0u 0x12 (desliga) parar de piscar e fazer o que o comando pede
  {

   com = Serial.read();  //recebe o byte referente ao comando
    
     // piscar sem delay
       currentMillis = millis(); //armazena o valor referente ao tempo de execução do programa
        if(currentMillis - previousMillis > intervalo) 
         {   
          previousMillis = currentMillis;   

          if (lampState == LOW)
             lampState = HIGH;
          else
            lampState = LOW;

          digitalWrite(lampada, lampState);
         }
     //
    
    // se receber 0x14 aumenta o intervalo entre as piscadas   
    if(com == 0x14 && intervalo < 1000) 
    {
    intervalo +=100;
    }
    // se receber 0x14 diminue o intervalo entre as piscadas 
    if(com == 0x15 && intervalo > 100)
    {
    intervalo -=100;
    }
   
  // se receber 0x11 (liga) 0u 0x12 (desliga) para de piscar
  }while(com != 0x11 && com != 0x12);
}
}
}