PDA

Afficher la version complète : Programmation Arduino pour Nunchuk .



Sav
21/02/2009, 15h54
Salut les Roboticiens !! :)

Comme le titre l'indique je suis en train de programmer une carte Arduino (Duemilanove) pour exploiter un Nunchuk , une des manettes de la fameuse console Wii .

J'ai trouver le Code qui permet de lire les infos de l'accéléromètre 3 axes et d'autre codes pour faire bouger des servos suivant la position de la manette .

Seulement je voudrais à la place des signaux de commande des servos , un signal analogique 0 / 5 Volts avec 2.5 Volts au neutre (capteur à l'horizontale ) .

Le problème est que je suis une quiche en programmation .

La ligne de code qui me pose probléme :

{
analogWrite(ledPin1,outbuf[3]-50 ) ; //commande en PWM la led1 , j'ai mis -50 à outbuf[3] au hazard .
}

Comme vous pouvez le voir j'y vais au pif car je suis larguer .

Merci d'avoir lu cette tartine , si vous voulez plus d'info sur Arduino+Nunchuk n' hésitez pas !

MadProf
22/02/2009, 20h55
Salut Sav,

Peut tu en dire plus sur ton problème ?
(Quelle est l'erreur, quand se produit-elle...)
Une ligne de code seule n'aide pas beaucoup, il faudrait le reste pour se faire une idée. Là on ne sait pas ce que contient ton tableau "outbuf".

Ta sortie analogique attend une valeur entre 0 et 255. Pour avoir un retour au neutre, dans ton cas il faut que tu envoie la valeur 128 pour avoir 2,5V. Du moins je pense que ça marche ainsi.


++

MadProf

Sav
23/02/2009, 14h36
Salut MadProf , merci d'avoir pris le temps de me répondre

Le probléme est qu'avec cette ligne de code j'ai un signal analogique mais avec de mauvaises valeurs , de téte il est compris entre 1 et 3 volts .

J' hesitais à mettre le code en entier car il prend pas mal de place , je le mettrais ce soir .

Pour outbuf , je ne sait pas l'utiliser, la réponse doit etre sur ce site
http://www.windmeadow.com/node/42 mais ou ? Je suis vraiment paumé .

Il y a bien un tableau au debut (Bit /Description/Values of sample Nunchuk )

En lisant ça :
X-axis acceleration value Min(at 1G):0x48 / Medium(at 1G):0x7D / Max(at 1G):0xB0

Je me dit que 0x48 = 0 ; 0x7D = 128 et 0xB0 = 255 , non ?

PS: mon code est basé sur celui du site http://www.windmeadow.com/node/42 , j'ai juste rajouté la commande d'une led pour visualiser mon signal , je le poste ce soir.

MadProf
23/02/2009, 14h41
C'est bien l'exemple de code que j'avais en tête. Je l'inspecte un peu plus j'essaye de t'envoyer une réponse avant la fin de la journée.

MadProf
23/02/2009, 15h06
Je me dit que 0x48 = 0 ; 0x7D = 128 et 0xB0 = 255 , non ?
Bah non justement il me semble que c'est plutot 0x48 = 72, 0x7D = 125 et 0xB0 =176 (hexa)

Ton nunchuk te renvoi bien en max et en min les valeurs que tu as mis, mais toi tu veux envoyer autre chose à ta sortie analogique de ta carte arduino (entre 0 et 255)
Ton voltage de sortie parait donc tout à fait normal, 72 doit correspondre à peu près à 1V, et 176 à 3V

D'ailleurs, une petite règle de 3 vite fait te donne :

72 ->1.41V
125 ->2.45V
176 ->3.45V

Donc :
y=(22/9)x-(2304/13) où x est ta valeur envoyée par le nunchuck et y ta valeur attendue par ta carte Arduino

Après reste plus qu'à faire une function pour transformer ton résultat, dans le genre :

int out(int x){
y=(22/9)*x-(2304/13);
return y;
}

j'ai mis "dans le genre" car tu peux très bien tomber sur un résultat qui ne sera pas un entier en retour, donc fais un contrôle sur y avant de le retourner.

Vérifie bien la fonction que j'ai écris, je ne suis pas sûr du résultat et j'ai pas le temps de tester je suis au boulot. Si ça se trouve je t'ai dis des grosses co....ies mais c'est ce qui me vient à l'esprit.

Tiens moi au jus.

++

MadProf

Sav
23/02/2009, 19h51
Voici le code , j' espère que ce ne sera pas trop grand :rolleyes:

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

#undef int
#include <stdio.h>

uint8_t outbuf[6]; // array to store arduino output
int cnt = 0;
int ledPin = 13;
int ledPin1 = 11; // Led broche digital PWM 11 pour visualisation du signal


void
setup ()
{
beginSerial (19200);
Serial.print ("Finished setup\n");
Wire.begin (); // join i2c bus with address 0x52
nunchuck_init (); // send the initilization handshake
pinMode(ledPin1, OUTPUT); // configure broche 11 en sortie

}



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 ()
{
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 ();
}
{
analogWrite(ledPin1,outbuf[3] -50 ) ; //commande en PWM la led1 , j'ai mis -50 à outbuf[3] au hazard .
}

cnt = 0;
send_zero (); // send the request for next bytes
delay (100);
}

// 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 ()
{
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;

// 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;
}

Sav
23/02/2009, 20h38
Alors avec ce code en sortie j'ai environ 0.400 Volt à 2.270 Volts avec 1.278 Volts à l'horizontale .

(Petite précision , depuis le début je parle de signal analogique mais en faite le signal que fournit l'Arduino est en PWM .)

Je ne connais pas la fonction "int out" , et d'où viens "22/9" et "2304/13" je suis très très débutant en Programmation ça doit faire 4 semaines que j'ai l'Arduino . Un vrai boulet en fait . :(

MadProf
24/02/2009, 02h00
Essaye ça pour voir si la valeur renvoyée est correcte. J'ai fait rapidement et j'ai pas de nunchuck pour tester, mais j'ai pas d'erreur de compilation c'est déjà çà.
La fonction de conversion faut pas trop regarder sa tête, les matheux rigolerons...

J'ai acheté ma carte arduino y'a 1 mois et demi à peu près comme toi, vraiment c'est sympathique quand on voit le nombre d'applications possibles, particulièrement en modélisme. Et le prix est encourageant ;)

++

MadProf


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

#undef int
#include <stdio.h>

uint8_t outbuf[6]; // array to store arduino output
int cnt = 0;
int ledPin = 13;
int ledPin1 = 11; // Led broche digital PWM 11 pour visualisation du signal
int nouvelleValeur = 128;
int valeurRetour = 128;

void
setup ()
{
beginSerial (19200);
Serial.print ("Finished setup\n");
Wire.begin (); // join i2c bus with address 0x52
nunchuck_init (); // send the initilization handshake
pinMode(ledPin1, OUTPUT); // configure broche 11 en sortie

}



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 ()
{
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 ();
}
{
valeurRetour = nunchuk_decode_byte(outbuf[3]); //je décompose ici volontairement : tu récupère ta donnée sous la forme d'un entier
valeurRetour = conversion(valeurRetour); //ensuite on converti avec la fonction "conversion" en dessous.
analogWrite(ledPin1, valeurRetour) ; //commande en PWM la led1 , j'ai mis -50 à outbuf[3] au hazard .
}

cnt = 0;
send_zero (); // send the request for next bytes
delay (100);
}

//la fonction de conversion (qui doit etre acceptable mais pas parfaite, je peux pas tester j'ai pas de nunchuck :( )
//elle prend un entier compris entre 72 et 176 en parametre, et renvoi un entier compris entre 0 et 255
int conversion (int x){
nouvelleValeur=(int)(2805*x/1144-(2295/13));
return nouvelleValeur;
}

// 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 ()
{
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;

// 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;
}

Sav
24/02/2009, 19h38
Je viens d'essayer ton code , le signal est bizarre la tension ne cesse de varier (1.8 V à 1.5 V avec 1.4 V à l 'horizontale ) il n'est pas proportionnel .

En fait pendant le mouvement du nunchuk la diode clignote "aléatoirement " .
(variation de luminosité , elle ne s'éteint pas)



C'est clair que l'Arduino est sympathique , sur le net il y a plein de projet à base d' Arduino , du jeu de lumière , au pilote automatique d' Avion RC en passant par des Robots en tous genre ...

Et en modélisme j'ai déjà pensé à moult systèmes , notamment pour le Vol en immersion . D'ailleur ce montage me servira à faire bouger la caméra de mon Easystar .

PS: Je te remerci encore pour ton aide , surtout quand je vois l'heure à laquelle tu a posté le code !

MadProf
24/02/2009, 21h37
Oui en y repensant ça ne doit pas fonctionner comme je le pensais. Je jette un œil tout à l'heure. J'ai vu que tu as posté sur le forum Arduino également, il me semble qu'une des réponse donnait une bonne piste.

T'inquiète si je poste tard c'est normal, je me couche jamais avant 2h30 :D

++

MadProf

Sav
24/02/2009, 22h21
Oui j'avais posté sur le forum français Arduino pour savoir si le module était adapté à mon cas puis j'ai dérivé sur mon projet . Et quand j'ai vu la section Robotique ici je me suis dit pourquoi pas .

Justement j'étais en train de relire les réponses sur le forum arduino et tes réponses ici et la documentation sur les fonctions de l'Arduino http://arduino.cc/en/Reference/HomePage pour remettre de l'ordre dans ma tête .

Je commence à cerner un peu mon problème et à comprendre certaines choses , en fin je crois !:rolleyes: Dis moi si je me trompe .

Entre 0 et 255 est un entier qui correspond au duty cycle du signal PWM.
Plus le nombre est grand plus la tension est grande .
Ça ok je connais, mais dans l'automobile on appel ça le "Rapport cyclique" et on l'exprime en pourcentage . C' est une sortie .

J'ai vu aussi une autre "variable" , 0 à 1024 , qui serait en rapport avec un convertisseur analogique/numérique . Cette variable serait une entrée .

Si on a 1024 en entrée (donné par un capteur quelconque ) on aurait 255 en sortie .

Le problème c'est que l'on ne connaît pas la valeur en entier donné par le nunchuk car il nous donne des bytes ? Donc il faudrait connaitre la valeur en entier des bytes reçu (entre 0 et 1024?) et c'est là qu' intervient le produit en crois pour convertir en 0_255 .

C'est bien ça ou je suis complètement a l'ouest ?

Si c'est bien ça , la question est : comment connaitre la valeur d'un byte ?



PS: Je viens de me rendre compte que c'est ce que me disait alxblog sur Arduino FR :rolleyes:

PS2: 0 à 1024 se ne serait pas des octets ? Et 0 à 255 serait les nombres représenté par un octet ?

MadProf
25/02/2009, 02h29
Je commence à cerner un peu mon problème et à comprendre certaines choses , en fin je crois !:rolleyes: Dis moi si je me trompe .

Entre 0 et 255 est un entier qui correspond au duty cycle du signal PWM.
Plus le nombre est grand plus la tension est grande .
Ça ok je connais, mais dans l'automobile on appel ça le "Rapport cyclique" et on l'exprime en pourcentage . C' est une sortie .

J'ai vu aussi une autre "variable" , 0 à 1024 , qui serait en rapport avec un convertisseur analogique/numérique . Cette variable serait une entrée .

Si on a 1024 en entrée (donné par un capteur quelconque ) on aurait 255 en sortie .
Il me semble justement que le nunchuk ne renvoi pas une valeur comprise entre 0 et 1024, mais plutôt entre 72 et 176, mais j'ai peut être pas bien lu.


Le problème c'est que l'on ne connaît pas la valeur en entier donné par le nunchuk car il nous donne des bytes ? Donc il faudrait connaitre la valeur en entier des bytes reçu (entre 0 et 1024?) et c'est là qu' intervient le produit en crois pour convertir en 0_255 .

C'est bien ça ou je suis complètement a l'ouest ?
Dans ton code, sans lire dans le détail, j'ai vu la fonction nunchuk_decode_byte() et j'en ai déduis, peu être trop rapidement, que c'est exactement ce qu'elle faisait...
En fait cette fonction ne nous est pas utile.
Je ne vois pas trop l'intérêt d'un produit en croix, je me suis dit qu'il fallait trouver la fonction qui permet de convertir tes données entre 72 et 176 en des valeurs entre 0 et 255.
J'ai testé çà, qui à l'air de fonctionner :

int conversion (float test){
nouvelleValeur=(int)(255*test/104)-(2295/13);
return nouvelleValeur;
}

J'ai changé la valeur d'entrée "test" d'un int en un float, après avoir lu ceci :

"Programming Tips:

* Know that integer constants default to int, so some constant calculations may overflow (e.g. 60 * 1000 will yield a negative result)."



Voici un code qui "devrai" fonctionner


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

#undef int
#include <stdio.h>

uint8_t outbuf[6]; // array to store arduino output
int cnt = 0;
int ledPin = 13;
int ledPin1 = 11; // Led broche digital PWM 11 pour visualisation du signal
int nouvelleValeur = 128;
int valeurRetour = 128;

void
setup ()
{
beginSerial (9600);
Serial.print ("Finished setup\n");
Wire.begin (); // join i2c bus with address 0x52
nunchuck_init (); // send the initilization handshake
pinMode(ledPin1, OUTPUT); // configure broche 11 en sortie

}



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 ()
{
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 ();
}
{
valeurRetour = conversion(outbuf[3]); // on converti la valeur recue avec la fonction "conversion" en dessous.
analogWrite(ledPin1, valeurRetour) ; //commande en PWM la led1 , j'ai mis -50 à outbuf[3] au hazard .
}

cnt = 0;
send_zero (); // send the request for next bytes
delay (100);
}

//fonction de conversion
//elle prend un float compris entre 72 et 176 en parametre, et renvoi un entier compris entre 0 et 255
int conversion (float test){
nouvelleValeur=(int)(255*test/104)-(2295/13);
return nouvelleValeur;
}

// 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 ()
{
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;

// 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;
}
J'ai testé avec différentes valeurs mais sans nunchuck impossible de dire si c'est bon. En tout cas j'espère que ça fera avancer le schmilblik :D

++

MadProf

Sav
25/02/2009, 20h37
Alors avec ce nouveau code j'ai 2.5 Volts à l'horizontale ! Le signal descend proportionnellement lorsque que j' incline le capteur vers le haut mais arrivé à peu prés à la verticale , il remonte brusquement à 4.8 Volts .

Lorsque j' incline vers le bas le capteur c'est bien l'inverse , le signale varie de 2.5 Volts à quasi 4.8 Volts puis a peu prés à la verticale il redescend brusquement à 0 Volt .

En résumé , j'ai un signal proportionnel sur une rotation du nunchuk d'environ 80 degré . =D

C'est très très bien comme résultat , dans le cadre de mon projet "suiveur de tète" ce doit être acceptable comme signal , mais dans une application du genre "pilotage d'un modèle grâce au nunchuk" ça sera plus délicat .

Je ne voudrait pas t'embêter , tu m'a déjà énormément aidé , mais pourrais tu me dire sur quelle valeur jouer pour élargir la plage de mouvement ?

Je vais essayer d'envoyer se signal à ma radio , résultat dans quelques instant .

Sav
25/02/2009, 21h07
Ça fonctionne avec ma radio mais le servo à la bougeotte , le signal PWM est trop lent , et je n'arrive pas à augmenter la fréquence avec "TCCR1B = 0x09; " pourtant ça fonctionnait bien avec un autre code , je passais de 490Hz à 64KHz . :(

MadProf
25/02/2009, 21h13
Petit conseil, met serial.print() pour voir dans le serial monitor ce que te renvoi réellement le nunchuck :

valeurRetour = conversion(outbuf[3]);
serial.print(outbuf[3]);
serial.print(conversion(outbuf[3]));
analogWrite(ledPin1, valeurRetour) ;

dis moi ce que renvoie le nunchuk avant et après la fonction de conversion

phildc
25/02/2009, 21h31
Glovepie ne peut-il pas aider en montrant les valeurs reçues du Nunchuck ?

http://wiipiicii.blogspot.com/2006/12/glovepie-intgration-du-nunchuk.html

Phil.

MadProf
25/02/2009, 21h40
Je ne connais pas le logiciel que tu cites mais c'est tout à fait çà. Tu peux le faire également avec Processing ou tout autre logiciel qui "monitorera" le port série.
Mais de façon plus simple, le logiciel arduino comprend justement un serial monitor :

http://www.pouliquen-gildas.info/modelisme/photos/arduino/serial_monitor.jpg

Sav
25/02/2009, 21h42
Alors dans le serial monitor j'ai ceci (capteur à l'horizontale , immobile)


Finished setup

255 255 1023 1023 1
1
128 134 503 499 1
1
128 134 503 500 1
1


Je ne sais pas lire ces infos , je ne connaissais pas cette fonction .

Peut tu m'explique brièvement ?

A tiens je connais GlovePie , je l'utilise pour faire fonctionner une Wimote sur mon PC , effectivement avec certain script on vois la valeur d'accélération en G de chaque axe . Je suis pas sur de l'intérêt de ceci pour le cas présent , mais peut être connais tu un script qui nous en dit un peu plus ?

MadProf
25/02/2009, 23h11
Je t'ai envoyé un message, on peut voir ça sur msn si tu veux ça sera plus simple.
J'ai été bien trop vite et j'ai vraiment fait n'importe quoi !

De ce que j'ai compris, ces lignes représentes chacune un ensemble de valeurs reçues par ta carte arduino, suite à sa demande.

La première valeur est l'axe x du stick analogique
La 2eme l'axe y du stick analogique
La 3eme X-axis acceleration value
La 4eme Y-axis acceleration value
La 5eme Z-axis acceleration value
La 6eme le bouton z 1=relaché, 0=pressé
La 7eme le bouton c 1=relaché, 0=pressé

Essaye ça, on va finir par y arriver...


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

#undef int
#include <stdio.h>

uint8_t outbuf[6]; // array to store arduino output
int cnt = 0;
int ledPin = 13;
int ledPin1 = 11; // Led broche digital PWM 11 pour visualisation du signal
int nouvelleValeur = 0;

void
setup ()
{
beginSerial (9600);
Serial.print ("Finished setup\n");
Wire.begin (); // join i2c bus with address 0x52
nunchuck_init (); // send the initilization handshake
pinMode(ledPin1, OUTPUT); // configure broche 11 en sortie

}



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 ()
{
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
delay (100);
}

// 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 ()
{
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;

// 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("Axe x : ");
Serial.print (accel_x_axis, DEC);
Serial.print("/");
Serial.print(accel_x_axis/2);
Serial.print ("\t");

Serial.print("Axe y : ");
Serial.print (accel_y_axis, DEC);
Serial.print ("\t");
Serial.print("/");
valeurRetour = accel_y_axis/2;
Serial.print (valeurRetour) ;
Serial.print ("\r\n");

analogWrite(ledPin1, valeurRetour) ;
}

// 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;
}

Sav
26/02/2009, 20h08
Ok pour msn MadProf .

Je viens d'essayer le code , j'ai du rajouter " int valeurRetour = 0; " au début sinon ça me sortait une erreur comme quoi valeurRetour n'etais pas déclaré .

Là dans Serial Monitor c'est un peu plus clair :


Finished setup

Axe x : 1023/511 Axe y : 1023 /511

Axe x : 564/282 Axe y : 511 /255

Axe x : 563/281 Axe y : 512 /256

.....

Par contre niveau signal de sortie c'est un peu comme ton premier code .
Mais c'est peut étre normale j'ai pas vu de ligne de commande de ledPin1 ?

MadProf
26/02/2009, 22h00
Oui tu as raison pour la variable de retour je me suis trompé de nom, c'était "valeurRetour" que je voulais déclarer et j'ai mis "nouvelleValeur".
Là tu peux voir les valeurs renvoyées par ton nunchuck.
La première ligne à mon avis sert à étalonner ou un truc du genre puisque tu as la valeur max (1024) sur les 2 axes x et y
Ensuite les autres valeurs indiquent que tu es à l'horizontal (environ 512).
J'ai divisé les valeurs par 2 pour avoir le résultat sur l'intervalle [0..255] car je pensais que les valeurs renvoyées étaient comprises entre 0 et 512. Mais en fait fallait diviser par 4.

Serial.print("Axe x : ");
Serial.print (accel_x_axis, DEC);
Serial.print("/");
Serial.print(accel_x_axis/4);
Serial.print ("\t");

Serial.print("Axe y : ");
Serial.print (accel_y_axis, DEC);
Serial.print("/");
valeurRetour = accel_y_axis/4;
Serial.print (valeurRetour) ;
Serial.print ("\r\n");

La valeur de retour sur ta led correspond à l'inclinaison sur l'axe y :

analogWrite(ledPin1, valeurRetour) ;

Sav
27/02/2009, 14h07
C'est vraiment genial ce Serial Monitor !

Ca me fait penser au "mesure parametre" qu'on l'on a sur l' outil de diagnostic qu'on branche sur les voitures , ça nous permet de voir les valeurs mesurées par les capteurs et les valeurs de commande des actionneurs en temps réel .

Ok , je vais donc supprimer nouvelle valeur puisqu'il ne sert pas et diviser par 4 les valeurs d ' accélération des axes .

J'ai hate de quitter le boulot pour essayer tous ça , et puis en plus c'est le WEEK END !!!!!!! :D

Bon week end ...

MadProf
27/02/2009, 14h36
Oui c'est sur que c'est indispensable d'utiliser cet outil. Si tu veux aller plus loin encore, et sortir des courbes, schémas, histogrammes ou autre d'après tes valeurs tu peux utiliser Processing. Je ne le connais pas mais il parait que c'est très bien. Personnellement j'utilise un utilitaire que j'ai fait qui me permet d'envoyer et recevoir ce que je veux vers ma carte Arduino.

J'espère que t'arrivera au bout de ton projet. Je serai dispo demain en fin d'aprèm et durant la soirée pour aller sur msn.
Tiens moi au courant.

bon weekend

MadProf

Sav
28/02/2009, 00h45
Je rentre du ciné , Underworld 3 est très sympa ! :)

Avant de partir j'ai testé en divisant par 4 .

Ça recentre bien autour de l' horizontale (Axe y : 514 / 128) , mais en max j'ai 173 (Axe y : 694 / 173 ) et au mini j' ai 68 (Axe y : 279 / 69 ) . :/

Dur dur d'avoir 0 à 255 .

Je devrais pouvoir me connecter sur msn Samedi en soirée .

MadProf
02/03/2009, 02h50
Désolé j'ai pas pu me connecter sur msn, j'ai pas eu trop de temps ce weekend.

Vu les résultat que tu obtiens ça correspond à peu près à ce que je pensais au début : un intervalle de 72 à 176 environ. Il suffit donc de remettre le fonction de conversion, l'adapter pour des valeurs légèrement plus basse que 72 et légèrement supérieure à 176 et l'appliquer au bon endroit.

++

MadProf

Sav
03/03/2009, 21h58
Salut MadProf , pas grave pour msn .

La fonction de conversion c'est bien celle ci :

//fonction de conversion
//elle prend un float compris entre 72 et 176 en paramètre, et renvoi un entier compris entre 0 et 255
int conversion (float test){
nouvelleValeur=(int)(255*test/104)-(2295/13);
return nouvelleValeur;


Je ne comprend pas bien cette fonction , j'ai remarqué que "2295/13" était égale à environ 176 donc je me dit que "255*test/104" devrait être égale à environ 72 ?

Mais la valeur de "test" c'est quoi ?

MadProf
03/03/2009, 23h14
Salut Sav,

Je t'explique vite fait la fonction de conversion :

Une fonction prend un/plusieurs paramètre(s) d'entrée et un paramètre de sortie. Ici j'ai mis un float en entrée que j'ai nommé "test". Elle renvoi en sortie un entier, car c'est ce que tu as besoin comme type pour envoyer vers la led.
Le float en entrée c'est en raison de pb liés aux divisions/multiplications :


Know that integer constants default to int, so some constant calculations may overflow (e.g. 60 * 1000 will yield a negative result)
int conversion (float test){ //déclaration de la fonction
nouvelleValeur=(int)(255*test/104)-(2295/13);//calcul
return nouvelleValeur;//renvoi de la valeur de sortie
}

La deuxième ligne est celle qui fait tout le travail. J'ai simplement fait une fonction du type y=ax+b pour convertir. On ne peut pas faire de règle de 3 car ce n'est pas proportionnel. Tu noteras que j'ai mis un (int) avant les calculs pour "caster"(convertir) mon résultat en un entier. Sans ça les valeurs de retour pourraient prendre une virgule.
La dernière ligne sers à renvoyer le résultat.

La fonction s'utilise donc ainsi :

int nouvelleValeur=conversion(ancienneValeur);

Ex:
// ancienne valeur =125 (sur l'intervalle 72-176)

nouvelle valeur = (255*ancienneValeur/104)-(2295/13);
soit :
nouvelle valeur = (255*125/104)-(2295/13);
nouvelle valeur = (255*ancienneValeur/104)-(2295/13);
nouvelle valeur = 129

ancienne valeur = 72 => 0
ancienne valeur = 176 => 255

En revanche tu as l'air d'avoir des valeurs qui descendent un peu en dessous de 72, ce qui te donneras un résultat négatif, et les pb que ça engendre. Il faut surement refaire une fonction qui prend un intervalle plus large en entrée.

++

MadProf

Sav
06/03/2009, 23h37
Salut,

Ah !!! Une fonction affine !!! :mad: Je ré entend mes prof de math qui me disent : "Mais si ça te servira un jour ..."
J 'aurais du les écouter :rolleyes:

Pour récapituler et éclaircir un peu on a :

y=ax - b

nouvelle valeur = y = valeur de sortie
a = 255
x = un entier variable entre 72 et 176 ( pourquoi diviser par 104 ? )
b = 176 (pourquoi mettre (2295/13) ? )

Je me replonge dans mes cours de troisième pour revoir un peu cette fonction affine , Jamais j'aurais cru ça il y a quelques années !!!!!

Sav
04/05/2009, 22h38
Salut ,

Me re-voila !

Bon , j ' arrive pas a piger le truc des fonctions de conversion , en fait je commence avec trop gros pour moi en programmation !

Mais je vais utiliser un de tes programmes MadProf , celui ou on avait qu'un petit angle de fonctionnement mais ça devrait suffire pour le moment .

Il faut que je m' attaque à un autre problème , celui de la fréquence du signal de sortie , celle ci est trop faible pour le circuit de ma radio , car je veux émuler les potentiomètres des manches , donc elle s' attend à un signal plus lisse .

Il faut que je me fasse un ptit montage qui me lisse tous ça !

A+ et merci MadProf !