HMC5883L Calibration

Hey all,

I'm working on my first project on arduino, which is to guide a robotic car to certain locations. So far I have completed the setups for most of the modules (ie. gps, bluetooth, motors), but I'm facing some difficulties with the compass calibration. I'm using the arduino-HMC5883L library (GitHub - jarzebski/Arduino-HMC5883L: HMC5883L Triple Axis Digital Compass Arduino Library) and running the calibrate code:

#include <Wire.h>
#include <HMC5883L.h>

HMC5883L compass;

int minX = 0;
int maxX = 0;
int minY = 0;
int maxY = 0;
int offX = 0;
int offY = 0;

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

 // Initialize Initialize HMC5883L
 while (!compass.begin())
 {
   delay(500);
 }

 // Set measurement range
 compass.setRange(HMC5883L_RANGE_1_3GA);

 // Set measurement mode
 compass.setMeasurementMode(HMC5883L_CONTINOUS);

 // Set data rate
 compass.setDataRate(HMC5883L_DATARATE_30HZ);

 // Set number of samples averaged
 compass.setSamples(HMC5883L_SAMPLES_8);
}

void loop()
{
 Vector mag = compass.readRaw();

 // Determine Min / Max values
 if (mag.XAxis < minX) minX = mag.XAxis;
 if (mag.XAxis > maxX) maxX = mag.XAxis;
 if (mag.YAxis < minY) minY = mag.YAxis;
 if (mag.YAxis > maxY) maxY = mag.YAxis;

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

 Serial.print(mag.XAxis);
 Serial.print(":");
 Serial.print(mag.YAxis);
 Serial.print(":");
 Serial.print(minX);
 Serial.print(":");
 Serial.print(maxX);
 Serial.print(":");
 Serial.print(minY);
 Serial.print(":");
 Serial.print(maxY);
 Serial.print(":");
 Serial.print(offX);
 Serial.print(":");
 Serial.print(offY);
 Serial.print("\n");
}

After obtaining the X and Y values I substitute them into the following code (Compass):

#include <Wire.h>
#include <HMC5883L.h>

HMC5883L compass;

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

 // Initialize Initialize HMC5883L
 Serial.println("Initialize HMC5883L");
 while (!compass.begin())
 {
   Serial.println("Could not find a valid HMC5883L sensor, check wiring!");
   delay(500);
 }

 // Set measurement range
 compass.setRange(HMC5883L_RANGE_1_3GA);

 // Set measurement mode
 compass.setMeasurementMode(HMC5883L_CONTINOUS);

 // Set data rate
 compass.setDataRate(HMC5883L_DATARATE_30HZ);

 // Set number of samples averaged
 compass.setSamples(HMC5883L_SAMPLES_8);

 // Set calibration offset. See HMC5883L_calibration.ino
 compass.setOffset(0, 0);
}

void loop()
{
 Vector norm = compass.readNormalize();

 // Calculate heading
 float heading = atan2(norm.YAxis, norm.XAxis);

 // Set declination angle on your location and fix heading
 // You can find your declination on: http://magnetic-declination.com/
 // (+) Positive or (-) for negative
 // For Bytom / Poland declination angle is 4'26E (positive)
 // Formula: (deg + (min / 60.0)) / (180 / M_PI);
 float declinationAngle = (4.0 + (26.0 / 60.0)) / (180 / M_PI);
 heading += declinationAngle;

 // 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; 

 // Output
 Serial.print(" Heading = ");
 Serial.print(heading);
 Serial.print(" Degress = ");
 Serial.print(headingDegrees);
 Serial.println();

 delay(100);
}

The issue I'm having with the compass is that the accuracy is off by like 40 degrees. The average x and y value I got for 3 trials were x = 15.67 and y = 597. However, after playing with x and y values I get an accuracy of 3-4 degrees (in all 4 directions) when i changed the x and y to 32 and 910 manually. What I don't understand is that why am I not getting a high accuracy from the actual x and y value from the code?

I have the compass attached at a high elevation, away from any interference.

Please read the instructions for how to use this forum and fix your code posting.

Please use code tags when posting code.

The method you are using for calibration is not good enough to make a reasonable compass. At the very least you also need to rescale the axes, which you can do with the same basic procedure. And, the calibration MUST be done in the final mounting place, as magnetic and iron containing materials distort the Earth's magnetic field.

The best and most effective approach to calibrating a compass is described in this tutorial. For a short working example, see this post.

Thanks for the reply Jim.

I read your article on "Correcting the Balboa magnetometer". I ran the code "Calibrate2", and used the Teraterm terminal program. However, I am getting the error "Failed to detect and initialize magnetometer". How do i fix this issue?

If you are using the code I posted, that was intended for a very different magnetometer. Some changes will have to be made for the HMC5883L.

I tried modifying your codes so that it works for the HMC5883L, but I had no success.

Do you think it would be reasonable to post problematic code (using code tags, of course), along with an explanation of what the code should do, and what it does instead?

Or do you just want to complain?