In questi giorni ho trovato in rete un paio di video dove gli “attori” utilizzavano il nunchuck della wii per comandare servomotori o semplici macchinine, allora mi sono chiesto come fanno. La risposta è semplice, il nunchuck comunica tramite protocollo I2C e guarda caso l’arduino tramite la libreria wire è in grado di utilizzare questo protocollo.
Mi sono subito precipitato a comprare un nunchuck (da gamestop, uno compatibile costa 15€).
Il codice presente sul sito però non mi dava la possibilità di controllare i servomotori quindi ho dovuto scrivere qualche parte del codice.
Il nunchuck dispone di un joypad, due pulsanti (C e Z) e di un accellerometro.
Il joypad comanda direttamente i servo su tutti e due gli assi, il pulsante C accende un semplice LED ed il pulsante Z, se premuto, permette di pilotare i servo tramite l’accellerometro.
#include <Wire.h>
#include <string.h>
/*Come collegare i 4 fili del Nunchuck:
Bianco: Massa
Rosso: +3.3V oppure +5V
Verde: Data -> A4
Giallo: Clock -> A5
*/
#include <Servo.h>
Servo servo_orizzontale;
Servo servo_verticale;
int posor = 90;
int posve = 90;
long wait = 0;
long waitservo = 0;
#undef int
#include <stdio.h>
uint8_t outbuf[6]; // array to store arduino output
int cnt = 0;
int ledPin = 13;
int led = 8;
int joy_x_axis = 0;
int joy_y_axis = 0;
int accel_x_axis = 0;
int accel_y_axis = 0;
int accel_z_axis = 0;
int z_button = 1;
int c_button = 1;
void
setup ()
{
pinMode(led, OUTPUT);
servo_orizzontale.attach(3);
servo_orizzontale.write(posor);
servo_verticale.attach(5);
servo_verticale.write(posve);
Serial.begin (19200);
Serial.print (“Finished setup\n”);
Wire.begin (); // join i2c bus with address 0x52
nunchuck_init (); // send the initilization handshake
}
void
nunchuck_init ()
{
Wire.beginTransmission (0x52); // transmit to device 0x52
Wire.send (0x40); // sends memory address
Wire.send (0x00); // sends sent a zero.
Wire.endTransmission (); // stop transmitting
}
void
send_zero ()
{
Wire.beginTransmission (0x52); // transmit to device 0x52
Wire.send (0x00); // sends one byte
Wire.endTransmission (); // stop transmitting
}
void
loop ()
{
if (wait < millis()){
wait = millis() + 100;
Wire.requestFrom (0x52, 6); // request data from nunchuck
while (Wire.available ())
{
outbuf[cnt] = nunchuk_decode_byte (Wire.receive ()); // receive byte as an integer
digitalWrite (ledPin, HIGH); // sets the LED on
cnt++;
}
// If we recieved the 6 bytes, then go print them
if (cnt >= 5)
{
print ();
}
cnt = 0;
send_zero (); // send the request for next bytes
}
//Comando led con il pulsante C
if (c_button == 0){
digitalWrite(led, HIGH);
}
else if (c_button == 1){
digitalWrite(led, LOW);
}
//Comando servomotori
if (z_button == 1){
if (waitservo < millis()){
waitservo = millis() + 10;
//Servo orizzontale
posor = map(joy_x_axis, 0, 255, 0, 180);
servo_orizzontale.write(posor);
//Servo verticale
posve = map(joy_y_axis, 0, 255, 0, 180);
servo_verticale.write(posve);
}
}
else if (z_button == 0){
if (waitservo < millis()){
waitservo = millis() + 10;
//Servo orizzontale
posor = map(accel_x_axis, 300, 700, 0, 180);
servo_orizzontale.write(posor);
//Servo verticale
posve = map(accel_y_axis, 300, 700, 0, 180);
servo_verticale.write(posve);
}
}
}
// 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
print ()
{
joy_x_axis = outbuf[0];
joy_y_axis = outbuf[1];
accel_x_axis = outbuf[2] * 2 * 2;
accel_y_axis = outbuf[3] * 2 * 2;
accel_z_axis = outbuf[4] * 2 * 2;
z_button = 0;
c_button = 0;
// 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]
if ((outbuf[5] >> 0) & 1)
{
z_button = 1;
}
if ((outbuf[5] >> 1) & 1)
{
c_button = 1;
}
if ((outbuf[5] >> 2) & 1)
{
accel_x_axis += 2;
}
if ((outbuf[5] >> 3) & 1)
{
accel_x_axis += 1;
}
if ((outbuf[5] >> 4) & 1)
{
accel_y_axis += 2;
}
if ((outbuf[5] >> 5) & 1)
{
accel_y_axis += 1;
}
if ((outbuf[5] >> 6) & 1)
{
accel_z_axis += 2;
}
if ((outbuf[5] >> 7) & 1)
{
accel_z_axis += 1;
}
Serial.print (joy_x_axis, DEC);
Serial.print (“\t”);
Serial.print (joy_y_axis, DEC);
Serial.print (“\t”);
Serial.print (accel_x_axis, DEC);
Serial.print (“\t”);
Serial.print (accel_y_axis, DEC);
Serial.print (“\t”);
Serial.print (accel_z_axis, 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;
}