Go Down

Topic: Wireless Wii Nunchuck with Arduino (Read 799 times) previous topic - next topic

Jedidiah

Mar 04, 2012, 12:28 am Last Edit: Mar 05, 2012, 07:35 pm by Jedidiah Reason: 1
Hi guys,

I've dug through various codes for processing the nunchuck via the i2c protocol, and eventually came up with something that works relatively smoothly.

The new problem I came up with, is that when the chuck powers down or goes out of range, the receiver unit keeps sending the same digits for a while before zeroing out.
I haven't found a way to see if there's ACK's at all... So I decided to check and see if I get the same message over and over.... It starts a count that works as a filter, once there's enough duplicates, the connection is set as bad and tries to re-init. This fixed my problem, though it's a band-aid. Maybe someone else can fix it better, or find it of use.

Code: [Select]

// Wireless Nunchuck error checking - Jedidiah
// adapt to your hardware config
#define CPU_FREQ (16000000L)

#include <Wire.h>
//#include <string.h>
//#include <utility\twi.h>
#include <Servo.h>
//#include <stdio.h>
byte ZeroByteData = 0x00; // overcome faulty wire.h library problems, in arduino 1.0
int  OutBuff[6];
int  PrevBuff[6];
int  ByteCounter=0;
int  DuplicateCounter=0;
int  ConnectionFilter=10; // Filter on how quickly we judge a lost connection
bool GoodConnection=false;
/*
// check if nunchuk is really connected
 if ((outbuf[4]&0x01)==0x01) {
 */

void setup ()
{
 delay(2500);
 digitalWrite(13,HIGH);
 delay(150);
 digitalWrite(13,LOW);
 delay(75);
 digitalWrite(13,HIGH);
 delay(150);
 digitalWrite(13,LOW);
 Serial.begin (9600);//  Serial.begin (57600);  
 
 
 
 Serial.println("x - LED Off, end transmission");
 Serial.println("o - LED On, initalize nunchuck");
 Serial.println("r - Set to 0x00, Request current data");
 Serial.println("s - Set to pointer Ox08");
 Serial.println("#ii - Set to pointer 0xii");  
   //Setup servos
ReInit();
}
void loop ()
{
 Wire.beginTransmission(0x52);
 Wire.write(ZeroByteData);
 Wire.endTransmission();
 Wire.requestFrom(0x52,6);
 if(GoodConnection ==true){digitalWrite(13,HIGH);}else{digitalWrite(13,LOW);}  
 if(Wire.available() >= 6){
   for (ByteCounter=0; ByteCounter < 6; ByteCounter++) {OutBuff[ByteCounter]=Wire.read();}
   if (
      ((OutBuff[0] == 255) && (OutBuff[1] == 255) && (OutBuff[5] == 255)) ||
      ((OutBuff[0] == 0  ) && (OutBuff[1] == 0  ) && (OutBuff[5] == 0  ))  ){  
        Serial.println("Junk Received. Reinitalizing.");
        ReInit();  
   }
   else {//      Serial.print("REC:"); for (Counter=0; Counter < 6; Counter++) {Serial.print(OutBuff[Counter],HEX); Serial.print(" ");} Serial.print("   ");
     int joy_x_axis = OutBuff[0];
     int joy_y_axis = OutBuff[1];
     int z_button=((OutBuff[5] & 0x01)==0);
     int c_button=((OutBuff[5] & 0x02)==0);
     int accel_x_axis = ((OutBuff[2]) << 2) +(((OutBuff[5]) >> 2) & 0x03);// int accel_x_axis = (OutBuff[2] << 2) + ((OutBuff[5] >> 3) & 2);
     int accel_y_axis = ((OutBuff[3]) << 2)+(((OutBuff[5]) >> 4) & 0x03);// int accel_y_axis = (OutBuff[3] << 2) + ((OutBuff[5] >> 4) & 2);
     int accel_z_axis = ((OutBuff[4]) << 2)+(((OutBuff[5]) >> 6) & 0x03);// int accel_z_axis = (OutBuff[4] << 2) + ((OutBuff[5] >> 5) & 6);
     // Serial.print ("  JoyX=");  Serial.print (joy_x_axis, DEC);      Serial.print ("  JoyY=");  Serial.print (joy_y_axis, DEC);      Serial.print ("  AccX=");  Serial.print (accel_x_axis, DEC);      Serial.print ("  AccY=");  Serial.print (accel_y_axis, DEC);      Serial.print ("  AccZ=");  Serial.print (accel_z_axis, DEC);      Serial.print ("  ");      if (z_button==1){Serial.print ("Z_button ");}      if (c_button==1){Serial.print ("C_button ");}  Serial.print("   Counter:"); Serial.print(SameCounter);    Serial.println(".");
     
      if (CompareArray(OutBuff,PrevBuff)==true){
        DuplicateCounter++;
        if(DuplicateCounter > ConnectionFilter && GoodConnection == true){
          GoodConnection=false;
          Serial.println("Bad Connection");
          SilentReInit();
        }

}
      else {
        for (int x=0;x<=6;x++){
          PrevBuff[x] = OutBuff[x];
        }
        DuplicateCounter = 0;
        if (GoodConnection == false) { GoodConnection=true; }
        //Serial.print("   Counter:"); Serial.println(SameCounter);
        Serial.print ("[JOY  X:" + Format(joy_x_axis) + " Y:"+ Format(joy_y_axis) + "]");
        Serial.print ("#[ACC  X:" + Format(accel_x_axis) + " Y:" +Format(accel_y_axis) + " Z:" + Format(accel_z_axis) + "]##");
        if (z_button==1){Serial.print ("[Z]");} else {Serial.print("[ ]");}
        if (c_button==1){Serial.println ("=[C]");} else {Serial.println("=[ ]");}                    
       }
   for (ByteCounter=0; ByteCounter < 6; ByteCounter++) {OutBuff[ByteCounter]=0;}
  }
 }
 if(Serial.available()){
   int TEXT = Serial.read();
   if(TEXT=='x'){Wire.endTransmission(); Serial.println("Ended Transmission.");}
   if(TEXT=='o'){ Serial.println("Initalizing."); ReInit();}
   if(TEXT=='r'){
     Serial.println("Refreshing Data.");
     Wire.beginTransmission(0x52);
     Wire.write(ZeroByteData);
     Wire.endTransmission();
     Wire.requestFrom(0x52,6);            
   }
   if(TEXT=='s'){
     Wire.beginTransmission(0x52);
     Wire.write(0x08);
     Wire.endTransmission();
     delay(100);
     Wire.requestFrom(0x52,6);            
   }
   if(TEXT=='#'){
      int digit = Serial.read(); int digit2 = Serial.read();
      if ((digit >= 'A') && (digit <= 'F')){digit = ((digit -'A') +10)*16;}
      else if ((digit >= 'a') && (digit <= 'f')){digit = ((digit -'a') +10)*16;}
      else if ((digit >= '0') && (digit <= '9')){digit = (digit -'0')*16;}
      if ((digit2 >= 'A') && (digit2 <= 'F')){digit2 = (digit2 -'A') +10;}
      else if ((digit2 >= 'a') && (digit2 <= 'f')){digit2 = (digit2 -'a') +10;}
      else if ((digit2 >= '0') && (digit2 <= '9')){digit2 = (digit2 -'0');}
      digit = digit + digit2;
      Wire.beginTransmission(0x52);
      Wire.write(digit);
      Wire.endTransmission();
      Wire.requestFrom(0x52,6);      
      //      Serial.print("REC:"); for (Counter=0; Counter < 6; Counter++) {OutBuff[Counter]=Wire.read(); Serial.print(OutBuff[Counter],HEX);}Serial.println("");
   }
 }
}  
bool CompareArray(int Array1[6],int Array2[6]){
 int Xcount=0;
 for (int x=0; x<=6;x++){
   if (Array1[x]==Array2[x]){Xcount++;}
  }
  if(Xcount==6){return true;} else {return false;}
 }

void SetArray(int Array1[6],int Array2[6]){
   for (int x=0;x<=6;x++){
    Array2[x] = Array1[x];
   }
 }

void ReInit(){
  Wire.endTransmission ();
 delay(50);
 Wire.begin();
 Wire.beginTransmission (0x52);
 Wire.write (0xF0);
 Wire.write (0x55);
 Wire.endTransmission ();
 Wire.beginTransmission (0x52);
 Wire.write (0xFB);
 Wire.write (ZeroByteData);
 Wire.endTransmission ();
 Wire.beginTransmission (0x52);
 Wire.write (0xFA);
 Wire.endTransmission ();
    delay(1);
   Wire.requestFrom(0x52, 6);    // request 6 bytes from slave device #2
   if(Wire.available()){
     int TOTAL;
     Serial.print("Data Available, DEVID:");
     for (ByteCounter = 0; (ByteCounter < 6) && Wire.available (); ByteCounter++){
       OutBuff[ByteCounter] = Wire.read (); // receive byte as an integer
       Serial.print(OutBuff[ByteCounter], HEX);   // print the character
     }
     Serial.println(".");
   }
   else {}//Serial.println("Data Unavailable.");}
 }

void SilentReInit(){
  Wire.endTransmission ();
  delay(50);
  Wire.begin();
  Wire.beginTransmission (0x52);
  Wire.write (0xF0);
  Wire.write (0x55);
  Wire.endTransmission ();
  Wire.beginTransmission (0x52);
  Wire.write (0xFB);
  Wire.write (ZeroByteData);
  Wire.endTransmission ();
  Wire.beginTransmission (0x52);
  Wire.write (0xFA);
  Wire.endTransmission ();
    delay(1);
  Wire.requestFrom(0x52, 6);    // request 6 bytes from slave device #2
  if(Wire.available()){
    int TOTAL;
    for (ByteCounter = 0; (ByteCounter < 6) && Wire.available (); ByteCounter++){ OutBuff[ByteCounter] = Wire.read ();}
   }
}

String Format(int Text2Decode){
String Text = "";
Text = Text + Text2Decode;
for (int x = Text.length(); x<4; x++){
  Text = Text + " ";
}
return Text;
}

oric_dan

I can't comment on your code, but maybe there is something on this page that
will be of help.

http://www.windmeadow.com/node/42

Jedidiah

#2
Mar 05, 2012, 05:43 pm Last Edit: Mar 05, 2012, 07:32 pm by Jedidiah Reason: 1
That's where I started when I bought my zx nunchuck pcb adapter board. It has a 3.3v regulator on board.

The problem I found is that there's no way to check if the chuck itself gets out of range of its' receiver.

There may be a way, I just haven't discovered it yet.

My code above triggers a stop and tries to reinitialize communications... this works well for me, as in my case I'm running a 4wd RC rock crawler with it.
When the rig gets out of range, it stops throttle input until it resumes, this is also beautiful in-case the remotes (nunchuck) battery dies.

Without any way of checking, the arduino will think that the chuck receiver is getting good data and will continue to tell the rig to do what the chuck was doing last when the signal was lost....

Picture my rig running off down the street into traffic... bummer!  :smiley-eek:

One note: Because my application is a 4wd crawler, I only used the filter to stop or start the throttle, this way, if communication is lost in a hairy event, you stay put, with your steering and other accessories staying the same as they were. Mind you, you can use an If (GoodConnection){ servo.write();} in anyway you'd wish.


Here's an update with an attempt at signal strength. It counts how many times it Asks for bytes and how many times it receives good different data, and shows you.. IE (Rx/TX) Signal:4/7

Also, there's a new addition, turning off serial with the bool serialout=true/false...
This can speed up your code by a lot if you turn off serial communications.

Will post below...

Jedidiah

#3
Mar 05, 2012, 07:33 pm Last Edit: Mar 05, 2012, 07:36 pm by Jedidiah Reason: 1
Code: [Select]
// Wireless Nunchuck error checking, Signal Strength and Serial disable switch- Jedidiah
// adapt to your hardware config
#define CPU_FREQ (16000000L)

#include <Wire.h>
//#include <string.h>
//#include <utility\twi.h>
#include <Servo.h>
//#include <stdio.h>
byte ZeroByteData = 0x00; // overcome faulty wire.h library problems, in arduino 1.0
int  OutBuff[6];
int  PrevBuff[6];
int  ByteCounter=0;
int  DuplicateCounter=0;
int  ConnectionFilter=10; // Filter on how quickly we judge a lost connection
bool GoodConnection=false;
int Variable4;
int PacketCounter,PrevPacketCounter;
int SendCounter,PrevSendCounter;
long StrengthTimer;
long CurrentTime;
bool SerialOut = true;
int joy_x_axis,joy_y_axis;
int z_button,c_button;
int accel_x_axis,accel_y_axis,accel_z_axis;

void setup ()
{
 delay(2500);
 digitalWrite(13,HIGH);
 delay(150);
 digitalWrite(13,LOW);
 delay(75);
 digitalWrite(13,HIGH);
 delay(150);
 digitalWrite(13,LOW);
 if(SerialOut){
   Serial.begin (9600);//  Serial.begin (57600);  
   Serial.println("x - LED Off, end transmission");
   Serial.println("o - LED On, initalize nunchuck");
   Serial.println("r - Set to 0x00, Request current data");
   Serial.println("s - Set to pointer Ox08");
   Serial.println("#ii - Set to pointer 0xii");  
 }
   //Setup servos
ReInit();
}
void loop ()
{
 CurrentTime = millis();
 Wire.beginTransmission(0x52);
 Wire.write(ZeroByteData);
 Wire.endTransmission();
 Wire.requestFrom(0x52,6);
 SendCounter++;
 if(GoodConnection ==true){digitalWrite(13,HIGH);}else{digitalWrite(13,LOW);}  
 if(Wire.available() >= 6){
   for (ByteCounter=0; ByteCounter < 6; ByteCounter++) {OutBuff[ByteCounter]=Wire.read();}
   if (
      ((OutBuff[0] == 255) && (OutBuff[1] == 255) && (OutBuff[5] == 255)) ||
      ((OutBuff[0] == 0  ) && (OutBuff[1] == 0  ) && (OutBuff[5] == 0  ))
      //((OutBuff[0] == 255) || (OutBuff[0] == 0)) &&
      //((OutBuff[1] == 255) || (OutBuff[1] == 0)) &&      
      //((OutBuff[5] == 255) || (OutBuff[5] == 0))
      ){  
        Serial.println("Junk Received. Reinitalizing.");
        ReInit();  
   }
   else {//if(SerialOut{ Serial.print("REC:"); for (Counter=0; Counter < 6; Counter++) {Serial.print(OutBuff[Counter],HEX); Serial.print(" ");} Serial.print("   ");}
     joy_x_axis = OutBuff[0];
     joy_y_axis = OutBuff[1];
     z_button=((OutBuff[5] & 0x01)==0);
     c_button=((OutBuff[5] & 0x02)==0);
     accel_x_axis = ((OutBuff[2]) << 2) +(((OutBuff[5]) >> 2) & 0x03);// int accel_x_axis = (OutBuff[2] << 2) + ((OutBuff[5] >> 3) & 2);
     accel_y_axis = ((OutBuff[3]) << 2)+(((OutBuff[5]) >> 4) & 0x03);// int accel_y_axis = (OutBuff[3] << 2) + ((OutBuff[5] >> 4) & 2);
     accel_z_axis = ((OutBuff[4]) << 2)+(((OutBuff[5]) >> 6) & 0x03);// int accel_z_axis = (OutBuff[4] << 2) + ((OutBuff[5] >> 5) & 6);
 //    Variable4 = ((OutBuff[4]&0x01));//((OutBuff[4]&0x01)==0x01);
      if (CompareArray(OutBuff,PrevBuff)==true){
        DuplicateCounter++;
        if(DuplicateCounter > ConnectionFilter && GoodConnection == true){
          GoodConnection=false;
          if(SerialOut){Serial.println("Bad Connection");}
          SilentReInit();
        }
      }
      else {
        PacketCounter++;
        for (int x=0;x<=6;x++){
          PrevBuff[x] = OutBuff[x];
        }
        DuplicateCounter = 0;
        if (GoodConnection == false) { GoodConnection=true; }
        if(SerialOut){
        /*  Serial.print("   Counter:"); Serial.println(SameCounter);
          Serial.print ("[JOY  X:" + Format(joy_x_axis) + " Y:"+ Format(joy_y_axis) + "]");
          Serial.print ("#[ACC  X:" + Format(accel_x_axis) + " Y:" +Format(accel_y_axis) + " Z:" + Format(accel_z_axis) + "]##");
          if (z_button==1){Serial.print ("[Z]");} else {Serial.print("[ ]");}
          if (c_button==1){Serial.print ("=[C]");} else {Serial.print("=[ ]");}                    
          Serial.print ("  Variable4:"); Serial.print(Variable4,DEC);
          Serial.print ("  Dropped:"); Serial.print(PacketCounter-100,DEC);
          Serial.println("%");
        */  
        }
      }
   for (ByteCounter=0; ByteCounter < 6; ByteCounter++) {OutBuff[ByteCounter]=0;}
  }
 }
 if(SerialOut){
   if(Serial.available()){
     int TEXT = Serial.read();
     if(TEXT=='x'){Wire.endTransmission(); Serial.println("Ended Transmission.");}
     if(TEXT=='o'){ Serial.println("Initalizing."); ReInit();}
     if(TEXT=='r'){
       Serial.println("Refreshing Data.");
       Wire.beginTransmission(0x52);
       Wire.write(ZeroByteData);
       Wire.endTransmission();
       Wire.requestFrom(0x52,6);            
     }
     if(TEXT=='s'){
       Wire.beginTransmission(0x52);
       Wire.write(0x08);
       Wire.endTransmission();
       delay(100);
       Wire.requestFrom(0x52,6);            
     }
     if(TEXT=='#'){
       int digit = Serial.read(); int digit2 = Serial.read();
       if ((digit >= 'A') && (digit <= 'F')){digit = ((digit -'A') +10)*16;}
       else if ((digit >= 'a') && (digit <= 'f')){digit = ((digit -'a') +10)*16;}
       else if ((digit >= '0') && (digit <= '9')){digit = (digit -'0')*16;}
       if ((digit2 >= 'A') && (digit2 <= 'F')){digit2 = (digit2 -'A') +10;}
       else if ((digit2 >= 'a') && (digit2 <= 'f')){digit2 = (digit2 -'a') +10;}
       else if ((digit2 >= '0') && (digit2 <= '9')){digit2 = (digit2 -'0');}
       digit = digit + digit2;
       Wire.beginTransmission(0x52);
       Wire.write(digit);
       Wire.endTransmission();
       Wire.requestFrom(0x52,6);      
       //if(SerialOut){Serial.print("REC:"); for (Counter=0; Counter < 6; Counter++) {OutBuff[Counter]=Wire.read(); Serial.print(OutBuff[Counter],HEX);}Serial.println("");}
   }
 }
 }
 if(SerialOut){
   if (GoodConnection==true){
     Serial.print ("[JOY  X:" + Format(joy_x_axis) + " Y:"+ Format(joy_y_axis) + "]");
     Serial.print ("#[ACC  X:" + Format(accel_x_axis) + " Y:" +Format(accel_y_axis) + " Z:" + Format(accel_z_axis) + "]##");
     if (z_button==1){Serial.print ("[Z]");} else {Serial.print("[ ]");}
     if (c_button==1){Serial.print ("=[C]");} else {Serial.print("=[ ]");}                    
   }
   else {
     Serial.print ("[JOY  X:     Y:    ]#[ACC  X:     Y:     Z:    ]##[ ]=[ ]");
   }
 }
 if (CurrentTime > StrengthTimer) {StrengthTimer = CurrentTime +250;PrevPacketCounter = PacketCounter;PrevSendCounter=SendCounter;SendCounter=0;PacketCounter =0;}  
 if(SerialOut){
   Serial.print ("  Signal:"); Serial.print(PrevPacketCounter,DEC) ;Serial.print("/");Serial.print(PrevSendCounter,DEC);
   Serial.println(" ");
 }
}  
bool CompareArray(int Array1[6],int Array2[6]){
 int Xcount=0;
 for (int x=0; x<=6;x++){
   if (Array1[x]==Array2[x]){Xcount++;}
  }
  if(Xcount==6){return true;} else {return false;}
 }

void SetArray(int Array1[6],int Array2[6]){
   for (int x=0;x<=6;x++){
    Array2[x] = Array1[x];
   }
 }

void ReInit(){
  Wire.endTransmission ();
 delay(50);
 Wire.begin();//  TWBR = ((CPU_FREQ / 400000L) - 16) / 2;
//  #define TWI_FREQ_NUNCHUCK 400000L
//TWBR = ((CPU_FREQ / TWI_FREQ_NUNCHUCK) - 16) / 2;
 Wire.beginTransmission (0x52);
 Wire.write (0xF0);
 Wire.write (0x55);
 Wire.endTransmission ();
 Wire.beginTransmission (0x52);
 Wire.write (0xFB);
 Wire.write (ZeroByteData);
 Wire.endTransmission ();
 Wire.beginTransmission (0x52);
 Wire.write (0xFA);
 Wire.endTransmission ();
    delay(1);
   Wire.requestFrom(0x52, 6);    // request 6 bytes from slave device #2
   if(Wire.available()){
     int TOTAL;
     if(SerialOut){Serial.print("Data Available, DEVID:");}
     for (ByteCounter = 0; (ByteCounter < 6) && Wire.available (); ByteCounter++){
       OutBuff[ByteCounter] = Wire.read (); // receive byte as an integer
       if(SerialOut){Serial.print(OutBuff[ByteCounter], HEX);}   // print the character
     }
     if(SerialOut){Serial.println(".");}
   }
   else {}//Serial.println("Data Unavailable.");}
 }

void SilentReInit(){
  Wire.endTransmission ();
  delay(50);
  Wire.begin();
  Wire.beginTransmission (0x52);
  Wire.write (0xF0);
  Wire.write (0x55);
  Wire.endTransmission ();
  Wire.beginTransmission (0x52);
  Wire.write (0xFB);
  Wire.write (ZeroByteData);
  Wire.endTransmission ();
  Wire.beginTransmission (0x52);
  Wire.write (0xFA);
  Wire.endTransmission ();
    delay(1);
  Wire.requestFrom(0x52, 6);    // request 6 bytes from slave device #2
  if(Wire.available()){
    int TOTAL;
    for (ByteCounter = 0; (ByteCounter < 6) && Wire.available (); ByteCounter++){ OutBuff[ByteCounter] = Wire.read ();}
   }
}

String Format(int Text2Decode){
String Text = "";
Text = Text + Text2Decode;
for (int x = Text.length(); x<4; x++){
  Text = Text + " ";
}
return Text;
}



oric_dan

I don't know about wireless nunchuck operation. I just connected one directly to the
Arduino I2C pins [must be 3.3V operation] and used the code from the windmeadow page.
The code worked 100% the first time.

rodrigodasilva

Have you found a solution for this problem?

Go Up