Problems with getting QMC5883 to work - incorrect values?

Hi!

I have recently purchased a QMC5883 magnetometer and I am having some trouble getting it to work. I’ve tried using the QMC5883LCompass library by MPrograms. I get X, Y and Z values which I would assume are correct according to tutorials that I’ve watched.

I have tried running the calibration program which is included as an example and that returns the code “compass.setCalibration(-807, 2416, 0, 3746, -2888, 921);”. However when I then try to use the following code it never goes correctly like a compass would. I basically only get reports towards East/North (bearing 1->5) no matter how I turn the compass (laying flat on my table).

#include <QMC5883LCompass.h>


QMC5883LCompass compass;

void setup() {
  Serial.begin(9600);
  compass.init();
  compass.setCalibration(-807, 2416, 0, 3746, -2888, 921);

}

void loop() {

  int x, y, z, a, b;
  char myArray[3];

  compass.read();
  
  x = compass.getX();
  y = compass.getY();
  z = compass.getZ();
  Serial.print("X: ");
  Serial.print(x);

  Serial.print(" Y: ");
  Serial.print(y);

  Serial.print(" Z: ");
  Serial.print(z);
  
  a = compass.getAzimuth();
  
  b = compass.getBearing(a);

  compass.getDirection(myArray, a);
  
  Serial.print(" Azimuth: ");
  Serial.print(a);

  Serial.print(" Bearing: ");
  Serial.print(b);

  Serial.print(" Direction: ");
  Serial.print(myArray[0]);
  Serial.print(myArray[1]);
  Serial.print(myArray[2]);

  Serial.println();

  delay(250);
}

Is my magnetometer broken or am I doing something incorrectly? I have also tried other libraries and they don’t work either.

which I would assume are correct

There is no reason to assume so.

To test whether your compass is correctly calibrated, place it flat on a table, away from any iron containing or magnetic objects, and rotate it 360 degrees while printing out X and Y values for the magnetic field measurement.

Plot those data on an X,Y plot and they should make a circle centered on 0,0, something like the blue circle:
.

If the points are off center, like the red circle, or not a circle, the calibration was done incorrectly. More info here: Accelerometer Calibration II: Simple Methods | Chionotech

Best procedure here: Tutorial: How to calibrate a compass (and accelerometer) with Arduino | Underwater Arduino Data Loggers

Keeping the magnetometer flat on my table and turning it around 360 degrees gives the following output: (no calibration made). So what does this tell me? I was unable to understand how the links you gave me applies to my case (sorry!).
CompassOutput.png

CompassOutput.png

That plot shows that your magnetometer is working well, but is desperately in need of calibration. The pink crosses do not form a circle, and they aren't centered on (0,0). A textbook-quality example, in fact!

Digital compass code assumes that the pink crosses lie on the circumference of a circle centered at (0,0).

Since the data points lie on an ellipse, for usable results you need the more advanced calibration method, described here: Tutorial: How to calibrate a compass (and accelerometer) with Arduino | Underwater Arduino Data Loggers

I am trying to follow along the guide you linked, using the Magneto v1.2 program. The problem I have is that I am uncertain what the following code does and how I would transform it to work for my case.

Xm_nanoTesla = rawCompass.m.x*(100000.0/1100.0);
// Gain X [LSB/Gauss] for selected input field range (1.3 in these case)
Ym_nanoTesla = rawCompass.m.y*(100000.0/1100.0);
Zm_nanoTesla = rawCompass.m.z*(100000.0/980.0);

I understand that it transforms the output into nanoTesla but I am unsure how the 100000/1100 part works. Here is a link for the datasheet for the magnetometer which I am using: QMC5883L Datasheet | QST - Datasheetspdf.com
There is a line which says "Sensitivity : Field Range = +- 2G 12000 LSB/G" as well as "Sensitivity : Field Range = +- 8G 3000 LSB/G". Are these the numbers which I would replace the 1100 with and in that case, which one of them?

Just get rid of the constants. They convert the units of measurement, which are completely irrelevant for use in an electronic compass.

Alright so I get something along the lines of this:

int biasx = -272.650448;
  int biasy = 93.638597;
  int biasz = 501.982728;

  Xm_off = x - biasx;
  Ym_off = y - biasy;
  Zm_off = z - biasz;

  Xm_cal =  33.592182 * Xm_off + 0.095298 * Ym_off + -0.365428 * Zm_off; //X-axis correction for combined scale factors (Default: positive factors)
  Ym_cal =  0.095298 * Xm_off + 31.618979 * Ym_off + 3.488379 * Zm_off; //Y-axis correction for combined scale factors
  Zm_cal =  -0.365428 * Xm_off + 3.488379 * Ym_off + 32.730493 * Zm_off; //Z-axis correction for combined scale factors

Testing the x,y,z output (calibrated) is now much better (aka more like a cylinder). However the bias seems to be wrong as the output is not centered around (0,0,0). I have tried running the calibration program multiple times (Magneto) and it gives somewhat consistent output (some "small" variations). What could I be doing wrong? I tried manually setting the bias since I could see that it was mostly the Y-axis being off and that worked and produced the following output which works really well. I would however like to be able to do the calibration without having to guess the biases.

CompassOutput2.png

CompassOutput2.png

Always post ALL the code, for the code you used to collect the data, and the code used to apply the calibration. NOTE: "biasx" etc. should be declared float, not int.

int biasx = -272.650448;

I agree that the correction is not working as it should. The bias is still wrong in both X and Y, even after your manual correction, so please post the original plot.

Please post the output of Magneto (e.g. a screenshot) so that we can compare it with your code.

Were you careful that no iron-containing or magnetic objects were nearby during both the calibration and the test with corrected data?

If you want to compare your work with a difficult case that was successfully solved, see this post: https://forum.pololu.com/t/correcting-the-balboa-magnetometer/14315

Nearest iron object is the breadboard which is about 30cm away.

Code for gathering x,y,z values:

#include <QMC5883LCompass.h>

QMC5883LCompass compass;

void setup() {
  Serial.begin(9600);
  compass.init();
}

void loop() {
  int x, y, z, a, b;

  compass.read();
  x = compass.getX();
  y = compass.getY();
  z = compass.getZ();

  Serial.print(x);
  Serial.print(" ");
  Serial.print(y);
  Serial.print(" ");
  Serial.print(z);
  Serial.println();

  delay(10);
}

Code for printing "corrected" x,y,z values:

#include <QMC5883LCompass.h>


QMC5883LCompass compass;

float biasx = -271.462827;
float biasy = 189.738167;
float biasz = 480.003240;

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

}

void loop() {

  int x, y, z, a, b;
  float Xm_off, Ym_off, Zm_off, Xm_cal, Ym_cal, Zm_cal;
  char myArray[3];

  compass.read();

  x = compass.getX();
  y = compass.getY();
  z = compass.getZ();

  Xm_off = x - biasx;
  Ym_off = y - biasy;
  Zm_off = z - biasz;

  Xm_cal =  35.370434 * Xm_off + -0.250872 * Ym_off + 0.426877 * Zm_off; //X-axis correction for combined scale factors (Default: positive factors)
  Ym_cal =  -0.250872 * Xm_off + 32.730363 * Ym_off + 2.123213 * Zm_off; //Y-axis correction for combined scale factors
  Zm_cal =  0.426877 * Xm_off + 2.123213 * Ym_off + 33.824386 * Zm_off; //Z-axis correction for combined scale factors

  /*int heading = atan2(Xm_cal, Ym_cal) / 0.0174532925;
    if (heading < 0) {
    heading += 360;
    }
    heading = 360 - heading;
    Serial.print("Heading: ");
    Serial.println(heading);
  */
  
  Serial.print(Xm_cal);
  Serial.print(" ");
  Serial.print(Ym_cal);
  Serial.print(" ");
  Serial.print(Zm_cal);
  Serial.println();

  delay(20);
}

Magneto screenshot:

Plot of uncorrected values (XY):
UncorrectedOutput.png

Plot of corrected values (XY):
CorrectedOutput.png

CorrectedOutput.png

UncorrectedOutput.png

That is very mysterious. I don't see a problem with the code, so please post the set of measurements that you used for calibrating the compass, and I will run it through my routines.

(I always run my original, raw calibration data through the correction procedure to make sure that the correction is coded properly, before applying the correction to new data.)

I also don't understand the "spiral" in the last plot, which suggests that the compass module is not electronically stable. Perhaps it is being powered incorrectly, or there is an I/O voltage mismatch. Are you directly connecting a 5V Arduino to a 3.3V sensor? Please post a wiring diagram, and a link to the compass module.

I have attached the measurements as a .txt. Here is a link for the module (in Swedish): Magnetisk kompass med 3 axlar 16 bitar ADC. Passar Arduino - PchButik
Not sure about the spiral but I would think I probably didn’t keep it completely level whilst testing it in the XY-plane. As for a wiring diagram I have the arduino nano connected to a breadboard and then jumper cables which connect the following: Vcc connected to 5v (I tried 3.3v aswell), GND to GND, SCL to A5, SDA to A4. If you would like a diagram I can make one. Also, thank you a lot for your help, I really appreciate it!

Mag_raw.txt (25.7 KB)

OK, if you can't hold the module level, that would explain the spiral. The Earth's magnetic field points rather steeply into the ground, in the Northern hemisphere.

To use the unit as a digital compass, you must either hold it level, or add an accelerometer to use for tilt correction.

I calibrated the data using my version of magneto, and your magnetometer is working fine. Here is the offset and matrix I use to correct the data, which preserve the raw data scale factor:

Combined bias vector B:
 -271.46   189.74   480.00

Correction matrix Ainv, using Hm=1548.900000:
  1.06353  -0.00754   0.01284
 -0.00754   0.98415   0.06384
  0.01284   0.06384   1.01704

I've attached the corrected raw data and below a 3D plot of the normalized data, together with a unit sphere.

mag_raw_corr.png

mag_raw_corr.png

mag_raw_corr.txt (47.6 KB)

I did notice that the correction numbers you've posted scale exactly to those number which I used in my correction-program. I tried running with your numbers anyway but they return the exact same type of problems, i.e the Y-axis being a bit off. I tried running the Magneto program again and this time I got much closer (see picture) but as you can see the Y-axis is still off. I really cannot figure out what is causing this... Could maybe my table be tilted enough to cause this big misalignments (I don't notice any tilt but I don't know how sensitive these things are)?CorrectedOutput2.png

CorrectedOutput2.png

Could maybe my table be tilted enough to cause this big misalignments

Yes. You can additionally correct just those (X,Y) data for offset, but then you have to make sure that the compass is held in the same plane as it is rotated.

Look up the direction of the Earth’s magnetic field in your locality, or figure it out by pointing the compass in various directions until you see the maximum value along some axis.

A tilt compensated compass works much better. For that, a combination magnetometer/accelerometer sensor like this one is preferred.