segunda-feira, 27 de setembro de 2010

Arduino tocando xilofone







Essa é minha primeira postagem neste blog. Minha intenção é compartilhar um pouco do que estou aprendendo sobre microcontroladores e outros assuntos relacionados. Contribuições, sugestões e criticas serão sempre bem vindas.


A idéia de fazer o Arduino tocar um xilofone surgiu quase que por acaso. Eu estava vendo alguns vídeos sobre CNC, pois queria construir algo para confecção de placas de circuito impresso, percebi que não seria tão fácil assim. Lembrei então do pequeno xilofone de minha filha de três anos e tive a idéia de fazer com que o arduino o tocasse.


O Arduino


Foto do site arduino.cc
Pra quem ainda não conhece o Arduino. Ele é um hardware livre, você pode baixar o esquema e montá-lo ou comprá-lo pronto de algumas lojas de eletrônica ou até no mercado livre. Ele integra um microcontrolador da Atmel no meu caso Atmega 168, e demais componentes necessários para o funcionamento, inclusive gravação, do microcontrolador. Outra característica do arduino é o bootloader - programa que é executado assim que o arduino é ligado . O Arduino, a depender do modelo escolhido, pode ser conectado ao micro para gravação através da porta serial ou USB. O site oficial http://www.arduino.cc/ disponibiliza gratuitamente o programa para elaboração e gravação do código para o arduino usando uma linguagem baseada em C++. O site trás também muitos tutoriais e exemplos de utilização.

O funcionamento básico

O carro é movido até a primeira nota a ser tocada. Após tocar a primeira nota começa a contar o tempo de intervalo entre esta e a segunda nota enquanto move o carro para tocá-la . Ao se posicionar para tocar a segunda nota verifica se o tempo de interva-lo  foi concluido. Se sim  toca a segunda nota imediatamente, caso contrario aguara a conclusão da contagem de tempo antes de tocar. Esse processo se repete para todas as notas até o fim da música. É importante notar que a capacidade de movimento do conjunto limita o andamento máximo da música.

A estrutura mecânica

                                                                                                                                                                             

A parte mecânica é composta basicamente de rosca sem fim e carro, peças retiradas de  uma velha impressora matricial que eu estava guardando há muito tempo sem saber se um dia serviria para algo. A estrutura onde foi montado o conjunto foi feita em madeira, improvisei rolamentos nas extremidades do sem fim para facilitar o giro. O que eu chamo de carro é o conjunto formado por pequeno cilindro plástico com uma espécie de rosca interna que, quando acoplado ao sem fim se movimenta horizontalmente em função da rotação deste e uma chapa fina de alumínio dobrada de modo à  funcionar como uma mola. Esta chapa carrega uma pequena solenóide retirada de uma antiga secretária eletrônica e a baqueta que é acionada pela solenóide, e retorna a posição de descanso pela força da chapa de alumínio.



A estrutura eletroeletrônica

O motor usado é um motor dc com redução, 24v (por questão de coveniência, no circuito é usada apenas com 12v). Este motor tem a função de girar o eixo sem fim que, por sua vez movimenta o carro até a nota a ser tocada. O sentido de rotação do motor implica no avanço ou retorno do carro. Pra garantir o posicionamento correto do carro para que a baqueta acerte apenas a nota desejada foi usado um potenciômetro como sensor de posição. O potenciômetro foi acoplado extremidade do eixo oposta ao motor através de engrenagens e retorna um valor de 0 a 5v proporcional a posição de seu eixo que, por sua vez é proporcional a posição do carro. O sinal é aplicado a uma entrada analógica do Arduino que converte esse valor para um número entre 0 a 1023 que é usado convenientemente no programa que será mencionado mais tarde. Usando um programinha, no arduino, que lê este valor e o mostra no terminal foi possível, posicionando o carro manualmente, determinar o valor retornado em cada nota. Esse valor é usado para associar a nota a ser tocada à posição do carro.
Para controlar o sentido de rotação do motor foram usados dois relés. Cada relé quando acionado pelo arduino faz o motor gira em um sentido. Um TIP 120 foi adicionado para possibilita o controle da rotação do motor por PWM mas, com os testes prático ficou melhor usar sempre o PWM máximo.


O programa

O programa funciona mas ainda esta longe de ser o ideal. Preciso trocar os vetor int por char usar strlen pra não precisra informar a quantidade de notas da música a ser tocada. Vou tentar também faser alterações para poder enviar a musica via serial no formato MIDI. 

Abaixo você tem o código comentado. A idéia pricipal é a seguinte:
  •  A música é armazenada em  um vetor;
  • As notas são armazanadas neste vetor seguidas do multiplicador do tempo de intervalo entre uma nota e a proxima.   { nota, intervalo, nota, intervalo, ..........};
  •  Para represntar as notas foi usada a notação: C , D, E, F, G, A, B, c  para respectivamente dó (mais grave), ré mi, fá, sol, lá, sí, dó (mais agudo).
  • Como para cada posição do carro é atribuido um valor inteiro. O valor referente a nota a ser tocada é comparado com o valor da posição atual do carro. A partir dessa comparação decide-se o sentido de movimentação do carro.


Código




int C = 1000;  // dó mais grave
int D = 905;
int E = 808;
int F = 710;
int G = 614;
int A = 516;
int B = 417;
int c = 334;  // dó mais agudo

int tempo = 130;    // pausa entre notas
long previousMillis = 0;   // usada para cotar o tempo que o carro leva para ir de uma noa para outra

int potPin = 0;        // pino do potenciometro (usado como sensor de posição)
int baquetaPin = 2;    // pino que acionara a solenoide (ligada abaqueTA)
int esquerdaPin = 3;   // pino do relé sentido horario ( carro para esquerda)
int direitaPin = 5;    // pino do relé sentido antihorario ( carro para direita)
int pwmPin = 9;        // pino PWM velocidade de rotação do motor
 int i=0;
  float soma =0;

float val;

////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////
//////////////////// MUSICAS//////////////////////////////////


int qtdNotas = 164;
int quero_ver[195] = {E,1,D,1,C,1,D,1,E,1,F,1,E,1,D,1,E,1,F,1,  
                      G,1,F,1,E,1,F,1,G,1,A,1,G,1,F,1,E,1,F,1,
                      D,4,
                      E,1,D,1,C,1,D,1,E,1,F,1,E,1,D,1,E,1,F,1, 
                      G,1,F,1,E,1,F,1,G,1,A,1,G,1,F,1,G,1,A,1,
                      B,4,
                      c,1,B,1,A,1,G,1,A,1,B,1,A,1,G,1,F,1,G,1,
                      A,1,G,1,F,1,E,1,F,1,D,4,
                      D,1,E,1,F,1,G,1,F,2,E,2,E,1,F,1,G,1,A,1,
                      G,2,F,2,F,1,G,1,A,1,B,1,A,2,G,1,B,4,c,1,
                      B,1,A,1,G,1,A,1,B,1,A,1,G,1,F,1,G,1,A,1,
                      G,1,F,1,E,1,F,1,D,4,E,2,F,2,D,4,C,8,0};
                      
                      
/*int ia_ia_oh[105] =  {F,2,F,2,F,1,C,1,D,2,D,2,C,1,A,2,A,2,G,2,
                      G,2,F,4,
                              F,2,F,2,F,1,C,1,D,2,D,2,C,1,A,2,
                      A,2,G,2,G,2,F,4,
                                      C,2,C,1,F,2,F,2,F,1,C,1,
                      D,3,                
                          C,2,C,1,F,2,F,2,F,1,C,2,D,3,
                                                      C,2,C,1,
                      F,2,F,2,F,1,C,2,D,2,D,2,C,1,A,2,
                                                      A,2,G,2,
                      G,2,F,16,0};*/
                      
                      
                      
                      
 int asa_br[164] =     {C,2,D,2,E,4,G,4,G,4,E,4,F,12,C,2,D,2,E,4,
                        G,4,G,4,F,2,E,10,
                        C,2,C,1,D,2,E,5,G,6,G,2,F,2,E,2,C,3,F,5,E,2,E,2,D,2,D,3,E,6,D,2,D,2,C,2,C,5,
                        
                        C,2,C,1,D,2,E,5,G,6,G,2,F,2,E,2,C,3,F,5,E,2,E,2,D,2,D,3,E,6,D,2,D,2,C,2,C,5,
                        
                        c,1,A,1,B,1,G,1,A,1,F,1,G,1,E,1,F,1,D,1,E,1,
                        C,2,C,2,D,4,C,4,
                        c,1,A,1,B,1,G,1,A,1,F,1,G,1,E,1,F,1,D,1,E,1,
                        C,2,C,2,D,4,C,8};
                   
                   
////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////


void setup()
{

  pinMode(potPin, INPUT);
  pinMode(baquetaPin, OUTPUT);
  pinMode(esquerdaPin, OUTPUT);
  pinMode(direitaPin, OUTPUT);
  pinMode(pwmPin, OUTPUT);
  
}

//////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////

void loop()
{
 val = analogRead(potPin);
 int  i ;
 int *aux;
 
 aux = asa_br;
 
 posicione(aux[0]);           // move o carro para primeira nota

 for(i=0;i<qtdNotas; i=i+2)    // toca todas as notas
 tocar(aux[i+2], aux[i+1]);   // chama a função tocar passando a px nota e o tempo
 
}  
   
//////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////
   
 
 void tocar(int nota, int pausa)     // função tocar
 {
   
   previousMillis = millis();        // millis retorna o tempo de excução do programa até este ponto
   
   digitalWrite(baquetaPin, HIGH);    // toca a nota
   delay(10);                         //
   digitalWrite(baquetaPin, LOW);     //
  
   posicione(nota);
    
   if( (tempo * pausa) > int(millis() - previousMillis))       // se pausa entre notas for maior que o tempo gasto para
   delay((tempo * pausa) -  int(millis() - previousMillis) );  // mover o carro ate a nota completa a pausa antes de tocar
   
}
 
//////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////


void posicione(int nota)        // posiciona o carro na posição da nota a ser tocada
{
  while(val < nota -5 || val > nota + 5)   // tolerancia da posição + ou - 5
    {


  if(val > nota + 5)             // se o carro estiver a esquerda da nota a ser tocada
  {
  digitalWrite(direitaPin, HIGH);  // move o carro para a direita
  analogWrite(pwmPin,255);         // manda o pulso PWM por 200 microsegundos
  delayMicroseconds(150);          //
  analogWrite(pwmPin,0);           // zera PWM
  digitalWrite(direitaPin,LOW);    // abre relé
  val = analogRead(potPin);        // lê posição
  }
  
  else if(val < nota - 5)    // se o carro estiver a direita da nota a ser tocada
  {
  digitalWrite(esquerdaPin, HIGH);   // move o carro para a esquerda alimenta o relé correspondente
  analogWrite(pwmPin,255);           // manda o pulso PWM 
  delayMicroseconds(150);            // por 200 microsegundos
  analogWrite(pwmPin,0);             // zera PWM
  digitalWrite(esquerdaPin,LOW);     // abre relé
  val = analogRead(potPin);          // lê posição
  }
 
 
}

}