Checking Wii Nunchuck range

This sketch allows the checking of the range of values you get from a Wii nunchuck plugged into a MP.

It was based on various conversations and code here.

It is interesting to note the NC range I got when it was moved violently.

Enjoy
Mark

PS be kind I should have learnt C 20 years ago, rather than last month...

/* .......................................................................
 Code for reading data from a Wii Motion plus device connected to a Nunchuck
 The purpose is to detect the maximum values and send them to the display.
 Hardware Arduino with ATMega 168
 Connections SCA to AD4 (Analog4) and SCL to AD5 (Analog5)

----------------------------------------------------------------
   Code sources
   8/9/2009 - by dimkasta @ www.kastaniotis.net
   Adapted for use with the transistor-less switching code originally written by krulkip on
   http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1248889032/60
   Calibration and utility code based on the code by duckhead
   9/9/2009 - by dimkasta @ www.kastaniotis.net
   Added Accelerometer calibration
   Removed the casting to double and the multiplying with millis/sec from the cycle saving to further greately
   increase the free time to ~1/50 in comparison to the reading time.
   18/9/2009 - by Ardvark
   Slow/fast bit reading fixed: Slow degree/sec scale value appears correct.

   modified form a collection of contributions
   19 May 2010
   by Mark Beckett


  In working my way through the various pieces of the software, in order to understand (and learn C)
  It became apparent that a few conclusions were made, in regard to the MIN/MAX values of the Nunchuck
  This little hack gives the capability of capturing the values.

  It was interesting to note that if the device was moved violently, then the range was greater.
  ( I don't think its my maths doing it ...)
    
                axMIN    axMAX  |  ayMIN    ayMAX  |  azMIN    azMAX
      Gentle     294      754   |   300      746   |   304      764
      Violent    100      986   |   228     1018   |    76      796

  Anyway thanks to all the people in the forum whom contributed to the makeup of the donor sketch.
  
  Now if I could only get used the damn ; after each line
  
  Mark Beckett

*/
//=========================================================
// TODO LIST - Known issues
// ---------
// Learn C (20 years ago) so I can tidy it up.
// add something to check the Gyro MAX and MIN values.
// remove anything not needed if the above is not used.
//========================================================

#include <Wire.h>

boolean DataChanged = false;

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

//wiibrew info seems to be incorrect with regards to scaling, see instead Xevel's comments: http://www.assembla.com/wiki/show/alicewiimotionplus/slow_and_fast_modes
static const int wmpSlowToDegreePerSec = 16; //when gyro speed 1, 16 units = 1°/s
static const int wmpFastToDegreePerSec = 4; //when gyro speed 0, 4 units = 0,25°/s

// Hardware identifiers. Polling data[5]&0x03 for present device
static const int NC = 0x00;
static const int MP = 0x02;
int currentDevice;

// WM+ state variables - if true, then in slow (high res) mode
boolean slowYaw = 0;
boolean slowPitch = 0;
boolean slowRoll = 0;

int rollScale;
int pitchScale;
int yawScale;

// Initial gyro values (- yaw0 etc)
int yaw = 0;
int pitch = 0;
int roll = 0;

// accelerometer values
int ax_m = 0;
int ay_m = 0;
int az_m = 0;

int axMIN = 500;
int axMAX = 0;
int ayMIN = 500;
int ayMAX = 0;
int azMIN = 500;
int azMAX = 0;

double x;
double y;
double z;


void setup ()
{
  Serial.begin (115200);
  
  Wire.begin(); // initialize i2c
  // we need to switch the TWI speed, because the nunchuck uses Fast-TWI
  // Not sure I could actually detect any difference.
  
    TWBR = ((16000000 / 400000L) - 16) / 2;

  initializeSensors();
}

void send_zero ()
{
    delay(5); //5 mS delay between reads see (http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1259091426/109#109)
    Wire.beginTransmission(0x52);
    Wire.send(0x00);
    Wire.endTransmission();
    delayMicroseconds(200); //200 microseconds delay between send zero and read see (http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1259091426/109#109)
} //stitch

2nd half of the code

Mark

//stitch

void loop ()
{ 
    send_zero (); // send the request for next bytes
    
    // now follows conversion command instructing extension controller to get
    // all sensor data and put them into 6 byte register within the extension controller
    Wire.requestFrom (0x52,6);
   
    data[0] = Wire.receive();
    data[1] = Wire.receive();
    data[2] = Wire.receive();
    data[3] = Wire.receive();
    data[4] = Wire.receive();
    data[5] = Wire.receive();
 
  currentDevice = data[5]&0x03;
  DataChanged =false;          //reset this so that it doesn't update the dispaly unless it needs to
    if (currentDevice == NC)
    {

  // Dimitris version of accl readings
      x = (data[2] << 2) + ((data[5] >> 3) & 2) ;
      y = (data[3] << 2) + ((data[5] >> 4) & 2);
      z = (data[4] << 2) + ((data[5] >> 5) & 6) ;
    
    
  // There has to be a better method ....oh well here goes
     if (x > axMAX){
      axMAX = x;
      DataChanged =true;
     }
     if (x < axMIN){
      axMIN = x;
      DataChanged =true;
     }
     if (y > ayMAX){
      ayMAX = y;
      DataChanged =true;
     }
     if (y < ayMIN){
      ayMIN = y;
      DataChanged =true;
     }
     if (z > azMAX){
      azMAX = z;
      DataChanged =true;
     }
     if (z < azMIN){
      azMIN = z;
      DataChanged =true;
     }
     
    }
 
  else
  if  (currentDevice == MP)
  {
  // Gyroscopes: dual-axis IDG-600, see http://www.invensense.com/products/idg_600.html and EPSON TOYOCOM labelled X3500W (yaw)
    pitch = (((data[3]&0xFC)<<6) + data[2]);
    roll = (((data[4]&0xFC)<<6) + data[1]);
    yaw = (((data[5]&0xFC)<<6) + data[0]);
    
      slowPitch = (data[3]&0x01)>>0;      
      slowRoll = (data[4]&0x02)>>0;
      slowYaw = (data[3]&0x02)>>0;
      
      
      rollScale  = slowRoll  ? wmpSlowToDegreePerSec : wmpFastToDegreePerSec; // if speed == 1, then wmpSlowToDegreePerSec, else wmpFastToDegreePerSec
      pitchScale = slowPitch ? wmpSlowToDegreePerSec : wmpFastToDegreePerSec;
      yawScale   = slowYaw   ? wmpSlowToDegreePerSec : wmpFastToDegreePerSec;
      
 
      roll = roll/rollScale;    // deg/s = mV/(mV/deg/s)
      pitch = pitch/pitchScale;
      yaw = yaw/yawScale;

    }

  if (DataChanged)
  { 
    exportdata();
  }
}

void initializeSensors()
{
  
  digitalWrite(13,HIGH);  // first flash the LED to show activity
  Serial.println ("Now detecting WM+");

  // now make Wii Motion plus the active extension
  // nunchuk mode = 05, wm+ only = 04, classic controller = 07
  Serial.println ("Activating WM+ in NC mode (5)...");
   Wire.beginTransmission(0x53);
   Wire.send(0xFE);
       delayMicroseconds(100);
   Wire.send(0x05);// nunchuk
   Wire.endTransmission();
  Serial.println (" OK done");
  
   delay (100);
   
  // now innitiate Wii Motion plus
   Serial.println ("Innitialising Wii Motion plus ........");
    Wire.beginTransmission(0x53);
    Wire.send(0xF0);
      delayMicroseconds(100);
    Wire.send(0x55);
    Wire.endTransmission();
  Serial.println(" OK done");
    delay (30);
  Serial.println ("Reading address at 0xFA .......");
    Wire.beginTransmission(0x52);
    Wire.send(0xFA);
    Wire.endTransmission();
  Serial.println(" OK done");
  
   delayMicroseconds(100);
   Wire.requestFrom (0x52,6);
   data[0] = Wire.receive();
   data[1] = Wire.receive();
   data[2] = Wire.receive();
   data[3] = Wire.receive();
   data[4] = Wire.receive();
   data[5] = Wire.receive();
  
   xID= data[0] + data[1] + data[2] + data[3] + data[4] + data[5];
  Serial.println("Extension controller xID = 0x");
   Serial.print(xID,HEX);
   if (xID == 0xCB) { Serial.println ("MP+ on but not active"); }
   if (xID == 0xCE) { Serial.println ("MP+ on and active"); }
   if (xID == 0x00) { Serial.println ("MP+ not on"); }
   
   
   delay (100);
   // Now we want to point the read adress to 0xa40008 where the 6 byte data is stored
  Serial.println ("Reading address at 0x08 .........");
    Wire.beginTransmission(0x52);
    Wire.send(0x08);
    Wire.endTransmission();
  delay(5);
  Serial.println(" OK done");
  Serial.println ("Finished setup");
  digitalWrite(13,LOW); // Led off
   delay(1000);
}

void exportdata()
{
    Serial.print ("  axMIN :");
    Serial.print (axMIN);
    
    Serial.print ("  axMAX :");
    Serial.print (axMAX);
  
    Serial.print ("  ayMIN :");
    Serial.print (ayMIN);
    Serial.print ("  ayMAX :");
    Serial.print (ayMAX);
    
    Serial.print ("  azMIN :");
    Serial.print (azMIN);
    Serial.print ("  azMAX :");
    Serial.print (azMAX);    
    Serial.println();
//  
     //Serial.print (" ");
     //Serial.print ("roll= ");
     //Serial.print (roll);
//  
     //Serial.print (" ");
     //Serial.print ("pitch= ");
     //Serial.print (pitch);
//  
     //Serial.print (" ");
     //Serial.print ("yaw= ");
     //Serial.println (yaw);
//    
//     Serial.print (" ");
//     Serial.print(slowPitch);
//     Serial.print (" ");
//     Serial.println(slowYaw);
//     Serial.print (" ");

// During the testing with the other sketch, I found that occassionally the display would not be right, hence this delay
  delay(100);
}