arduino_nunchuk

library to get data out of a Nintendo Wii nunchuk
git clone https://git.e1e0.net/arduino_nunchuk.git
Log | Files | Refs | README

commit 4f2bfec4b178e0854d2764ffd9a4788cb16d702d
Author: Paco Esteban <paco@e1e0.net>
Date:   Tue, 29 Sep 2020 17:12:08 +0200

initial commit

Diffstat:
Anunchuk.cpp | 289++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Anunchuk.h | 73+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 362 insertions(+), 0 deletions(-)

diff --git a/nunchuk.cpp b/nunchuk.cpp @@ -0,0 +1,289 @@ +/* + * Copyright (c) 2020, Paco Esteban <paco@e1e0.net> + * Copyright (c) 2016, Robert Eisele <robert@xarg.org> + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include <Wire.h> +#include "nunchuk.h" + +/* + * Constructor accets values for the "zero" point of the accelerometers and the + * joystick. This is a calibration that should be done for every Nunchuk, so + * better to have it configurable on class creation + */ +Nunchuk::Nunchuk(uint16_t axz, uint16_t ayz, uint16_t azz, + uint16_t jxz, uint16_t jyz) { + _accelX_zero = axz; + _accelY_zero = ayz; + _accelZ_zero = azz; + _joystickX_zero = jxz; + _joystickY_zero = jyz; +} + +void +Nunchuk::init() { +#ifdef NUNCHUK_DISABLE_ENCRYPTION + Wire.beginTransmission(NUNCHUK_ADDRESS); + Wire.write(0xF0); + Wire.write(0x55); + Wire.endTransmission(true); + + Wire.beginTransmission(NUNCHUK_ADDRESS); + Wire.write(0xFB); + Wire.write(0x00); + Wire.endTransmission(true); +#else + Wire.beginTransmission(NUNCHUK_ADDRESS); + Wire.write(0x40); + Wire.write(0x00); + Wire.endTransmission(true); +#endif + +#ifdef NUNCHUK_DEBUG + /* + * 0xA4200000 for Nunchuck, 0xA4200101 for Classic, + * 0xA4200402 for Balance + */ + Serial.print("Ident: "); + + Wire.beginTransmission(NUNCHUK_ADDRESS); + Wire.write(0xFA); + Wire.endTransmission(true); + + Wire.requestFrom(NUNCHUK_ADDRESS, 6); + for (uint8_t i = 0; i < 6; i++) { + if (Wire.available()) { + Serial.print(Wire.read(), HEX); + Serial.print(" "); + } + } + Wire.endTransmission(true); + Serial.println(""); + + delay(100); /* Wait for serial transfer, before loop()ing */ +#endif +} + +/* + * Decodes a byte if encryption is used + * + * @param x The byte to be decoded + */ +uint8_t +Nunchuk::decode_byte(uint8_t x) { +#ifdef NUNCHUK_DISABLE_ENCRYPTION + return x; +#else + return (x ^ 0x17) + 0x17; +#endif +} + +/* + * Central function to read a full chunk of data from Nunchuk + * + * @return A boolean if the data transfer was successful + * + * Returned data is organized this way: + * Byte 0 --> Stick X position + * Byte 1 --> Stick Y position + * Byte 2 --> Accel X MSB + * Byte 3 --> Accel Y MSB + * Byte 4 --> Accel Z MSB + * Byte 5 --> | AccelZ LSB | AccelY LSB | AccelX LSB | Button C | Button Z | + * | 1 | 0 | 1 | 0 | 1 | 0 | 0 | 0 | + * (Button C and Z are "active low") + */ +uint8_t +Nunchuk::read() { + uint8_t i; + Wire.beginTransmission(NUNCHUK_ADDRESS); + Wire.write(0x00); + + Wire.requestFrom(NUNCHUK_ADDRESS, 6); + for (i = 0; i < 6 && Wire.available(); i++) { + _nunchuk_data[i] = decode_byte(Wire.read()); + } + + Wire.endTransmission(true); + return i == 6; +} + +uint8_t +Nunchuk::buttonZ() { + return (~_nunchuk_data[5] & 0x01); +} + +uint8_t +Nunchuk::buttonC() { + return (~(_nunchuk_data[5] >> 1) & 0x01); +} + +uint8_t +Nunchuk::joystickX_raw() { + return _nunchuk_data[0]; +} + +uint8_t +Nunchuk::joystickY_raw() { + return _nunchuk_data[1]; +} + +/* + * Retrieves the calibrated X-value of the joystick + */ +int16_t +Nunchuk::joystickX() { + return (int16_t)joystickX_raw() + - (int16_t)_joystickX_zero; +} + +/* + * Retrieves the calibrated Y-value of the joystick + */ +int16_t +Nunchuk::joystickY() { + return (int16_t)joystickY_raw() + - (int16_t)_joystickY_zero; +} + +/* + * Calculates the angle of the joystick + */ +float +Nunchuk::joystick_angle() { + return atan2((float)joystickY(), (float)joystickX()); +} + +/* + * Retrieves the raw X-value of the accelerometer + */ +uint16_t +Nunchuk::accelX_raw() { + return ((uint16_t)_nunchuk_data[2] << 2) + | ((_nunchuk_data[5] >> 2) & 0x03); +} + +/* + * Retrieves the raw Y-value of the accelerometer + */ +uint16_t +Nunchuk::accelY_raw() { + return ((uint16_t)_nunchuk_data[3] << 2) + | ((_nunchuk_data[5] >> 4) & 0x03); +} + +/* + * Retrieves the raw Z-value of the accelerometer + */ +uint16_t +Nunchuk::accelZ_raw() { + return ((uint16_t)_nunchuk_data[4] << 2) + | ((_nunchuk_data[5] >> 6) & 0x03); +} + +/* + * Retrieves the calibrated X-value of the accelerometer + */ +int16_t +Nunchuk::accelX() { + return (int16_t)accelX_raw() - (int16_t)_accelX_zero; +} + +/* + * Retrieves the calibrated Y-value of the accelerometer + */ +int16_t +Nunchuk::accelY() { + return (int16_t)accelY_raw() - (int16_t)_accelY_zero; +} + +/* + * Retrieves the calibrated Z-value of the accelerometer + */ +int16_t +Nunchuk::accelZ() { + return (int16_t)accelZ_raw() - (int16_t)_accelZ_zero; +} + +/* + * Calculates the pitch angle THETA around y-axis of the Nunchuk in radians + */ +float +Nunchuk::pitch() { /* tilt-y */ + return atan2((float)accelY(), (float)accelZ()); +} + +/* + * Calculates the roll angle PHI around x-axis of the Nunchuk in radians + */ +float +Nunchuk::roll() { /* tilt-x */ + return atan2((float)accelX(), (float)accelZ()); +} + +/* + * A handy function to print either verbose information of the Nunchuk or a CSV + * stream for Processing + */ +void +Nunchuk::print() { +#ifdef NUNCHUK_DEBUG + char buf[100]; + + sprintf(buf, + "Joy X=%4d(%4d) Y=%4d(%4d) Ang %3.2f " + "Acc X=%4d(%4d) Y=%4d(%4d) Z=%4d(%4d) " + "(P=%3.2f R=%3.2f) " + "Btn Z=%1d C=%1d ", + joystickX(), joystickX_raw(), + joystickY(), joystickY_raw(), + (joystick_angle()*180)/3.1416, + accelX(), accelX_raw(), + accelY(), accelY_raw(), + accelZ_raw(), accelZ_raw(), + (pitch()*180)/3.1416, (roll()*180)/3.1416, + buttonZ(), buttonC()); + Serial.print(buf); + Serial.println(); +#else + Serial.print(joystickX(), DEC); + Serial.print(","); + Serial.print(joystickY(), DEC); + Serial.print(","); + Serial.print(joystick_angle(), DEC); + Serial.print(","); + Serial.print(accelX(), DEC); + Serial.print(","); + Serial.print(accelY(), DEC); + Serial.print(","); + Serial.print(accelZ(), DEC); + Serial.print(","); + Serial.print(pitch(), DEC); + Serial.print(","); + Serial.print(roll(), DEC); + Serial.print(","); + Serial.print(buttonZ(), DEC); + Serial.print(","); + Serial.print(buttonC(), DEC); + Serial.println(); +#endif +} + diff --git a/nunchuk.h b/nunchuk.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2020, Paco Esteban <paco@e1e0.net> + * Copyright (c) 2016, Robert Eisele <robert@xarg.org> + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef NUNCHUK_H +#define NUNCHUK_H + +#include "Arduino.h" +#include "Print.h" + +/* + * Whether to disable encryption. Enabling encryption means that every packet + * must be decrypted, which wastes cpu cycles. Cheap Nunchuk clones have + * problems with the encrypted init sequence, so be sure you know what you're + * doing + */ +#define NUNCHUK_DISABLE_ENCRYPTION + +/* Print debug information instead of a CSV stream to the serial port */ +/* #define NUNCHUK_DEBUG */ + +/* The Nunchuk I2C address */ +#define NUNCHUK_ADDRESS 0x52 + +class Nunchuk { + public: + Nunchuk(uint16_t, uint16_t, uint16_t, uint16_t, uint16_t); + void print(); + float roll(); + float pitch(); + int16_t accelZ(); + int16_t accelY(); + int16_t accelX(); + float joystick_angle(); + uint8_t buttonC(); + uint8_t buttonZ(); + int16_t joystickY(); + int16_t joystickX(); + uint8_t read(); + void init(); + private: + uint8_t _nunchuk_data[6]; + uint16_t _accelX_zero, _accelY_zero, _accelZ_zero; + uint16_t _joystickX_zero, _joystickY_zero; + + uint8_t decode_byte(uint8_t); + uint16_t accelZ_raw(); + uint16_t accelY_raw(); + uint16_t accelX_raw(); + uint8_t joystickY_raw(); + uint8_t joystickX_raw(); +}; + +#endif