With a little hacking, data can be read from a wii nunchuck directly into an Arduino, using TWI (aka I2C).

Materials

Nintendo Wii Nunchuck
Wii Nunchuck Adapter

Characteristics


Because it uses standard I2C, it's easy to make the Nunchuck work with Arduino, Basic Stamp or most other microcontrollers.

The nunchuck uses a proprietary connector. Just cut the end off of the nunchuck cable. The cable has 4 wires.
  1. white - ground
  2. red - 3.3+v
  3. green - data
  4. yellow - clock


The nunchuck is only supposed to get 3.3+ volts.

Arduino code for Writing Data:
#include <Wire.h>

void setup(){
    Wire.begin();
}

byte x=0;

void loop(){
    Wire.beginTransmission(4);//transmit to device
    Wire.send("x is ");       //send five bytes
    Wire.send(x);			  //send one byte
    Wire.endTransmission();   //stop transmission
    
    x++;
    delay(500);
}


Arduino code for Reading Data:
#include <Wire.h>

void setup(){
    Wire.begin();
    Serial.begin(9600);
}



void loop(){
    Wire.requestFrom(2,6);     //request 6 bytes from slave device #2 
   
   while(Wire.available()){       //slave may send less than requested
      char c=Wire.receive();	  //receive a byte as character
      Serial.print(c);
    }
   delay(500);
}

Using the Adapter makes it cleaner. Just keep iin mind the labels on the adapter are wrng.


Sample Program

#include <Wire.h>

void setup()
{
  Serial.begin(19200);
  nunchuck_init(); // send the initilization handshake
  Serial.print ("Finished setup\n");
}

void loop()
{
  nunchuck_get_data();
  nunchuck_print_data();
  delay(100);
}


//
// Nunchuck functions
//

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
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()"
void nunchuck_send_request()
{
  Wire.beginTransmission(0x52);	// transmit to device 0x52
  Wire.send(0x00);		// sends one byte
  Wire.endTransmission();	// stop transmitting
}

// Receive data back from the nunchuck, 
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
}

// 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 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++;
}

// 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;
}

Adding a Servo


/*
 * NunchuckServo
 *
 * 2007 Tod E. Kurt, http://todbot.com/blog/
 *
 * The Wii Nunchuck reading code is taken from Windmeadow Labs
 *   http://www.windmeadow.com/node/42
 */

#include <Wire.h>

int ledPin = 13;
int servoPin = 7;      // Control pin for servo motor

int pulseWidth = 0;    // Amount to pulse the servo
int refreshTime = 20;  // the time in millisecs needed in between pulses
long lastPulse;
int minPulse = 700;   // minimum pulse width
int loop_cnt=0;

void setup()
{
  Serial.begin(19200);
  pinMode(servoPin, OUTPUT);  // Set servo pin as an output pin
  pulseWidth = minPulse;      // Set the motor position to the minimum

  nunchuck_init(); // send the initilization handshake
  Serial.print("NunchuckServo ready\n");
}

void loop()
{
  checkNunchuck();
  updateServo();   // update servo position

  if( nunchuck_zbutton() )      // light the LED if z button is pressed
    digitalWrite(ledPin, HIGH);
  else 
    digitalWrite(ledPin,LOW);

  delay(1);        // this is hear to give a known time per loop
}


void checkNunchuck()
{
  if( loop_cnt > 100 ) {  // loop()s is every 1msec, this is every 100msec
    
    nunchuck_get_data();
    nunchuck_print_data();

    float tilt = nunchuck_accelx();    // x-axis, in this case ranges from ~70 - ~185
    tilt = (tilt - 70) * 1.5;        // convert to angle in degrees, roughly  
    pulseWidth = (tilt * 9) + minPulse; // convert angle to microseconds
    
    loop_cnt = 0;  // reset for 
  }
  loop_cnt++; 
  
}

// called every loop().
// uses global variables servoPin, pulsewidth, lastPulse, & refreshTime
void updateServo()
{
  // pulse the servo again if rhe refresh time (20 ms) have passed:
  if (millis() - lastPulse >= refreshTime) {
    digitalWrite(servoPin, HIGH);   // Turn the motor on
    delayMicroseconds(pulseWidth);  // Length of the pulse sets the motor position
    digitalWrite(servoPin, LOW);    // Turn the motor off
    lastPulse = millis();           // save the time of the last pulse
  }
}


//
// Nunchuck functions
//

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
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()"
void nunchuck_send_request()
{
  Wire.beginTransmission(0x52);	// transmit to device 0x52
  Wire.send(0x00);		// sends one byte
  Wire.endTransmission();	// stop transmitting
}

// Receive data back from the nunchuck, 
// returns 1 on successful read. returns 0 on failure
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
}

// 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 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++;
}

// 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;
}

// returns zbutton state: 1=pressed, 0=notpressed
int nunchuck_zbutton()
{
   return ((nunchuck_buf[5] >> 0) & 1) ? 0 : 1;  // voodoo
}

// returns zbutton state: 1=pressed, 0=notpressed
int nunchuck_cbutton()
{
   return ((nunchuck_buf[5] >> 1) & 1) ? 0 : 1;  // voodoo
}

// returns value of x-axis joystick
int nunchuck_joyx()
{
  return nunchuck_buf[0]; 
}

// returns value of y-axis joystick
int nunchuck_joyy()
{
  return nunchuck_buf[1];
}

// returns value of x-axis accelerometer
int nunchuck_accelx()
{
  return nunchuck_buf[2];   // FIXME: this leaves out 2-bits of the data
}

// returns value of y-axis accelerometer
int nunchuck_accely()
{
  return nunchuck_buf[3];   // FIXME: this leaves out 2-bits of the data
}

// returns value of z-axis accelerometer
int nunchuck_accelz()
{
  return nunchuck_buf[4];   // FIXME: this leaves out 2-bits of the data
}
Arduino's chip 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, you need to change the default speed:
#define TWI_FREQ 400000L

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
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.

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, You can use your favorite serial terminal program. The Arduino can't keep up with reading both serial and TWI at the same time. The Arduino reads in about 50 bytes from the nunchuck then prints 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. That's because of the serial connection interfering with the TWI connection:
include <Wire.h>
#include <string.h>
#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;
}