Account
Projects Forums Code & Files Design Sketches Photos Videos Chat Sites People Sounds  
 
  •  
 
 
Articles
28.01.2010

With a little hacking, data can be read from a wii nunchuck directly into an Arduino, using TWI (aka I2C). The nunchuck contains a 3 axis accelerometer, joystick and buttons for only .95. The same accelerometer in kit form, cost .95 at Sparkfun. Plus the nunchuck is already wired up in a nice clean case! So the wii nunchuck should fit nicely into anyones robotic project.

Arduino Nunchuck

The nunchuck uses a proprietary connector. I just cut the end off of my nunchuck cable. The cable has 4 wires.
white - ground
red - 3.3+v
green - data
yellow - clock

Attach white to the Arduino's ground, red to 5 volt+, green to analog pin 4, yellow to analog pin 5. The nunchuck is only supposed to get 3.3+ volts. So far it has worked fine at 5 volts, but be warned. I am guessing that using the higher voltage will shorten the nunchucks lifespan.

My Arduino has an Atmel atmega168 chip. The atmega168 can read the TWI protocol. The "Wire" library is bundled with the Arduino IDE and contains a number of libraries that will be used for reading the TWI protocol. A few small changes have to be made to the default wire library. The Arduino's twi.h header needs two changes. Look in lib/targets/libraries/Wire/utility. Then delete twi.o. Open up twi.h. Uncomment line:
// #define ATMEGA8.

Since the nunchuck uses "Fast" I2C, we will need to change the default speed:
#define TWI_FREQ 400000L.

For the Arduino to communicate with the nunchuck, it must send a handshake. So first send 2 bytes "0x40,0x00". Then send one byte "0x00" each time you request data from the nunchuck. The data from the nunchuck will come back in 6 byte chunks.

 

Byte Description Values of sample Nunchuk
1 X-axis value of the analog stick Min(Full Left):0x1E / Medium(Center):0x7E / Max(Full Right):0xE1
2 Y-axis value of the analog stick Min(Full Down):0x1D / Medium(Center):0x7B / Max(Full Right):0xDF
3 X-axis acceleration value Min(at 1G):0x48 / Medium(at 1G):0x7D / Max(at 1G):0xB0
4 Y-axis acceleration value Min(at 1G):0x46 / Medium(at 1G):0x7A / Max(at 1G):0xAF
5 Z-axis acceleration value Min(at 1G):0x4A / Medium(at 1G):0x7E / Max(at 1G):0xB1
6 Button state (Bits 0/1) / acceleration LSB 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

see wiili.org

Here is a simple program to read data from the nunchuck. It will read in data from the nunchuck then send it out over the Arduino's serial connection to your PC. On the PC, I just read it in with minicom, but you can use your favorite serial terminal program. The Arduino can't keep up with reading both serial and TWI at the same time. I have the Arduino read in about 50 bytes from the nunchuck then print that back to the PC over the serial connection. This means there will be a slight delay. Also you may see some strange characters every now and then. I think that is because of the serial connection interfering with the TWI connection.

Update: I updated the code some to slow down the serial data transmit and TWI requests. That seems to have fixed the bad data I was seeing.
If you are able to reproduce this hack, please drop me an email at chad AT chadphillips . org

#include <Wire.h>
#include <string.h>

#undef int
#include <stdio.h>

uint8_t outbuf[6];		// array to store arduino output
int cnt = 0;
int ledPin = 13;

void
setup ()
{
  beginSerial (19200);
  Serial.print ("Finished setup\n");
  Wire.begin ();		// join i2c bus with address 0x52
  nunchuck_init (); // send the initilization handshake
}

void
nunchuck_init ()
{
  Wire.beginTransmission (0x52);	// transmit to device 0x52
  Wire.send (0x40);		// sends memory address
  Wire.send (0x00);		// sends sent a zero.  
  Wire.endTransmission ();	// stop transmitting
}

void
send_zero ()
{
  Wire.beginTransmission (0x52);	// transmit to device 0x52
  Wire.send (0x00);		// sends one byte
  Wire.endTransmission ();	// stop transmitting
}

void
loop ()
{
  Wire.requestFrom (0x52, 6);	// request data from nunchuck
  while (Wire.available ())
    {
      outbuf[cnt] = nunchuk_decode_byte (Wire.receive ());	// receive byte as an integer
      digitalWrite (ledPin, HIGH);	// sets the LED on
      cnt++;
    }

  // If we recieved the 6 bytes, then go print them
  if (cnt >= 5)
    {
      print ();
    }

  cnt = 0;
  send_zero (); // send the request for next bytes
  delay (100);
}

// Print the input data we have recieved
// accel data is 10 bits long
// so we read 8 bits, then we have to add
// on the last 2 bits.  That is why I
// multiply them by 2 * 2
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] 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 ((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;
}

Update I just tried running my code under Arduino 10. I had to make a different change to twi.h. Here are the first few lines of twi.h
#define ATMEGA8

#ifndef CPU_FREQ^M
#define CPU_FREQ 16000000L
#endif

#ifndef TWI_FREQ^M
#define TWI_FREQ 100000L
#endif

 

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

 

 
Comments
Order by: 
Per page: 
 
  •  asicsning wrote 127 Days Ago (neutral) 
     
    0
    http://www.northfacesaleuk.co.uk/
     
       
     
     
    -3 points
     
  • Comment by asicsning is hidden. Show.
    -4 points
     
  •  asicsning wrote 179 Days Ago (neutral) 
     
    0
    http://www.toryburchusashoes.com/
     
       
     
     
    -4 points
     
  •  asicsning wrote 192 Days Ago (neutral) 
     
    0
    http://www.ghdstraightenersuksale.co.uk/
     
       
     
     
    -3 points
     
  •  asicsning wrote 198 Days Ago (neutral) 
     
    0
    [url=http://www.mbttrainersuksale.co.uk/]MBT[/url] [url=http://www.mbtukshoessale.co.uk/]MBT Shoes[/url] [url=http://www.oakleyuksunglassessale.co.uk/]Oakley Sunglasses[/url] [url=http://www.cheapghdstraightenerssale.co.uk/]GHD Straighteners[/url] [url=http://www.cheapuggsaleuk.co.uk/]UGG Boots[/url]
     
       
     
     
    -3 points
     
  •  ArdHack wrote 742 Days Ago (neutral) 
     
    0
    Nice! I've used my nunchucks with windows games before, but I'll have to try this.
     
       
     
     
    0 points
     
Actions
Rating
2 votes
Copyright © 2012 Arduino User Community -
Not affiliated with or endorsed by Arduino (Arduino.cc)