dimanche 11 mars 2012

Servo

Pilotage d'un servomoteur à partir d'un accéléromètre.
Le but du montage est d'actionner un servomoteur suivant l'inclinaison d'un accéléromètre afin de reproduire le même mouvement.

Branchement

Le branchement est le suivant :
Arduino - Servo
5V - rouge
GND - noir
PIN9 - jaune

Arduino - MMA7361
3.3V - VCC
GND - GND
3.3V - SLP
A0 - XOUT

La difficulté avec l'accéléromètre est de bien gérer les parasites. Pour les limiter, je fais une moyenne sur plusieurs mesures en excluant les valeurs trop hautes ou trop basses.
Les mesures sont triées avant que la moyenne soit calculée avec la moitié des valeurs au centre de la liste. Néanmoins, on observe quand même un effet d'oscillation après un mouvement.


J'ai utilisé la librairie Servo de Arduino, un tutoriel simple est disponible sur le site officiel.

Programme

#include <Servo.h> 
 
Servo myservo;
int pos = 0;

const int MAX_MESURES = 20;
int mesures[MAX_MESURES];
int mesuresTriees[MAX_MESURES];
int nbMesures = 0;

void setup() 
  myservo.attach(9);
  //Serial.begin(9600);
 
 
void loop() 
  nbMesures = mesurer(mesures, nbMesures, MAX_MESURES);
  recopier(mesures,mesuresTriees,nbMesures);
  trier(mesuresTriees,nbMesures);
  //debugTab(mesuresTriees,nbMesures);
  
  pos = moyenneSansExtremes(mesuresTriees,nbMesures);
  //Serial.println(pos);
  
  myservo.write(pos);
  delay(20);
}

int mesurer(int tab[], int nb, int max) {
  int sensorValue = analogRead(A0);
  pos = map(sensorValue, 165, 510, 0, 180); 
  pos = constrain(pos, 0, 180);
  
  if(nb < max) {
    tab[nb] = pos;
    nb++;
  } else {
    for(int i=0; i<max-1; i++) {
      tab[i] = tab[i+1];
    }
    tab[max-1] = pos;
  }
  return nb;
}

void debugTab(int tab[], int nb) {
  Serial.print("[");
  for(int i=0;i<nb;i++) {
    Serial.print(tab[i],DEC);
    if(i<nb-1) {
      Serial.print(",");
    }
  }
  Serial.print("]");
  Serial.println();
}

void recopier(int source[], int destination[], int nb) {
  for(int i=0;i<nb;i++) {
    destination[i] = source[i];
  }
}

void trier(int tab[], int nb) {
  int min, imin, tmp;
  for(int i=0;i<nb-1;i++) {
    min = tab[i];
    imin = i;
    for(int j=i+1;j<nb;j++) {
      if(min > tab[j]) {
        min = tab[j];
        imin = j;
        break;
      }
    }
    if(i != imin) {
      tmp = tab[i];
      tab[i] = tab[imin];
      tab[imin] = tmp;
    }
  }
}

int moyenneSansExtremes(int tab[], int nb) {
  int min = nb/4;
  int max = nb - (nb/4);
  int moyenne = 0;
  int j = 0;
  for(int i=min; i<max; i++) {
    moyenne += tab[i];
    j++;
  }
  moyenne = moyenne / j;
  return moyenne;
}

6 commentaires:

  1. Bonjour
    Votre tuto est très intéressant,cependant mon gyro ne possède pas les même abréviations :

    - vcc
    - gnd
    - scl
    - sda
    - xda
    - xcl
    - ado
    - int

    Pourriez vous me dire quelles sont les correspondances si possible?

    merci beaucoup

    RépondreSupprimer
  2. Bonjour,
    un gyroscope ne va pas mesurer les mêmes choses qu'un accéléromètre, le système d'entrée/sortie est donc différent. Il faut regarder la documentation du composant pour savoir à quoi correspondent les branchements.
    Sinon une recherche sur google avec le nom du gyro suivi de arduino pourra peut être donner des tutoriels intéressants.
    Bon courage

    RépondreSupprimer
  3. Bonjour,
    Très intéressant et très complet comme blog. Je vous en remercie.

    Par contre, vous en arrivez au même point que moi! Je suis capable de faire bouger un servo lorsque l'on bascule l’accéléromètre mais qu'en ai t-il lorsqu'on veut contrôler un servo pour faire correspondre un déplacement horizontal. Je veux dire lorsque la gravité n'affecte pas le senseur (gauche-droit)? Là c'est de l'accélération-décélération pure et je tombe sur un os. Avez-vous réalisé un tel projet? Si oui, j'aimerais en savoir plus. Merci!

    RépondreSupprimer
  4. En fait, il faut bien comprendre le fonctionnement du capteur pour résoudre ce genre de problème. L'accéléromètre peut s'imaginer comme une masse suspendu à un ressort, dans un tube. Regarde ici : http://sweetrandomscience.blogspot.fr/2013/07/comment-les-telephones-portables-et.html
    Du coup, on peut facilement savoir dans quelle position est le capteur par rapport au sol. Par contre, pour connaître l'angle exact dans tous les cas, ca sera impossible. Il faut alors utiliser un autre capteur (gyroscope, boussole, inclinomètre,...).
    Même chose pour mesurer la position en déplaçant l'accéléromètre. Il n'est pas fait pour ca, du coup à cause des erreurs de mesure (bruit), l'accélération sera mesurée plus ou moins bien suivant les cas. Les résultats des calculs ne seront jamais satisfaisants, à cause de la qualité des données en entrée.
    J'avais espérer calculer la position d'un robot avec ce capteur, mais après avoir tourner le problème dans tous les sens j'en ai déduit que ce n'est pas possible. Après, suivant la qualité du capteur, on peut avoir des résultats plus précis. Pour capter une position il faut plutôt se tourner vers des capteurs optiques, ou des balises de localisation.

    RépondreSupprimer
  5. Hello, I used your code for this accelerometer " http://s3.amazonaws.com/media-us.metatiendas.com/images/1047/MMA7361-Acceleration-Module-Slant-Angle-Sensor-Position-Sensor-090321.jpg " But this never stay calm ( you know how I can get more precision for my accelerometer)
    Thank you Sebarduino for your tutorial, Kind Regards!!

    RépondreSupprimer