Maîtriser le MPU6050 : Tutoriel Accéléromètre et Gyroscope pour Arduino
Dans ce tutoriel, nous allons apprendre à utiliser le capteur MPU6050 Accéléromètre et Gyroscope avec Arduino. D'abord, j'expliquerai comment fonctionne le MPU6050 et comment lire ses données, puis nous ferons deux exemples pratiques. Vous pouvez regarder la vidéo suivante ou lire le tutoriel écrit ci-dessous. Dans le premier exemple, en utilisant l'environnement de développement Processing, nous ferons une visualisation 3D de l'orientation du capteur. Dans le second, nous réaliserons une plateforme auto-stabilisée simple ou un Gimbal DIY. Basé sur l'orientation du MPU6050 et ses données fusionnées accéléromètre/gyroscope, nous contrôlons trois servos qui maintiennent la plateforme à l'horizontale. Le MPU6050 IMU intègre sur une seule puce un accéléromètre 3 axes et un gyroscope 3 axes. Le gyroscope mesure la vitesse de rotation ou le taux de changement de position angulaire dans le temps, selon les axes X, Y et Z. Il utilise la technologie MEMS et l'effet Coriolis. Pour plus de détails, consultez mon tutoriel "Comment Fonctionnent les Capteurs MEMS". Les sorties du gyroscope sont en degrés par seconde ; pour obtenir la position angulaire, il suffit d'intégrer la vitesse angulaire. De son côté, l'accéléromètre du MPU6050 mesure l'accélération comme expliqué dans la vidéo précédente pour l'ADXL345. En résumé, il mesure l'accélération gravitationnelle sur les 3 axes et avec un peu de trigonométrie, on calcule l'angle d'inclinaison du capteur. En fusionnant (combinant) les données accéléromètre et gyroscope, on obtient une information très précise sur l'orientation du capteur. Le MPU6050 IMU est aussi appelé dispositif de suivi de mouvement 6 axes ou 6 DoF (6 Degrés de Liberté), à cause de ses 6 sorties : 3 accéléromètre + 3 gyroscope. Voyons comment connecter et lire les données du MPU6050 avec Arduino. On utilise le protocole I2C, donc seulement 2 fils pour la communication, plus 2 pour l'alimentation. Voici le code Arduino pour lire les données du MPU6050. Description détaillée ci-dessous. On inclut Dans On peut aussi sélectionner la plage de sensibilité (Full-Scale Range) pour l'accéléromètre et le gyroscope via leurs registres de configuration. Pour cet exemple, on utilise les défauts : ±2g pour l'accéléromètre et 250°/s pour le gyroscope, donc cette partie est commentée. Dans Pour tout lire, on commence au premier registre et avec Pour obtenir des valeurs de -1g à +1g (adaptées au calcul d'angles), on divise par la sensibilité choisie. Avec ces deux formules, on calcule les angles de roulis (roll) et tangage (pitch) depuis les données accéléromètre. Ensuite, même méthode pour le gyroscope. On lit les 6 registres gyroscope, on combine les données et on divise par la sensibilité pour obtenir degrés/seconde. On corrige les sorties avec les petites valeurs d'erreur calculées (expliquées après). Comme les sorties sont en °/s, on les multiplie par le temps pour obtenir des degrés. Le temps est capturé avant chaque itération avec Enfin, on fusionne accéléromètre et gyroscope avec un filtre complémentaire. On prend 96% du gyroscope (très précis, pas affecté par forces externes) et 4% de l'accéléromètre (pour corriger la dérive du gyroscope à long terme). Pour le Yaw (lacet), on ne peut pas utiliser l'accéléromètre, donc pas de filtre complémentaire possible. Avant les résultats, expliquons comment obtenir les valeurs de correction d'erreur. On appelle On affiche les valeurs sur le moniteur série, puis on les implémente dans le code pour corriger roll, pitch et les 3 axes gyroscope. Enfin, avec Pour la visualisation 3D, il suffit de recevoir les données envoyées par l'Arduino sur le port série dans l'environnement Processing. Voici le code Processing complet : On lit les données entrantes de l'Arduino et on les met dans les variables Roll, Pitch, Yaw. Dans la boucle Si on lance le sketch, on voit comme le MPU6050 suit bien l'orientation. L'objet 3D suit précisément et de façon réactive. Le seul inconvénient : le Yaw dérive avec le temps car pas de filtre complémentaire possible. Pour améliorer, il faut un capteur supplémentaire : généralement un magnétomètre pour correction à long terme de la dérive Yaw du gyroscope. Cependant, le MPU6050 a une fonctionnalité appelée Digital Motion Processor (DMP) pour calculs embarqués, capable d'éliminer la dérive Yaw. Même exemple 3D avec le DMP activé. Le suivi d'orientation est maintenant précis, sans dérive Yaw. Le processeur embarqué calcule aussi les Quaternions pour représenter orientations et rotations en 3D, évitant le blocage de Gimbal (Gimbal lock) des angles d'Euler. Cependant, récupérer ces données est plus complexe. Il faut connecter un fil supplémentaire à une broche numérique Arduino (broche d'interruption) pour lire ce type de données du MPU6050. Le code est plus complexe, donc on utilise la bibliothèque i2cdevlib de Jeff Rowberg (disponible sur GitHub, lien dans l'article web). Une fois la bibliothèque installée, on ouvre l'exemple On peut sélectionner le type de sortie : quaternions, angles d'Euler, yaw/pitch/roll, valeurs d'accélération, ou quaternions pour visualisation 3D. La bibliothèque inclut aussi un sketch Processing pour la 3D. Je l'ai modifié pour avoir la forme de pavé. Voici le code Processing pour la sortie "OUTPUT_TEAPOT" : Ici, avec Pour ne pas surcharger ce tutoriel, j'ai mis le second exemple (Gimbal DIY / Plateforme auto-stabilisée) sur un article séparé. N'hésitez pas à poser vos questions dans les commentaires et consultez ma collection de projets Arduino.Introduction
Vue d'Ensemble
Comment Ça Marche

Arduino et MPU6050

Composants Nécessaires
Code Arduino MPU6050
/* Arduino et MPU6050 Accéléromètre et Gyroscope par Dejan, https://howtomechatronics.com */
#include <Wire.h>
const int MPU = 0x68; // Adresse I2C MPU6050
float AccX, AccY, AccZ;
float GyroX, GyroY, GyroZ;
float accAngleX, accAngleY, gyroAngleX, gyroAngleY, gyroAngleZ;
float roll, pitch, yaw;
float AccErrorX, AccErrorY, GyroErrorX, GyroErrorY, GyroErrorZ;
float elapsedTime, currentTime, previousTime;
int c = 0;
void setup() {
Serial.begin(19200);
Wire.begin();
Wire.beginTransmission(MPU);
Wire.write(0x6B); // Registre 6B (PWR_MGMT_1)
Wire.write(0x00); // Reset - met 0 dans registre 6B
Wire.endTransmission(true);
/* // Configuration sensibilité accéléromètre (défaut ±2g)
Wire.beginTransmission(MPU);
Wire.write(0x1C); // Registre ACCEL_CONFIG (1C hex)
Wire.write(0x10); // ±8g full scale
Wire.endTransmission(true);
// Configuration sensibilité gyroscope (défaut ±250°/s)
Wire.beginTransmission(MPU);
Wire.write(0x1B); // Registre GYRO_CONFIG (1B hex)
Wire.write(0x10); // 1000°/s full scale
Wire.endTransmission(true);
delay(20); */
// Appeler cette fonction pour obtenir les valeurs d'erreur de votre module
calculate_IMU_error();
delay(20);
}
void loop() {
// === Lecture accéléromètre ===
Wire.beginTransmission(MPU);
Wire.write(0x3B); // Registre ACCEL_XOUT_H
Wire.endTransmission(false);
Wire.requestFrom(MPU, 6, true); // Lit 6 registres (2 par axe)
// Pour plage ±2g, diviser valeurs brutes par 16384 (datasheet)
AccX = (Wire.read() << 8 | Wire.read()) / 16384.0;
AccY = (Wire.read() << 8 | Wire.read()) / 16384.0;
AccZ = (Wire.read() << 8 | Wire.read()) / 16384.0;
// Calcul Roll et Pitch depuis données accéléromètre
accAngleX = (atan(AccY / sqrt(pow(AccX, 2) + pow(AccZ, 2))) * 180 / PI) - 0.58; // AccErrorX ~(0.58)
accAngleY = (atan(-1 * AccX / sqrt(pow(AccY, 2) + pow(AccZ, 2))) * 180 / PI) + 1.58; // AccErrorY ~(-1.58)
// === Lecture gyroscope ===
currentTime = millis();
elapsedTime = (currentTime - previousTime) / 1000.0; // En secondes
Wire.beginTransmission(MPU);
Wire.write(0x43); // Registre GYRO_XOUT_H
Wire.endTransmission(false);
Wire.requestFrom(MPU, 6, true);
// Pour plage 250°/s, diviser par 131.0 (datasheet)
GyroX = (Wire.read() << 8 | Wire.read()) / 131.0;
GyroY = (Wire.read() << 8 | Wire.read()) / 131.0;
GyroZ = (Wire.read() << 8 | Wire.read()) / 131.0;
// Correction avec erreurs calculées
GyroX = GyroX + 0.56; // GyroErrorX ~(-0.56)
GyroY = GyroY - 2; // GyroErrorY ~(2)
GyroZ = GyroZ + 0.79; // GyroErrorZ ~(-0.8)
// Intégration : deg/s * s = deg
gyroAngleX = gyroAngleX + GyroX * elapsedTime;
gyroAngleY = gyroAngleY + GyroY * elapsedTime;
yaw = yaw + GyroZ * elapsedTime;
// Filtre complémentaire : fusion accéléromètre + gyroscope
roll = 0.96 * gyroAngleX + 0.04 * accAngleX;
pitch = 0.96 * gyroAngleY + 0.04 * accAngleY;
// Affichage sur moniteur série
Serial.print(roll);
Serial.print("/");
Serial.print(pitch);
Serial.print("/");
Serial.println(yaw);
}
void calculate_IMU_error() {
// Calcule les erreurs accéléromètre et gyroscope. À appeler dans setup().
// Placer l'IMU à plat pour obtenir les bonnes valeurs de correction.
// Lecture accéléromètre 200 fois
while (c < 200) {
Wire.beginTransmission(MPU);
Wire.write(0x3B);
Wire.endTransmission(false);
Wire.requestFrom(MPU, 6, true);
AccX = (Wire.read() << 8 | Wire.read()) / 16384.0;
AccY = (Wire.read() << 8 | Wire.read()) / 16384.0;
AccZ = (Wire.read() << 8 | Wire.read()) / 16384.0;
AccErrorX = AccErrorX + ((atan((AccY) / sqrt(pow((AccX), 2) + pow((AccZ), 2))) * 180 / PI));
AccErrorY = AccErrorY + ((atan(-1 * (AccX) / sqrt(pow((AccY), 2) + pow((AccZ), 2))) * 180 / PI));
c++;
}
AccErrorX = AccErrorX / 200;
AccErrorY = AccErrorY / 200;
c = 0;
// Lecture gyroscope 200 fois
while (c < 200) {
Wire.beginTransmission(MPU);
Wire.write(0x43);
Wire.endTransmission(false);
Wire.requestFrom(MPU, 6, true);
GyroX = Wire.read() << 8 | Wire.read();
GyroY = Wire.read() << 8 | Wire.read();
GyroZ = Wire.read() << 8 | Wire.read();
GyroErrorX = GyroErrorX + (GyroX / 131.0);
GyroErrorY = GyroErrorY + (GyroY / 131.0);
GyroErrorZ = GyroErrorZ + (GyroZ / 131.0);
c++;
}
GyroErrorX = GyroErrorX / 200;
GyroErrorY = GyroErrorY / 200;
GyroErrorZ = GyroErrorZ / 200;
// Affichage erreurs sur moniteur série
Serial.print("AccErrorX: "); Serial.println(AccErrorX);
Serial.print("AccErrorY: "); Serial.println(AccErrorY);
Serial.print("GyroErrorX: "); Serial.println(GyroErrorX);
Serial.print("GyroErrorY: "); Serial.println(GyroErrorY);
Serial.print("GyroErrorZ: "); Serial.println(GyroErrorZ);
}Description du Code
Wire.h pour la communication I2C et on définit les variables pour stocker les données.setup(), on initialise la bibliothèque Wire et on réinitialise le capteur via le registre de gestion d'alimentation (Power Management). Il faut consulter la datasheet pour l'adresse du registre.
// Configure Accelerometer Sensitivity - Full Scale Range (default +/- 2g)
Wire.beginTransmission(MPU);
Wire.write(0x1C); // ACCEL_CONFIG register
Wire.write(0x10); // ±8g full scale range
Wire.endTransmission(true);
// Configure Gyro Sensitivity - Full Scale Range (default +/- 250deg/s)
Wire.beginTransmission(MPU);
Wire.write(0x1B); // GYRO_CONFIG register
Wire.write(0x10); // 1000deg/s full scale
Wire.endTransmission(true);loop(), on commence par lire l'accéléromètre. Les données de chaque axe sont sur 2 octets/registres. Les adresses sont dans la datasheet.
requestFrom() on demande 6 registres (X, Y, Z). On lit chaque registre et comme les sorties sont en complément à deux, on les combine correctement.Wire.beginTransmission(MPU);
Wire.write(0x3B); // ACCEL_XOUT_H
Wire.endTransmission(false);
Wire.requestFrom(MPU, 6, true);
AccX = (Wire.read() << 8 | Wire.read()) / 16384.0;
AccY = (Wire.read() << 8 | Wire.read()) / 16384.0;
AccZ = (Wire.read() << 8 | Wire.read()) / 16384.0;
accAngleX = (atan(AccY / sqrt(pow(AccX, 2) + pow(AccZ, 2))) * 180 / PI) - 0.58;
accAngleY = (atan(-1 * AccX / sqrt(pow(AccY, 2) + pow(AccZ, 2))) * 180 / PI) + 1.58;
currentTime = millis();
elapsedTime = (currentTime - previousTime) / 1000.0;
Wire.beginTransmission(MPU);
Wire.write(0x43); // GYRO_XOUT_H
Wire.endTransmission(false);
Wire.requestFrom(MPU, 6, true);
GyroX = (Wire.read() << 8 | Wire.read()) / 131.0;
GyroY = (Wire.read() << 8 | Wire.read()) / 131.0;
GyroZ = (Wire.read() << 8 | Wire.read()) / 131.0;
millis().GyroX = GyroX + 0.56;
GyroY = GyroY - 2;
GyroZ = GyroZ + 0.79;
gyroAngleX = gyroAngleX + GyroX * elapsedTime;
gyroAngleY = gyroAngleY + GyroY * elapsedTime;
yaw = yaw + GyroZ * elapsedTime;roll = 0.96 * gyroAngleX + 0.04 * accAngleX;
pitch = 0.96 * gyroAngleY + 0.04 * accAngleY;calculate_IMU_error() dans le setup avec le capteur à plat et immobile. On fait 200 lectures pour chaque sortie, on les somme et divise par 200. Comme le capteur est à plat, les valeurs attendues sont 0. On obtient ainsi l'erreur moyenne du capteur.void calculate_IMU_error() {
while (c < 200) {
Wire.beginTransmission(MPU);
Wire.write(0x3B);
Wire.endTransmission(false);
Wire.requestFrom(MPU, 6, true);
AccX = (Wire.read() << 8 | Wire.read()) / 16384.0;
AccY = (Wire.read() << 8 | Wire.read()) / 16384.0;
AccZ = (Wire.read() << 8 | Wire.read()) / 16384.0;
AccErrorX = AccErrorX + ((atan((AccY) / sqrt(pow((AccX), 2) + pow((AccZ), 2))) * 180 / PI));
AccErrorY = AccErrorY + ((atan(-1 * (AccX) / sqrt(pow((AccY), 2) + pow((AccZ), 2))) * 180 / PI));
c++;
}
AccErrorX = AccErrorX / 200;
AccErrorY = AccErrorY / 200;
c = 0;
while (c < 200) {
Wire.beginTransmission(MPU);
Wire.write(0x43);
Wire.endTransmission(false);
Wire.requestFrom(MPU, 6, true);
GyroX = Wire.read() << 8 | Wire.read();
GyroY = Wire.read() << 8 | Wire.read();
GyroZ = Wire.read() << 8 | Wire.read();
GyroErrorX = GyroErrorX + (GyroX / 131.0);
GyroErrorY = GyroErrorY + (GyroY / 131.0);
GyroErrorZ = GyroErrorZ + (GyroZ / 131.0);
c++;
}
GyroErrorX = GyroErrorX / 200;
GyroErrorY = GyroErrorY / 200;
GyroErrorZ = GyroErrorZ / 200;
Serial.print("AccErrorX: "); Serial.println(AccErrorX);
Serial.print("AccErrorY: "); Serial.println(AccErrorY);
Serial.print("GyroErrorX: "); Serial.println(GyroErrorX);
Serial.print("GyroErrorY: "); Serial.println(GyroErrorY);
Serial.print("GyroErrorZ: "); Serial.println(GyroErrorZ);
}
Serial.print on affiche Roll, Pitch, Yaw pour vérifier le bon fonctionnement.Suivi d'Orientation MPU6050 – Visualisation 3D
/* Arduino et MPU6050 IMU - Visualisation 3D par Dejan, https://howtomechatronics.com */
import processing.serial.*;
import java.awt.event.KeyEvent;
import java.io.IOException;
Serial myPort;
String data="";
float roll, pitch, yaw;
void setup() {
size(2560, 1440, P3D);
myPort = new Serial(this, "COM7", 19200);
myPort.bufferUntil('\n');
}
void draw() {
translate(width/2, height/2, 0);
background(233);
textSize(22);
text("Roll: " + int(roll) + " Pitch: " + int(pitch), -100, 265);
rotateX(radians(-pitch));
rotateZ(radians(roll));
rotateY(radians(yaw));
textSize(30);
fill(0, 76, 153);
box(386, 40, 200);
textSize(25);
fill(255, 255, 255);
text("www.HowToMechatronics.com", -183, 10, 101);
}
void serialEvent(Serial myPort) {
data = myPort.readStringUntil('\n');
if (data != null) {
data = trim(data);
String items[] = split(data, '/');
if (items.length > 1) {
roll = float(items[0]);
pitch = float(items[1]);
yaw = float(items[2]);
}
}
}draw(), on utilise ces valeurs pour faire pivoter l'objet 3D (ici un pavé coloré avec texte).



MPU6050_DMP6 qui est bien commenté ligne par ligne.
/* Arduino et MPU6050 IMU - Visualisation 3D par Dejan, https://howtomechatronics.com */
import processing.serial.*;
import java.awt.event.KeyEvent;
import java.io.IOException;
Serial myPort;
String data="";
float roll, pitch, yaw;
void setup() {
size(2560, 1440, P3D);
myPort = new Serial(this, "COM7", 19200);
myPort.bufferUntil('\n');
}
void draw() {
translate(width/2, height/2, 0);
background(233);
textSize(22);
text("Roll: " + int(roll) + " Pitch: " + int(pitch), -100, 265);
rotateX(radians(-pitch));
rotateZ(radians(roll));
rotateY(radians(yaw));
textSize(30);
fill(0, 76, 153);
box(386, 40, 200);
textSize(25);
fill(255, 255, 255);
text("www.HowToMechatronics.com", -183, 10, 101);
}
void serialEvent(Serial myPort) {
data = myPort.readStringUntil('\n');
if (data != null) {
data = trim(data);
String items[] = split(data, '/');
if (items.length > 1) {
roll = float(items[0]);
pitch = float(items[1]);
yaw = float(items[2]);
}
}
}serialEvent(), on reçoit les quaternions de l'Arduino et dans draw() on les utilise pour faire pivoter l'objet 3D. On voit comme les quaternions sont efficaces pour la rotation 3D.
Processus de fabrication
- Créer un verrou RFID sécurisé avec Arduino – Guide étape par étape
- Créer des animations et jeux sur LCD avec Arduino UNO
- Arduino et MPU6050 : Contrôle précis de servo-moteur avec SG90 et MG996R
- Contrôle Arduino UNO depuis Python 3 – Communication Série et Démo LED
- Construire une Radio FM Compacte avec Arduino Nano et RDA5807M
- Calculer les angles d'inclinaison à partir de l'accélération MPU6050 avec Arduino Nano et Visuino
- Enregistreur de Données Environnementales Arduino avec Carte SD et RTC
- Construisez un mini piano avec Arduino UNO – Tutoriel pas à pas
- Tutoriel Arduino Débutant 01 : Démarrez votre Premier Projet