domenica 1 maggio 2011

[DRAFT] Nintendo Wii Controller Nunchuck as simple Mouse

3D and high definition are the masters at gaming market. The gameplay, thanks to these factors, has become a critical yardstick for players, that require more interactivity. Nintendo Wii firstly made a large piece of ​​history in the seventh generation console with an innovative interface system: I'm talking about Nintendo Wii Remote (nicknamed Wiimote), a free hand controller; the interest of Nintendo was, and it is, to be attractive to a wide public. The real strength of Wii Remote is the low cost, high versatility and availability: a lot of curious people have made crazy applications and strange use (see on youtube).
Wii Remote has to expand, using a proprietary port, with an accessory: the most famous and used is Controller Nunchuck. It's an another free hand controller that allows to have a directional analogic joystick controller plus two buttons (Z and C) and an accelerometer. Ours goal is to use Nunchuck as PC device, so get state information on Nunchuck Controller, i.e.:

  • If Z or C button is pressed
  • The position of analogic in therm of carthesian coordinates
  • The values of accelerometer
Now let's focus on the most interesting thing, that's accelerometer. In the Nunchuck we have a LIS3L02AL, a three-axis linear accelerometer; this device is physically rated to measure accelerations over a range of at least +/- 2g. Here you can find the complete datasheet of LIS3L02AL. With an accelerometer it's possible to take information about direction, sense and magnitude of accelerations in X,Y, Z carthesian coordinates system.






In particular we can get the sigle component on each axis.
Unexpectedly the cost of nunchuck is lower than of the only accelerometer. If you already have a Wii can use the Nunchuck you have; otherwise you can buy it at very cheap price. In fact if you want learn to use a acceleretion sensor you can start with that.
Please note: the LIS3L02AL is a MEMS accelerometer; in this type of accelerometer is possible to approximate the movement made ​​with the acceleration measured.
So before continue be sure to have:
  • Arduino 2009 or Uno board
  • Some wires (minimum 4)
  • Isolator adhesive tape (or common liquid glue)
  • The Nintendo Nunchuck
Also be sure a serial client and a version of Matlab installed on your PC. Matlab can help you to comprehend the best way to acquire and elaborate the value of accelerometer with Plot function.
First we have to create a connector to reach the contact of Nunchuck connector. Take a strip of ordinary paper and fold it to obtain a thicker strip. In this way we can position some wires on the strip as true connector.

The homemade connectors: so you cannot cut the port of Nunchuck to reach wires directly
Put 2 wires upon with 4~4,5 mm between and others 2 in back in same way. We need only 4 wires because 2 of 6 connectors of Nunchuck port are connected:
The standard of communication used by periferical device of Wii Remote is TWI bus, that is the same of I²C, and we are very happy! In fact this standard is supported by a lot of software libraries. On our Arduino Board we can use the library Wire.h, programmated to work on Analog 5 and 6 pins to communicate with a TWI bus device.
So if you want to get more information see the link above. You just know that Vdd of TWI devices is 3,3V or 5V (in our case Nunchuck required 3,3V) and each device has a ID to be addressable. Thus as you can see in pictures SCL (Serial Clock Line) and SDA (Serial DAta) must to be connected respectively with A5 and A4 pins of Arduino Board and are the only two wire (except for the power supply) required from standard (In fact, the acronym is Two Wire Interface).
We have to connect (finally!) Nunchuck to Arduino using the connector you have made.
Please note: in the pictures that you're seeing I'm using a breadboard; it's not required, but I doing only for a comfort.
Nunchuck connected properly to Arduino Uno
Second let's to use Wire.h! Before to proceed define this costant necessary for the communication:


#define KEY 0x17
#define DEVICE 0x52
#define INIT 0x40
#define ACK_PACKET 0

The first value, named Key, is necessary to uncrypt the bits that we received from Nunchuck; I honestly tell you that there is a way to receive unencrypted data directly, but my implementation doesn't use this new way. You can try implement by yourself.
The second is the ID of Nunchuck device on TWI bus; the third rappresent the value of communication startup and last the acknowledgment packet that we have to send to Nunchuck after reading of bytes stream.
Now we have to define some functions that we'll using in our code:

startup(){
  Wire.begin();                     
  Wire.beginTransmission(DEVICE);
  Wire.send(INIT);
  Wire.send(ACK_PACKET);
  Wire.endTransmission();
}

sendAcknoledge(){
  Wire.beginTransmission(DEVICE);     // send a zero to device 0x52
  Wire.send(ACK_PACKET);
  Wire.endTransmission();
}

decode(uint8_t x){
  return (x^KEY)+KEY;
}

On read line of TWI interface we have to read 6 byte once a time; to comprehend the motivation we can discover what's the data structure:

byte[] reading <-- read();
reading[0] contains analog X value
reading[1] contains analog Y value
reading[2] contains the first 8 bits of accelerometer X axis value
reading[3] contains the first 8 bits of accelerometer Y axis value
reading[4] contains the first 8 bits of accelerometer Z axis value
reading[5] contains 5 fields: the bit in first position indicates if the Z button is pressed; the bit in second position indicates if the C button is pressed; third and fourth contains the LSBs of accelerometer X axis value; fiveth and sixth contains the LSBs of accelerometer Y axis value; seventh and eighth contains the LSBs of accelerometer Z axis value;
So we are ready to write a properly function to decode the byte stream:

read(){
  uint8_t buf[6];
  int i=0;
  Wire.requestFrom(DEVICE, 6);        
  while(Wire.available()){
    buf[i++] = decode(Wire.receive());
  }
  if(i>=6){ //check if the whole record is been received
      decode_packet(buf);
 sendAcknoledge(); 
  }
}

decode_packet(uint8_t* packet){
    analog_x = (int)packet[0];//-123;
    analog_y = (int)packet[1];//-123;  
    axis_x = (int)(packet[2]<<2)+((packet[5]>>2)&1);  //Axis X from accelerometer
    axis_y = (int)(packet[3]<<2)+((packet[5]>>4)&2);  //Axis Y from accelerometer
    axis_z = (int)(packet[4]<<2)+((packet[5]>>6)&3);  //Axis Z from accelerometer
    button_z = !(packet[5]&1);
    button_c = !(packet[5]&2);               
}

Now all we need is done and can start with acquisition on ours PC. In my opinion the best and simplest way to excange data between Arduino and PC is the sync communication; in this way you can request data when you want and software application are less critical on acquisition.
If we now try to use this raw data we realize that all is wrong! But don't be afraid: we just need to convert the values. Freely you can choose if do this on Arduino or on Software; I like the second choise. So we can see that the analogical joiystick value are rappresented by 8 bit, 0 to 255; when the joystick is on center the value of X and Y are 125 (in my case; maybe is different to you): if we subtract always this offset obtain correct signal! Similarly we can apply this concept to X, Y, Z axis of accelerometer; in fact this 3 values are rappresented by 10 bit for each, o to 1023: in this case we have to subtract 512.
Please note: the position of accelerometer in Nunchuck permit to read, when you hold the Nunchuck in a hand, the -Z moving it up and down, the Y when you move it farward and back, the X when you move it left or right. When you read Z remember that on this axis there is -g when the board inner Nunchuck is perpendicular respect gravity
Also if you want obtain a range of value [-2g, 2g] is sufficient divide normalized X, Y and Z with 256.

Plot of 1000 X, Y, Z axis values catched from Serial COM transmission; all the axis are plotted normalized to [-2g, 2g]
To comprehend how the accelerometer is positioned you can test with these graphs all movements.