dimanche 17 juillet 2011

MMA7361

Premiers tests avec l'accéléromètre 3 axes MMA7361.




Ce composant a pour but de m'aider à définir la position d'un robot. Voir la doc sur Sparkfun. Il mesure la gravité et son orientation.
Une video d'explication sur les accéléromètres est disponible ici.

Le branchement est le suivant :
MMA7361 - Arduino
VCC - 3.3V
GND - GND
XOUT - A0
YOUT - A1
ZOUT - A2
SLP - 3.3V

L'alimentation 3.3V de l'entrée GSEL permet de passer de la précision 1.5G à 6G.

Processing

Afin de visualiser les mesures de l'accéléromètre je me suis intéressé au logiciel Processing. Il ressemble au logiciel Arduino et est dédié à la programmation graphique via du Java.
Voir le site officiel Processing.
Voir le tutorial de communication entre Arduino et Processing.
Site en français concernant Processing.


Visualisation graphique des valeurs d'accélération




Ci-dessus les valeurs brutes X, Y et Z de l'accéléromètre sont affichées sous forme de graphe. En-dessous, utilisation de ces valeurs pour agir sur un cube virtuel.




Programme Arduino


void setup() {
 analogReference(EXTERNAL);
 Serial.begin(9600);
}

void loop() {
  int xValue = analogRead(A0);
  int yValue = analogRead(A1);
  int zValue = analogRead(A2);

  Serial.print(xValue);
  Serial.print(",");
  Serial.print(yValue);
  Serial.print(",");
  Serial.print(zValue);
  Serial.println(",");
}

Programme Processing Graphe


import processing.serial.*;

 Serial myPort;
 int xPos = 1;

 void setup () {
   size(1200, 300);    
   println(Serial.list());
   myPort = new Serial(this, Serial.list()[1], 9600);
   myPort.bufferUntil('\n');
   background(0);
 }

 void draw () {
 }

 void serialEvent (Serial myPort) {
   float inByte;
   String inString = myPort.readStringUntil('\n');
   if (inString != null) {
     String[] tokens = inString.split(",");
   
     if (tokens.length == 4) {
       inString = trim(inString);
     
       // rouge
       inByte = int(tokens[0]);
       inByte = map(inByte, 0, 1023, 0, height);
       stroke(255,0,0);
       line(xPos, height, xPos, height - inByte);
     
       // vert
       inByte = int(tokens[1]);
       inByte = map(inByte, 0, 1023, 0, height);
       stroke(0,255,0);
       line(xPos+400, height, xPos+400, height - inByte);
     
       // bleu
       inByte = int(tokens[2]);
       inByte = map(inByte, 0, 1023, 0, height);
       stroke(0,0,255);
       line(xPos+800, height, xPos+800, height - inByte);
     
       if (xPos >= 400) {
         xPos = 0;
         background(0);
       } else {
         xPos++;
       }
     }
   }
 }



Programme Processing 3D


import processing.serial.*;

Serial myPort;
float xMag, yMag = 0;

int xMin = 1024;
int yMin = 1024;
int zMin = 1024;

int xMax = 0;
int yMax = 0;
int zMax = 0;

void setup()
{
  size(640, 360, P3D);
  noStroke();
  colorMode(RGB, 1);

  println(Serial.list());
  myPort = new Serial(this, Serial.list()[1], 9600);
  myPort.bufferUntil('\n');
}

void draw()
{
  background(0.5);
  pushMatrix();
  translate(width/2, height/2, -30);

  rotateX(-xMag);
  rotateZ(yMag);

  scale(90);
  beginShape(QUADS);

  fill(1, 0, 0); vertex(-1,  0.5,  1);
  fill(1, 0, 0); vertex( 1,  0.5,  1);
  fill(1, 0, 0); vertex( 1, -0.5,  1);
  fill(1, 0, 0); vertex(-1, -0.5,  1);

  fill(0, 1, 0); vertex( 1,  0.5,  1);
  fill(0, 1, 0); vertex( 1,  0.5, -1);
  fill(0, 1, 0); vertex( 1, -0.5, -1);
  fill(0, 1, 0); vertex( 1, -0.5,  1);

  fill(1, 0, 0); vertex( 1,  0.5, -1);
  fill(1, 0, 0); vertex(-1,  0.5, -1);
  fill(1, 0, 0); vertex(-1, -0.5, -1);
  fill(1, 0, 0); vertex( 1, -0.5, -1);

  fill(0, 1, 0); vertex(-1,  0.5, -1);
  fill(0, 1, 0); vertex(-1,  0.5,  1);
  fill(0, 1, 0); vertex(-1, -0.5,  1);
  fill(0, 1, 0); vertex(-1, -0.5, -1);

  fill(0, 0, 1); vertex(-1,  0.5, -1);
  fill(0, 0, 1); vertex( 1,  0.5, -1);
  fill(0, 0, 1); vertex( 1,  0.5,  1);
  fill(0, 0, 1); vertex(-1,  0.5,  1);

  fill(0, 0, 1); vertex(-1, -0.5, -1);
  fill(0, 0, 1); vertex( 1, -0.5, -1);
  fill(0, 0, 1); vertex( 1, -0.5,  1);
  fill(0, 0, 1); vertex(-1, -0.5,  1);

  endShape();
  popMatrix();
}

void serialEvent (Serial myPort) {
 int xValue;
 int yValue;
 String inString = myPort.readStringUntil('\n');
 if (inString != null) {
   String[] tokens = inString.split(",");
   if(tokens.length == 4) {
   
     xValue = int(tokens[0]);
     if (xValue > xMax) xMax = xValue;
     if (xValue < xMin) xMin = xValue;
     xValue = int(map(xValue,xMin,xMax,-90,90));
     if (abs(xValue) > 6) { // pour éviter le tremblement du au bruit
       xMag = xValue * PI / 180.0;
     }
   
     yValue = int(tokens[1]);
     if (yValue > yMax) yMax = yValue;
     if (yValue < yMin) yMin = yValue;
     yValue = int(map(yValue,xMin,xMax,-90,90));
     if (abs(yValue) > 6) { // pour éviter le tremblement du au bruit
       yMag = yValue * PI / 180.0;
     }
   }
 }
}

11 commentaires:

  1. Bonjour,

    je suis très intéresse par ton projet sur arduino, y'aurait-il un moyen de te contacter ?

    RépondreSupprimer
  2. Salut,
    que veux tu savoir de plus sur ce projet ?
    Seb

    RépondreSupprimer
  3. Je voudrais, si c'est possible, que tu m'aides à arriver à le réaliser également.

    Je n'arrive pas à récupérer les données de l'accéléromètre pour les transmettrent sur la arduino et arriver a un rendu tel que le tien

    Merci d'avoir pris le temps de me répondre.

    RépondreSupprimer
  4. Finalement après m'y être investi toute la journée, j'ai réussi à récupérer les données ...
    Subsiste un problème .. l'affichage. Les données n'arrivent pas suffisamment vite pour que le cube ou les courbes apparaissent et bougent instantanément. Problème de delay ? de débits ? Augmenter le baud ?

    Merci de l'attention que tu me portes.

    RépondreSupprimer
  5. En fait les données sont envoyées sur le port série Serial (RX et TX) http://arduino.cc/en/Reference/Serial. Le débit est de 9600 par défaut. Sur le arduino, ne met pas de délai, afin des les données soient envoyées à chaque boucle. Sur la partie processing, la fonction serialEvent est appelé à chaque réception d'un évènement. Peut être que a peut poser un problème si cette fonction est trop longue à s'exécuté. Essaye de voir quelle partie du traitement est chronophage. Il n'y a pas de raison que tu n'obtienne pas le même résultat.

    RépondreSupprimer
  6. Bonjour, merci de votre réponse qui nous à permis de voir, que le contrôle de flux était activé et il nous prenait un maximum de débit.

    Pourrait tu me donner ton mail afin que je puisse te soumettre une idée de programme ?

    J'aimerai en effet, faire apparaitre sur le programmes aux trois courbes, les variations en fonctions de x, y et de z ! Sur celui que tu as crée, seul x entre en compte non ? Pourrais tu m'aider afin d'obtenir un résultat probant ?

    Bien cordialement,

    RépondreSupprimer
  7. Salut, tu peux m'envoyer des mails à sebaplus@yahoo.fr ou continuer à discuter directement sur les commentaires du blog.

    En fait, sur mon projet j'utilise les 3 axes x,y,z dans les 2 cas d'affichage. Sur les graphes, il s'agit des 3 couleurs différentes.

    RépondreSupprimer
  8. Salut,
    j'ai travaillé sur une autre utilisation de l'accéléromètre. Tu peux la retrouver sur mon dernier post : http://sebarduino.blogspot.com/2012/03/servo.html

    RépondreSupprimer
  9. Bonjour,
    ce serait bien de mettre un flush() dans le sketch à la fin de chaque ligne. Sinon, j'ai l'impression que le programme fait des mesures plus vite qu'il ne peut les transmettre et le résultat n'est pas optimal. (Mieux encore serait de commander la saisie et/ou de faire du contrôle de flux mais là, cela compliquerait l'exemple dont la simplicité même est l'intérêt principal) -- xof

    RépondreSupprimer
  10. Je suis d'accord que les mesures sont beaucoup plus rapides que le transfert avec Serial. Mais les deux actions, se faisant l'une après l'autre, ça ne pose pas vraiment de problème dans ce cas. Si les données devaient être traitées sur le module Arduino, il faudrait effectivement gérer le Serial différemment.

    RépondreSupprimer
  11. Bonjour, est-il possible et utile d'amplifier le signal de x,y,z avec des composants du marché, afin d'avoir plus de précision de mesure? Je n'ai pas encore tout à fait compris l'intérêt de la fonction accelero.setSensitivity(HIGH) ou LOW...

    RépondreSupprimer