« Micro contrôleurs AVR/Travail pratique/Utilisation d'un Accéléromètre MPU6050 » : différence entre les versions

Contenu supprimé Contenu ajouté
Ligne 25 :
* un capteur accéléromètre 3 axes (x,y et z) qui mesure une [[w:accélération|accélération]] ;
* un capteur gyroscope 3 axes qui mesure une [[w:vitesse angulaire|vitesse angulaire]] ;
* un «  Digital Motion Processor  » (DMP) pouvant stocker et restituer des données.
 
[[Fichier:Accelerometre 1.png|thumb|300px|Utiliser Processing pour visualiser des données d'un accéléromètre et d'un gyroscope.]]
Ligne 39 :
[[w:Attitude_%28astronautique%29|L'attitude]] en robotique (et en astronautique) désigne la direction des axes de la pièce mobile du robot ; généralement caractérisée par trois angles ([[w:Roulis|roulis]], [[w:Tangage|tangage]] et cap ou [[w:Lacet_%28mouvement%29|lacet]]).
 
Ce mot «  attitude  » ne doit pas être confondu avec «  '''altitude'''  » (ils n'ont en commun qu'une orthographe voisine) !
 
La notion d'attitude est très liée aux rotations en trois dimensions. Nous allons donc commencer par examiner ces rotations d'un point de vue mathématique.
Ligne 57 :
 
Voici un code SCILAB permettant de définir ces trois matrices pour des valeurs particulières d'angle :
<sourcesyntaxhighlight lang="scilab">
//******* SCILAB
phi=%pi/4;
Ligne 68 :
roty=[cos(theta) 0 -sin(theta);0 1 0;sin(theta) 0 cos(theta)];
rotz=[cos(psi) sin(psi) 0;-sin(psi) cos(psi) 0;0 0 1];
</syntaxhighlight>
</source>
 
=== Euler 123 ===
Ligne 82 :
 
Le code SCILAB permettant de réaliser le calcul de la matrice d'Euler 123 est :
<sourcesyntaxhighlight lang="scilab">
//******* SCILAB
// construction matrice de rotation Euler 123
Ligne 88 :
// construction matrice de rotation Euler 321
R2=rotz*roty*rotx;
</syntaxhighlight>
</source>
 
Une rotation en dimension 3 peut aussi être définie par un axe de rotation et un angle (soit à priori 4 paramètres). Les quatre paramètres sont naturellement les trois composantes du vecteur qui définit l'axe et l'angle de rotation. Il est en fait possible d'économiser un paramètre en définissant l'axe à partir du centre d'une sphère ainsi que la longitude et latitude du point de rencontre de l'axe avec la sphère. Une autre manière d'économiser une donnée est de définir l'axe de rotation par un vecteur unitaire pour lequel trois coordonnées suffisent. '''Bref seulement 3 paramètres suffisent à définir une rotation'''.
Ligne 105 :
Le code SCILAB permettant le calcul d'angle est donc :
 
<sourcesyntaxhighlight lang="scilab">
//******* SCILAB
// matrice R de rotation 3x3
angle= acos((trace(R)-1)/2)
</syntaxhighlight>
</source>
 
=== Axe de rotation ===
L'axe de rotation est plus difficile à calculer si l'on ne dispose pas d'une puissance de calcul suffisante. Sur notre PC ce n’est pas un problème : il faut chercher le vecteur invariant par cette rotation. Techniquement cela revient à chercher le seul et unique vecteur propre associé à la valeur propre +1. Plutôt que d’en faire la théorie, nous préférons donner le code de SCILAB qui permet facilement ce genre de calcul :
<sourcesyntaxhighlight lang="scilab">
//******* SCILAB
// premiere maniere
[Ab,X]=bdiag(R)
</syntaxhighlight>
</source>
affiche :
<pre>
Ligne 134 :
 
Il existe une autre méthode avec SCILAB :
<sourcesyntaxhighlight lang="scilab">
//******* SCILAB
//deuxième manière
[al,be]=spec(R)
</syntaxhighlight>
</source>
qui donne
<pre>
Ligne 171 :
 
'''Exemple en SCILAB'''
<sourcesyntaxhighlight lang="scilab">
//******* SCILAB
// recupération de l'axe : troisième colonne de X
Ligne 183 :
Z=[0 -axis(3) axis(2);axis(3) 0 -axis(1);-axis(2) axis(1) 0];
R3=expm(angle*Z); // redonne R2
</syntaxhighlight>
</source>
redonne exactement la même matrice que R pour les deux techniques de construction de R2 et R3.
 
Ligne 282 :
==== Axe de rotation du vecteur g ====
Le script suivant :
<sourcesyntaxhighlight lang="scilab">
//******* SCILAB
// réalisation du produit vectoriel
Ligne 294 :
// calcul de l'axe à partir du produit vectoriel : IL EST MONTRE PLUS LOIN QUE CETTE IDÉE SIMPLE EST FAUSSE
axis2=CrossProd(g0,g1);
</syntaxhighlight>
</source>
nécessite l’utilisation de CrossProd.sci qui doit contenir :
<sourcesyntaxhighlight lang="scilab">
//******* SCILAB
function [p] = CrossProd(u,v)
Ligne 314 :
p = [px, py, pz]
//end function
</syntaxhighlight>
</source>
[[Fichier:Accelerometer3.png|thumb|L'axe de rotation d'une rotation 3D ne peut pas être retrouvé à l'aide d'un produit vectoriel]]
{{attention|
Ligne 362 :
 
L'utilisation de SCILAB nous a permis cependant de trouver une relation entre les deux. En effet le code :
<sourcesyntaxhighlight lang="scilab">
anglex=%pi/4; //phi
angley=-%pi/4; //theta
Ligne 381 :
erreurx = (anglex-phi)*180/%pi
erreury= (angley-rho)*180/%pi
</syntaxhighlight>
</source>
donne :
<pre>
Ligne 458 :
1°) Nous allons commencer par le programme tout simple :
 
<sourcesyntaxhighlight lang="C">
// MPU-6050 Short Example Sketch
// By Arduino User JohnChi
Ligne 489 :
delay(333);
}
</syntaxhighlight>
</source>
 
Essayez ce programme sur la liaison série.
Ligne 518 :
 
{{Solution|contenu=
<sourcesyntaxhighlight lang="C">
#include<Wire.h>
const int MPU=0x68; // I2C address of the MPU-6050
Ligne 554 :
delay(333);
}
</syntaxhighlight>
</source>
{{Remarque|contenu=
Ce code pose problème dans le cas où les composantes de g sont nulles sur les deux axes X et Z (cela peut arriver : accéléromètre sur la tranche). Dans ce cas, ce qui est retourné par atan2 est NaN (Not a Number) et ne peut pas être interprété par un logiciel de visualisation. Il vous faut donc gérer cette situation sauf si vous vous interdisez de mettre l'accéléromètre dans cette situation.
Ligne 575 :
'''<u>Indication</u>''' : Voici un programme capable de récupérer la chaîne "Phi = -0.67" envoyée par l'Arduino et de la transformer en nombre réel :
 
<sourcesyntaxhighlight lang="C">
import processing.serial.*;
 
Ligne 605 :
}
}
</syntaxhighlight>
</source>
{{Solution|contenu=
<sourcesyntaxhighlight lang="java">
import processing.serial.*;
Ligne 649 :
}
}
</syntaxhighlight>
</source>
}}
À partir de maintenant, la partie processing sera fournie. Elle sera bien plus sophistiquée que ce que l’on vient de faire puisqu'elle sera destinée à recevoir les données de notre capteur et d’en faire plusieurs représentations 3D.
Ligne 656 :
Soit le programme Processing suivant :
{{Boîte déroulante|titre=Programme Processing pour visualisation|contenu=
<sourcesyntaxhighlight lang="java">
/**
* Show GY521 Data.
Ligne 881 :
}
}
</syntaxhighlight>
</source>
}}
C'est le programme que l’on utilisera systématiquement par la suite. Il peut être trouvé dans la partie [http://www.geekmomprojects.com/gyroscopes-and-accelerometers-on-a-chip/ à télécharger de cette page].
Ligne 887 :
Ce programme est sensible au type de liaison série utilisé et particulièrement au système d'exploitation. La ligne en début de programme :
 
<sourcesyntaxhighlight lang="java">
String portName = "/dev/ttyACM0"; // parfois "/dev/ttyACM1" chez moi
</syntaxhighlight>
</source>
 
est propre à Linux et devra donc être adaptée !
Ligne 895 :
{{remarque|contenu=
Ce programme utilise la représentation d'Euler des rotations. Ceci peut être vu avec l'extrait de code
<sourcesyntaxhighlight lang="C">
rotateX(radians(-x_fil - x_rotation));
rotateY(radians(-y_fil));
</syntaxhighlight>
</source>
La rotation autour de l'axe Z est donc supposée être nulle. Ceci semble assez normal pour l'accéléromètre mais on peut faire mieux pour les rotations (gyroscope). Nous serons donc éventuellement amenés à modifier ceci.
}}
Ligne 910 :
 
{{Solution|contenu=
<sourcesyntaxhighlight lang="C">
float accel_angle_x=0.0,accel_angle_y=0.0,accel_angle_z=0.0;
Ligne 950 :
delay(300);
}
</syntaxhighlight>
</source>
}}
2°) Construire ensuite le même programme en vous intéressant maintenant à la position de l'accélération de pesanteur. Pour simplifier commencez par faire fonctionner le programme Processing avec la résolution 2D que vous avez réalisé dans l'exercice précédant. Les données que vous allez envoyer au programme processing seront maintenant liées à votre position de l'accéléromètre par rapport à l'axe x. L'angle doit être fourni en ° et non en radians !
{{Solution|contenu=
<sourcesyntaxhighlight lang="C">
#include<Wire.h>
const int MPU=0x68; // I2C address of the MPU-6050
Ligne 1 012 :
delay(30);
}
</syntaxhighlight>
</source>
}}
 
Ligne 1 031 :
{{Solution|contenu=
L'utilisation des deux premières formules peut laisser croire que le problème est résolu... mais une étude expérimentale attentive peut nous conduite à de fortes divergences entre la position de l'accéléromètre dans notre main et sa visualisation 3D avec Processing.
<sourcesyntaxhighlight lang="C">
#include<Wire.h>
const int MPU=0x68; // I2C address of the MPU-6050
Ligne 1 098 :
delay(30);
}
</syntaxhighlight>
</source>
}}
[[Fichier:Accelerometre 3.png|thumb|300px|Améliorer les données de l'accéléromètre avec un filtrage]]
Ligne 1 111 :
}}
{{Solution|contenu=
<sourcesyntaxhighlight lang="C">
#include<Wire.h>
const int MPU=0x68; // I2C address of the MPU-6050
Ligne 1 176 :
//delay(30);
}
</syntaxhighlight>
</source>
}}
 
Ligne 1 185 :
 
{{Boîte déroulante|titre=Code pour retrouver l'attitude avec l'accéléromètre|contenu=
<sourcesyntaxhighlight lang="C">
#include<Wire.h>
const int MPU=0x68; // I2C address of the MPU-6050
Ligne 1 301 :
delay(5);
}
</syntaxhighlight>
</source>
Le calcul de la matrice de rotation R doit être amélioré : tel qu’il est écrit ici il fait appel plusieurs fois à des cosinus et sinus identiques.
}}
Ligne 1 323 :
On donne :
 
<sourcesyntaxhighlight lang="C">
// MPU-6050 Short Example Sketch
// By Arduino User JohnChi
Ligne 1 356 :
delay(333);
}
</syntaxhighlight>
</source>
 
==== Exercice 6 ====
Ligne 1 377 :
 
ii) La sortie sera réalisée par quelque chose comme :
<sourcesyntaxhighlight lang="C">
// Send the data to the serial port
Serial.print(F("DEL:")); //Delta T
Ligne 1 400 :
Serial.print(0.0, 2);
Serial.println(F(""));
</syntaxhighlight>
</source>
si l’on veut rester compatible avec Processing.
 
Ligne 1 406 :
 
iv) L'obtention de la vitesse en °/s se fait par <u>une division</u> à l'aide d'une valeur
<sourcesyntaxhighlight lang="C">
// Convert gyro values to degrees/sec
float FS_SEL = 131;
</syntaxhighlight>
</source>
{{Solution|contenu=
<sourcesyntaxhighlight lang="c">
#include<Wire.h>
const int MPU=0x68; // I2C address of the MPU-6050
Ligne 1 500 :
delay(30);
}
</syntaxhighlight>
</source>
}}
 
Ligne 1 510 :
Voici donc un nouveau programme qui respecte les mathématiques des rotations 3D. Il est destiné à comparer l'intégration naïve ci-dessus à celle que l’on est sensé faire.
{{solution|contenu=
<sourcesyntaxhighlight lang="C">
#include<Wire.h>
 
Ligne 1 723 :
delay(30);
}
</syntaxhighlight>
</source>
Il a été testé avec le programme Processing très légèrement modifié pour l’occasion :
<sourcesyntaxhighlight lang="C">
/**
* Show GY521 Data.
Ligne 1 959 :
}
}
</syntaxhighlight>
</source>
L'objectif a été de départager expérimentalement les deux méthodes. On bouge pendant environ 5s et on revient à la position de départ. Le gagant est celui qui s'est alors le moins éloigné de la position de départ et le gagnant n'a pas vraiement pu être départagé !
}}
Ligne 1 978 :
Nous donnons un programme très simple qui relève les donnée de l'accéléromètre et celles du gyroscope. Remarquez que vous avez en bonus la température.
 
<sourcesyntaxhighlight lang="C">
// MPU-6050 Short Example Sketch
// By Arduino User JohnChi
Ligne 2 019 :
delay(333);
}
</syntaxhighlight>
</source>
Si vous avez suivi jusque là, vous pouvez facilement déduire de ce programme qu’il n’est pas prévu pour des visualisations de données avec processing. En effet il fonctionne à 9600 bauds (au lieu des 38400 exigées). Les données ne peuvent être visibles qu’à l'aide du moniteur série.
 
Ligne 2 030 :
 
1°) Si nous mélangeons les données de l'accéléromètre et du gyroscope, nous aurons une sortie comme :
<sourcesyntaxhighlight lang="C">
// Send the data to the serial port
Serial.print(F("DEL:")); //Delta T
Ligne 2 053 :
Serial.print(0.0, 2);
Serial.println(F(""));
</syntaxhighlight>
</source>
On vous demande de réaliser un sous-programme appelé "envoiAProcessing()" ayant un paramètre de type :
<sourcesyntaxhighlight lang="C">
struct data
{
Ligne 2 066 :
int z_gyro;
};
</syntaxhighlight>
</source>
qui regroupe donc toutes les données importantes et un autre paramètre de type float pour envoyer dt.
 
Ligne 2 073 :
{{solution|contenu=
Voici une version sans sous-programme :
<sourcesyntaxhighlight lang="C">
#include<Wire.h>
const int MPU=0x68; // I2C address of the MPU-6050
Ligne 2 185 :
}
 
</syntaxhighlight>
</source>
}}
 
Ligne 2 200 :
{{solution|contenu=
Voici une version d'essai qui ne fonctionne pas correctement, en tout cas pas mieux que la solution de l'exercice 6. '''Cette solution doit être corrigée au plus vite'''.
<sourcesyntaxhighlight lang="java">
#include<Wire.h>
const int MPU=0x68; // I2C address of the MPU-6050
Ligne 2 321 :
}
 
</syntaxhighlight>
</source>
}}
 
Ligne 2 344 :
Elles nécessitent l’utilisation des vecteurs sous forme de tableau.
{{Boîte déroulante|titre=Routines mathématiques pour le calcul sur vecteurs|contenu=
<sourcesyntaxhighlight lang="C">
#ifndef VECTOR3D__H
#define VECTOR3D__H
Ligne 2 409 :
}
#endif
</syntaxhighlight>
</source>
}}
 
Ligne 2 416 :
Les matrices sont supposées être des tableaux à une seule dimension dans les routines proposées ci-dessous.
{{Boîte déroulante|titre=Routines mathématiques pour les matrices 3x3|contenu=
<sourcesyntaxhighlight lang="C">
#ifndef MATRIX_H
#define MATRIX_H
Ligne 2 553 :
}
#endif
</syntaxhighlight>
</source>
}}
Pour ceux qui seraient frustrés d’utiliser un tableau à une dimension pour les matrices, on vous présente maintenant un autre code.
Ligne 2 561 :
 
{{Boîte déroulante|titre=Routines mathématiques pour les matrices 3x3 (avec classe objet)|contenu=
<sourcesyntaxhighlight lang="C">
/*
* matrixtools.h
Ligne 2 626 :
};
#endif /* MATRIXTOOLS_H_ */
</syntaxhighlight>
</source>
}}
 
Et maintenant le code (Merci à Loïc Kaemmerlen et Pascal Madesclair)
{{Boîte déroulante|titre=Routines mathématiques pour les matrices 3x3|contenu=
<sourcesyntaxhighlight lang="C">
/*
* matrixtools.cpp
Ligne 2 890 :
}
}
</syntaxhighlight>
</source>
}}
 
Ligne 2 897 :
Voici un ensemble de routines utilisant les quaternions proposé par Jeff Rowberg.
{{Boîte déroulante|titre=Routines mathématiques pour Quaternions|contenu=
<sourcesyntaxhighlight lang="C">
// I2C device class (I2Cdev) demonstration Arduino sketch for MPU6050 class, 3D math helper
// 6/5/2012 by Jeff Rowberg <jeff@rowberg.net>
Ligne 3 114 :
 
#endif /* _HELPER_3DMATH_H_ */
</syntaxhighlight>
</source>
}}
 
Ligne 3 121 :
 
Dans les codes d'exemple d'utilisation de l'accéléromètre, vous pouvez trouver des lignes du genre :
<sourcesyntaxhighlight lang="Arduino">
// supply your own gyro offsets here, scaled for min sensitivity
mpu.setXGyroOffset(220);
Ligne 3 127 :
mpu.setZGyroOffset(-85);
mpu.setZAccelOffset(1788); // 1688 factory default for my test chip
</syntaxhighlight>
</source>
et votre problème consiste à trouver toutes les valeurs correspondants à votre MPU6050. Pour cela vous pouvez utiliser du code que l'on trouve sur Internet.
{{Boîte déroulante|titre=Code de calibration trouvé sur Internet (luisrodenas)|contenu=
[https://www.i2cdevlib.com/forums/topic/96-arduino-sketch-to-automatically-calculate-mpu6050-offsets/ article de '''luisrodenas''']
<sourcesyntaxhighlight lang="Arduino">
// Arduino sketch that returns calibration offsets for MPU6050 // Version 1.1 (31th January 2014)
// Done by Luis Ródenas <luisrodenaslorda@gmail.com>
Ligne 3 244 :
}
}
</syntaxhighlight>
</source>
 
Remplacer
<sourcesyntaxhighlight lang="Arduino">
Serial.println("...");
</syntaxhighlight>
</source>
par
<sourcesyntaxhighlight lang="Arduino">
Serial.print(mean_ax);
Serial.print("\t");
Ligne 3 263 :
Serial.print("\t");
Serial.println(mean_gz);
</syntaxhighlight>
</source>
pour avoir des données lisibles.
}}