Wii nunchuck data logger
I wanted to use the wii nunchuck accelerometer for some measurements. I didn't really want to drag my computer around, so I built a little data logger. The nunchuck accelerometer data gets written to an eeprom. Then later I can download the data to my PC.

I used a Microchip 25AA512 eeprom. It holds 64000 bytes. Normally the accelerometer data for each axis is in a range of about 1 to 1000. I scaled that down to 1 to 255, so that I could fit one accelerometer reading to a byte. By doing that, the eeprom can hold over 21,000 nunchuck readings. Then I connected the eeprom and nunchuck to an arduino board.
Pressing the Z button starts writing accelerometer data out to the eeprom. The C button stops the data recording and will also write the data out over the USB/Serial connection. You can view the data in any serial terminal program like hyperterminal or minicom.
I used version .10 of the Arduino software. See my earlier entry on setting up an Arduino to read the nunchuck.
The schematics for the data logger are as follows:

Here are a few readings I got from swinging on a swingset:

The X (red) axis measures the left to right G force. That line stays pretty stable. Just a little bit of movement. The Y (purple) axis measures front/back G force. You can see it move up down with the swing moving back and forth. I didn't keep the nunchuck level with the ground. So as the swing tilted up, the nunchuck would tilt up. That kind of mutes the G force on the Y axis. The Z (grey) axis shows the greatest range. When still, that the Z axis is at about 177 or 1 G. As the swing moves up and down, you can see quite a bit of range in the Z axis. I let the swing slowly come to a stop. By looking at the Z axis you can easily see when the swing started to slow down and came to a stop.
Code:
// eeprom program code by Heather Dewey-Hagborg, http://www.arduino.cc/en/Tutorial/SPIEEPROM // Wii nunchuck code and all other code by Chad Phillips #include#include #include int DEBUG = 1; uint8_t outbuf[6]; // array to store arduino output int ledPin = 8; int startRecording = 1; #define DATAOUT 11 //MOSI #define DATAIN 12 //MISO #define SPICLOCK 13 //sck #define SLAVESELECT 10 //ss //opcodes #define WREN 6 #define WRDI 4 #define RDSR 5 #define WRSR 1 #define READ 3 #define WRITE 2 /* Min, Max, Middle, range X: 74, 177, 125.5, 103 Y: 72, 175, 123.5, 103 Z: 79, 187, 133 , 108 */ byte clr; int gCnt = 0; char spi_transfer (volatile char data) { SPDR = data; // Start the transmission while (!(SPSR & (1 << SPIF))) // Wait the end of the transmission { }; return SPDR; // return the received byte } void setup () { Serial.begin (19200); if (DEBUG) { Serial.println ("Setup start"); } pinMode (DATAOUT, OUTPUT); pinMode (DATAIN, INPUT); pinMode (SPICLOCK, OUTPUT); pinMode (SLAVESELECT, OUTPUT); digitalWrite (SLAVESELECT, HIGH); //disable device // SPCR = 01010000 //interrupt disabled,spi enabled,msb 1st,master,clk low when idle, //sample on leading edge of clk,system clock/4 rate (fastest) SPCR = (1 << SPE) | (1 << MSTR); clr = SPSR; clr = SPDR; Wire.begin (); // join i2c bus with address 0x52 nunchuck_init (); // send the initilization handshake if (DEBUG) { Serial.println ("Setup End"); } } void start_eeprom_transfer (char xData, char yData, char zData, int gCnt) { // Write to first two bytes of eeprom // what the count of acceleration readings is write_byte ((char) (gCnt >> 8), 0); write_byte (gCnt, 1); // Write acceleration data to eeprom write_byte (xData, gCnt * 3 + 2); write_byte (yData, gCnt * 3 + 3); write_byte (zData, gCnt * 3 + 4); } void write_byte (char data, int address) { digitalWrite (SLAVESELECT, LOW); spi_transfer (WREN); //write enable digitalWrite (SLAVESELECT, HIGH); delay (10); digitalWrite (SLAVESELECT, LOW); spi_transfer (WRITE); //write instruction spi_transfer ((char) (address >> 8)); //send MSByte address first spi_transfer ((char) (address)); //send LSByte address // start spi transfer spi_transfer (data); //write data byte digitalWrite (SLAVESELECT, HIGH); //release chip delay (20); } byte read_eeprom (int EEPROM_address) { //READ EEPROM int data; digitalWrite (SLAVESELECT, LOW); spi_transfer (READ); //transmit read opcode spi_transfer ((char) (EEPROM_address >> 8)); //send MSByte address first spi_transfer ((char) (EEPROM_address)); //send LSByte address data = spi_transfer (0xFF); //get data byte digitalWrite (SLAVESELECT, HIGH); //release chip, signal end transfer return data; } void loop () { int cnt = 0; Wire.requestFrom (0x52, 6); // request data from nunchuck while (Wire.available ()) { outbuf[cnt] = nunchuk_decode_byte (Wire.receive ()); // receive byte as an integer cnt++; } // If we recieved the 6 bytes, then go print them if (cnt >= 5) { process_nunchuck_data (); } cnt = 0; send_zero (); // send the request for next bytes delay (10); } void unload_data () { if (DEBUG) { Serial.println ("=====Data dump start======"); } int address = 0; byte eeprom_output_data; int aCnt = read_eeprom (address); address++; int bCnt = read_eeprom (address); address++; unsigned int cCnt = aCnt * 256 + bCnt; if (DEBUG) { Serial.print ("Count"); Serial.println (gCnt, DEC); Serial.print ("Top bits: "); Serial.print (aCnt, DEC); Serial.print (" bottom bits: "); Serial.println (bCnt, DEC); Serial.print (" computed bits: "); Serial.println (cCnt, DEC); delay (3000); } while (address < (cCnt * 3 + 2)) { int xData = read_eeprom (address); address++; int yData = read_eeprom (address); address++; int zData = read_eeprom (address); address++; Serial.print (xData, DEC); Serial.print (","); Serial.print (yData, DEC); Serial.print (","); Serial.print (zData, DEC); Serial.println (); delay (20); } if (DEBUG) { Serial.println ("=====Data dump end======"); } delay (3000); } void nunchuck_init () { if (DEBUG) { Serial.println ("Nunchuck init start."); } Wire.beginTransmission (0x52); // transmit to device 0x52 Wire.send (0x40); // sends memory address Wire.send (0x00); // sends sent a zero. Wire.endTransmission (); // stop transmitting if (DEBUG) { Serial.println ("Nunchuck init end."); } } void send_zero () { Wire.beginTransmission (0x52); // transmit to device 0x52 Wire.send (0x00); // sends one byte Wire.endTransmission (); // stop transmitting } // 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 process_nunchuck_data () { // 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] int joy_x_axis = outbuf[0]; int joy_y_axis = outbuf[1]; int accel_x_axis = (outbuf[2] << 2) + ((outbuf[5] >> 2) & 0x03); int accel_y_axis = (outbuf[3] << 2) + ((outbuf[5] >> 4) & 0x03); int accel_z_axis = (outbuf[4] << 2) + ((outbuf[5] >> 6) & 0x03); int z_button = outbuf[5] & 1; int c_button = outbuf[5] & 2; if (startRecording < 1) { digitalWrite (ledPin, HIGH); // sets the LED on start_eeprom_transfer (accel_x_axis / 4, accel_y_axis / 4, accel_z_axis / 4, gCnt); gCnt++; } else { digitalWrite (ledPin, LOW); // sets the LED off } if (c_button < 1) { digitalWrite (ledPin, LOW); // sets the LED off unload_data (); gCnt = 0; startRecording = 1; } if (z_button < 1) { startRecording = 0; gCnt = 0; digitalWrite (ledPin, HIGH); // sets the LED on } else { digitalWrite (ledPin, LOW); // sets the LED off } if (DEBUG) { Serial.print (joy_x_axis / 4, DEC); Serial.print ("\t"); Serial.print (joy_y_axis / 4, DEC); Serial.print ("\t"); Serial.print (accel_x_axis / 4, DEC); Serial.print ("\t"); Serial.print (accel_y_axis / 4, DEC); Serial.print ("\t"); Serial.print (accel_z_axis / 4, 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; }

Awesome Job
You did a fantastic job on this! However, if you made a pcb for this project, you could get an smd atmega168, smd ftdi chip, the eeprom, and all the components on one small pcb. Then, you could cut the nunchuck's cord and place a female usb connector (or maybe a mini usb connector?) so you can download the data without everything else taking up space.
Post new comment