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;  
 }  



segunda-feira, 14 de fevereiro de 2011

Picaxe, Servo e potenciômetro



Na ultima postagem sobre o Picaxe comentei que pretendia compra um para testá-lo e aprender sobre ele. Pois bem, comprei um 08M, o mais simples de todos com exceção do picaxe 08.

A montagem que descrevo aqui é bastante simples, mas não deixa de ser útil para aqueles, que como eu, estão começando a programar o picaxe. A idéia é receber o sinal 0 a 5v de um potenciômetro através de uma entrada analógica que em 10 bits  retorna um valor de 0 a 1023  (2^10 = 1024 valores possíveis), mudar esse valor para uma escala de 75 a 225 e  usando a função  "servopos  pino, valor”,  aplicá-lo ao servo  ligado ao pino 4 do picaxe através de um resistor de 330R, recomendado pelo manual.

O diagrama é mostrado no vídeo. Dependendo da marca do servo utilizado existe uma variação das cores dos fios de conexão. O positivo normalmente é vermelho o negativo preto ou marrom e o fio de sinal amarelo ou branco. Pra garantir é melhor pesquisar pelo modelo do servo. O potenciômetro pode ser de qualquer valor.
Um cuidado especial deve ser tomado com a alimentação do picaxe. Inverter positivo e negativo significa queimá-lo. Não é aconselhável, também, usar tensões acima de 5v.

O código:


symbol pot_value = w1
symbol servo_value = w2

init: servo 4,75 ; inicializa o servo

main: 'loop principal

READADC10 2, pot_value    ' le o valor do potenciometro ligado ao pino 2 e armazena em pot_value

pot_value = pot_value * 5 / 34  ' mudando da escala lida no pot 0 - 1023 para 75 a 225 aprox

servo_value = pot_value + 75 
   
servopos 4,servo_value 'manda o valor para o servo no saida 4 do picaxe (pino 3 do CI)

goto main 'fim do loop principal