[non réglé] programmation d'un magnétomètre mag3110 en boussole magnétique.

Bonjour,

Je suis étudiant en DUT et je travaille en ce moment sur un projet consistant à comparer 4 magnétomètres : HMC5883, CMPS11, LIS3MDL et MAG3110. L’objectif de leur programmation est d’avoir une boussole magnétique.
J’ai réussi à programmer les 3 premiers mais pas le MAG3110.

J’ai téléchargé la bibliothèque arduino “Sparkfun MAG3110 Magnetometer” pour réaliser mon programme. Je me suis inspiré du code “SparkFun_MAG3110_Basic” pour lire les valeurs des axes et du site “https://appelsiini.net/2018/calibrate-magnetometer” pour le calibrer.

Voici mon code :

#include <SparkFun_MAG3110.h>

MAG3110 mag = MAG3110(); //Instantiate MAG3110

int minX = 0;
int maxX = 0;
int minY = 0;
int maxY = 0;
int minZ = 0;
int maxZ = 0;


void setup() {
  Serial.begin(9600);

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

void loop() {

  int x, y, z;
  //Only read data when it's ready
  if(mag.dataReady()) {
    //Read the data
    mag.readMag(&x, &y, &z);
    
// First : calibrate captor   
// Determine min and max values
  if (x < minX) minX = x;
  if (x > maxX) maxX = x;
  if (y < minY) minY = y;
  if (y > maxY) maxY = y;

// calculate offsets
  int offX = (maxX + minX)/2;
  int offY = (maxY + minY)/2;

// determine magnetic compensation
  float avg_delta_x = (maxX-minX)/2;
  float avg_delta_y = (maxX-minX)/2;
  float avg_delta_z = (maxX-minX)/2;
  float avg_delta = (avg_delta_x + avg_delta_y + avg_delta_z)/3;
  float ech_x = avg_delta/avg_delta_x;
  float ech_y = avg_delta/avg_delta_y;



// After calibrate captor and know offsets and magnetic compensation values
// correct axes x and y. 
// Exemple : corrected_x = (sensor_x - offset_x)*scale_x

float X = (x-offX)*ech_x ;
float Y = (y-offY)*ech_y ;

// Calculate heading
  float heading = atan2(Y,X);
  
// Correct for heading < 0deg and heading > 360deg
  if (heading < 0)
  {
    heading += 2 * PI;
  }

  if (heading > 2 * PI)
  {
    heading -= 2 * PI;
  }

  // Convert to degrees
  float headingDegrees = heading * 180/M_PI; 


 


  
    /*Serial.print("X: ");
    Serial.print(x);
    Serial.print(", Y: ");
    Serial.print(y);
    Serial.print(", Z: ");
    Serial.println(z);
    
    Serial.print("offset x=");
    Serial.print(offX);
    Serial.print("offset y =");
    Serial.print(offY);
    Serial.print("echelle x =");
    Serial.print(ech_x);
    Serial.print("echelle y =");
    Serial.print(ech_y);
        
    */Serial.print(" Degress = ");
    Serial.print(headingDegrees);
    Serial.println("--------");
  }
}

Je téléverse une première fois pour connaitre mes valeurs d’offsets et de compensations magnétiques. Je les obtiens en faisant tourner mon capteur jusqu’à ce que ces valeurs se stabilisent.
Je rentre alors ces valeurs dans les formules "float X " et “float Y” pour obtenir la bonne calibration des axes X et Y.

Ensuite je re-téléverse pour afficher l’angle de mon capteur, que j’obtiens grâce à la formule “heading = atan2(Y,X)”.

Mais les résultats obtenus ne sont pas cohérents : mon angle varie uniquement entre 310° et 350° ou alors il passe de 259° à 45° en une seconde.

Est ce que quelqu’un aurait une idée du problème, s’il vous plait?

Je vous remercie d’avance.

Es-tu sûr de cette ligne là (X ou Y ?) :

float avg_delta_y = (maxX-minX)/2;

De plus pour avoir des float, il faudrait utiliser des float :

  float avg_delta_x = (maxX-minX)/2.0;
  float avg_delta_y = (maxX-minX)/2.0;
  float avg_delta_z = (maxX-minX)/2.0;

Bonjour,

Je vous remercie pour votre réponse.

Pour tout ce qui est calibrage, n'étant pas un expert, je me suis inspiré du site "How to Calibrate a Magnetometer? ". J'ai utilisé ce même type de calibrage pour le magnetomètre LIS3MDL et celui fonctionnait correctement avec.

J'ai corrigé les erreurs que vous m'avez signalées sur mon code et refais un test, mais le problème est toujours là..

Un grand merci pour votre aide.

Poste ton code STP ainsi que ce qui s'affiche sur la console.

Bonjour,

Voici le code utilisé :

#include <SparkFun_MAG3110.h>

MAG3110 mag = MAG3110(); //Instantiate MAG3110

int minX = 0;
int maxX = 0;
int minY = 0;
int maxY = 0;
int minZ = 0;
int maxZ = 0;


void setup() {
  Serial.begin(9600);

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

void loop() {

  int x, y, z;
  //Only read data when it's ready
  if(mag.dataReady()) {
    //Read the data
    mag.readMag(&x, &y, &z);
    
// First : calibrate captor   
// Determine min and max values
  if (x < minX) minX = x;
  if (x > maxX) maxX = x;
  if (y < minY) minY = y;
  if (y > maxY) maxY = y;

// calculate offsets
  int offX = (maxX + minX)/2;
  int offY = (maxY + minY)/2;

// determine magnetic compensation
  float avg_delta_x = (maxX-minX)/2.0;
  float avg_delta_y = (maxX-minX)/2.0;
  float avg_delta_z = (maxX-minX)/2.0;
  float avg_delta = (avg_delta_x + avg_delta_y + avg_delta_z)/3.0;
  float ech_x = avg_delta/avg_delta_x;
  float ech_y = avg_delta/avg_delta_y;



// After calibrate captor and know offsets and magnetic compensation values
// correct axes x and y. 
// Exemple : corrected_x = (sensor_x - offset_x)*scale_x

float X = (x-523.0)*1.0 ;
float Y = (y+190.0)*1.0 ;

// Calculate heading
  float heading = atan2(Y,X);
  
// Correct for heading < 0deg and heading > 360deg
  if (heading < 0)
  {
    heading += 2 * PI;
  }

  if (heading > 2 * PI)
  {
    heading -= 2 * PI;
  }

  // Convert to degrees
  float headingDegrees = heading * 180.0/M_PI; 

 
    /*Serial.print("X: ");
    Serial.print(x);
    Serial.print(", Y: ");
    Serial.print(y);
    Serial.print(", Z: ");
    Serial.println(z);
    
    Serial.print("offset x=");
    Serial.print(offX);
    Serial.print("offset y =");
    Serial.print(offY);
    Serial.print("echelle x =");
    Serial.print(ech_x);
    Serial.print("echelle y =");
    Serial.print(ech_y);
        
    */Serial.print(" Degress = ");
    Serial.print(headingDegrees);
    Serial.println("--------");
  }
}

En appliquant ce code, au lieu d’avoir un angle variant continuellement de 0 à 360° lorsque je fais tourner mon capteur; j’obtiens un angle qui va partir de 0°, croître jusque 41° et puis repartir vers 0°… (voir PJ)

Sur la pièce jointe, on voit qu’au dessus de la ligne noire, l’angle croît. En dessous de cette ligne , il repart vers 0°…

Merci d’avance pour votre aide.

Déjà, tu utilises PI partout sauf dans cette ligne ou tu mets M_PI :
float headingDegrees = heading * 180.0/M_PI;Conserve PI ici aussi.

Ensuite, le programme fait ce que tu lui demandes :

float X = (x-523.0)*1.0 ;
float Y = (y+190.0)*1.0 ;

// Calculate heading
  float heading = atan2(Y,X);

Les 2 arguments de atan2 peuvent varier entre -1 et 1 et quand tu fais un tour complet avec ton capteur, ces deux arguments devraient en effet passer par les valeurs -1 et 1, ce qui te donnerait des angles variant entre 0 et 360°.

Mais tu fais une compensation avant le atan2, donc il n'est plus sûr que les arguments varient dans cet intervalle. Si tu veux en savoir plus, il te faut afficher les valeurs de X et Y : remplace

Serial.print(" Degress = ");
    Serial.print(headingDegrees);
    Serial.println("--------");

par

    Serial.print(" X = ");
    Serial.print(X);
    Serial.print(" Y = ");
    Serial.print(Y);
    Serial.print(" Degrees = ");
    Serial.println(headingDegrees);

et regarde ce que ça donne sur la console.

Je vous remercie.

J’ai apporté les modifications que vous avez suggérées, à mon code.

Je poste les résultats obtenus en pièce jointe. Il semble en effet, que les arguments ne respectent pas leur bonne plage.

Je pensais que c'était entre -1 et 1 mais ce lien indique que d'autres valeurs sont possibles. quoi qu'il en soit, je pense que c'est la calibration et la compensation qui posent problème.

Ce qui est étonnant c'est que les valeurs restent toujours proches (entre 70 et 100) ce qui donne des angles proches de 45° (entre 40 et 50). Je n'ai jamais utilisé ce capteur, donc je ne peux guère aider plus... Cherche des sites qui précisent bien la procédure d'étalonnage.

Bonjour,

Je vais retravailler sur cela alors.

Je vous remercie pour votre aide.