Problemas calibración Nonchacku WII + Arduino MEGA + Servo

Hola tod@s.

Vuelvo a la carga con el cacharreo con el mando nunchacku wii y necesito vuestra ayuda y/o comentarios.

Después de liarme con las librería de aquí para aya de Arduino Playground - WiiChuckClass, para los demás será muy sencillo, pero me parece que estoy haciendo un castillo de arena con esto, he encontrado un código para leer el joystick, los 2 botones y el acelerómetro de 3 ejes, sin necesidad de utilizar librerías específicas, código a lo burro y librerías standar para mi MEGA2560 y SDK 0.22. ]:slight_smile:

Se trata de un código que ..... recorcholis , ¿de donde lo saque? :blush:

Simplemente pegando y mandarlo al Arduino MEGA2560 "funciono". Lo pongo entre comillas porque me da la sensación que hay un problema en la calibración. En un primer momento pensé que el problema estaba en el mando que estaba utilizando. Aunque es nuevo, y aunque tiene que cumplir el protocolo de comunicación de Wii para que funcione con la consola, no se comporta muy fino, sobre todo la parte del acelerómetro.

He probado a utiliza un mando de Wii original después de comprobar que en la wii funciona correctamente, y un mando Wii inalámbrico, pero todos con resultados nefastos. El que mejor resultados me ha dada a sido el de "la roja", en el apartado de botones y joystick, de los datos del acelerometro ni los comento porque van a su bola.

Los datos mostrados por puerto serie son: Joystick eje X, eje Y Acelerómetro: Eje X, eje Y, eje Z, botones: Z y C.

El servo lo tengo conectado al ping PWM 9 para controlar el eje X del joystick.

El código base sin añadir la librería "servo" ni el control del servo es el siguiente:

#include <Wire.h>
#include <WProgram.h>

static uint8_t nunchuck_buf[6];   // array to store nunchuck data,

// initialize the I2C system, join the I2C bus,
// and tell the nunchuck we're talking to it
static 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()"
static void nunchuck_send_request()
{
   Wire.beginTransmission(0x52);// transmit to device 0x52
   Wire.send(0x00);// sends one byte
   Wire.endTransmission();// stop transmitting
}

// Encode data to format that most wiimote drivers except
// only needed if you use one of the regular wiimote drivers
static char nunchuk_decode_byte (char x)
{
   x = (x ^ 0x17) + 0x17;
   return x;
}

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

static void nunchuck_print_data()
{
   static int i=0;
   int joy_x_axis = nunchuck_buf[0];
   int joy_y_axis = nunchuck_buf[1];
   int accel_x_axis = nunchuck_buf[2]; // * 2 * 2;
   int accel_y_axis = nunchuck_buf[3]; // * 2 * 2;
   int accel_z_axis = nunchuck_buf[4]; // * 2 * 2;

   int z_button = 0;
   int c_button = 0;

   // byte nunchuck_buf[5] contains bits for z and c buttons
   // it also contains the least significant bits for the accelerometer data
   // so we have to check each bit of byte outbuf[5]
   if ((nunchuck_buf[5] >> 0) & 1)
       z_button = 1;
   if ((nunchuck_buf[5] >> 1) & 1)
       c_button = 1;

   if ((nunchuck_buf[5] >> 2) & 1)
       accel_x_axis += 2;
   if ((nunchuck_buf[5] >> 3) & 1)
       accel_x_axis += 1;

   if ((nunchuck_buf[5] >> 4) & 1)
       accel_y_axis += 2;
   if ((nunchuck_buf[5] >> 5) & 1)
       accel_y_axis += 1;

   if ((nunchuck_buf[5] >> 6) & 1)
       accel_z_axis += 2;
   if ((nunchuck_buf[5] >> 7) & 1)
       accel_z_axis += 1;

   Serial.print(i,DEC);
   Serial.print("\t");

   Serial.print("joy:");
   Serial.print(joy_x_axis,DEC);
   Serial.print(",");
   Serial.print(joy_y_axis, DEC);
   Serial.print("  \t");

   Serial.print("acc:");
   Serial.print(accel_x_axis, DEC);
   Serial.print(",");
   Serial.print(accel_y_axis, DEC);
   Serial.print(",");
   Serial.print(accel_z_axis, DEC);
   Serial.print("\t");

   Serial.print("but:");
   Serial.print(z_button, DEC);
   Serial.print(",");
   Serial.print(c_button, DEC);

   Serial.print("\r\n");  // newline
   i++;
}

int loop_cnt=0;

void setup()
{
   Serial.begin(19200);
   nunchuck_init();
}

void loop()
{
   if( loop_cnt > 1000 ) { // every 100 msecs get new data
       loop_cnt = 0;          
       nunchuck_get_data();
       nunchuck_print_data();
   }
   loop_cnt++;
}

La modificación que he hecho es: coger la función "nunchuck_print_data" copiar y pegar más abajo, y en vez de imprimir los datos en el puerto serie, mando los valores del joystick eje X al servo, utilizando la librería estandar "servo", pero en el código no lo he introducido para evitar enmorroñarlo ya que el problema no esta en como mover el servo, sino porque obtengo esos valores tan inestables. En el acelerómetro puedo entenderlo cuando lo tengo en la mano si es muy sensible, pero el eje X del joystick y el resultado con otros mandos, ....

Dejo un documento gráfico para ver como se comporta y como manipulo el mando y su resultado en el servio y telemetría obtenida por el puerto serie : Test Nunchacku WII + servo - YouTube

Muchas gracias por la ayuda por adelantada.

A mi me parecen lecturas bastante normales (excepto en el rosa), es imposible que se te queden todos los valores estáticos aun sin tocar nada.
Si no quieres que el servo se mueva, métele una zona muerta o filtra la señal/datos.

¿y como le introduzco una zona muerta?

Tomas un dato, si los siguientes tienen una diferencia menor de, por ejemplo, 2 no actualizas el servo.

hoy estoy sembrado :*

Gracias Chivas por quitarme las telarañas de la cabeza.

Yo he estado últimamente jugueteando con nunchucks, y hay dos códigos, dependiendo si el nunchick es Original o es uno OEM.

Te paso un de este foro donde ponen la solución espero que te solucione tu problema.
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1264805255

Un saludo.

Gracias ElRodri.

Le echaré un vistazo al hilo. aunque esta en ingles, intentaré hacer tratucciones con google traslator :wink: para ir entendiéndolo.

Aun así, tengo un pseudocódigo en la cabeza para realizar una especie de calibrado.

Os contaré que tal van los abancez.

Yo me estoy haciendo como una pistola arcade pero no esta echo con las placas arduino sino con teensy 2.0 pero con lenguage arduino.

Video del primer test: Arcade Handgun - First Test on Modern Warfare 2 (Teensy 2.0 & Arduino Soft.) - YouTube

///MOVE MOUSE X
if(accel_x_axis > 570){
Mouse.move((accel_x_axis-570)/8,0);}
if(accel_x_axis < 490){
Mouse.move((accel_x_axis-490)/8,0);}

///MOVE MOUSE Y
if(accel_y_axis > 630){
Mouse.move(0,(accel_y_axis-630)/4);}
if(accel_y_axis < 580){
Mouse.move(0,(accel_y_axis-580)/4);}

se puede utilizar un wii nunchuck (chino en mi caso) para medir la "fuerza G"?

Sergegsx:
se puede utilizar un wii nunchuck (chino en mi caso) para medir la "fuerza G"?

Si, lleva un acelerómetro de tres ejes (X,Y,Z), un joystick (X,Y) y dos botones (C,Z) :slight_smile:

gracias elrodri, entonces tengo que mirarlo mejor porque no entiendo los resultados que me lee.
la aceleracion (fuerza G) deberia medirla unicamente cuando se produce un cambio de velocidad en el tiempo. pero el aparatejo lee valores cuando se inclina.
vamos que voy aun poco perdido ya que todos los ejemplos de internet usan la inclinacion para mover un servo por ejemplo, pero yo quiero saber la aceleración en el eje x e y.
gracias