クラシックコントローラーのコードはこちら。
http://www.arduino.cc/playground/Main/WiiClassicController
2箇所の変更が必要。
ヘッダーに
#include "Arduino.h"
を追加。
Wire.send()→Wire.write() Wire.receive()→Wire.read()
に変更する。
http://forum.pololu.com/viewtopic.php?f=14&t=4728
配線は以下。電源は5Vを使った。
赤:電源→5V、茶:GND→GND
黄色:Clock→A5、緑:Data→A4
WiiClassic.h
/* * Wii Classic -- Use a Wii Classic Controller * by Tim Hirzel http://www.growdown.com * * * This code owes thanks to the code by these authors: * Tod E. Kurt, http://todbot.com/blog/ * * The Wii Nunchuck reading code is taken from Windmeadow Labs * http://www.windmeadow.com/node/42 * * and the reference document on the wii linux site: * http://www.wiili.org/index.php/Wiimote/Extension_Controllers/Classic_Controller */ #include <Wire.h> #include "Arduino.h" #ifndef WiiClassic_h #define WiiClassic_h class WiiClassic { private: byte cnt; uint8_t status[4]; // array to store wiichuck output byte averageCounter; //int accelArray[3][AVERAGE_N]; // X,Y,Z uint8_t buttons[2]; uint8_t lastButtons[2]; public: void begin() { Wire.begin(); cnt = 0; averageCounter = 0; Wire.beginTransmission (0x52); // transmit to device 0x52 Wire.write (0x40); // sends memory address Wire.write (0x00); // sends memory address Wire.endTransmission (); // stop transmitting lastButtons[0] = 0xff; lastButtons[1] = 0xff; buttons[0] = 0xff; buttons[1] = 0xff; update(); } void update() { Wire.requestFrom (0x52, 6); // request data from nunchuck while (Wire.available ()) { // receive byte as an integer if (cnt < 4) { status[cnt] = _nunchuk_decode_byte (Wire.read()); //_nunchuk_decode_byte () } else { lastButtons[cnt-4] = buttons[cnt-4]; buttons[cnt-4] =_nunchuk_decode_byte (Wire.read()); } cnt++; } if (cnt > 5) { _send_zero(); // send the request for next bytes cnt = 0; } } byte * getRawStatus() { return status; } byte * getRawButtons() { return buttons; } boolean leftShoulderPressed() { return _PressedRowBit(0,5); } boolean rightShoulderPressed() { return _PressedRowBit(0,1); } boolean lzPressed() { return _PressedRowBit(1,7); } boolean rzPressed() { return _PressedRowBit(1,2); } boolean leftDPressed() { return _PressedRowBit(1,1); } boolean rightDPressed() { return _PressedRowBit(0,7); } boolean upDPressed() { return _PressedRowBit(1,0); } boolean downDPressed() { return _PressedRowBit(0,6); } boolean selectPressed() { return _PressedRowBit(0,4); } boolean homePressed() { return _PressedRowBit(0,3); } boolean startPressed() { return _PressedRowBit(0,2); } boolean xPressed() { return _PressedRowBit(1,3); } boolean yPressed() { return _PressedRowBit(1,5); } boolean aPressed() { return _PressedRowBit(1,4); } boolean bPressed() { return _PressedRowBit(1,6); } int rightShouldPressure() { return status[3] & 0x1f; //rightmost 5 bits } int leftShouldPressure() { return ((status[2] & 0x60) >> 2) + ((status[3] & 0xe0) >> 5); //rightmost 5 bits } int leftStickX() { return ( (status[0] & 0x3f) ); } int leftStickY() { return ((status[1] & 0x3f)); } int rightStickX() { return ((status[0] & 0xc0) >> 3) + ((status[1] & 0xc0) >> 5) + ((status[2] & 0x80) >> 7); } int rightStickY() { return status[2] & 0x1f; } private: boolean _PressedRowBit(byte row, byte bit) { byte mask = (1 << bit); return (!(buttons[row] & mask )) && (lastButtons[row] & mask); } byte _nunchuk_decode_byte (byte x) { x = (x ^ 0x17) + 0x17; return x; } void _send_zero() { Wire.beginTransmission (0x52); // transmit to device 0x52 Wire.write (0x00); // sends one byte Wire.endTransmission (); // stop transmitting } }; #endif
WiiClassic_test.ino
/* WiiClassic Test Code This code prints the current controller status to the serial port. Button pressed calls poll whether the button was pressed since the last update call. as a result, it will just briefly print the last button pressed once. Tim Hirzel May 2008 */ #include "Wire.h" #include "WiiClassic.h" WiiClassic wiiClassy = WiiClassic(); void setup() { Wire.begin(); Serial.begin(9600); wiiClassy.begin(); wiiClassy.update(); } void loop() { delay(100); // 1ms is enough to not overload the wii Classic, 100ms seems to ease the serial terminal a little wiiClassy.update(); // /* // PRINT RAW BYTES FOR DEBUG // STATUS IS FIRST FOUR BYTES for (int i = 0; i < 4; i ++) { for (int j = 7; j >= 0; j--) { if ((wiiClassy.getRawStatus()[i] & (1 << j)) == 0) { Serial.print("0"); } else{ Serial.print("1"); } } Serial.println(); } // BUTTONS IS NEXT TWO BYTES for (int i = 0; i < 2; i ++) { for (int j = 7; j >= 0; j--) { if ((wiiClassy.getRawButtons()[i] & (1 << j)) == 0) { Serial.print("0"); } else{ Serial.print("1"); } } Serial.println(); } Serial.println("---"); */ Serial.print("Buttons:"); if (wiiClassy.leftShoulderPressed()) { Serial.print("LS."); } if (wiiClassy.rightShoulderPressed()) { Serial.print("RS."); } if (wiiClassy.lzPressed()) { Serial.print("lz."); } if (wiiClassy.rzPressed()) { Serial.print("rz."); } if (wiiClassy.leftDPressed()) { Serial.print("LD."); } if (wiiClassy.rightDPressed()) { Serial.print("RD."); } if (wiiClassy.upDPressed()) { Serial.print("UD."); } if (wiiClassy.downDPressed()) { Serial.print("DD."); } if (wiiClassy.selectPressed()) { Serial.print("select."); } if (wiiClassy.homePressed()) { Serial.print("home."); } if (wiiClassy.startPressed()) { Serial.print("start."); } if (wiiClassy.xPressed()) { Serial.print("x."); } if (wiiClassy.yPressed()) { Serial.print("y."); } if (wiiClassy.aPressed()) { Serial.print("a."); } if (wiiClassy.bPressed()) { Serial.print("b."); } Serial.println(); Serial.print("right shoulder: "); Serial.println(wiiClassy.rightShouldPressure()); Serial.print(" left shoulder: "); Serial.println(wiiClassy.leftShouldPressure()); Serial.print(" left stick x: "); Serial.println(wiiClassy.leftStickX()); Serial.print(" left stick y: "); Serial.println(wiiClassy.leftStickY()); Serial.print(" right stick x: "); Serial.println(wiiClassy.rightStickX()); Serial.print(" right stick y: "); Serial.println(wiiClassy.rightStickY()); Serial.println("---"); //pulse = (int)500+8*wiiClassy.leftStickX(); //updateServo(); }
WiiChuck.h
/* * Nunchuck -- Use a Wii Nunchuck * Tim Hirzel http://www.growdown.com * notes on Wii Nunchuck Behavior. This library provides an improved derivation of rotation angles from the nunchuck accelerometer data. The biggest different over existing libraries (that I know of ) is the full 360 degrees of Roll data from teh combination of the x and z axis accelerometer data using the math library atan2. It is accurate with 360 degrees of roll (rotation around axis coming out of the c button, the front of the wii), and about 180 degrees of pitch (rotation about the axis coming out of the side of the wii). (read more below) In terms of mapping the wii position to angles, its important to note that while the Nunchuck sense Pitch, and Roll, it does not sense Yaw, or the compass direction. This creates an important disparity where the nunchuck only works within one hemisphere. At a result, when the pitch values are less than about 10, and greater than about 170, the Roll data gets very unstable. essentially, the roll data flips over 180 degrees very quickly. To understand this property better, rotate the wii around the axis of the joystick. You see the sensor data stays constant (with noise). Because of this, it cant know the difference between arriving upside via 180 degree Roll, or 180 degree pitch. It just assumes its always 180 roll. * * This file is an adaptation of the code by these authors: * Tod E. Kurt, http://todbot.com/blog/ * * The Wii Nunchuck reading code is taken from Windmeadow Labs * http://www.windmeadow.com/node/42 * * Conversion to Arduino 1.0 by Danjovic * http://hotbit.blogspot.com * */ #ifndef WiiChuck_h #define WiiChuck_h #include "Arduino.h" #include <Wire.h> #include <math.h> // these may need to be adjusted for each nunchuck for calibration #define ZEROX 510 #define ZEROY 490 #define ZEROZ 460 #define RADIUS 210 // probably pretty universal #define DEFAULT_ZERO_JOY_X 124 #define DEFAULT_ZERO_JOY_Y 132 class WiiChuck { private: uint8_t cnt; uint8_t status[6]; // array to store wiichuck output uint8_t averageCounter; //int accelArray[3][AVERAGE_N]; // X,Y,Z int i; int total; uint8_t zeroJoyX; // these are about where mine are uint8_t zeroJoyY; // use calibrateJoy when the stick is at zero to correct int lastJoyX; int lastJoyY; int angles[3]; bool lastZ, lastC; public: uint8_t joyX; uint8_t joyY; bool buttonZ; bool buttonC; void begin() { Wire.begin(); cnt = 0; averageCounter = 0; // instead of the common 0x40 -> 0x00 initialization, we // use 0xF0 -> 0x55 followed by 0xFB -> 0x00. // this lets us use 3rd party nunchucks (like cheap $4 ebay ones) // while still letting us use official oness. // only side effect is that we no longer need to decode bytes in _nunchuk_decode_byte // see http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1264805255 // Wire.beginTransmission(0x52); // device address Wire.write(0xF0); Wire.write(0x55); Wire.endTransmission(); delay(1); Wire.beginTransmission(0x52); Wire.write(0xFB); Wire.write((uint8_t)0x00); Wire.endTransmission(); update(); for (i = 0; i<3;i++) { angles[i] = 0; } zeroJoyX = DEFAULT_ZERO_JOY_X; zeroJoyY = DEFAULT_ZERO_JOY_Y; } void calibrateJoy() { zeroJoyX = joyX; zeroJoyY = joyY; } void update() { Wire.requestFrom (0x52, 6); // request data from nunchuck while (Wire.available ()) { // receive byte as an integer status[cnt] = _nunchuk_decode_byte (Wire.read()); // cnt++; } if (cnt > 5) { lastZ = buttonZ; lastC = buttonC; lastJoyX = readJoyX(); lastJoyY = readJoyY(); //averageCounter ++; //if (averageCounter >= AVERAGE_N) // averageCounter = 0; cnt = 0; joyX = (status[0]); joyY = (status[1]); for (i = 0; i < 3; i++) //accelArray[i][averageCounter] = ((int)status[i+2] << 2) + ((status[5] & (B00000011 << ((i+1)*2) ) >> ((i+1)*2))); angles[i] = (status[i+2] << 2) + ((status[5] & (B00000011 << ((i+1)*2) ) >> ((i+1)*2))); //accelYArray[averageCounter] = ((int)status[3] << 2) + ((status[5] & B00110000) >> 4); //accelZArray[averageCounter] = ((int)status[4] << 2) + ((status[5] & B11000000) >> 6); buttonZ = !( status[5] & B00000001); buttonC = !((status[5] & B00000010) >> 1); _send_zero(); // send the request for next bytes } } // UNCOMMENT FOR DEBUGGING //byte * getStatus() { // return status; //} float readAccelX() { // total = 0; // accelArray[xyz][averageCounter] * FAST_WEIGHT; return (float)angles[0] - ZEROX; } float readAccelY() { // total = 0; // accelArray[xyz][averageCounter] * FAST_WEIGHT; return (float)angles[1] - ZEROY; } float readAccelZ() { // total = 0; // accelArray[xyz][averageCounter] * FAST_WEIGHT; return (float)angles[2] - ZEROZ; } bool zPressed() { return (buttonZ && ! lastZ); } bool cPressed() { return (buttonC && ! lastC); } // for using the joystick like a directional button bool rightJoy(int thresh=60) { return (readJoyX() > thresh and lastJoyX <= thresh); } // for using the joystick like a directional button bool leftJoy(int thresh=60) { return (readJoyX() < -thresh and lastJoyX >= -thresh); } int readJoyX() { return (int) joyX - zeroJoyX; } int readJoyY() { return (int)joyY - zeroJoyY; } // R, the radius, generally hovers around 210 (at least it does with mine) // int R() { // return sqrt(readAccelX() * readAccelX() +readAccelY() * readAccelY() + readAccelZ() * readAccelZ()); // } // returns roll degrees int readRoll() { return (int)(atan2(readAccelX(),readAccelZ())/ M_PI * 180.0); } // returns pitch in degrees int readPitch() { return (int) (acos(readAccelY()/RADIUS)/ M_PI * 180.0); // optionally swap 'RADIUS' for 'R()' } private: uint8_t _nunchuk_decode_byte (uint8_t x) { //decode is only necessary with certain initializations //x = (x ^ 0x17) + 0x17; return x; } void _send_zero() { Wire.beginTransmission (0x52); // transmit to device 0x52 Wire.write ((uint8_t)0x00); // sends one byte Wire.endTransmission (); // stop transmitting } }; #endif
WiiChuck_test.ino
#include "Wire.h" //#include "WiiChuckClass.h" //most likely its WiiChuck.h for the rest of us. #include "WiiChuck.h" WiiChuck chuck = WiiChuck(); void setup() { //nunchuck_init(); Serial.begin(115200); chuck.begin(); chuck.update(); //chuck.calibrateJoy(); } void loop() { delay(20); chuck.update(); Serial.print(chuck.readJoyX()); Serial.print(", "); Serial.print(chuck.readJoyY()); Serial.print(", "); if (chuck.buttonZ) { Serial.print("Z"); } else { Serial.print("-"); } Serial.print(", "); //not a function// if (chuck.buttonC()) { if (chuck.buttonC) { Serial.print("C"); } else { Serial.print("-"); } Serial.println(); }