Una de las mejores cosas que tiene la electrónica es que puedes usar aparatos que se fabrican en serie con unas características increibles a precios muy bajos. En esta ocasión voy a explicar cómo usar el nunchuk de la wii para poder adaptarlo a vuestros proyectos electrónicos. En este artículo me centraré en la plataforma Arduino.
No es necesario tener la wii para adquirir un nunchuk, de hecho ni siquiera tiene por qué ser el oficial, un clónico puede llegar a costar 7 €. Por otra parte es necesario tener el wiichuck, que es un adaptador para el nunchuk con una tira de pines y hace más manejable el uso de este (no supera los 4€).
El nunchuk trabaja con una tensión de 3,3 v., pero también puede hacerlo a 5 v. (Limitando su vida útil, pero por 7€ …). Funciona mediante el bus I2C en su variante Fast (400Kb/s) y lo que podemos leer son los datos del acelerómetro XYZ, del joystick y de los dos botones que contiene. Lo que haré en este artículo es recuperar esa información y mostrarla por el puerto serie.
Para empezar hay que inicializar el nunchuk de la siguiente forma:
- Enviar a la dirección 0x52 los bytes 0xF0 y 0x55.
- Enviar a la dirección 0x52 los bytes 0xFB y 0x00.
A partir de entonces cada vez que queramos leer los datos tenemos que:
- Enviar a la dirección 0x52 el byte 0x00.
- Leer de la dirección 0x52 seis bytes.
Los 6 bytes que hemos leido contienen la información del acelerómetro, del joystick y de los botones, pero vienen formateados:
- Primer byte: La posición X del joystick (0-255)
- Segundo byte: La posición Y del joystick (0-255)
- Tercer byte: Los 8 bits de mayor peso del eje X del acelerómetro (Finalmente tendrá un valor entre 0 y 1023)
- Cuarto byte: Los 8 bits de mayor peso del eje Y del acelerómetro (Finalmente tendrá un valor entre 0 y 1023)
- Quinto byte: Los 8 bits de mayor peso del eje Z del acelerómetro (Finalmente tendrá un valor entre 0 y 1023)
- Sexto byte: que contiene
- los dos bits de menor peso del eje Z del acelerómetro
- los dos bits de menor peso del eje Y del acelerómetro
- los dos bits de menor peso del eje X del acelerómetro
- Un bit indicando el estado del botón C (0 si pulsado, 1 si no lo está)
- Un bit indicando el estado del botón Z (0 si pulsado, 1 si no lo está)
Tomaremos los 3,3 v. y la masa que ofrece arduino, conectaremos el pin de data del wiichuck al pin analógico 4 y el pin de clock al pin analógico 5. No son necesarias las resistencias pull-up típicas del bus I2C ya que los pines analógicos 4 y 5 ya las tienen implementadas internamente y son activadas al inicializar la librería wire:
El código fuente simplificado al máximo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
#include <Wire.h> // Necesario para trabajar con el bus I2C #include <utilitytwi.h> // Necesario para la constante CPU_FREQ void setup() { Serial.begin(4800); // Inicializamos el puerto serie a una velocidad baja para que se puedan ver los datos Wire.begin(); // Inicializamos la librería wire para trabajar con I2C TWBR = ((CPU_FREQ / 400000L) - 16) / 2; // Configuramos el I2C para el modo Fast (400Kb/s) // Inicializamos el nunchuk sin encriptación Wire.beginTransmission(0x52); Wire.send(0xF0); Wire.send(0x55); Wire.endTransmission(); Wire.beginTransmission(0x52); Wire.send(0xFB); Wire.send(0x00); Wire.endTransmission(); } void loop () { uint8_t buffer[6]; // Pedimos que se actualicen los datos Wire.beginTransmission(0x52); Wire.send(0); Wire.endTransmission(); // Recogemos y guardamos los datos Wire.requestFrom(0x52, 6); for(int indice = 0; indice < 6; indice++) { buffer[indice] = Wire.receive(); } // Imprimimos los datos en el puerto serie Serial.print("JX:"); Serial.print(buffer[0], DEC); Serial.print(" JY:"); Serial.print(buffer[1], DEC); Serial.print(" AX:"); Serial.print((buffer[2] << 2) | ((buffer[5] & 0x0c) >> 2)); Serial.print(" AY:"); Serial.print((buffer[3] << 2) | ((buffer[5] & 0x30) >> 4)); Serial.print(" AZ:"); Serial.print((buffer[4] << 2) | ((buffer[5] & 0xc0) >> 6)); Serial.print(" C:"); Serial.print((buffer[5] >> 1) & 1); Serial.print(" Z:"); Serial.println(buffer[5] & 1); } |
Y así es como se ven los datos de una de las pruebas que he hecho:
Si os ha gustado me plantearé hacer otro artículo donde explico cómo hacer lo mismo para microcontroladores AVR y PIC.
Menudo crack. Gracias por la información!!
En una tienda de chinos de Vallecas me vendían el mando «no oficial» de la wii entero creo recordar por 10 euros, para la mano izqda y drcha, enterito. El wiichuck donde se puede comprar¿? Un saludete
El wiichuck me lo compré en seeedstudio: http://www.seeedstudio.com/depot/wiichuck-a-wiinunchuck-break-out-board-p-586.html, aunque lo tienes más barato en sparkfun: http://www.sparkfun.com/products/9281
Yo en lugar del Wiichuck uso un trozo del conector de una placa ISA: http://www.karbosguide.com/images/u1930.jpg
Corto de forma que tenga 3 contactos por cada cara y sueldo unos pines hembra o unos cables, según convenga más.
Vaya no se me había ocurrido, pero es una forma muy original de hacer un conector para el nunchuk.
esta genial esta guia, pero para cuando un post sobre cómo programarlo en AVR sin librerias (seria para mi robby, ya le conoces, y el micro el atmegau16 de jorge), ya que tengo pensado mover la pinza y el robby en general con el nunchuck, ya tengo todo comprado (Estan en el avion jeje)
saludos
hice exactamente lo que dijiste (en lo de las conexiones y todo) y me da
JX:0 JY:0 AX:0 AY:0 AZ:0 C:0 Z:0
JX:0 JY:0 AX:0 AY:0 AZ:0 C:0 Z:0
JX:0 JY:0 AX:0 AY:0 AZ:0 C:0 Z:0
JX:0 JY:0 AX:0 AY:0 AZ:0 C:0 Z:0
JX:0 JY:0 AX:0 AY:0 AZ:0 C:0 Z:0
JX:0 JY:0 AX:0 AY:0 AZ:0 C:0 Z:0
JX:0 JY:0 AX:0 AY:0 AZ:0 C:0 Z:0
JX:0 JY:0 AX:0 AY:0 AZ:0 C:0 Z:0
JX:0 JY:0 AX:0 AY:0 AZ:0 C:0 Z:0
JX:0 JY:0 AX:0 AY:0 AZ:0 C:0 Z:0
JX:0 JY:0 AX:0 AY:0 AZ:0 C:0 Z:0
JX:0 JY:0 AX:0 AY:0 AZ:0 C:0 Z:0
JX:0 JY:0 AX:0 AY:0 AZ:0 C:0 Z:0
JX:0 JY:0 AX:0 AY:0 AZ:0 C:0 Z:0
infinitamente, tengo el wiichuck de sparkfun, y el control es un original con cable.. que podrá ser???
Saludos.-
HOla monstruo!!.pude finalmente hacerlo funcionar.gracias asu code.
del autor no me funcionaba, me faltaba agregar en utilitytwi.h
TWBR = ((CPU_FREQ / 400000L) – 16) / 2
yo no cambie la velocidad a 400Kb/s osea aqui:
#define TWI_FREQ 100000L
funciona bien!!
aqui, me modesto codigo para processing.donde emboza la idea de como
interpetar los datos q nos envia via el purto seri el del nunchuk.
del codigo del autor suprimos JX, JY…etc por una coma «,».es decir:
Serial.print(buffer[0], DEC);
Serial.print(«,»);
Serial.print(buffer[1], DEC);
Serial.print(«,»);
Serial.print((buffer[2] <> 2));
Serial.print(«,»);
Serial.print((buffer[3] <> 4));
Serial.print(«,»);
Serial.print((buffer[4] <> 6));
Serial.print(«,»);
Serial.print((buffer[5] >> 1) & 1);
Serial.print(«,»);
Serial.println(buffer[5] & 1);
====================
bueno aqui mi code:
import processing.serial.*;
Serial myport;
char delim= ‘,’;
float joyX,joyY;
int sensorcount =7;
void setup()
{
size(255, 255); smooth();noStroke();
myport = new Serial(this,Serial.list()[1],4800);
myport.clear();
}
float[] sensorValues = new float[sensorcount];
void serialEvent(Serial myport){
String serialString = myport.readStringUntil(‘n’);
if (serialString != null){
String[] numbers = split(serialString, delim);
if ( numbers.length == sensorcount){
for(int i=0;i< numbers.length;i++){
if(i <= sensorcount){
numbers[i] = trim(numbers[i]);
sensorValues[i]= float(numbers[i]);
}
}
}
}
}
//==============================0
void draw()
{
background( 51 );
float val=0 ;
val= (sensorValues[2]/(1023+2));
ellipse(val*200, sensorValues[1], 33, 33);println(val );// para aclerometroX y joyY
}
//==============================
los datos q nos suministra el nunchuk, son doatos g, mv,datos en brutos.
necesito saber como convertilos a angulos.
En radianes:
atan2(AX, AZ) para el cabeceo
atan2(AY, AZ) para el alabeo
En grados:
atan2(AX, AZ) * 180 / PI para el cabeceo
atan2(AX, AZ) * 180 / PI para el alabeo
hola, me encontre con esto.con su formula no me concide en en la posicion q se encuentra el sensor.
Rx=528
Ry=516
Rz=744
normalize vector (convert to a vector with same direction and with length 1)
R = sqrt(square(Rx) + square(Ry) + square(Rz)); //teotema pitagoras
R=1048.129
Rx =Rx/ R; = 0.503
Axr = arccos (Rx / R) =89.97 //precen q esta en grados
—-
segun esto el vector esta parallelo al eje z(fucionado),donde esta formando en cada eje un angulo de 90º–
—
CRE QUE ESTO ESTA CORRECTO, USTED QUE DICE ?
http://www.starlino.com/imu_kalman_arduino.html
Le recomiendo la lectura de este artículo y de la función atan2:
http://gotoandplay.freeblog.hu/archives/2010/06/15/Get_pitch_and_roll_angles_from_the_iPhones_accelerometer_vector/
http://en.wikipedia.org/wiki/Atan2
Pues la verdad es que me estoy haciendo un lio buscando la librería » utilitytwi.h».
No la encuentro por ningún lado.