Utilisation d'un gyroscope, problème de code

Bonjour !

Je voudrais utiliser un gyroscope (qui fait aussi accéléromètre et magnétomètre mais bref). Il s'agit d'un MPU 92.65
(DATASHEET : https://www.invensense.com/wp-content/uploads/2015/02/PS-MPU-9250A-01-v1.1.pdf)

J'ai trouvé un code sur internet pour acquérir des données en "même temps" pour acquérir des positions, des intensités et des vitesses. Le problème est que ça ne marche pas bien, vu que toutes mes données sont fixées à part la première colonne (qui correspond à l'axe x des vitesses). Si quelqu'un pouvait jeter un coup d'oeil au code et me dire s'il trouve quelque chose de bizarre, parce que même après avoir modifié quelques trucs, le code se compile normalement.

Code en question :

// Initial time
long int ti;
volatile bool intFlag=false;

// Initializations
void setup()
{
  // Arduino initializations
  Wire.begin();
  Serial.begin(9600);
  
  // Set accelerometers low pass filter at 5Hz
  I2CwriteByte(MPU9265_ADDRESS,29,0x06);
  // Set gyroscope low pass filter at 5Hz
  I2CwriteByte(MPU9265_ADDRESS,26,0x06);
 
  
  // Configure gyroscope range
  I2CwriteByte(MPU9265_ADDRESS,27,GYRO_FULL_SCALE_1000_DPS);
  // Configure accelerometers range
  I2CwriteByte(MPU9265_ADDRESS,28,ACC_FULL_SCALE_4_G);
  // Set by pass mode for the magnetometers
  I2CwriteByte(MPU9265_ADDRESS,0x37,0x02);
  
  // Request continuous magnetometer measurements in 16 bits
  I2CwriteByte(MAG_ADDRESS,0x0A,0x16);
  
   pinMode(13, OUTPUT);
  Timer1.initialize(10000);         // initialize timer1, and set a 1/2 second period
  Timer1.attachInterrupt(callback);  // attaches callback() as a timer overflow interrupt
  
  
  // Store initial time
  ti=millis();
}





// Counter
long int cpt=0;

void callback()
{ 
  intFlag=true;
  digitalWrite(13, digitalRead(13) ^ 1);
}

// Main loop, read and display data
void loop()
{
  while (!intFlag);
  intFlag=false;
  
  // Display time
  Serial.print (millis()-ti,DEC);
  Serial.print ("\t");

  
  // _______________
  // ::: Counter :::
  
  // Display data counter
//  Serial.print (cpt++,DEC);
//  Serial.print ("\t");
  
 
 
  // ____________________________________
  // :::  accelerometer and gyroscope ::: 

  // Read accelerometer and gyroscope
  uint8_t Buf[14];
  I2Cread(MPU9250_ADDRESS,0x3B,14,Buf);
  
  // Create 16 bits values from 8 bits data
  
  // Accelerometer
  int16_t ax=-(Buf[0]<<8 | Buf[1]);
  int16_t ay=-(Buf[2]<<8 | Buf[3]);
  int16_t az=Buf[4]<<8 | Buf[5];

  // Gyroscope
  int16_t gx=-(Buf[8]<<8 | Buf[9]);
  int16_t gy=-(Buf[10]<<8 | Buf[11]);
  int16_t gz=Buf[12]<<8 | Buf[13];
  
    // Display values
  
  // Accelerometer
  Serial.print (ax,DEC); 
  Serial.print ("\t");
  Serial.print (ay,DEC);
  Serial.print ("\t");
  Serial.print (az,DEC);  
  Serial.print ("\t");
  
  // Gyroscope
  Serial.print (gx,DEC); 
  Serial.print ("\t");
  Serial.print (gy,DEC);
  Serial.print ("\t");
  Serial.print (gz,DEC);  
  Serial.print ("\t");

  
  // _____________________
  // :::  Magnetometer ::: 

  
  // Read register Status 1 and wait for the DRDY: Data Ready
  
  uint8_t ST1;
  do
  {
    I2Cread(MAG_ADDRESS,0x02,1,&ST1);
  }
  while (!(ST1&0x01));

  // Read magnetometer data  
  uint8_t Mag[7];  
  I2Cread(MAG_ADDRESS,0x03,7,Mag);
  

  // Create 16 bits values from 8 bits data
  
  // Magnetometer
  int16_t mx=-(Mag[3]<<8 | Mag[2]);
  int16_t my=-(Mag[1]<<8 | Mag[0]);
  int16_t mz=-(Mag[5]<<8 | Mag[4]);
  
  
  // Magnetometer
  Serial.print (mx+200,DEC); 
  Serial.print ("\t");
  Serial.print (my-70,DEC);
  Serial.print ("\t");
  Serial.print (mz-700,DEC);  
  Serial.print ("\t");
  
  
  
  // End of line
  Serial.println("");
//  delay(100);    
}

Et voilà ce que ça me fait sur le moniteur série :
https://image.noelshack.com/fichiers/2019/17/2/1555987590-gyro-pas-compris.png

D'ailleurs pour la mise en forme : 1ère à 3ème colonne : ax, ay, az (a pour accéléromètre).
4ème à 6ème colonne : gx, gy, gz (g -> gyroscope).
7ème à 9ème : mx, my, mz (m-> magnétomètre).

Cordialement.

votre code ne compile même pas... manque pas un truc là .... ? Postez tout le code, lien vers les librairies utilisées éventuellement

Votre image (c'est du texte, c'est quand même plus simple de le copier/ coller..)

Merci c'est gentil.

Et sinon, une idée de ce qui pourrait foirer dans le code ? :slight_smile:

Ohmyduddy:
Et sinon, une idée de ce qui pourrait foirer dans le code ? :slight_smile:

ben on ne sait pas puisque vous n'avez pas eu l'idée de poster tout le code... ça compile même pas, on ne sait pas quelle librairie vous utilisez, comment vous avez câblé ni même quel arduino vous utilisez

bref lisez les règles pour bien poster...

PS: testez avec cette librairie et ses exemples, ça vous permettra au moins de valider votre montage (calibrez le)

Autant pour moi.

J'utilise un Arduino UNO avec Vcc sur 5v, GND sur GND, SCL sur A5, SDA sur A4.

Voici le code en entier cette fois :

#include <Wire.h>
#include <TimerOne.h>

#define    MPU9250_ADDRESS            0x68
#define    MAG_ADDRESS                0x0C

#define    GYRO_FULL_SCALE_250_DPS    0x00  
#define    GYRO_FULL_SCALE_500_DPS    0x08
#define    GYRO_FULL_SCALE_1000_DPS   0x10
#define    GYRO_FULL_SCALE_2000_DPS   0x18

#define    ACC_FULL_SCALE_2_G        0x00  
#define    ACC_FULL_SCALE_4_G        0x08
#define    ACC_FULL_SCALE_8_G        0x10
#define    ACC_FULL_SCALE_16_G       0x18



// This function read Nbytes bytes from I2C device at address Address. 
// Put read bytes starting at register Register in the Data array. 
void I2Cread(uint8_t Address, uint8_t Register, uint8_t Nbytes, uint8_t* Data)
{
  // Set register address
  Wire.beginTransmission(Address);
  Wire.write(Register);
  Wire.endTransmission();
  
  // Read Nbytes
  Wire.requestFrom(Address, Nbytes); 
  uint8_t index=0;
  while (Wire.available())
    Data[index++]=Wire.read();
}


// Write a byte (Data) in device (Address) at register (Register)
void I2CwriteByte(uint8_t Address, uint8_t Register, uint8_t Data)
{
  // Set register address
  Wire.beginTransmission(Address);
  Wire.write(Register);
  Wire.write(Data);
  Wire.endTransmission();
}



// Initial time
long int ti;
volatile bool intFlag=false;

// Initializations
void setup()
{
  // Arduino initializations
  Wire.begin();
  Serial.begin(9600);
  
  // Set accelerometers low pass filter at 5Hz
  I2CwriteByte(MPU9250_ADDRESS,29,0x06);
  // Set gyroscope low pass filter at 5Hz
  I2CwriteByte(MPU9250_ADDRESS,26,0x06);
 
  
  // Configure gyroscope range
  I2CwriteByte(MPU9250_ADDRESS,27,GYRO_FULL_SCALE_1000_DPS);
  // Configure accelerometers range
  I2CwriteByte(MPU9250_ADDRESS,28,ACC_FULL_SCALE_4_G);
  // Set by pass mode for the magnetometers
  I2CwriteByte(MPU9250_ADDRESS,0x37,0x02);
  
  // Request continuous magnetometer measurements in 16 bits
  I2CwriteByte(MAG_ADDRESS,0x0A,0x16);
  
   pinMode(13, OUTPUT);
  Timer1.initialize(10000);         // initialize timer1, and set a 1/2 second period
  Timer1.attachInterrupt(callback);  // attaches callback() as a timer overflow interrupt
  
  
  // Store initial time
  ti=millis();
}





// Counter
long int cpt=0;

void callback()
{ 
  intFlag=true;
  digitalWrite(13, digitalRead(13) ^ 1);
}

// Main loop, read and display data
void loop()
{
  while (!intFlag);
  intFlag=false;
  
  // Display time
  Serial.print (millis()-ti,DEC);
  Serial.print ("\t");

  
  // _______________
  // ::: Counter :::
  
  // Display data counter
//  Serial.print (cpt++,DEC);
//  Serial.print ("\t");
  
 
 
  // ____________________________________
  // :::  accelerometer and gyroscope ::: 

  // Read accelerometer and gyroscope
  uint8_t Buf[14];
  I2Cread(MPU9250_ADDRESS,0x3B,14,Buf);
  
  // Create 16 bits values from 8 bits data
  
  // Accelerometer
  int16_t ax=-(Buf[0]<<8 | Buf[1]);
  int16_t ay=-(Buf[2]<<8 | Buf[3]);
  int16_t az=Buf[4]<<8 | Buf[5];

  // Gyroscope
  int16_t gx=-(Buf[8]<<8 | Buf[9]);
  int16_t gy=-(Buf[10]<<8 | Buf[11]);
  int16_t gz=Buf[12]<<8 | Buf[13];
  
    // Display values
  
  // Accelerometer
  Serial.print (ax,DEC); 
  Serial.print ("\t");
  Serial.print (ay,DEC);
  Serial.print ("\t");
  Serial.print (az,DEC);  
  Serial.print ("\t");
  
  // Gyroscope
  Serial.print (gx,DEC); 
  Serial.print ("\t");
  Serial.print (gy,DEC);
  Serial.print ("\t");
  Serial.print (gz,DEC);  
  Serial.print ("\t");

  
  // _____________________
  // :::  Magnetometer ::: 

  
  // Read register Status 1 and wait for the DRDY: Data Ready
  
  uint8_t ST1;
  do
  {
    I2Cread(MAG_ADDRESS,0x02,1,&ST1);
  }
  while (!(ST1&0x01));

  // Read magnetometer data  
  uint8_t Mag[7];  
  I2Cread(MAG_ADDRESS,0x03,7,Mag);
  

  // Create 16 bits values from 8 bits data
  
  // Magnetometer
  int16_t mx=-(Mag[3]<<8 | Mag[2]);
  int16_t my=-(Mag[1]<<8 | Mag[0]);
  int16_t mz=-(Mag[5]<<8 | Mag[4]);
  
  
  // Magnetometer
  Serial.print (mx+200,DEC); 
  Serial.print ("\t");
  Serial.print (my-70,DEC);
  Serial.print ("\t");
  Serial.print (mz-700,DEC);  
  Serial.print ("\t");
  
  
  
  // End of line
  Serial.println("");
//  delay(100);    
}

Les librairies utilisées sont TimerOne.h :
GitHub - PaulStoffregen/TimerOne: TimerOne Library with optimization and expanded hardware support.
Et Wire.h :
GitHub - PaulStoffregen/Wire: Wire library used on Teensy boards.

Cordialement.

EDIT : J'avais déjà essayé l'exemple mais aucun succès, la compilation s'effectue et le téléversement aussi. Cela dit je n'avais pas noté l'I2C error code 2 qui vient de s'afficher.

c'est pas un 3.3 volt votre shield ??

vous avez pris le code ici ?

J'ai voulu essayer de câbler en 5V, rien n'y a fait. Mais normalement je le câble en 3.3V
D'ailleurs je m'étais appuyé sur un post précédent :
How to connect IMU 9250 - Sensors - Arduino Forum. (post 2).

Sinon oui j'ai pris le code de là.

Cordialement.

EDIT : J'ai essayé de brancher AD0 de mon capteur à la masse pour avoir une adresse 0x68 et résoudre I2C error code 2 mais ça n'a pas fonctionné.

Quelques petits trucs à modifier dans le code :

long int ti;enunsigned long ti = 0;
Ceci initialise la période du timer à 10ms pas une demi seconde.

Timer1.initialize(10000);         // initialize timer1, and set a 1/2 second period

As-tu vérifié avec un scanner que l'adresse du capteur est bien 0x68 ?#define    MPU9250_ADDRESS            0x68

Merci pour la réponse !

J'ai vérifié au scanner, le capteur n'est pas détecté...
J'ai vérifié au multimètre la tension d'alimentation du capteur, elle est bien de 3.3V (ou 5V selon lsortie de l'UNO), par contre SCL et SDA sont tous les deux à 0V. Mais ducoup là je suis un peu bloqué parce que ça veut dire pour moi que :

  • Soit j'ai des pull up internes qui descendent mes tensions en LOW, mais pour moi c'est complètement improbable.
  • Soit j'ai mon circuit qui a grillé à un moment.

Dans les deux cas je suis pas bien.
Y'a-t-il une autre option ?

Cordialement.

As-tu un autre arduino pour tester le MPU dessus ?
As-tu un autre device I2C pour le tester sur ton uno ?

Bonjour,

Je viens de réessayer le scanner sur le même arduino UNO mais avec un mag3110, le scanner ne détecte rien.
Par contre, lorsque j'ajoute une résistance de 4,7kOhms sur chaque voie SCL et SDA, mon capteur est détecté.

Ce qui me laisse penser que c'est au niveau des résistances de pull up qu'il faut que je cherche (et que dans mon post d'avant j'avais pas bien compris le terme). Cependant, ce qui me fait réfléchir c'est que sur la datasheet du MAG3110 ( bon en soit ça l'est pas exactement mais bon) :
https://learn.sparkfun.com/tutorials/mag3110-magnetometer-hookup-guide-/all
Il y a déjà des résistances de pull up intégrés. Donc cette partie où je rajoute des résistances alors qu'il y en a déjà me laisse un peu perplexe mais bon "tant que ça marche". :slight_smile:

La question maintenant est de savoir s'il faut que je laisse ces résistances pour mon gyroscope...

Cordialement.

EDIT: En laissant mes résistances de pull up, mon scanner reconnaît bien mon capteur et renvoi l'adresse 0x68, mais en lançant le code, j'ai une I2C error code 4...

Ohmyduddy:
Il y a déjà des résistances de pull up intégrés. Donc cette partie où je rajoute des résistances alors qu'il y en a déjà me laisse un peu perplexe mais bon "tant que ça marche". :slight_smile:

Le pont de soudure, près du connecteur, pour raccorder les résistance au Vcc est bien présent?

Oui il est bien présent !

EDIT : Après avoir regardé la signification d'error code 4, j'ai essayé d'augmenter la valeur des résistances de pull up à 10kOhms, et là j'ai à nouveau une error code 2, et quand je repasse avec 4,7k, et bien j'ai de nouveau l'error code 2 là où j'avais l'error code 4, je comprends plus ou moins plus rien.

2 c'est mieux que 4 :slight_smile:

Sur la page de référence de Wire.endTransmission(), on trouve :

Returns
byte, which indicates the status of the transmission:

0:success
1:data too long to fit in transmit buffer
2:received NACK on transmit of address
3:received NACK on transmit of data
4:other error

Il faut que tu trouves à quel endroit de ton programme ce code d'erreur s'affiche : mets des Serial.println un peu partout pour voir ceux qui apparaissent avant ton code d'erreur. Est-ce juste après le premier appel de I2CwriteByte(MPU9250_ADDRESS,29,0x06); ? Ou bien plus loin dans le code ?

Bon eh bien j'ai trouvé.

Rien à voir avec les pull-up ou quoi que ce soit.

J'avais juste un problème de connectique (fil pas assez bien soudé).

C'est presque une chute à la fin d'une histoire tellement c'est nul.

Merci pour vos réponses !

L'important c'est que ça marche !!!

C'est encore moi.

J'ai essayé de faire marcher en même temps les deux capteurs (MAG3110 et MPU9265), et ça n'a pas marché.

Déjà, je sais que le mpu me permet d'obtenir une mesure du champs magnétique, mais on m'a demandé d'utiliser les deux, donc j'utilise les deux !

Bon alors mon gyro marche bien (en tant qu'accéléromètre et gyroscope), mais par contre mon magnétomètre a fait le fatigué.

Un truc qui me bloque c'est que j'ai connecté mes 2 SDA SCL aux sorties de l'arduino UNO. Je sais que ces capteurs utilisent des adresses différentes mais ça me plaît pas trop.

Ducou j'ai comme branchement :
+3.3V -> Vcc MAG et MPU
GND -> GND MAG et MPU
A4 -> SDA MPU / SDA (Arduino) -> SDA MAG
A5 -> SCL MPU / SCL (Arduino) -> SCL MAG

Et j'utilise le code suivant :

#include "MPU9250.h"
#include <SparkFun_MAG3110.h>

MAG3110 mag = MAG3110(); //Instantiate MAG3110

// an MPU9250 object with the MPU-9250 sensor on I2C bus 0 with address 0x68
MPU9250 IMU(Wire,0x68);
int status;
float timer;
void setup() {
  // serial to display data
  Serial.begin(9600);

  mag.initialize(); //Initializes the mag sensor
  mag.start();      //Puts the sensor in active mode
  
  while(!Serial) {}

  // start communication with IMU 
  status = IMU.begin();
  if (status < 0) {
    Serial.println("IMU initialization unsuccessful");
    Serial.println("Check IMU wiring or try cycling power");
    Serial.print("Status: ");
    Serial.println(status);
    while(1) {}
  }
}

void loop() {
  // read the sensor
  IMU.readSensor();
  // display the data
  Serial.print("AccelX: ");
  Serial.print(IMU.getAccelX_mss(),6);
  Serial.print("  ");
  Serial.print("AccelY: ");  
  Serial.print(IMU.getAccelY_mss(),6);
  
  Serial.print(" ");
  Serial.print("GyroX: ");
  Serial.print(IMU.getGyroX_rads(),6);
  Serial.print("  ");
  Serial.print("GyroY: ");  
  Serial.print(IMU.getGyroY_rads(),6);
  Serial.print("  ");
  Serial.print("GyroZ: ");  
  Serial.print(IMU.getGyroZ_rads(),6);

  Serial.print(" ");
  Serial.print("timer: ");
  Serial.println(timer);
  timer = timer+0.2 ;
  
  int x, y, z;
  //Only read data when it's ready
  if(mag.dataReady()) {
    //Read the data
    mag.readMag(&x, &y, &z);

   
    int a = sqrt(x*x+y*y+z*z);
    Serial.print (", Norm:");
    Serial.println (a);
  }
  
  Serial.println();
  
  delay(200);
 
}

Je soupçonne l'acquisition "simultanée" d'être ici mon problème, mais je ne me suis jamais confrontré à ça ducoup je nage dans la soupe.
Où alors tout simplement mon code...

Des avis ?

Cordialement.

L'I2C est prévu pour faire fonctionner plusieurs devices sur le même bus, les mêmes fils. Donc ça ne devrait pas poser de problème.

Es-tu sûr que les adresses sont différentes : as-tu vérifié avec un I2C scanner ?
As-tu mis ou vérifié que tes modules ont des résistances de pull-up ?

Quand tu dis que le magnétomètre ne marche pas, peux-tu préciser ? Ça peut venir du code pour plusieurs raisons :

  • Pas la bonne adresse du capteur
  • Capteur pas calibré (voir les exemples de la bibli)
  • Lecture imprécise : tu utilises readMag mais il existe aussi readMicroTeslas
  • Calcul imprécis : une racine carrée en entier ça donne des résultats imprécis. Racine de 168 te donner 12, or 13 * 13 = 169.
    L'exemple readMagnitude fais son calcul comme suit :
    mag.readMag(&x, &y, &z);
    float magnitude = sqrt(pow(x*mag.x_scale, 2) + pow(y*mag.y_scale, 2)); //x_scale and y_scale are set by calibration! Do not modify them!
    Serial.println(magnitude);

mag.x_scale et mag.y_scale sont des valeurs issues de la calibration (méthode calibrate)

Merci pour la réponse !

J'avais déjà vérifié, le gyroscope est à 0x68 et le magnéto à 0x0E (de mémoire).

Là c'est pas du tout un problème de calibration ou quoi, le problème se trouve dans l'acquisition de la valeur en elle même. J'ai mis ce que le moniteur m'affichait en pièce jointe.

Ici ce qui m'intéresse c'est la norme (racine de la somme des intensités au carré suivant chaque axe) du champs magnétique. Dans l'exemple je n'ai pas mis d'aimant à proximité, ce qui veut dire qu'il varie de 0 à 100 comme ça. Mais quand j'applique un aimant "fort", la valeur reste entre 0 et 100. Et cette variation de 0 à 100 est limite périodique.

Donc je me dis que si le capteur marche tout seul sans aucun problème, et que lorsque je copie-colle le code et que je le met avec un autre capteur ça marche plus, c'est qu'il y a un problème en lien avec le deuxième capteur.

Cordialement.

PS: Merci pour le int sur le calcul de la racine, j'avais complètement zappé, j'ai mis un float à la place.

EDIT: Lorsque j'ai remplacé mon int par float, j'ai maintenant "nan" qui est renvoyé.
EDIT : J'ai trouvé c'est bon ! J'ai fais n'importe quoi lorsque j'ai passé d'un programme à un autre... J'avais mal calibré le temps entre chaque acquisition des deux, ducoup ça me faisait n'importe quoi. Merci à toutes les personnes qui ont aidé !! :smiley: