nunchuck e motion plus

Hola,
ieri stavo testando un algoritmo per i giroscopi per ma imu a 6 gradi di libertà (3 accelerometro e 3 giroscopio), quando mi sono accorto che uno dei giroscopi non funziona bene. Quindi ho comprato un motion plus.
Si utilizza con il bus i2c e fin quì tutto ok. Ora però devo usarlo insieme ad un nunchuck, anch'esso in i2c. li ho collegati in parallelo (giusto?) a vcc, sda, scl e gnd.
ho poi recuperato il codice, che però non sembra funzionare. Non so se questo sia dovuto al fatto che il nunchuck non è originale (ma mi pare strano, altrimenti la wii come fa?)e quindi volevo sapere se qualcuno ha provato, o se i collegamenti sono corretti.
Il codice l'ho preso quì: voidbot.net purtroppo il nunchuck è già smontato e quindi non riesco a collegarlo come in figura (nel retro del motion plus), e non possiedo il cacciavite perticolare richiesto per aprire il motion plus.

Suggerimenti? le viti sono a Y, ovvero stella a 3 punte, più tardi vedo se ce l'ha il ferramenta sotto casa :slight_smile:

vi tengo informati, se avete suggerimenti sono tutto orecchi :slight_smile:

collegarlo sul retro è meglio perchè a quanto so hanno stesso inidirizzo I2C e non è possibile settarlo.

infatti tutti quelli che fanno i quadricotteri lo collegano dietro :stuck_out_tongue:

attento che alcuni cloni del WMP funzionano a 400Hz invece che 100Hz come l'originale sull'i2C e vanno alimentati a 3.3 e non 5V

anche il nunchuck va alimentato a 3,3V

per le viti io usato un cacciavite piatto molto piccolo tanto la scocca non l'avrei più riutilizzata :smiley:

si, l'indirizzo infatti è lo stesso, mi pare che il tutto usi una tecnologia fuori standard, o meglio uno standard della nintendo. Il WMP è originale, e dagli esperimenti viaggia tranquillo sia a 100kHz che a 400kHz! stessa cosa il nunchuck non originale, quindi proverò a farli girare a 400kHz, così da non avere un calo di letture al secondo, poichè dubito che andare a 100kHz sia comunque vantaggioso rispetto a 3 letture analogiche.

lesto:
Hola,
ieri stavo testando un algoritmo per i giroscopi per ma imu a 6 gradi di libertà (3 accelerometro e 3 giroscopio), quando mi sono accorto che uno dei giroscopi non funziona bene. Quindi ho comprato un motion plus.
Si utilizza con il bus i2c e fin quì tutto ok. Ora però devo usarlo insieme ad un nunchuck, anch’esso in i2c. li ho collegati in parallelo (giusto?) a vcc, sda, scl e gnd.
ho poi recuperato il codice, che però non sembra funzionare. Non so se questo sia dovuto al fatto che il nunchuck non è originale (ma mi pare strano, altrimenti la wii come fa?)e quindi volevo sapere se qualcuno ha provato, o se i collegamenti sono corretti.
Il codice l’ho preso quì: voidbot.net purtroppo il nunchuck è già smontato e quindi non riesco a collegarlo come in figura (nel retro del motion plus), e non possiedo il cacciavite perticolare richiesto per aprire il motion plus.

Suggerimenti? le viti sono a Y, ovvero stella a 3 punte, più tardi vedo se ce l’ha il ferramenta sotto casa :slight_smile:

vi tengo informati, se avete suggerimenti sono tutto orecchi :slight_smile:

Non so se ti può essere d’aiuto, ma questo codice per il nunchuck sicuramente funziona:

// Piedinatura per Joystick 
//
//     3
//     |       tasto C = 8
//   5- -6     tasto Z = 7
//     |
//     11
//
// Collegamenti connettore Nunchuck
// GIALLO = A5
// VERDE = A4
// ROSSO = 3.3
// BIANCO = GND
//
// Collegamenti LED e servocomandi
// BLU (UP) = 3
// VERDE (LEFT) = 5
// ARANCIO (DOWN) = 11
// GIALLO (RIGHT) = 6
// ARANCIO/NERO (C) = 8
// GIALLO/NERO (Z) = 7
//
// Collegamento servocomando
// Asse X = 9
// Asse Y = 10

#include <Wire.h>
#include <Servo.h>

#define  up        3
#define  down     11
#define  left      5
#define  right     6
#define  cbutton   8
#define  zbutton   7

uint8_t  buf[6];    
int      cnt=0;         

Servo    srvx;
Servo    srvy;

uint8_t nunchuk_decode(uint8_t x) 
{
  return (x^0x17)+0x17;           
}

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


void setup()                      
{
  int n;
  
  Serial.begin(115200);

  for(n=0; n<6; n++) buf[n]=0;    

  Wire.begin();                    
  
  Wire.beginTransmission(0x52);    
  Wire.send(0x40);
  Wire.send(0);
  Wire.endTransmission();

  srvx.attach(9);
  srvy.attach(10);
  
  pinMode(cbutton, OUTPUT);
  pinMode(zbutton, OUTPUT);
  pinMode(up, OUTPUT);
  pinMode(down, OUTPUT);
  pinMode(left, OUTPUT);
  pinMode(right, OUTPUT);
  
  analogWrite(up, 0);
  analogWrite(down, 0);
  analogWrite(left, 0);
  analogWrite(right, 0);
}


void loop()               
{
  int n, x ,y;
  
  Wire.requestFrom(0x52, 6); 
  while(Wire.available())    
  {
    buf[cnt++] = nunchuk_decode(Wire.receive());
  }

  if(cnt>=6)                 
  {
    // Asse X
    n=(buf[2]<<2)+((buf[5]>>2)&3)-524;  // accel X
    n = map(n,-200,200, 0, 180);
    srvx.write(n);
  
    // Asse Y
    n=(buf[3]<<2)+((buf[5]>>4)&3)-597;  // accel Y
    n = map(n,-200,200, 0, 180);
    srvy.write(n);
/*    
    // Asse Z
    n=(buf[4]<<2)+((buf[5]>>6)&3); //-668;  // accel Z
    n = map(n,-150,150, 0, 180);
    srvz.write(n);
*/
 
    x = buf[0]-127;
    y = buf[1]-127;
 
    if (y > 10) digitalWrite(up, HIGH);
    else digitalWrite(up, LOW);
 
    if (y < -10) digitalWrite(down, HIGH);
    else digitalWrite(down, LOW);
  
    if (x > 10) digitalWrite(right, HIGH);
    else digitalWrite(right, LOW);

    if (x < -10) digitalWrite(left, HIGH);
    else digitalWrite(left, LOW);
 
    digitalWrite(zbutton, buf[5]&1 ? LOW : HIGH);
    digitalWrite(cbutton, buf[5]&2 ? LOW : HIGH);

    cnt=0;                   
    nunchuck_ack();          
    delay(10);                 
    }
}

Il risultato è questo:

Magari prova a vedere anche questo, potrebbe aiutarti: http://www.multiwii.it/come-preparare-il-nunchuck/

Spero di esserti stato di aiuto.
Ciao.

il nunchuck già funziona, anzi il tuo codice ha bisogno di alcuni cambiamenti perchè essendo il mio nun non originale, usa dei valori di inizializzazione diversi. Ma quando usato come "schiavo" del motion plus, allora non necessita di inizializzazione perchè ci pensa il wmp

finalmente son riuscito ad aprire il WMP, ho trapano la testa delle viti e poi si è aperto abbastanza facilemente. stasera col fresco mi dedico al “saldaggio”, poi vi faccio sapere.

allora, ho finalmente collegato il nunchuck al motion plu seguendo questo schema:
poi ho collegato il wmp all'arduino così tramite VCC, GND, SDA e SCL.
Riesco a leggere tranquillamente il WMP, ma il nunchuck non restituisce valori. probabilmente il fatto deriva da una diversa inizializzazione o codice di richiesta. Il nunchuck viene rilevato, c'è un bit apposito che va ad 1

vedete che i multicotteri servono anche fuori dal loro ambito? ]:smiley:

veramente è per il quadricottero. A quanto pare i giroscopi analogici che usavo erano veramente pessimi :smiley:

nei multicotteri rientrano anche i quadricotteri ma quel setup vale anche per hexa, octo e tri :stuck_out_tongue:

lesto:
poi ho collegato il wmp all'arduino così tramite VCC, GND, SDA e SCL.

Le hai messe le due pull up da 3.3k su SDA e SCL verso il +3.3V ?

Riesco a leggere tranquillamente il WMP, ma il nunchuck non restituisce valori. probabilmente il fatto deriva da una diversa inizializzazione o codice di richiesta. Il nunchuck viene rilevato, c'è un bit apposito che va ad 1

Che address usi per il nunchuk e per il m.p. ?

lesto:
allora, ho finalmente collegato il nunchuck al motion plu seguendo questo schema:
poi ho collegato il wmp all'arduino così tramite VCC, GND, SDA e SCL.
Riesco a leggere tranquillamente il WMP, ma il nunchuck non restituisce valori. probabilmente il fatto deriva da una diversa inizializzazione o codice di richiesta. Il nunchuck viene rilevato, c'è un bit apposito che va ad 1

Attenzione che in questa configurazione, il motion plus e nunchuck vengono alimentati dal pin 12 a 5V ed effettivamente molti hanno problemi.
Di solito si risolve mettendo 2 diodi in serie per creare una caduta di tensione.
Ciao.

ok, mangano le pull up, e alimento tutto a 5V. Il numchuck e il WMP utilizzando lo stesso indirizzo, e si usa una modalità detta “pass through”. Posto il codice che mi sembra ottimo per capire cosa succede:

// .......................................................................
// Code for reading data from a Wii Motion plus device connected to a Nunchuck
// Links to other sites
// http://www.windmeadow.com/node/42   .... first time i saw arduino nunchuk interface
// http://www.kako.com/neta/2009-017/2009-017.html# .....Japanese site with lots of Wii info
// http://wiibrew.org/wiki/Wiimote/Extension_Controllers#Wii_Motion_Plus    .... the one and only
// http://randomhacksofboredom.blogspot.com/2009/06/wii-motion-plus-arduino-love.html
// ....original motion plus but not passthrough
// http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1248889032/35   .... great Kalman filter code
// thanks to duckhead and knuckles904. I will be using that code for sure.
// http://obex.parallax.com/objects/471/   .... ideas for passthrough
// by Krulkip
// Here is the bitmapping which is changed from the standard nunchuk mapping
// In Nunchuk mode:
//	    Bit
// Byte     7	 6	 5	 4	 3	 2	 1	 0
// 0	 SX<7-----------------------------------------------------0>
// 1	 SY<7-----------------------------------------------------0>
// 2	 AX<9-----------------------------------------------------2>
// 3	 AY<9-----------------------------------------------------2>
// 4	 AZ<9---------------------------------------------3>	1
// 5	 AZ<2-----1>     AY<1>   AX<1>   BC	BZ	 0	 0
// Please note also the loss of the bit0 resolution.
// Byte 5 Bit 0 and 1 is used for nunchuk (0 0) = nunchuk or motion plus  (1 0) is motion plus detection.
// Byte 4 Bit 0 which is the extention controller detection bit. (1 = extension present)
// Hardware Arduino with ATMega 168
// Connections SCA to AD4 (Analog4) and SCL to AD5 (Analog5)
//........................................................................
#include <Wire.h>
#include <string.h>
#include <stdio.h>
uint8_t outbuf[6];		// array to store arduino output
int cnt = 0;
int ledPin = 13;
int xID;
void
setup (){
  Serial.begin (19200);
  Wire.begin();
  Serial.print ("Finished setup\n");
  Serial.print ("Now detecting WM+\n");
  delay(100);
  // now make Wii Motion plus the active extension
  // nunchuk mode = 05, wm+ only = 04, classic controller = 07
  Serial.print ("Making Wii Motion plus the active extension in nunchuk mode = 05 ........");
  Wire.beginTransmission(0x53);
  Wire.send(0xFE);
  Wire.send(0x05);// nunchuk
  Wire.endTransmission();
  Serial.print (" OK done");
  Serial.print ("\r\n");
  delay (100);
  // now innitiate Wii Motion plus
  Serial.print ("Innitialising Wii Motion plus ........");
  Wire.beginTransmission(0x53);
  Wire.send(0xF0);
  Wire.send(0x55);
  Wire.endTransmission();
  Serial.print (" OK done");
  Serial.print ("\r\n");
  delay (100);
  Serial.print ("Set reading address at 0xFA .......");
  Wire.beginTransmission(0x52);
  Wire.send(0xFA);
  Wire.endTransmission();
  Serial.print(" OK done");
  Serial.print ("\r\n");
  delay (100);
  Wire.requestFrom (0x52,6);
  outbuf[0] = Wire.receive();
  Serial.print(outbuf[0],HEX);
  Serial.print(" ");
  outbuf[1] = Wire.receive();
  Serial.print(outbuf[1],HEX);
  Serial.print(" ");
  outbuf[2] = Wire.receive();
  Serial.print(outbuf[2],HEX);
  Serial.print(" ");
  outbuf[3] = Wire.receive();
  Serial.print(outbuf[3],HEX);
  Serial.print(" ");
  outbuf[4] = Wire.receive();
  Serial.print(outbuf[4],HEX);
  Serial.print(" ");
  outbuf[5] = Wire.receive();
  Serial.print(outbuf[5],HEX);
  Serial.print(" ");
  Serial.print ("\r\n");
  xID= outbuf[0] + outbuf[1] + outbuf[2] + outbuf[3] + outbuf[4] + outbuf[5];
  Serial.print("Extension controller xID = 0x");
  Serial.print(xID,HEX);
  if (xID == 0xCB) { 
    Serial.print (" Wii Motion plus connected but not activated"); 
  }
  else if (xID == 0xCE) { 
    Serial.print (" Wii Motion plus connected and activated"); 
  }
  else if (xID == 0x00) { 
    Serial.print (" Wii Motion plus not connected"); 
  }
  else{
    Serial.print (" Unkonw command:");
    Serial.print (xID, HEX);
  }
  Serial.print ("\r\n");
  delay (100);
  // Now we want to point the read adress to 0xa40008 where the 6 byte data is stored
  Serial.print ("Set reading address at 0x08 .........");
  Wire.beginTransmission(0x52);
  Wire.send(0x08);
  Wire.endTransmission();
  Serial.print(" OK done");
  Serial.print ("\r\n");
}

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

void loop (){
  // now follows conversion command instructing extension controller to get
  // all sensor data and put them into 6 byte register within the extension controller
  send_zero (); // send the request for next bytes
  delay (100);
  Wire.requestFrom (0x52,6);
  outbuf[0] = Wire.receive();
  outbuf[1] = Wire.receive();
  outbuf[2] = Wire.receive();
  outbuf[3] = Wire.receive();
  outbuf[4] = Wire.receive();
  outbuf[5] = Wire.receive();
  print ();
  cnt = 0;

}

void print (){
  // check if nunchuk is really connected
  if ((outbuf[4]&0x01)==0x01) {
    Serial.print("Ext con: ");
  }
  else{
    Serial.print("No Ext con: ");
    Serial.println(outbuf[4], BIN);
  }

  if ((outbuf[5]&0x03)==0x00) {
    int joy_x_axis = outbuf[0];
    int joy_y_axis = outbuf[1];
    int accel_x_axis = (outbuf[2] << 2) + ((outbuf[5] >> 3) & 2);
    int accel_y_axis = (outbuf[3] << 2) + ((outbuf[5] >> 4) & 2);
    int accel_z_axis = (outbuf[4] << 2) + ((outbuf[5] >> 5) & 6);
    int z_button = (outbuf[5]>>2) & 1;
    int c_button = (outbuf[5]>>3) & 1;
    Serial.print ("joyx= ");
    Serial.print (joy_x_axis, HEX);
    Serial.print ("  joyy=");
    Serial.print (joy_y_axis, HEX);
    Serial.print ("  accx= ");
    Serial.print (accel_x_axis, HEX);
    Serial.print ("  accy= ");
    Serial.print (accel_y_axis, HEX);
    Serial.print (" accz= ");
    Serial.print (accel_z_axis, HEX);
    Serial.print ("  ");
    if (z_button == 0) { 
      Serial.print ("z_button "); 
    }
    if (c_button == 0) { 
      Serial.print ("c_button "); 
    }
    Serial.print ("\r\n");
  }
  else if  ((outbuf[5]&0x03)==0x02) {
    int yaw = (((outbuf[5]&0xFC)<<6) + outbuf[0]);
    int pitch = (((outbuf[4]&0xFC)<<6) + outbuf[1]);
    int roll = (((outbuf[3]&0xFC)<<6) + outbuf[2]);
    Serial.print ("yaw= ");
    Serial.print (yaw);
    Serial.print ("  pitch= ");
    Serial.print (pitch);
    Serial.print ("  roll= ");
    Serial.print (roll);
    Serial.print ("\r\n");
  }
  else{
    Serial.print ("Unkow code:");
    Serial.print ( (outbuf[5]&0x03), HEX );
    Serial.print ("\r\n");
  }
}

lesto:
ok, mangano le pull up, e alimento tutto a 5V

Ma perché ti devi fare male da solo ? :grin:
Su Arduino hai disponibile il pin per l'alimentazione a 3.3V, non vedo per quale motivo devi torturare quei poveri componenti elettronici alimentandoli a 5V.

astrobeed:

lesto:
ok, mangano le pull up, e alimento tutto a 5V

Ma perché ti devi fare male da solo ? :grin:
Su Arduino hai disponibile il pin per l'alimentazione a 3.3V, non vedo per quale motivo devi torturare quei poveri componenti elettronici alimentandoli a 5V.

Nel progetto multiwii è stata abbandonata questa possibilità perchè dava dei problemi, si è preferito usare il pin 12 a 5v e mettere 2 diodi in serie per l'abbattimento di tensione.
Cosa che io non ho mai fatto perchè sono passato direttamente a freeimu.

Stefanoxjx:
Nel progetto multiwii è stata abbandonata questa possibilità perchè dava dei problemi, si è preferito usare il pin 12 a 5v e mettere 2 diodi in serie per l'abbattimento di tensione.

Questa è quasi peggio :smiley:
Se i 3.3V sono ricavati dal generatore interno del FTDI presente su Arduino 2009 in effetti possono verificarsi problemi per via della poca corrente erogabile, circa 50 mA, però lo stesso problema lo si ha utilizzando un gpio di Arduino per prelevare 5V, ridotti a poco più di 3 con i due diodi in serie, visto che la corrente prelevabile è pure minore, max 40 mA e per giunta la tensione cala sensibilmente con la corrente.
La soluzione era prendere i 5V dal relativo connettore di Arduino e mettere su questa i due diodi in serie, sulla UNO il problema non si pone perché i 3.3V dispongono di un regolatore dedicato che può erogare svariate centinaia di mA.

loro usano un pin digitale per poter resettare i sensori "al volo"... ammetto che è una triste idea.
E comunque così facendo lo alimento a 3,3v(credo che potrei fare un partitore di tensione, diodi sotto mano non ne ho, oppure posso mettere un 7805 che col drop-out se di input ci do 5v ne spara fuori 3V... o dite che il 7805 "sfasa"?)

ma comunque dovrei farlo anche per i segnali no? non è peggio se alimenti a 3,3 e poi i segnali arrivano a 5v? e quì per forza partitore perchè il cavo dati è bidirezionale, giusto? Una cosa ho notato, l'xID che ottengo è CD, che non è previsto (funzione setup)

più tardi provo a dare un'occhiata al codice multiwii, per vedere che codici usa

lesto:
loro usano un pin digitale per poter resettare i sensori "al volo"... ammetto che è una triste idea.

C'è un comando apposto per il reset da inviare tramite I2C.

oppure posso mettere un 7805 che col drop-out se di input ci do 5v ne spara fuori 3V... o dite che il 7805 "sfasa"?)

Lascia perdere, non è una soluzione.

ma comunque dovrei farlo anche per i segnali no? non è peggio se alimenti a 3,3 e poi i segnali arrivano a 5v? e quì per forza partitore perchè il cavo dati è bidirezionale, giusto? Una cosa ho notato, l'xID che ottengo è CD, che non è previsto (funzione setup)

La tensione sulla I2C dipende dalle resistenze di pull up, sono uscite di tipo open drain, ecco perchè ti ho chiesto se hai messo le pull up al 3.3V, su alcune versioni del nunchuk le pull up ci sono di serie, facilmente verificabile misurando la tensione su SDA e SCL che deve essere a 3.3V in condizioni di riposo.

ho fatto un paio di esperimenti veloci che poi devo uscire.
Allora ho messo in pratica il partitore di tensione, ma qualcosa non mi quadra:
esperimento 1: r1=r2=680ohm
arrivano giusti 3,3V, ma se collego il wmp e misuro la tensione, leggo 2.13v
allora
esperimento 2:r1=220ohm, r2=680ohm
leggo 4v, ma quando collego il wmp leggo 1,88V!
forse devo usare resistenze più grosse?

tengo a precisare che le tensioni su SCL e SDA sono == alle tensioni in ingresso

Ah ovvimente il wmp non funziona con quetse 2 tensioni, credo che l'1 logico non venga letto perchè inferiore ai 2.5v e quindi "sembra" 0.

ah NON ho una board arduino, ma un atmega 328 stand alone.

Ah sia il nun che il wmp a 5v e da soli funzionano... uff non so che pesci pigliare

lesto:
ho fatto un paio di esperimenti veloci che poi devo uscire.
Allora ho messo in pratica il partitore di tensione, ma qualcosa non mi quadra:

Te l'ho spiegato nel precedente post, le due linee per l'I2C sono bidirezionali e sono del tipo open drain, ovvero il pin può solo chiudere verso GND la linea interessata, la condizione di uno logico è determinata dalla resistenza di pull up e il livello di tensione dalla tensione a cui è agganciata la pull up.
Se alimenti nunchuk e m.p. non solo ti andranno in avaria in tempi brevi, ma ottieni pure letture falsate perché cambia il riferimento per gli ADC dell'elettronica interna ai moduli.
Se fai lavorare l'I2C con le pull up a 5V, con i moduli alimentati a 3.3V, probabilmente non rompi nulla, ma di sicuro il tutto funziona molto male.
Adesso mi spieghi perché ti ostini a voler alimentare a 5V un device che deve essere alimentato a 3.3V ?
Forse credi che i produttori mentono quando sul data sheet scrivono tensione massima in assoluto 3.6V ?