Advertisement
dustinrobotics

nunchuck.h

Mar 26th, 2012
390
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 12.80 KB | None | 0 0
  1. /*
  2.  * File  : wiinunchuk.h V0.9
  3.  * Author: Tim Teatro
  4.  * Date  : Feb 2012
  5.  * http://www.timteatro.net/2012/02/10/a-library-for-using-the-wii-nunchuk-in-arduino-sketches/
  6.  * Description:
  7.  *
  8.  *   Library to set up and poll a Wii nunchuk with Arduino. There are
  9.  * many libraries available to do this, none of which I really liked.
  10.  * I was fond of Tod Kurt's, but his was incomplete as it did not work
  11.  * with knockoff nunchuks, it did not consider the least significant
  12.  * bits of accelerometer data and didn't have any advanced functions
  13.  * for processing the data such as calculating pitch and roll angles.
  14.  *
  15.  *
  16.  * Provides functions:
  17.  *  void nunchuk_setpowerpins()
  18.  *  void nunchuk_init()
  19.  *  int nunchuk_get_data()
  20.  *  void nunchuk_calibrate_joy()
  21.  *  inline unsigned int nunchuk_zbutton()
  22.  *  inline unsigned int nunchuk_cbutton()
  23.  *  inline int nunchuk_joy_x()
  24.  *  inline int nunchuk_cjoy_x()
  25.  *  inline int nunchuk_cjoy_y()
  26.  *  inline uint16_t nunchuk_accelx()
  27.  *  inline uint16_t nunchuk_accely()
  28.  *  inline uint16_t nunchuk_accelz()
  29.  *  inline int nunchuk_caccelx()
  30.  *  inline int nunchuk_caccely()
  31.  *  inline int nunchuk_caccelz()
  32.  *  inline int nunchuk_joyangle()
  33.  *  inline int nunchuk_rollangle()
  34.  *  inline int nunchuk_pitchangle()
  35.  *  void nunchuk_calibrate_accelxy()
  36.  *  void nunchuk_calibrate_accelz()
  37.  *
  38.  * This library is inspired by the work of Tod E. Kurt,
  39.  *  (http://todbot.com/blog/bionicarduino/)
  40.  *
  41.  * (c) 2012 by Tim Teatro
  42.  *
  43.  * This program is free software: you can redistribute it and/or modify
  44.  * it under the terms of the GNU General Public License as published by
  45.  * the Free Software Foundation, either version 3 of the License, or
  46.  * (at your option) any later version.
  47.  *
  48.  * This program is distributed in the hope that it will be useful,
  49.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  50.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  51.  * GNU General Public License for more details.
  52.  *
  53.  * You should have received a copy of the GNU General Public License
  54.  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  55.  */
  56.  
  57. #if (ARDUINO >= 100)
  58. #include <Arduino.h>
  59. #else
  60. #include <WProgram.h>
  61. #endif
  62.  
  63. //
  64. // These are suitable defaults for most nunchuks, including knockoffs.
  65. // If you intend to use the same nunchuk all the time and demand accu-
  66. // racy, it is worth your time to measure these on your own.
  67. //     If you may want to use various nunchuks, you may want to
  68. // calibrate using functions
  69. //   nunchuk_calibrate_joy()
  70. //   nunchuk_calibrate_accelxy()
  71. //   nunchuk_calibrate_accelz()
  72. //
  73. #define DEFAULT_CENTRE_JOY_X 124
  74. #define DEFAULT_CENTRE_JOY_Y 132
  75. #define ACCEL_ZEROX 490
  76. #define ACCEL_ZEROY 500
  77. #define ACCEL_ZEROZ 525
  78.  
  79. //
  80. // Global vars are kept to a minimum.
  81. //
  82. uint8_t ctrlr_type[6];   // Used externally?
  83. uint8_t nunchuk_buf[6];  // Keeps data payload from nunchuk
  84. // Accelerometer values and callibration centres:
  85. uint16_t accel_zerox, accel_zeroy, accel_zeroz;
  86. // Joystick values and calibration centres:
  87. int joy_x, joy_y, joy_zerox, joy_zeroy;
  88.  
  89. //
  90. //
  91. // Uses port C (analog in) pins as power & ground for nunchuk
  92. //
  93. // void nunchuk_setpowerpins()
  94.     // {
  95.     // #define pwrpin PORTC3
  96.     // #define gndpin PORTC2
  97.     // DDRC |= _BV(pwrpin) | _BV(gndpin);
  98.     // PORTC &=~ _BV(gndpin);
  99.     // PORTC |=  _BV(pwrpin);
  100.     // delay(100); // wait for things to stabilize
  101.     // }
  102.  
  103. //
  104. //
  105. // Initialize and join the I2C bus, and tell the nunchuk we're
  106. // talking to it. This function will work both with Nintendo
  107. // nunchuks, or knockoffs.
  108. //
  109. // See http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1264805255
  110. //
  111. void nunchuk_init()
  112.     {
  113.   byte cnt;
  114.     Wire.begin();
  115.     delay(1);
  116.     Wire.beginTransmission(0x52);  // device address
  117.     #if (ARDUINO >= 100)
  118.         Wire.write((uint8_t)0xF0);  // 1st initialisation register
  119.         Wire.write((uint8_t)0x55);  // 1st initialisation value
  120.         Wire.endTransmission();
  121.         delay(1);
  122.         Wire.beginTransmission(0x52);
  123.         Wire.write((uint8_t)0xFB);  // 2nd initialisation register
  124.         Wire.write((uint8_t)0x00);  // 2nd initialisation value
  125.     #else
  126.         Wire.send((uint8_t)0xF0);   // 1st initialisation register
  127.         Wire.send((uint8_t)0x55);   // 1st initialisation value
  128.         Wire.endTransmission();
  129.         delay(1);
  130.         Wire.beginTransmission(0x52);
  131.         Wire.send((uint8_t)0xFB);   // 2nd initialisation register
  132.         Wire.send((uint8_t)0x00);   // 2nd initialisation value
  133.     #endif
  134.     Wire.endTransmission();
  135.     delay(1);
  136.            
  137.   // read the extension type from the register block        
  138.   Wire.beginTransmission(0x52);
  139.   Wire.write(0xFA);             // extension type register
  140.   Wire.endTransmission();
  141.   Wire.beginTransmission(0x52);
  142.   Wire.requestFrom(0x52, 6);            // request data from controller
  143.   for (cnt = 0; cnt < 6; cnt++) {
  144.       if (Wire.available()) {
  145.           ctrlr_type[cnt] = Wire.read(); // Should be 0x0000 A420 0101 for Classic Controller, 0x0000 A420 0000 for nunchuck
  146.       }
  147.   }
  148.   Wire.endTransmission();
  149.   delay(1);
  150.            
  151.   /* // send the crypto key (zeros), in 3 blocks of 6, 6 & 4.
  152.   Wire.beginTransmission(0x52);
  153.   Wire.write((uint8_t)0xF0);                // crypto key command register
  154.   Wire.write((uint8_t)0xAA);                // sends crypto enable notice
  155.   Wire.endTransmission();
  156.   delay(1);
  157.   Wire.beginTransmission(0x52);
  158.   Wire.write((uint8_t)0x40);                // crypto key data address
  159.   for (cnt = 0; cnt < 6; cnt++) {
  160.       Wire.write((uint8_t)0x00);                // sends 1st key block (zeros)
  161.   }
  162.   Wire.endTransmission();
  163.   Wire.beginTransmission(0x52);
  164.   Wire.write((uint8_t)0x40);                // sends memory address
  165.   for (cnt = 6; cnt < 12; cnt++) {
  166.       Wire.write((uint8_t)0x00);                // sends 2nd key block (zeros)
  167.   }
  168.   Wire.endTransmission();
  169.   Wire.beginTransmission(0x52);
  170.   Wire.write((uint8_t)0x40);                // sends memory address
  171.   for (cnt = 12; cnt < 16; cnt++) {
  172.       Wire.write((uint8_t)0x00);                // sends 3rd key block (zeros)
  173.   }
  174.   Wire.endTransmission();
  175.   delay(1); */
  176.   // end device init
  177.     //
  178.     // Set default calibration centres:
  179.     //
  180.     joy_zerox = DEFAULT_CENTRE_JOY_X;
  181.     joy_zeroy = DEFAULT_CENTRE_JOY_Y;
  182.     accel_zerox = ACCEL_ZEROX;
  183.     accel_zeroy = ACCEL_ZEROY;
  184.     accel_zeroz = ACCEL_ZEROZ;
  185.     }
  186.  
  187. //
  188. //
  189. // T.T.
  190. // Standard nunchuks use a byte-wise encryption using bit-wise XOR
  191. // with 0x17. This function decodes a byte.
  192. //
  193. // This function is not needed since the way we initialize the nunchuk
  194. // does not XOR encrypt the bits.
  195. //
  196. //static inline char nunchuk_decode_byte (char x)
  197. //  {
  198. //  x = (x ^ 0x17) + 0x17;
  199. //  return x;
  200. //  }
  201.  
  202. static void nunchuk_send_request()
  203. {
  204.     Wire.beginTransmission(0x52);// transmit to device 0x52
  205.     #if (ARDUINO >= 100)
  206.         Wire.write((uint8_t)0x00);// sends one byte
  207.     #else
  208.         Wire.send((uint8_t)0x00);// sends one byte
  209.     #endif
  210.     Wire.endTransmission();// stop transmitting
  211. }
  212.  
  213. //
  214. //
  215. // Gets data from the nunchuk and packs it into the nunchuk_buff byte
  216. // aray. That array will be processed by other functions to extract
  217. // the data from the sensors and analyse.
  218. //
  219. int nunchuk_get_data()
  220.     {
  221.     int cnt=0;
  222.       // Request six bytes from the chuck.
  223.     Wire.requestFrom (0x52, 6);
  224.     while (Wire.available ())
  225.         {
  226.       // receive byte as an integer
  227.         #if (ARDUINO >= 100)
  228.             nunchuk_buf[cnt] = Wire.read();
  229.         #else
  230.             nunchuk_buf[cnt] = Wire.receive();
  231.         #endif
  232.         cnt++;
  233.         }
  234.  
  235.     Wire.beginTransmission(0x52);// transmit to device 0x52
  236.     #if (ARDUINO >= 100)
  237.         Wire.write((uint8_t)0x00);// sends one byte
  238.     #else
  239.         Wire.send((uint8_t)0x00);// sends one byte
  240.     #endif
  241.     Wire.endTransmission();// stop transmitting
  242.  
  243.     if (cnt >= 5)
  244.         {
  245.         return 1;   // success
  246.         }
  247.     return 0; // failure
  248.     }
  249.  
  250. //
  251. //
  252. //
  253. // Calibrate joystick so that we read the centre position as (0,0).
  254. // Otherwise, we use the default values from the header.
  255. //
  256. void nunchuk_calibrate_joy()
  257.     {
  258.     joy_zerox = joy_x;
  259.     joy_zeroy = joy_y;
  260.     }
  261.  
  262. // Returns c and z button states: 1=pressed, 0=not
  263. // The state is in the two least significant bits of the 6th byte.
  264. // In the data, a 1 is unpressed and 0 is pressed, so this will be
  265. // reversed. These functions use a bitwise AND to determine the value
  266. // and then the () ? true : false; conditional structure to pass out
  267. // the appropriate state.
  268. //
  269. static inline unsigned int nunchuk_zbutton()
  270.     {
  271.     return ((nunchuk_buf[5] >> 0) & 1) ? 0 : 1;
  272.     }
  273.  
  274. static inline unsigned int nunchuk_cbutton()
  275.     {
  276.     return ((nunchuk_buf[5] >> 1) & 1) ? 0 : 1;
  277.     }
  278.  
  279. //
  280. //
  281. // Returns the raw x and y values of the the joystick, cast as ints.
  282. //
  283. static inline int nunchuk_joy_x()
  284.     {
  285.     return (int) nunchuk_buf[0];
  286.     }
  287.  
  288. static inline int nunchuk_joy_y()
  289.     {
  290.     return (int) nunchuk_buf[1];
  291.     }
  292.  
  293. //
  294. //
  295. // Return calibrated x and y values of the joystick.
  296. //
  297. static inline int nunchuk_cjoy_x()
  298.     {
  299.     return (int)nunchuk_buf[0] - joy_zerox;
  300.     }
  301.  
  302. static inline int nunchuk_cjoy_y()
  303.     {
  304.     return (int)nunchuk_buf[1] - joy_zeroy;
  305.     }
  306.  
  307. //
  308. //
  309. // Returns the raw 10-bit values from the 3-axis accelerometer sensor.
  310. // Of the six bytes recieved in a data payload from the nunchuk, bytes
  311. // 2, 3 and 4 are the most significant 8 bits of each 10-bit reading.
  312. // The final two bits are stored in the 6th bit along with the states
  313. // of the c and z button. These functions take the most significant
  314. // 8-bits and stacks it into a 16 bit unsigned integer, and then tacks
  315. // on the least significant bits from the 6th byte of the data
  316. // payload.
  317. //
  318. // Load the most sig digits into a blank 16-bit unsigned int leaving
  319. // two bits in the bottom ( via a 2-bit shift, << 2) for the least sig
  320. // bits:
  321. //  0x0000 | nunchuk_buff[*] << 2
  322. // Add to the above, the least sig bits. The code for x:
  323. //  nunchuk_buf[5] & B00001100
  324. // for example selects the 3rd and 4th bits from the 6th byte of the
  325. // payload to be concatinated with nunchuk_buff[2] to complete the 10-
  326. // bit datum for a given axis.
  327. //
  328. static inline uint16_t nunchuk_accelx()
  329.     {
  330.     return (  0x0000 | ( nunchuk_buf[2] << 2 ) +
  331.         ( ( nunchuk_buf[5] & B00001100 ) >> 2 )  );
  332.     }
  333.  
  334. static inline uint16_t nunchuk_accely()
  335.     {
  336.     return (  0x0000 ^ ( nunchuk_buf[3] << 2 ) +
  337.         ( ( nunchuk_buf[5] & B00110000 ) >> 4 )  );
  338.     }
  339.  
  340. static inline uint16_t nunchuk_accelz()
  341.     {
  342.     return (  0x0000 ^ ( nunchuk_buf[4] << 2 ) +
  343.         ( ( nunchuk_buf[5] & B11000000 ) >> 6 )  );
  344.     }
  345.  
  346. //
  347. //
  348. // Returns the x,y and z accelerometer values with calibration values
  349. // subtracted.
  350. //
  351. static inline int nunchuk_caccelx()
  352.     {
  353.         return (int)(nunchuk_accelx() - accel_zerox);
  354.     }
  355.  
  356. static inline int nunchuk_caccely()
  357.     {
  358.         return (int)(nunchuk_accely() - accel_zeroy);
  359.     }
  360.  
  361. static inline int nunchuk_caccelz()
  362.     {
  363.         return (int)(nunchuk_accelz() - accel_zeroz);
  364.     }
  365.  
  366. //
  367. //
  368. // Returns joystick angle in degrees. It uses the ratio of calibrated
  369. // x and y potentiometer readings to find the angle, zero being direct
  370. // right (positive x) and measured counter-clockwise from there.
  371. //
  372. // If the atan2 function returns a negative angle, it is rotated back
  373. // into a positive angle. For those unfamiliar, the atan2 function
  374. // is a more inteligent atan function which quadrant the vector <x,y>
  375. // is in, and returns the appropriate angle.
  376. //
  377. static inline int nunchuk_joyangle()
  378.     {
  379.     double theta;
  380.     theta = atan2( nunchuk_cjoy_y(), nunchuk_cjoy_x() );
  381.     while (theta < 0) theta += 2*M_PI;
  382.     return (int)(theta * 180/M_PI);
  383.     }
  384.  
  385. //
  386. //
  387. // Returns roll angle in degrees. Under the assumption that the
  388. // only acceleration detected by the accelerometer is acceleration due
  389. // to gravity, this function uses the ratio of the x and z
  390. // accelerometer readings to gauge pitch. This only works while the
  391. // nunchuk is being held still or at constant velocity with zero ext-
  392. // ernal force.
  393. //
  394. static inline int nunchuk_rollangle()
  395.     {
  396.     return (int) (  atan2( (double) nunchuk_caccelx(),
  397.         (double) nunchuk_caccelz() ) * 180 / M_PI  );
  398.     }
  399.  
  400. //
  401. //
  402. // Returns pitch angle in degrees. Under the assumption that the
  403. // only acceleration detected by the accelerometer is acceleration due
  404. // to gravity, this function uses the ratio of the y and z
  405. // accelerometer readings to gauge pitch.  This only works while the
  406. // nunchuk is being held still or at constant velocity with zero ext-
  407. // ernal force.
  408. //
  409. static inline int nunchuk_pitchangle()
  410.     {
  411.     return (int) (  atan2( (double) nunchuk_caccely(),
  412.         (double)nunchuk_caccelz() ) * 180 / M_PI  );
  413.     }
  414.  
  415. //
  416. //
  417. // Because gravity pulls down on the z-accelerometer while the nunchuk
  418. // is upright, we need to calibrate {x,y} and {z} separately. Execute
  419. // this function while the nunchuk is known to be upright and then
  420. // execute nunchuk_calibrate_accelz() when the nunchuk is on its side.
  421. //
  422. void nunchuk_calibrate_accelxy()
  423.     {
  424.     accel_zerox = nunchuk_accelx();
  425.     accel_zeroy = nunchuk_accely();
  426.     }
  427.  
  428. //
  429. //
  430. // See documentation for nunchuk_calibrate_xy()
  431. //
  432. void nunchuk_calibrate_accelz()
  433.     {
  434.     accel_zeroz = nunchuk_accelz();
  435.     }
  436. //
  437. //
  438. // EOF
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement