sábado, 26 de fevereiro de 2011

Wii Nunchuk, arduino e labirinto de madeira





Visitando o site instructables  que, diga-se de passagem, é um site muito bom, encontrei o projeto Servo Controlled Labyrinth by nivini . Decidi então, tendo como referência a ideia do autor, montar o jogo usando o arduino e o nunchunk para controlar o tabuleiro. Como não tinha  o jogo tradicional montei meu próprio tabuleiro usando duas caixas em mdf e quatro pedaços de compensado 4mm além de outras pequenas peças adaptadas de matérias disponíveis em casa, o que rendeu um pouco mais de trabalho, mas nada exagerado. Se você já tiver o labirinto pode montar toda a parte física como no projeto original, o que torna as coisas mais fáceis.

O labirinto
 
Para a confecção do labirinto usei uma caixa em MDF de 25cm x 25cm e a  tampa de outra caixa em MDF  20cm x 20cm, onde foi montado o labirinto propriamente dito com  pedaços das peças de um pega varetas "gigante" (5mm de diâmetro), um brinquedo abandonado por minha filha de três anos. Quatro pedaços de compensado serviram para fazer o quadro intermediário. Neste quadro foi fixado o primeiro servo que tem seu eixo preso no centro de uma das laterais da tampa 20x20 e é responsável pelo movimento no eixo Y. O segundo servo, que é  responsável pelo movimento no eixo X, é fixado à caixa maior e tem seu eixo preso em uma das laterais do quadro intermediário de modo a ficar perpendicular ao primeiro servo.

O código

O código, que pode ser visto abaixo, foi adaptado do código encontrado neste site: http://www.windmeadow.com/node/42 .
Eu substitui a parte do código que imprime os valores na tela pelo controle dos servos. Pra melhora a estabilidade o código faz uma media dos últimos 20 valores lidos, ajusta a escala e aplica os resultados aos servos.


 /*  
  * NunchuckPrint  
  *  
  * 2007 Tod E. Kurt, http://todbot.com/blog/  
 BRANCO------ GND  
 AZUL-------- SCL pino analogico 5  
 VERMELHO---- +3.3V  
 VERDE------- SDA pino analogico 4  
  */  
 #include <Wire.h>  
 #include <Servo.h>   
 Servo servo_y; // create servo object to control a servo   
 Servo servo_x; // create servo object to control a servo   
 #define m_movel 20 // quantidade de leituras para media  
 int media_leit_y =0;   
 int media_y_aux =0;  
 int aux_soma_y = 0;  
 int aux_m_y[m_movel];  
 int media_leit_x =0;   
 int media_x_aux =0;  
 int aux_soma_x = 0;  
 int aux_m_x[m_movel];  
 void setup()  
 {  
  servo_x.attach(9); // attaches the servo on pin 9 to the servo object   
  servo_y.attach(10);  
  Serial.begin(19200);  
  nunchuck_setpowerpins(); // use analog pins 2&3 as fake gnd & pwr  
  nunchuck_init(); // send the initilization handshake  
  Serial.print ("Finished setup\n");  
  for(int i=0; i < m_movel; i++)  
  {  
  aux_m_y[i] =0;  
  aux_m_x[i] =0;  
  }  
 }  
 void loop()  
 {  
  nunchuck_get_data(); // lê dados   
  aciona_servos();   // envia-os para os servos  
  delay(5);  
 }  
 //  
 // Nunchuck functions  
 //  
 static uint8_t nunchuck_buf[6];  // array to store nunchuck data,  
 // Uses port C (analog in) pins as power & ground for Nunchuck  
 static void nunchuck_setpowerpins()  
 {  
 #define pwrpin PORTC3  
 #define gndpin PORTC2  
   DDRC |= _BV(pwrpin) | _BV(gndpin);  
   PORTC &=~ _BV(gndpin);  
   PORTC |= _BV(pwrpin);  
   delay(100); // wait for things to stabilize      
 }  
 // initialize the I2C system, join the I2C bus,  
 // and tell the nunchuck we're talking to it  
 void nunchuck_init()  
 {   
  Wire.begin();             // join i2c bus as master  
  Wire.beginTransmission(0x52);     // transmit to device 0x52  
  Wire.send(0x40);          // sends memory address  
  Wire.send(0x00);          // sends sent a zero.   
  Wire.endTransmission();     // stop transmitting  
 }  
 // Send a request for data to the nunchuck  
 // was "send_zero()"  
 void nunchuck_send_request()  
 {  
  Wire.beginTransmission(0x52);     // transmit to device 0x52  
  Wire.send(0x00);          // sends one byte  
  Wire.endTransmission();     // stop transmitting  
 }  
 // Receive data back from the nunchuck,   
 int nunchuck_get_data()  
 {  
   int cnt=0;  
   Wire.requestFrom (0x52, 6);     // request data from nunchuck  
   while (Wire.available ()) {  
    // receive byte as an integer  
    nunchuck_buf[cnt] = nunchuk_decode_byte(Wire.receive());  
    cnt++;  
   }  
   nunchuck_send_request(); // send request for next data payload  
   // If we recieved the 6 bytes, then go print them  
   if (cnt >= 5) {  
    return 1;  // success  
   }  
   return 0; //failure  
 }  
 void aciona_servos()  
 {   
  for(int cnt = m_movel-1; cnt > 0; cnt --)  
  {  
  aux_m_y[cnt] = aux_m_y[cnt-1];  
  aux_soma_y = aux_soma_y + aux_m_y[cnt];  
  aux_m_x[cnt] = aux_m_x[cnt-1];  
  aux_soma_x = aux_soma_x + aux_m_x[cnt];  
  }  
  int joy_x_axis = nunchuck_buf[0];  
  int joy_y_axis = nunchuck_buf[1];  
  int z_button = nunchuck_buf[5] & 1;  
  int c_button = nunchuck_buf[5] >> 1 & 1;  
  int accel_x_axis = (nunchuck_buf[2] << 2) + ((nunchuck_buf[5] >> 2) & 0x03);  
  int accel_y_axis = (nunchuck_buf[3] << 2) + ((nunchuck_buf[5] >> 4) & 0x03);  
  int accel_z_axis = (nunchuck_buf[4] << 2) + ((nunchuck_buf[5] >> 6) & 0x03);  
  // media eixo Y ////  
  aux_m_y[0] = accel_y_axis;  
  aux_soma_y = aux_soma_y + aux_m_y[0];   
  media_y_aux = aux_soma_y /m_movel;  
  aux_soma_y = 0;  
  media_leit_y = constrain(media_y_aux, 375, 595);  
  media_leit_y = map(media_leit_y, 375, 595, 110, 70);  
  // media eixo X ////  
  aux_m_x[0] = accel_x_axis;  
  aux_soma_x = aux_soma_x + aux_m_x[0];   
  media_x_aux = aux_soma_x /m_movel;  
  aux_soma_x = 0;  
  media_leit_x = constrain(media_x_aux, 375, 595);  
  media_leit_x = map(media_leit_x, 375, 595, 70, 110);  
  servo_y.write(media_leit_y);       // tell servo to go to position in variable 'pos'   
  servo_x.write(media_leit_x);   
   }  
 char nunchuk_decode_byte (char x)  
 {  
  x = (x ^ 0x17) + 0x17;  
  return x;  
 }