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 "How to Calibrate a 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?
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à..
#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°...
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
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.