Estos últimos días seguramente vieron que no se estaba posteando mucho, no tienen porque desesperar... no es que abandonamos la página!! Solamente que encontramos unos juguetitos nuevos con que jugar jejejeje y lo primero que hicimos es comenzar a fabricar cosas. En las próximas semanas vamos a empezar una bitácora para que vayan viendo los avances :D.
Uno de esos juguetes es el famoso control de la Wii, el Nunchuck.
Como a nosotros nos interesa la parte de hardware, tenemos estas 2 páginas WiiBrew y WiiLi.
En las 2 ultimas podemos ver como conectar el Nunchuck, como es la forma de transmitir datos que tiene y sus características.
Cualquier semejanza del dibujo con la realidad es pura coincidencia (?) xD
¿Para que sirve el Nunchuck en nuestros proyectos?
Para infinidad de cosas! Desde robótica hasta helicopteros, pasando por camaras de video y brazos roboticos basta solamente poner Nunchuck y Arduino en Youtube para ver todas las cosas que pueden hacerse. Sus compañeros ideales son los servomotores, de los que hablaremos mas adelante :)
Lo que debemos saber es que usa el protocolo TWI (I2C) para transferir los datos, o sea que solo nos demandará 2 pines del Arduino (el Analog 4 y 5, SCL y SDA respectivamente), y que tiene un acelerometro LIS3L02 de la empresa STMicroelectronics, que pueden ver la datasheet de un modelo similar aca (660mV/g, y +-2g).
¿Como leo los datos?
El Nunchuck usa el protocolo TWI por lo que necesitaremos utilizar la libreria Wire para poder comunicarnos con el (ya viene incluida dentro de la IDE del Arduino). Tendremos que hacer unos pequeños cambios antes.
Vamos (dentro de la carpeta donde descomprimimos al Arduino) a hardware\libraries\Wire\utility (puede variar en otras versiones), borramos el archivo twi.o y abrimos el twi.h. Hacemos los siguientes cambios:
Eliminamos los // de la siguiente linea (la descomentamos)
// #define ATMEGA8
Como el Nunchuck usa el modo "I2C Rapido" debemos cambiar la frecuencia
#define TWI_FREQ 400000L -> (en mi caso, cuando uso una alimentación de 3,3V uso 100000L para reducir el ruido)
Para comunicarse con el nunchuck, le tenemos que mandar un handshake. Primero se mandan 2 bytes "0x40,0x00", y despues se manda 1 byte "0x00" cada vez que se quieren recibir datos del nunchuck. Vamos a recibir 6 bytes de la siguiente forma:
Bit 0: "Z"-Button (0 = pressed, 1 = released) / Bit 1: "C" button (0 = pressed, 1 = released) / Bits 2-3: X acceleration LSB / Bits 4-5: Y acceleration LSB / Bits 6-7: Z acceleration LSB
Los bytes 1-2 toman los valores del joystick, 3-4-5 toman valores del acelerometro y 6 toma el estado de los botones y los ultimos bits significativos de los acelerometros (esto lo podremos ver en mas detalle en el codigo).
Codigo para el Arduino
#include <Wire.h>
#include <string.h>
#undef int
#include <stdio.h>
uint8_t outbuf[6]; // array to store arduino output
int cnt = 0; //contador
int ledPin = 13;
void setup () //recuerden que esto se ejecuta 1 sola vez al inicio
{
beginSerial (19200); //abrimos el puerto serie a 19200 baudios
Serial.print ("Finished setup\n"); //imprimimos un mensaje en la pantalla
Wire.begin (); // juntamos el bus de datos i2c con la direccion 0x52
nunchuck_init (); // mandamos un handshake para inicializar el dispositivo
}
void nunchuck_init () // esto indica una funcion que luego sera llamada
{
Wire.beginTransmission (0x52); // transmite al dispositivo 0x52
Wire.send (0x40); // envia la direccion de la memoria
Wire.send (0x00); // manda un cero
Wire.endTransmission (); // deja de transmitir
}
void send_zero ()
{
Wire.beginTransmission (0x52); // transmite al dispositivo 0x52
Wire.send (0x00); // manda 1 byte, un cero
Wire.endTransmission (); // deja de transmitir
}
void loop ()
{
Wire.requestFrom (0x52, 6); // pide datos del nunchuck al dispositivo 0x52, y se recibirán 6 bytes
while (Wire.available ()) //similar al Serial.available() nos indica que se estan recibiendo datos por el puerto.
{
outbuf[cnt] = nunchuk_decode_byte (Wire.receive ()); // recibe el byte como un integer
digitalWrite (ledPin, HIGH); // prende el led
cnt++; //incrementa el contador
}
// Si recibimos los 6 bytes, entonces los imprimimos
if (cnt >= 5)
{
print (); // llamamos a la funcion print
}
cnt = 0; //volvemos a dejar el contador en 0
send_zero (); // manda el pedido para recibir mas bytes
delay (100);
}
// Print the input data we have recieved << Imprime la informacion que recibimos
// accel data is 10 bits long << La informacion de los acelerometros tiene una longitud de 10 bits
// so we read 8 bits, then we have to add << entonces leemos 8 bits y le agregamos los ultimos 2 bits
// on the last 2 bits. That is why I << por eso los multiplico por 2 * 2
// multiply them by 2 * 2 << Los bits que agregamos vienen en el 6to Byte que recibimos.
void print ()
{
int joy_x_axis = outbuf[0];
int joy_y_axis = outbuf[1];
int accel_x_axis = outbuf[2] * 2 * 2;
int accel_y_axis = outbuf[3] * 2 * 2;
int accel_z_axis = outbuf[4] * 2 * 2;
int z_button = 0;
int c_button = 0;
// byte outbuf[5] contiene los bits de los botones C y Z
// tambien contiene los ultimos bits significativos de los acelerometros
// por lo que tenemos que ver cada bit del byte outbuf[5]
if ((outbuf[5] >> 0) & 1)
{
z_button = 1;
}
if ((outbuf[5] >> 1) & 1)
{
c_button = 1;
}
if ((outbuf[5] >> 2) & 1)
{
accel_x_axis += 2;
}
if ((outbuf[5] >> 3) & 1)
{
accel_x_axis += 1;
}
if ((outbuf[5] >> 4) & 1)
{
accel_y_axis += 2;
}
if ((outbuf[5] >> 5) & 1)
{
accel_y_axis += 1;
}
if ((outbuf[5] >> 6) & 1)
{
accel_z_axis += 2;
}
if ((outbuf[5] >> 7) & 1)
{
accel_z_axis += 1;
}
Serial.print (joy_x_axis, DEC);
Serial.print ("\t");
Serial.print (joy_y_axis, DEC);
Serial.print ("\t");
Serial.print (accel_x_axis, DEC);
Serial.print ("\t");
Serial.print (accel_y_axis, DEC);
Serial.print ("\t");
Serial.print (accel_z_axis, DEC);
Serial.print ("\t");
Serial.print (z_button, DEC);
Serial.print ("\t");
Serial.print (c_button, DEC);
Serial.print ("\t");
Serial.print ("\r\n");
}
// Encode data to format that most wiimote drivers except
// only needed if you use one of the regular wiimote drivers
char
nunchuk_decode_byte (char x)
{
x = (x ^ 0x17) + 0x17;
return x;
}
Como es por dentro y como conectarlo
Fotos del Nunchuck por dentro
Las conexiones son las siguientes:
Blanco -> GND
Rojo -> 3,3V+
Verde -> Data -> Analog Pin 4
Amarillo -> Clock -> Analog Pin 5
Si usan la version estandar del Arduino, veran que tienen un pin de alimentacion de 3,3V, sino simplemente puede hacer un regulador con algun transistor (si lo consiguen, aca en Argentina es bastante dificil) o con un diodo zener. Se puede usar a 5V pero se reduce la vida util del Nunchuck.
Libreria especial para Arduino
Porque complicarnos tanto cuando alguien ya nos facilito el trabajo? :P
Aca les dejo un video mio jugando un poco (tiene mucho ruido porque en ese momento estaba usando 5V y una frecuencia muy alta en el twi.h, bajando la frecuencia y usandolo a 3,3V dio mejores resultados)
refreshTime (set to 20) - tiempo de refresco minimo para el pulso de los servos minPulse (set to 1000) - valor minimo del pulso para el servo 1 minPulse2 (set to 500) - valor minimo del pulso para el servo 2 dtime (set to10) - delay (en milisegundos) para cada loop pwbuffsize (set to 10) - cuantos valores deben ser guardados en un buffer y despues promediados (es el mismo valor para ambos servos)
Espero que todo esto les sea util, y puedan aplicarlo en sus proyectos. Y recuerden, si llegan a hacer algun proyecto que quieran compartir con los demás, seran mas que bienvenidos aqui asi que no duden en postearlos :)
Saludos! Nico
Comentarios
¡Sólo los usuarios registrados pueden escribir comentarios!
francisco
|2009-10-09 17:41:42
tengo el siguente problema la verdad es que cuando escribo el codigo en el programa arduino 0016 me aparece solo la libreria wire y se que esta por que aparece de un color amarillo pero las librerias
#include
#include
no aparecen mi pregunta es como puedo agregarlas y donde puedo obtenerlas te agradeceria un monton de antemano muchas gracias
francisco
|2009-10-09 17:45:29
no aparecieron los nombres de las librerias pero eran string.h y stdio.h