Een Wii Nunchuk integreren met Arduino: Stap-voor-stap Gids
Onderdelen en benodigdheden
| Nintendo Nunchuk | 1 | |
| SparkFun Level Shifter | 1 | |
| Arduino UNO | 1 |
Over dit project
Voorwoord
Dit artikel werd oorspronkelijk gepubliceerd op www.xarg.org.
Een Wii Nunchuk gebruiken met Arduino
We zijn allemaal opgegroeid met gamecontrollers in onze handen, wat ze ideaal maakt om te combineren met letterlijk elke mogelijke toepassing. Een geweldige uitvinding van Nintendo is de Nunchuk, een goedkope uitbreiding voor de Wii U remote. Omdat het I2C als communicatieprotocol gebruikt, is het makkelijk om de ruwe data van de controller te benaderen. Omdat het zo makkelijk is, dacht ik dat er een standaardoplossing zou zijn, maar ik kon alleen onstabiele code-snippets vinden. Daarom heb ik de gap gevuld en hier is de uitwerking. In dit artikel begeleid ik je door de details en implementeer ik het voor Arduino.
Hardware
De Nunchuk heeft twee membraanknoppen: knop C en knop Z. Bovenaan zit een analoge twee-as joystick en het hele apparaat is gevoelig voor bewegingen dankzij een accelerometer die krachten in alle drie dimensies meet. Het is aanbevolen om de Nunchuk met 3,3V te voeden en je zou zeker een level shifter moeten gebruiken als je die spanning niet kunt leveren, om de levensduur te verlengen. Minimaal heb je nodig:
- Nintendo Nunchuk (of replica)
- Arduino
- Level Shifter (optioneel)
- Nunchuk Adapter (optioneel)
Originele Nunchuk of replica
De grote vraag: originele Nintendo Nunchuk of Chinese replica? Voor het testen van mijn driver kocht ik beide. Het prijsverschil is ~10-15€. Wat ik kan zeggen: de kabels van de originele Nunchuk zijn afgeschermd, wat ze robuuster maakt tegen storingen. De joystick van de originele heeft hogere kwaliteit, het lost alle bewegingen op in het volledige bereik, terwijl de replica niet reageert op minimale bewegingen. Ook de accelerometer-kwaliteit is beter bij de originele. Ik heb echter een Kalman-filter toegepast, wat deze verschillen nivellert. Als je een langdurige controller wilt, ga voor de originele. Als je gewoon een goedkope input-device nodig hebt, kan een replica geluk hebben.
Nunchuk-connector
Nintendo gebruikt een proprietaire stecker. Omdat ik geen Wii heb en de controllers niet voor gaming gebruik, knipte ik de connector eraf. Je kunt een Nunchuk-adapter voor een paar euro kopen als je dit niet wilt, maar met soldeervaardigheden kun je de stecker ook repareren. Ik raad aan de stecker open te maken om te zien hoe de draden aan de pinnen zitten. Dit is vooral belangrijk voor replicas, want de draden kunnen willekeurig aangesloten zijn. Een ander vreemd ding: de originele controller heeft 4 draden, de replica 5, terwijl de connector 6 pinnen heeft. Laten we de connector openmaken:
En de draden afknippen:
Kijk je frontaal op de stecker, dan zie je deze pinnen:
Originele Nunchuk kleur/pin-indeling:
- Groen → SDA
- nc (niet aangesloten)
- Rood → 3V3
- Wit → GND
- nc
- Geel → SCL
Nunchuk-clone kleur/pin-indeling:
- Geel → SDA
- Zwart → nc
- Groen → 3V3
- Rood → GND
- nc
- Wit → SCL
Let op: Je moet zeker kijken hoe de draden liggen en niet op kleur verbinden. Acroniemen: nc = niet aangesloten, SDA = datalijn (moet met A4 op Arduino), SCL = klok (A5 op Arduino). De Arduino heeft een spanningsregelaar, dus 3V3 direct gebruiken. Als je een WiiChuck of vergelijkbare adapter gebruikt: verbind 3V3 met A2 en GND met A1 - je moet later nunchuk_init_power() aanroepen. Het volgende Fritzing-schema illustreert de verbinding:
Software
Ik schreef een kleine header-bibliotheek die de communicatie met de Nunchuk implementeert. Je hoeft je geen zorgen te maken over wat er achter de schermen gebeurt; het zou out-of-the-box moeten werken. Als je geïnteresseerd bent in de details, leg ik het hieronder uit.
Download Nunchuk Library
De communicatie met de Nunchuk gaat via de TWI-bus, een andere naam voor I2C (sommige details verschillen, maar niet voor ons doel). De I2C-snelheid staat standaard op Fast Mode (400kHz). Om de Nunchuk met je Arduino te gebruiken, is dit voldoende:
#include <Wire.h>
#include "nunchuk.h"
void setup() {
Serial.begin(9600);
Wire.begin();
// nunchuk_init_power(); // A1 en A2 als voeding
nunchuk_init();
}
void loop() {
if (nunchuk_read()) {
// Werk met nunchuk_data
nunchuk_print();
}
delay(10);
}
Wanneer je het Processing-bestand dat bij de bibliotheek zit start, kun je deze kegel balanceren met je Nunchuk:
In plaats van nunchuk_print() kun je veel functies gebruiken om de data te benaderen:
Nunchuk-functies
nunchuk_buttonZ(): 1 of 0, of knop Z ingedrukt isnunchuk_buttonC(): 1 of 0, of knop C ingedrukt isnunchuk_joystickX_raw() / nunchuk_joystickX()ennunchuk_joystickY_raw() / nunchuk_joystickY(): X- of Y-waarde van de joystick. Raw-versie geeft toegang tot data zonder kalibratie.nunchuk_joystick_angle(): Berekent de hoek van de joystick in radialen.nunchuk_accelX_raw() / nunchuk_accelX(),nunchuk_accelY_raw() / nunchuk_accelY(),nunchuk_accelZ_raw() / nunchuk_accelZ(): X-, Y-, Z-waarde van de accelerometer. Raw-versies zonder kalibratie.nunchuk_pitch(): Berekent de pitch-hoek (kantelen voor/achter) in radialen.nunchuk_roll(): Berekent de roll-hoek (kantelen links/rechts) in radialen.
Let op: Er is geen nunchuk_yaw() functie, omdat een accelerometer alleen richtingskrachten kan meten en geen rotatiesnelheid. Dit beperkt de pitch tot 180° en zorgt ervoor dat de roll-hoek onjuist is wanneer de pitch groter is dan 180°.
De berekening van pitch en roll werkt onder de vereenvoudigende aanname dat de enige kracht die op de controller werkt zwaartekracht is. Dit klopt omdat de Nunchuk stil gehouden wordt of een constante snelheid ervaart door een externe kracht.
Kalibratie
Zoals beschreven in het functieoverzicht, heeft elke joystick- en accelerometer-functie een gekalibreerde en een raw-versie. Aan het begin van het bibliotheekbestand definiëren constanten de nul-posities. Het beste is om de raw-metingen van je controller te lezen in neutrale houding en de constanten dienovereenkomstig aan te passen.
I2C-protocol
Deze sectie bespreekt het daadwerkelijke I2C-protocol. Als je de controller gewoon wilt gebruiken, is deze info niet nodig, maar als je het protocol wilt begrijpen, hoop ik je tijd te besparen.
Ik begon met scannen naar het adres van de Nunchuk met mijn I2C-scanner: 0x52. Het uitlezen van parameters uit het geheugen van de Nunchuk via I2C lijkt sterk op communicatie met een normale I2C EEPROM. Voordat data gelezen kan worden, is een initialisatiereeks nodig.
Om data te lezen, moet het adres worden gestuurd, want de Nunchuk-controller verhoogt het adres bij elke leesactie. De data die we willen ligt op adres 0x00 en is 6 bytes lang. Op adres 0x20 en 0x30 (lijkt exacte kopie van 0x20) zitten 16 bytes kalibratiedata. Op adres 0xFA vind je het identificatienummer: 0xA4200000 voor Nunchuk, 0xA4200101 voor Classic Controller, 0xA4200402 voor Balance Board, etc.
Bij schrijven naar de Nunchuk is het formaat analoog aan het leescommando: eerste byte is adres, gevolgd door data.
1. Nunchuk initialiseren (met encryptie):
START, 0x40, 0x00, STOP
Dit is de standaard initialisatie, die het encryptie-algoritme op default zet. Elke byte die gelezen wordt, moet gedecrypteerd worden met (x ^ 0x17) + 0x17.
2. Nunchuk initialiseren ZONDER encryptie (aanbevolen):
START, 0xF0, 0x55, STOP
START, 0xFB, 0x00, STOP
Voordeel: data kan direct gebruikt worden zonder decryptie en werkt ook met Nunchuk-clones.
3. Apparaat-ID uitlezen uit extensie-register:
START, 0xFA, STOP
READ 6 byte
4. Metingen uitlezen van het apparaat:
START, 0x00, STOP
READ 6 byte
Retourgegevens:
- Byte 1: Joystick X-as [7:0]
- Byte 2: Joystick Y-as [7:0]
- Byte 3: Accelerometer X-as [9:2]
- Byte 4: Accelerometer Y-as [9:2]
- Byte 5: Accelerometer Z-as [9:2]
- Byte 6: Az[1:0] Ay[1:0] Ax[1:0] ¬Bc ¬Bz
De knopwaarden zijn geïnverteerd, en de LSB-bits van de accelerometer zitten in byte 6. In de bibliotheek combineer ik de LSB-bits met de rest. Ik heb gezien dat mensen de waarden zonder LSB-bits gebruiken, wat een te vereenvoudigde manier is om het signaal stabieler te maken. Ik kies liever voor een ruisig signaal van een ADC, dat makkelijk gefilterd kan worden met een Complementaire of Kalman-filter, in plaats van af te ronden waar je veel informatie verliest.
5. Actuele kalibratiedata uitlezen:
START, 0x20, STOP
READ 16 byte
Retour:
- Byte 1: 0G-waarde X-as [9:2]
- Byte 2: 0G-waarde Y-as [9:2]
- Byte 3: 0G-waarde Z-as [9:2]
- Byte 4: LSB van nul-waarde X,Y,Zassen
- Byte 5: 1G-waarde X-as [9:2]
- Byte 6: 1G-waarde Y-as [9:2]
- Byte 7: 1G-waarde Z-as [9:2]
- Byte 8: LSB van 1G-waarde X,Y,Zassen
- Byte 9: Joystick X-as maximum
- Byte 10: Joystick X-as minimum
- Byte 11: Joystick X-as centrum
- Byte 12: Joystick Y-as maximum
- Byte 13: Joystick Y-as minimum
- Byte 14: Joystick Y-as centrum
- Byte 15: Checksum
- Byte 16: Checksum
Bytes 0-3 bevatten de nul-waarden van X, Y, Z-as; bytes 4-7 de waarden bij 1G (aardszwaartekracht). De kalibratiedata wordt nog niet in de software-implementatie gebruikt.
Code
Code snippet #1
#include <Wire.h>
#include "nunchuk.h"
void setup() {
Serial.begin(9600);
Wire.begin();
// nunchuk_init_power(); // A1 en A2 als voeding
nunchuk_init();
}
void loop() {
if (nunchuk_read()) {
// Werk met nunchuk_data
nunchuk_print();
}
delay(10);
}
GitHub
https://github.com/infusion/Fritzing/tree/master/Nunchuk
Aangepaste onderdelen en behuizingen
Productieproces
- IR-afstandsbediening-commando's vastleggen op Raspberry Pi zonder LIRC: Een Python UART-benadering
- LED helderheid regelen met PWM via drukknop op Arduino Mega
- Bouw een indrukwekkend monitor Ambilight-systeem met Arduino
- Betrouwbaar Arduino RFID Aanwezigheidssysteem Aangedreven door Python
- K30 CO2-sensor: Real-time binnenluchtkwaliteitmonitoring met Arduino
- Communicatie voor doofblinden vergemakkelijken met 1Sheeld en Arduino
- Slimme spaarpot bouwen: Muntenacceptor besturen met Arduino Nano
- Een slimme voltmeter bouwen met Arduino en smartphone – Eenvoudig DIY-project
- Real-time IoT hartslagmonitor met Arduino en MAX30100
- Een LED bedienen via Bluetooth met Arduino – Eenvoudige DIY Handleiding
- Arduino-gebaseerde 6-DoF Robotarm Gestoeerd met Wii Nunchuk