gyroscope GY-521 mpu6050

Bonjour
Je cherche à faire des quart de tour, des demi-tours avec un robot, mais sans encodeur aux roues.
Je pensais commander une boussole, mais je me suis souvenu que j’ai un GY-521.

On trouve des tas de codes qui marchent ou pas, avec parfois trois bibliothèques, certaines introuvables.
C’est la jungle.

Je cherche uniquement à connaître la rotation de mon robot.

Camarade, toi qui connais bien ce composant, qu’utilises-tu comme code et bibliothèque?

Actuellement, je teste ce code:

#include "Wire.h" // This library allows you to communicate with I2C devices.
const int MPU_ADDR = 0x68; // I2C address of the MPU-6050. If AD0 pin is set to HIGH, the I2C address will be 0x69.
int16_t accelerometer_x, accelerometer_y, accelerometer_z; // variables for accelerometer raw data
int16_t gyro_x, gyro_y, gyro_z; // variables for gyro raw data
int16_t temperature; // variables for temperature data
char tmp_str[7]; // temporary variable used in convert function
char* convert_int16_to_str(int16_t i) { // converts int16 to string. Moreover, resulting strings will have the same length in the debug monitor.
  sprintf(tmp_str, "%6d", i);
  return tmp_str;
}
void setup() {
  Serial.begin(9600);
  Wire.begin();
  Wire.beginTransmission(MPU_ADDR); // Begins a transmission to the I2C slave (GY-521 board)
  Wire.write(0x6B); // PWR_MGMT_1 register
  Wire.write(0); // set to zero (wakes up the MPU-6050)
  Wire.endTransmission(true);
}
void loop() {
  Wire.beginTransmission(MPU_ADDR);
  Wire.write(0x3B); // starting with register 0x3B (ACCEL_XOUT_H) [MPU-6000 and MPU-6050 Register Map and Descriptions Revision 4.2, p.40]
  Wire.endTransmission(false); // the parameter indicates that the Arduino will send a restart. As a result, the connection is kept active.
  Wire.requestFrom(MPU_ADDR, 7*2, true); // request a total of 7*2=14 registers
  
  // "Wire.read()<<8 | Wire.read();" means two registers are read and stored in the same variable
  accelerometer_x = Wire.read()<<8 | Wire.read(); // reading registers: 0x3B (ACCEL_XOUT_H) and 0x3C (ACCEL_XOUT_L)
  accelerometer_y = Wire.read()<<8 | Wire.read(); // reading registers: 0x3D (ACCEL_YOUT_H) and 0x3E (ACCEL_YOUT_L)
  accelerometer_z = Wire.read()<<8 | Wire.read(); // reading registers: 0x3F (ACCEL_ZOUT_H) and 0x40 (ACCEL_ZOUT_L)
  temperature = Wire.read()<<8 | Wire.read(); // reading registers: 0x41 (TEMP_OUT_H) and 0x42 (TEMP_OUT_L)
  gyro_x = Wire.read()<<8 | Wire.read(); // reading registers: 0x43 (GYRO_XOUT_H) and 0x44 (GYRO_XOUT_L)
  gyro_y = Wire.read()<<8 | Wire.read(); // reading registers: 0x45 (GYRO_YOUT_H) and 0x46 (GYRO_YOUT_L)
  gyro_z = Wire.read()<<8 | Wire.read(); // reading registers: 0x47 (GYRO_ZOUT_H) and 0x48 (GYRO_ZOUT_L)
  
  // print out data
  Serial.print("aX = "); Serial.print(convert_int16_to_str(accelerometer_x));
  Serial.print(" | aY = "); Serial.print(convert_int16_to_str(accelerometer_y));
  Serial.print(" | aZ = "); Serial.print(convert_int16_to_str(accelerometer_z));
  // the following equation was taken from the documentation [MPU-6000/MPU-6050 Register Map and Description, p.30]
  Serial.print(" | tmp = "); Serial.print(temperature/340.00+36.53);
  Serial.print(" | gX = "); Serial.print(convert_int16_to_str(gyro_x));
  Serial.print(" | gY = "); Serial.print(convert_int16_to_str(gyro_y));
  Serial.print(" | gZ = "); Serial.print(convert_int16_to_str(gyro_z));
  Serial.println();
  
  // delay
  delay(1000);
}

Ce que je vois à l’écran:
aX = 2960 | aY = 3292 | aZ = 13080 | tmp = 28.48 | gX = -1002 | gY = -9239 | gZ = -3738
aX = 12832 | aY = -668 | aZ = 16452 | tmp = 28.58 | gX = -10807 | gY = -8138 | gZ = -2576
aX = -672 | aY = -396 | aZ = 14716 | tmp = 28.44 | gX = 144 | gY = 45 | gZ = 26
aX = -1008 | aY = -332 | aZ = 14700 | tmp = 28.48 | gX = 123 | gY = 132 | gZ = 31
aX = -1216 | aY = -300 | aZ = 14640 | tmp = 28.34 | gX = 150 | gY = 92 | gZ = 34

C’est déroutant! Honnêtement, je ne vois même pas à l’écran le résultat de mes mouvements…

Suis-je incapable de lire ces données? (ok ça je l’accorde)
Ce module est-il un gadget?
Ou alors est-ce ce code qui exploite mal les capacités des composants?

En attendant, rien là-dedans ne ressemble à une rotation…

C’est vrai que c’est pas simple. Je n’ai pas le composant, mais j’en ai commandé un qui devrait arriver d’ici un mois. Donc continue à essuyer les plâtres, je passerai vérifier si c’est bien fait… :slight_smile:

Si je comprends bien le code et ce que j’ai lu par ailleurs, le capteur renvoie des données sur 16 bits, 8 de poids fort et 8 de poids faible. Les lignes suivantes servent à regrouper les deux octets pour en faire une donnée sur 16 bits :

// "Wire.read()<<8 | Wire.read();" means two registers are read and stored in the same variable
  accelerometer_x = Wire.read()<<8 | Wire.read(); // reading registers: 0x3B (ACCEL_XOUT_H) and 0x3C (ACCEL_XOUT_L)
  accelerometer_y = Wire.read()<<8 | Wire.read(); // reading registers: 0x3D (ACCEL_YOUT_H) and 0x3E (ACCEL_YOUT_L)
  accelerometer_z = Wire.read()<<8 | Wire.read(); // reading registers: 0x3F (ACCEL_ZOUT_H) and 0x40 (ACCEL_ZOUT_L)
  temperature = Wire.read()<<8 | Wire.read(); // reading registers: 0x41 (TEMP_OUT_H) and 0x42 (TEMP_OUT_L)
  gyro_x = Wire.read()<<8 | Wire.read(); // reading registers: 0x43 (GYRO_XOUT_H) and 0x44 (GYRO_XOUT_L)
  gyro_y = Wire.read()<<8 | Wire.read(); // reading registers: 0x45 (GYRO_YOUT_H) and 0x46 (GYRO_YOUT_L)
  gyro_z = Wire.read()<<8 | Wire.read(); // reading registers: 0x47 (GYRO_ZOUT_H) and 0x48 (GYRO_ZOUT_L)

Les lignes comme :
  Serial.print(" | gZ = "); Serial.print(convert_int16_to_str(gyro_z));servent à transformer la donnée non signée précédente en une donnée signée. C’est un peu tordu, mais on sent bien qu’une vitesse de rotation peut être positive ou négative selon le sens de la rotation.

Il y a 7 données :

  • 3 accélérations sur 3 axes (X, Y et Z),
  • 1 température,
  • 3 vitesses de rotation autour des mêmes 3 axes.
    La température te donne 28, c’est peut-être des degrés C et ça ne varie pas : c’est bon signe.

Les autres données, ça dépend de comment se tenait ton capteur lorsqu’il a fait ses mesures. Si tu veux avoir des données qui signifient quelque chose, il faut :

  • Lire la datasheet du composant : elle te dira ce que signifient les chiffres. Par exemple, à quel sens correspond quel signe ? Le chiffre fourni est une sorte de pourcentage de la valeur maximum mesurable. Si la gamme de mesure va de -100 à +100 pour une de ces données (hypothèse gratuite) et que la valeur fournie vaut 2000, la donnée réelle doit être calculée avec un map : il faut mapper depuis -32768 / +32768 vers -100 / +100 : 2000 deviendrait sauf erreur 6.1 (2000/32768*100)
  • Tester en conditions maîtrisées et reproductibles (pour étalonner le zinzin). Par exemple, capteur à plat sur une table horizontale : tu regardes ce qui se passe lorsque tu fais tourner le module horizontalement sur la table, lorsque tu l’inclines dans une direction, plus ou moins vite, etc.

pfiou, tu comprends tout quand tu parles ? ^^

Bon apparemment c'est de la vitesse angulaire que ça mesure. Mais la vitesse angulaire je crois que ça se donne en RAD et c'est simple d'avoir des DEGRES, une histoire de Pi...
En effet, on mesure 6 axes. La température, je ne vais pas trop approfondir...
3 axes je veux bien, mais 6 c'est abstrait pour moi...

Je vais manger des vidéos. Ce module est employé pour les drones, ça doit marcher.
Leurs besoins sont complexes, puisque les axes sont modulés par des PID et j'y comprends pas encore tout.

Je vais chercher des applications simples. Moi je veux juste un angle, mais c'est pas fait pour ça...
J'aurais peut-être intérêt à commander une boussole, mais 1 mois d'attente ça me rend dingue...

Je vais manger des vidéos, on verra ce que je peux en faire ^^

Point positif, c'est de l'i2c, et je commence à adorer ce système: 2 fils et ça roule.

Pas toujours, comme Maitre Gimm's.

C'est pas "6 axes" mais "6 degrés de liberté". Il n'y a que 3 axes, mais tu peux te déplacer dans ces 3 directions (donc accélérer : 3 accélérations) ou tourner autour d'eux (donc 3 rotations).

kammo:
Mais la vitesse angulaire je crois que ça se donne en RAD et c'est simple d'avoir des DEGRES, une histoire de Pi...

C'est en rad/s ou en deg/s (2pi = 360°)

Bonjour,

Si tu veux connaître l'angle, de rotation par rapport à la verticale, tu dois intégrer la vitesse de rotation:
angle = angle_precedent + vitesse_de_rotation * temps_entre_deux_mesures

Le problème est qu'avec l'offset et la dérive du capteur, une vitesse de rotation nulle n'est en général pas mesurée comme étant nulle par le capteur, ou alors c'est un coup de chance qui ne dure pas. Cette méthode donne donc rapidement n'importe quoi... sauf si si as un capteur qui intègre un magnétomètre (comme le mpu9250, pour rester dans la même famille), qui permet de recaler les calculs avec le nord, qui a tendance à rester fixe en première approximation.

Ceci étant, dans les bibliothèques et les exemples que l'on trouve assez facilement avec le mpu6050 (https://github.com/jrowberg/i2cdevlib/blob/master/Arduino/MPU6050/examples/MPU6050_DMP6/MPU6050_DMP6.ino), tu peux facilement afficher les angles d'euler et ça donne des résultats pas trop pourris sur du court terme. Concrètement, tu pourra faire tourner rapidement ton robot d'un quart de tour mais il ne faudra pas t'étonner s'il a lentement fait un demi-tour de plus non souhaité 15 minutes plus tard.