ultimo aggiornamento 2 marzo 2012


 

Com'è fatto il Nunchuck

Il controller Nunchuck della Nintendo Wii e' un ottimo accessorio di controllo. Ha switches, joystick e un accelerometro, tutto in un comodo package.   Il Nunchuk è identificato con una  costante a 16-bit 0x0000 (0xFEFE criptato) al registro 0xa400fe indirizzo.   Fornisce i dati di accelerazione a tre assi, due pulsanti digitali e uno stick analogico XY.

Formato dei dati

Il controller Nunchuck  trasmette le sue informazioni come 6 byte di dati, leggibile a 0xa40008 e in continuo utilizzando un formato di dati che includono byte Extension (i byte inutilizzati sono pieni di 0x00). Il dato è confezionato in sei byte nel modo seguente (dopo la decrittografia)

 

Bit

Byte 7 6 5 4 3 2 1 0
0

SX <7:0>

1 SY <7:0>
2 AX <7:0>
3 SY <9:2>
4 SZ <9:2>
5 SZ <1:0> AY <1:0> AX <1:0> BC BZ
Dove:
  • SX, SY sono i valori analogici delle posizioni X e Y dello Stick
  • AX, AY, e AZ sono i dati dell'accelerometro 10-bit
  • AC e BZ sono lo stato dei pulsanti C e Z (0 = premuto).

I valori restituiti dalla stick analogico del Nunchuk non comprendono tutta la gamma possibile, ma piuttosto sono i limiti superiori e inferiori.
Lo Stick analogico restituisce per il dato X valori da circa 35 (completamente a sinistra) a 228 (completamente a destra), mentre per il valore Y da circa 27 a 220. Centro per entrambi è di circa 128.
I dati accelerometrici sono compresi nell'intera gamma di 0-1024. Tuttavia, l'intera gamma è visto solo quando si spostano o ruotando il Nunchuk bruscamente.
Per misurare la rotazione nello spazio, i limiti si applicano la seguente approssimazione: X va da circa 300 (completamente inclinata a sinistra) a 740 (a destra inclinato), inizia a trasformare ulteriormente portando il valore più vicino a 512 (posizione neutra).
Allo stesso modo, Y passa da circa 280 (inclinato all'indietro) a 720 (in avanti). Z va da 320 (a testa in giù) a 760 (a destra in alto).

 

Hardware

Il controller Nunchuck  ufficiale di Nintendo è cablato elettricamente in modo molto semplice. Ha un unico joystick composto da un potenziometro da 30KΩ per asse, due switch, un chip accelerometro e un microcontrollore.

Funzione  

Componente

C

Pulsante a membrana

Z

Pulsante a membrana

Joystick X

potenziometro assiale, 30KΩ

Joystick Y

potenziometro assiale, 30KΩ

Accelerometro  

ST 8XRJ 3L02AE 820 MLT

Microcontroller

FNURVL 405 849KM

I potenziometri joystick sembrano essere collegati in parallelo. Il chip accelerometro è il modello LIS3L02 da STMicroelectronics.    Il chip microcontrollore sembra essere un  NEC (ora Renesas) uDP78F05 microcontrollore, o un equivalente pin-compatibile.

Informazioni tecniche del sensore a 3 assi

Tensione di alimentazione

da 2.4 a 3.6V

Range:  

+/-2g

Sensibilità

Vdd/5 V/g

Livello di zero

Vdd/2 V

Massima accelerazione  

10000g per 0.1ms, or 3000g for 0.5ms

Foto della scheda interna al controller

nunchunk circuito interno lato processore.jpg nunchunk circuito interno.jpg
Lato processore Lato accelerometro e Joystik

Adattatore per Nunchuck

Per il collegamento alla scheda Arduino, essendo un un peccato rovinare il connettore è possibile utilizzare appositi adattatori

Caratteristiche:

Codice SKU: 31040 Codice 031040

 

 

Componenti del kit, basetta, e due connettori 4 pin uno mascio e uno femmina

Montaggio del primo connettore maschio

Montaggio del connettore femmina

E' così terminato il montaggio dell'adattatore

 

Shield d'interfaccia

Lo shield d'interfaccia è estremamente semplice limitandosi ad alcuni connettori, un pulsante connesso al pin di reset, e due normali diodi che con la loro caduta di tensione riducono la tensione di +5V prelevata dalla scheda Arduino a quella di circa +3,8V che serve per alimentare, il controller Nunchuck.

 

Costruzione della scheda

Vista la semplicità dello schema, il montaggio potrà essere fatto utilizzando uno spezzone di basetta millefori dalle dimensioni di 35x53 mm (13x20 fori); se si optasse invece per la realizzazione di un apposto circuito stampato si potrà scaricare il PDF che riporta la traccia in scala 1:1. Per la sua realizzazione si utilizzerà una basetta in vetronite (monofaccia) di dimensioni 35x53mm circa, il metodo potrà essere quello della fotoincisione o del trasferimento termico utilizzando i cosiddetti fogli blu (PRESS-N-PELL).   Una volta inciso il rame, si verificherà in controluce o mediante l’utilizzo di un multimetro, che non vi siano cortocircuiti soprattutto tra le piste più vicine. Si passerà quindi alla foratura della stessa, utilizzando principalmente una punta da 0,8-1 mm.
Quindi si posizioneranno e salderanno i componenti seguendo lo schema riportato sotto.  Per la saldatura si utilizzerà un piccolo saldatore a punta fine, della potenza di circa 25 – 30 W.

Si inizierà montando i ponticelli, i diodi ricordando che quest’ultimi sono polarizzati, controllare la posizione della fascia sul loro corpo. Si proseguirà con il pulsante e si terminerà montando i vari connettori. Si è così concluso il montaggio della scheda.

nunchunk esempio uso.jpg

 

Altro esempio di utilizzo tratto da internet

Programma di gestione

Il programma qui presentato permette di azionare un dispositivo Pan & Tilt che può essere auto costruito seguendo le indicazioni riportate in questa pagina


Programma

/*
Programma:Comando_telecamera_Nunchuk.pde
 Versione: 1.0
 Comando dispositivo Pan & Tilt tramite Nunchuk
 di Adriano Gandolfo
 
 Configuazione delle porte per la gestione della  "WII NUNCHUCK"
 SDA sur port P18 (ANA4)
 SCK sur port P19 (ANA5)
 Lettura dei valeuri min e max
 Joystick X: mini=26 maxi=219 ==> a riposo  = 123
 Joystick Y: mini=31 maxi=229 ==> a riposo = 129
 Bottone C=1 a riposo C=0 premuto
 Bottone Z=1 a riposo Z=0 premuto
 */

#include <Wire.h>
#include <string.h>
#include <stdio.h>

uint8_t outbuf[6];

int cnt = 0;
int ledPin = 13;

int servoPin2 = 5; // Pin servo Rotazione telecamera
int servoPin  = 6; // Pin servo Rotazione base

int pulseWidth = 0;
int pulseWidth2 = 0;

long lastPulse = 0;
long lastPulse2 = 0;

int z_button = 0;
int c_button = 0;

int refreshTime = 20;

int minPulse   = 200; //
int minPulse2  = 200;
int zeroPulse  = 400; // Azzeramento posizione servo Rotazione base
int zeroPulse2 = 350; // Azzeramento posizione Rotazione telecamera


int dtime=10;

#define pwbuffsize 10
long pwbuff[pwbuffsize];
long pwbuffpos = 0;
long pwbuff2[pwbuffsize];
long pwbuffpos2 = 0;

void setup()
{
  Serial.begin (9600);
  Wire.begin ();
  nunchuck_init ();
  pinMode(servoPin, OUTPUT);
  pinMode(servoPin2, OUTPUT);

  pulseWidth = minPulse;
  pulseWidth2 = minPulse2;
  Serial.print ("Impostazione terminata");
}

void nunchuck_init()
{
  Wire.beginTransmission (0x52);
  Wire.send (0x40);
  Wire.send (0x00);  
  Wire.endTransmission ();
}

void send_zero()
{
  Wire.beginTransmission (0x52);
  Wire.send (0x00);
  Wire.endTransmission ();
}

int t = 0;

void loop()
{
  t++;
  long last = millis();

  if( t == 1) {

    t = 0;

    Wire.requestFrom (0x52, 6);

    while (Wire.available ()) {
      outbuf[cnt] = nunchuk_decode_byte (Wire.receive ());
      digitalWrite (ledPin, HIGH);
      cnt++;
    }

    if (cnt >= 5) {

      printNunchuckData();

      int z_button = 0;
      int c_button = 0;

      if ((outbuf[5] >> 0) & 1) 
        z_button = 1;
      if ((outbuf[5] >> 1) & 1)
        c_button = 1;

      switch (c_button) {
      case 1:
        switch (z_button) {
        case 0:
          break;
        case 1:
          muovi();
          break;
        }
        break;
      case 0:
        switch (z_button) {
        case 0:
          delay(10000);
          break;
        case 1:
          delay(3000);
          break;
        }
        break;
      }
    }

    cnt = 0;
    send_zero();

  } // if(t==)

  updateServo();

  delay(dtime);
}


void updateServo() {

  if (millis() - lastPulse >= refreshTime) {

    digitalWrite(servoPin, HIGH);
    delayMicroseconds(pulseWidth);
    digitalWrite(servoPin, LOW);

    digitalWrite(servoPin2, HIGH);
    delayMicroseconds(pulseWidth2);
    digitalWrite(servoPin2, LOW);

    lastPulse = millis();
  }
}

int i=0;
void printNunchuckData()
{
  int joy_x_axis = outbuf[0];
  int joy_y_axis = outbuf[1];
  int accel_x_axis = outbuf[2]; // * 2 * 2; 
  int accel_y_axis = outbuf[3]; // * 2 * 2;
  int accel_z_axis = outbuf[4]; // * 2 * 2;

  int z_button = 0;
  int c_button = 0;

  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 (i,DEC);
  Serial.print ("\t");

  Serial.print ("X: ");
  Serial.print (joy_x_axis, DEC);
  Serial.print ("\t");

  Serial.print ("Y: ");
  Serial.print (joy_y_axis, DEC);
  Serial.print ("\t");

  Serial.print ("Tasto Z: ");
  Serial.print (z_button, DEC);
  Serial.print (" ");
  Serial.print ("Tasto C: ");
  Serial.print (c_button, DEC);
  Serial.println ("");
  i++;
}

char nunchuk_decode_byte (char x)
{
  x = (x ^ 0x17) + 0x17;
  return x;
}

void muovi (){
  float tilt  = (zeroPulse - outbuf[0]);
  float tilt2 = (zeroPulse2 - outbuf[1]);

  tilt = (tilt);
  pulseWidth = (tilt * 5) + minPulse;

  tilt2 = (tilt2);
  pulseWidth2 = (tilt2 * 5) + minPulse2;

  pwbuff [pwbuffpos]  = pulseWidth;
  pwbuff2[pwbuffpos2] = pulseWidth2;

  if( ++pwbuffpos == pwbuffsize ) pwbuffpos = 0;
  if( ++pwbuffpos2 == pwbuffsize ) pwbuffpos2 = 0;


  pulseWidth=0;
  pulseWidth2=0;

  for( int p=0; p<pwbuffsize; p++ ){
    pulseWidth += pwbuff[p];
    pulseWidth2 += pwbuff2[p];
  }

  pulseWidth /= pwbuffsize;
  pulseWidth2 /= pwbuffsize;

}

 

Elenco revisioni
02/03/2012 Aggiornato pagina
21/02/2012 Aggiornato pagina, inserito descrizione scheda, inserito programma.
16/10/2011 Inserito filmato
16/01/2011 Emissione preliminare