WiiNunchuckReader

.:Intro:.

This version is a port from my own Arduino version, which in turn arose from trying to figure out the Wii Nunchuck I2C using the PIC Serial Analyser and writing some test scripts (which is a story in itself).

main.cpp is the demo program and is written for two nunchucks. The mbed supports two I2C ports, and as the nunchucks have the same I2C address, one goes on each port.

For my set-up I use the Solarbotics Nunchucky breakout adapters, and powered the 3.3V for the nunchucks from the 3.3V output of the mbed board. In order not to put a strain on my laptops USB (100ma limit), the mbed is powered (Vin) by a 5V PSU. I got my adapters from Active Robots in the UK (http://www.active-robots.com/products/controllr/solarbotics-microcontroller.shtml)

Now updated to use the I2C read/write error return values, so you can now leave one nunchuck unconnected without any issues.

Finally: you don't need any pull resistors, as the Wii Nunchuck has internal ones on the I2C lines.

.:How To Use:.

Connections:

These are defined in I2CConfig.h.

const PinName I2CPort_A::SDA = p9;
const PinName I2CPort_A::SCL = p10;

const PinName I2CPort_B::SDA = p28;
const PinName I2CPort_B::SCL = p27;

So for both adapters you need to route the mbed GND pin to Gnd on both adapters, and the mbed VOUT (3.3V regulated out) to 3.3V on both adapters. Finally mbed p9 to Data and p10 to Clk on adapter 1, and mbed p28 to Data, and p27 to Clk on adapter 2.

For the code to work you don't need both nunchucks connected, either one will do.

Demo:

The demo displays (on a terminal emulator such as Tera Term) the Z and C buttons, the X, Y, and Z accelerometer values, and the X and Y position values polled every second.

Usage:

The demo also illustrates how to use the library.

#include "I2CConfig.h"
#include "WiiNunchuckReader.h"

#define LOOP_DELAY    1    // seconds

// global declarations
Serial serial(USBTX, USBRX);

void ReadAndReport(WiiNunchuckReader* const nchk, const char* const portname)
{
    int bufSize = 0;
    char* bufPtr = NULL;
    bool debug = true;

    nchk->RequestRead();
    serial.printf("%s: ", portname);
        
    if (debug)
    {
        bufSize = nchk->getBufferSize();
        bufPtr = nchk->getReadBuf();
        if (bufPtr != NULL)
        {
            for (int i = 0; i < bufSize; i++)
            {
                serial.printf("%x ", bufPtr[i]);
            }
            serial.printf("\r\n");
        }
    }
        
    serial.printf("%d\t", nchk->getButtonZ());
    serial.printf("%d\t", nchk->getButtonC());
    serial.printf("%d\t", nchk->getAccelX());
    serial.printf("%d\t", nchk->getAccelY());
    serial.printf("%d\t", nchk->getAccelZ());
    serial.printf("%d\t", nchk->getJoyX());
    serial.printf("%d\r\n", nchk->getJoyY());
    serial.printf("\r\n");
}

int main() 
{
    WiiNunchuckReader nchkA(I2CPort_A::SDA, I2CPort_A::SCL, I2CPort_A::FREQ);
    WiiNunchuckReader nchkB(I2CPort_B::SDA, I2CPort_B::SCL, I2CPort_B::FREQ);
    
    while (true)
    {
        ReadAndReport(&nchkA, "PORT A");
        ReadAndReport(&nchkB, "PORT B");
                
        wait(LOOP_DELAY);
    }
    
    return EXIT_SUCCESS;
}

First step is to create one or two WiiNunchuckReader using the definitions from I2CConfig.h. This connects a nunchuck to an I2C port (A or B) with the required pin outs and clock frequency. Nunchuck values are then polled or read as required from each WiiNunchuckReader.

A read sequence is as follows:

  • call RequestRead( ). This sends an initialisation sequence to the nunchuck the first time its called. It then reads back the nunchuck values back and decodes them.
  • get the values - e.g. call getButtonZ( ), getButtonC( ), etc. All values are returned as un-normalized integers.

For debug you can read the WiiNunchuckReader internal buffer and get the raw nunchuck data (getBufferSize( ), getReadBuf( ) as in the example above).

Nunchuck I2C:

An I2C read operation consists of writing the device read address followed by requesting the data. A well behaved I2C device should be able to do this in one operation (with the two sequences seperated by an ACK). The Wii Nunchuck is unable to do this and requires a delay between writing the device 'read' address and the data read. Luckily the mbed I2C library doesn't support a single operation 'write address/read data', and this has to been done as a seperate read and write, allowing the delay to be inserted between them. I use a 10ms delay.

A good explanation of I2C can be found at http://www.robot-electronics.co.uk/htm/using_the_i2c_bus.htm. A useful table of nunchuck max/min values can be found at http://www.windmeadow.com/node/42 , which also has a sample Ardunio program.

.:Library Files:.

I2CConfig.h - defines I2C ports and pins.

WiiNunchuckDefs.h - Nunchuck related defines

WiiNunchuckReader.h - WiiNunchuckReader class declaration

WiiNunchuckReader.cpp - WiiNuchuckReader source

WiiNunchuckReader


2 comments

27 Apr 2011

Is it posible to use the values of the joystick to control a robot. Where are the values of the joystick stored ?

Could you make a program that doesn't send all the inf to the pc but just stores them so you can read them and make the controle a robot?

 

Thanks in advance.

Toon

03 Jul 2013
I think you need to add joyX = (joyX ^ 0x17) + 0x17; joyY = (joyY ^ 0x17) + 0x17; since data are coded.

You need to log in to post a comment