Home » Arduino, _Favourites, _Featured

Wii NunChuck controller, Arduino and servos

9 December 2009 3 Comments

The Wii nunchuck controller contains a 3 axis accelerometer, one joystick and 2 buttons for only 20 euro and you can easly use it to manage your Arduino applications.
In this article we’ll see how to move two servo motors using this controller (providing two videos, prototype images and complete source code)

I have read a lot about Arduino and Wii Nunchuck, so I have decided to buy a wiichuck adapter from Sparkfun, a Wii controller and I was very excited to do my first tests.
I was surprised because I only spent 30 minutes to put it in place and create this demo.

REQUIRED HARDWARE:

- 1 Nintendo Wii Nunchuck Controller (20 euro and you can buy it everywhere)

- 1 WiiChuck Adapter - 3 dollars on Sparkfun.com
NOTE: you can also cut the cable and directly connect the controller wires (search on Google and you’ll find a lot of articles)

- 2 Servo motors HS-422 (or similar, about 15/20 euro each one) and a Lynx Tilt kit (about 15/20 euro) - from robot-italy.com

- 1 Arduino (i have used Duemilanove version)

- 1 BreadBoard

CONNECTIONS
The Wii Controller requires only 4 pins: ground, 5 volt and 2 Arduino analog pins.
Each servo motor require 3 connections: ground, 5V and a Arduino PWM pin.

Check following images to get inspiration. It’s very simple
wiicontrollervoodoo

wiicontrollerbreadboard

CODE (wiring/Arduino):
I have found a lot of source code samples inside books and looking around the web but this is the best one and the more accurate I have found for my purpose (check following video to understand what I mean with ‘accurate’).
I don’t remember where I got it so I’m sorry if I didn’t post the author’s website.

#include <Wire.h>
#include <string.h>
#include <stdio.h>
 
uint8_t outbuf[6];
 
int cnt = 0;
int ledPin = 13;
 
int servoPin = 9;
int servoPin2 = 10;
 
int pulseWidth = 0;
int pulseWidth2 = 0;
 
long lastPulse = 0;
long lastPulse2 = 0;
 
int z_button = 0;
int c_button = 0;
 
int refreshTime = 20;
 
int minPulse = 1000;
int minPulse2 = 500;
 
int dtime=10;
 
#define pwbuffsize 10
long pwbuff[pwbuffsize];
long pwbuffpos = 0;
long pwbuff2[pwbuffsize];
long pwbuffpos2 = 0;
 
void setup()
{
    Serial.begin (9600);
    Wire.begin ();
    nunchuck_init ();
    pinMode(servoPin, OUTPUT);
    pinMode(servoPin2, OUTPUT);
 
    pulseWidth = minPulse;
    pulseWidth2 = minPulse2;
    Serial.print ("Finished setupn");
}
 
void nunchuck_init()
{
    Wire.beginTransmission (0x52);
    Wire.send (0x40);
    Wire.send (0x00);  
    Wire.endTransmission ();
}
 
void send_zero()
{
    Wire.beginTransmission (0x52);
    Wire.send (0x00);
    Wire.endTransmission ();
}
 
int t = 0;
 
void loop()
{
    t++;
    long last = millis();
 
    if( t == 1) {
 
        t = 0;
 
        Wire.requestFrom (0x52, 6);
 
        while (Wire.available ()) {
            outbuf[cnt] = nunchuk_decode_byte (Wire.receive ());
            digitalWrite (ledPin, HIGH);
            cnt++;
        }
 
        if (cnt >= 5) {
 
            //            printNunchuckData();
 
            int z_button = 0;
            int c_button = 0;
 
            if ((outbuf[5] >> 0) & 1) 
                z_button = 1;
            if ((outbuf[5] >> 1) & 1)
                c_button = 1;
 
            switch (c_button) {
            case 1:
                switch (z_button) {
                case 0:
                    break;
                case 1:
                    muovi();
                    break;
                }
                break;
            case 0:
                switch (z_button) {
                case 0:
                    delay(10000);
                    break;
                case 1:
                    delay(3000);
                    break;
                }
                break;
            }
        }
 
        cnt = 0;
        send_zero();
 
    } // if(t==)
 
    updateServo();
 
    delay(dtime);
}
 
 
void updateServo() {
 
    if (millis() - lastPulse >= refreshTime) {
 
        digitalWrite(servoPin, HIGH);
        delayMicroseconds(pulseWidth);
        digitalWrite(servoPin, LOW);
 
        digitalWrite(servoPin2, HIGH);
        delayMicroseconds(pulseWidth2);
        digitalWrite(servoPin2, LOW);
 
        lastPulse = millis();
    }
}
 
int i=0;
void printNunchuckData()
{
    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;
 
    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 (i,DEC);
    Serial.print ("t");
 
    Serial.print ("X: ");
    Serial.print (joy_x_axis, DEC);
    Serial.print ("t");
 
    Serial.print ("Y: ");
    Serial.print (joy_y_axis, DEC);
    Serial.print ("t");
 
    Serial.print ("AccX: ");
    Serial.print (accel_x_axis, DEC);
    Serial.print ("t");
 
    Serial.print ("AccY: ");
    Serial.print (accel_y_axis, DEC);
    Serial.print ("t");
 
    Serial.print ("AccZ: ");
    Serial.print (accel_z_axis, DEC);
    Serial.print ("t");
 
    Serial.print (z_button, DEC);
    Serial.print (" ");
    Serial.print (c_button, DEC);
    Serial.print ("rn");
    i++;
}
 
char nunchuk_decode_byte (char x)
{
    x = (x ^ 0x17) + 0x17;
    return x;
}
 
void muovi (){
    float tilt = (700 - outbuf[3]*2*2);
    float tilt2 = outbuf[2]*2*2;
 
    tilt = (tilt);
    pulseWidth = (tilt * 5) + minPulse;
 
    tilt2 = (tilt2-288);
    pulseWidth2 = (tilt2 * 5) + minPulse2;
 
    pwbuff[pwbuffpos] = pulseWidth;
    pwbuff2[pwbuffpos2] = pulseWidth2;
 
    if( ++pwbuffpos == pwbuffsize ) pwbuffpos = 0;
    if( ++pwbuffpos2 == pwbuffsize ) pwbuffpos2 = 0;
 
 
    pulseWidth=0;
    pulseWidth2=0;
 
    for( int p=0; p<pwbuffsize; p++ ){
        pulseWidth += pwbuff[p];
        pulseWidth2 += pwbuff2[p];
    }
 
    pulseWidth /= pwbuffsize;
    pulseWidth2 /= pwbuffsize;
 
}

3 Comments »

  • Chris Rojas said:

    Great work, great use of the wii-chuck. Also I like the little guy strapped to the front of it.

  • Fabio Biondi (author) said:

    Thanx Chris, i only got and merged some info from more resources but I love it too… it seems work very well.
    If you are interested the puppet collection name is VOODOO dools : P

  • blake said:

    I F’ing love you!! i’ve been searching for days for this code that didn’t have errors after compiling. if you could give me some pointers though ( cause im still a noob), i’m not sure how to assign the other buttons on the nunchuck. Like two more servos for the joystick! Thanks Fabio! You made my day

Leave your response!

Add your comment below, or trackback from your own site. You can also subscribe to these comments via RSS.

Be nice. Keep it clean. Stay on topic. No spam.

You can use these tags:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="">

This is a Gravatar-enabled weblog. To get your own globally-recognized-avatar, please register at Gravatar.