HMC5883L - GY271 incorrect values

I have a HMC5883L on a GY271 break out board.

I'm running the test script in the HMC588L library:

/*
HMC5883L_Example.pde - Example sketch for integration with an HMC5883L triple axis magnetomerwe.
Copyright (C) 2011 Love Electronics (loveelectronics.co.uk)

This program is free software: you can redistribute it and/or modify
it under the terms of the version 3 GNU General Public License as
published by the Free Software Foundation.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.

*/

// Reference the I2C Library
#include <Wire.h>
// Reference the HMC5883L Compass Library
#include <HMC5883L.h>

// Store our compass as a variable.
HMC5883L compass;
// Record any errors that may occur in the compass.
int error = 0;

// Out setup routine, here we will configure the microcontroller and compass.
void setup()
{
  // Initialize the serial port.
  Serial.begin(9600);

  Serial.println("Starting the I2C interface.");
  Wire.begin(); // Start the I2C interface.

  Serial.println("Constructing new HMC5883L");
  compass = HMC5883L(); // Construct a new HMC5883 compass.
    
  Serial.println("Setting scale to +/- 1.3 Ga");
  error = compass.SetScale(1.3); // Set the scale of the compass.
  if(error != 0) // If there is an error, print it out.
    Serial.println(compass.GetErrorText(error));
  
  Serial.println("Setting measurement mode to continous.");
  error = compass.SetMeasurementMode(Measurement_Continuous); // Set the measurement mode to Continuous
  if(error != 0) // If there is an error, print it out.
    Serial.println(compass.GetErrorText(error));
}

// Our main program loop.
void loop()
{
  // Retrive the raw values from the compass (not scaled).
  MagnetometerRaw raw = compass.ReadRawAxis();
  // Retrived the scaled values from the compass (scaled to the configured scale).
  MagnetometerScaled scaled = compass.ReadScaledAxis();
  
  // Values are accessed like so:
  int MilliGauss_OnThe_XAxis = scaled.XAxis;// (or YAxis, or ZAxis)

  // Calculate heading when the magnetometer is level, then correct for signs of axis.
  float heading = atan2(scaled.YAxis, scaled.XAxis);
  
  // Once you have your heading, you must then add your 'Declination Angle', which is the 'Error' of the magnetic field in your location.
  // Find yours here: http://www.magnetic-declination.com/
  // Mine is: 2� 37' W, which is 2.617 Degrees, or (which we need) 0.0456752665 radians, I will use 0.0457
  // If you cannot find your Declination, comment out these two lines, your compass will be slightly off.
  //float declinationAngle = 0.0457;
  //eading += declinationAngle;
  
  // Correct for when signs are reversed.
  if(heading < 0)
    heading += 2*PI;
    
  // Check for wrap due to addition of declination.
  if(heading > 2*PI)
    heading -= 2*PI;
   
  // Convert radians to degrees for readability.
  float headingDegrees = heading * 180/M_PI; 

  // Output the data via the serial port.
  Output(raw, scaled, heading, headingDegrees);

  // Normally we would delay the application by 66ms to allow the loop
  // to run at 15Hz (default bandwidth for the HMC5883L).
  // However since we have a long serial out (104ms at 9600) we will let
  // it run at its natural speed.
  // delay(66);
}

// Output the data down the serial port.
void Output(MagnetometerRaw raw, MagnetometerScaled scaled, float heading, float headingDegrees)
{
   Serial.print("Raw:\t");
   Serial.print(raw.XAxis);
   Serial.print("   ");   
   Serial.print(raw.YAxis);
   Serial.print("   ");   
   Serial.print(raw.ZAxis);
   Serial.print("   \tScaled:\t");
   
   Serial.print(scaled.XAxis);
   Serial.print("   ");   
   Serial.print(scaled.YAxis);
   Serial.print("   ");   
   Serial.print(scaled.ZAxis);

   Serial.print("   \tHeading:\t");
   Serial.print(heading);
   Serial.print(" Radians   \t");
   Serial.print(headingDegrees);
   Serial.println(" Degrees   \t");
}

It's not working though, the values fluctuate with motion, I've included a sample here as the sensor is rotated.

HeadingúStarting the I2C interface.
Constructing new HMC5883L
Setting scale to +/- 1.3 Ga
Setting measurement mode to continous.
Raw: 557   165   -265   Scaled: 512.44   151.80   -243.80   Heading: 0.29 Radians   16.50 Degrees   
Raw: 557   165   -265   Scaled: 512.44   151.80   -243.80   Heading: 0.29 Radians   16.50 Degrees   
Raw: 558   163   -264   Scaled: 513.36   149.96   -242.88   Heading: 0.28 Radians   16.28 Degrees   
Raw: 539   56   -277   Scaled: 495.88   51.52   -254.84   Heading: 0.10 Radians   5.93 Degrees   
Raw: 565   -23   -230   Scaled: 519.80   -21.16   -211.60   Heading: 6.24 Radians   357.67 Degrees   
Raw: 556   -20   -194   Scaled: 511.52   -18.40   -178.48   Heading: 6.25 Radians   357.94 Degrees   
Raw: 520   5   -194   Scaled: 478.40   4.60   -178.48   Heading: 0.01 Radians   0.55 Degrees   
Raw: 495   -2   -191   Scaled: 455.40   -1.84   -175.72   Heading: 6.28 Radians   359.77 Degrees   
Raw: 487   -53   -182   Scaled: 448.04   -48.76   -167.44   Heading: 6.17 Radians   353.79 Degrees   
Raw: 435   -115   -167   Scaled: 400.20   -105.80   -153.64   Heading: 6.02 Radians   345.19 Degrees   
Raw: 428   -87   -174   Scaled: 393.76   -80.04   -160.08   Heading: 6.08 Radians   348.51 Degrees   
Raw: 380   -42   -169   Scaled: 349.60   -38.64   -155.48   Heading: 6.17 Radians   353.69 Degrees   
Raw: 388   -23   -176   Scaled: 356.96   -21.16   -161.92   Heading: 6.22 Radians   356.61 Degrees   
Raw: 356   2   -164   Scaled: 327.52   1.84   -150.88   Heading: 0.01 Radians   0.32 Degrees   
Raw: 346   26   -158   Scaled: 318.32   35.88   -143.52   Heading: 0.11 Radians   6.43 Degrees   
Raw: 351   59   -158   Scaled: 322.92   54.28   -145.36   Heading: 0.17 Radians   9.54 Degrees   
Raw: 351   82   -158   Scaled: 322.92   75.44   -145.36   Heading: 0.23 Radians   13.15 Degrees   
Raw: 353   94   -155   Scaled: 324.76   86.48   -142.60   Heading: 0.26 Radians   14.91 Degrees   
Raw: 360   113   -153   Scaled: 331.20   103.96   -140.76   Heading: 0.30 Radians   17.43 Degrees   
Raw: 374   124   -153   Scaled: 344.08   114.08   -140.76   Heading: 0.32 Radians   18.34 Degrees   
Raw: 335   120   -146   Scaled: 308.20   110.40   -134.32   Heading: 0.34 Radians   19.71 Degrees   
Raw: 296   141   -127   Scaled: 272.32   129.72   -116.84   Heading: 0.44 Radians   25.47 Degrees   
Raw: 291   170   -121   Scaled: 267.72   156.40   -111.32   Heading: 0.53 Radians   30.29 Degrees   
Raw: 293   187   -114   Scaled: 269.56   172.04   -104.88   Heading: 0.57 Radians   32.55 Degrees   
Raw: 305   217   -107   Scaled: 280.60   199.64   -98.44   Heading: 0.62 Radians   35.43 Degrees   
Raw: 317   260   -96   Scaled: 291.64   239.20   -88.32   Heading: 0.69 Radians   39.36 Degrees   
Raw: 499   325   -82   Scaled: 459.08   299.00   -75.44   Heading: 0.58 Radians   33.08 Degrees   
Raw: 578   304   -78   Scaled: 531.76   279.68   -71.76   Heading: 0.48 Radians   27.74 Degrees   
Raw: 595   290   -83   Scaled: 547.40   266.80   -76.36   Heading: 0.45 Radians   25.98 Degrees   
Raw: 646   238   -88   Scaled: 594.32   218.96   -80.96   Heading: 0.35 Radians   20.22 Degrees   
Raw: 668   213   -89   Scaled: 614.56   195.96   -81.88   Heading: 0.31 Radians   17.69 Degrees    
Raw: 662   194   -101   Scaled: 609.04   178.48   -92.92   Heading: 0.29 Radians   16.33 Degrees   
Raw: 673   156   -107   Scaled: 619.16   143.52   -98.44   Heading: 0.23 Radians   13.05 Degrees   
Raw: 689   122   -108   Scaled: 633.88   112.24   -99.36   Heading: 0.18 Radians   10.04 Degrees   
Raw: 651   66   -137   Scaled: 598.92   60.72   -126.04   Heading: 0.10 Radians   5.79 Degrees   
Raw: 637   40   -146   Scaled: 586.04   36.80   -134.32   Heading: 0.06 Radians   3.59 Degrees   
Raw: 613   -9   -153   Scaled: 563.96   -8.28   -140.76   Heading: 6.27 Radians   359.16 Degrees    
Raw: 556   -88   -160   Scaled: 511.52   -80.96   -147.20   Heading: 6.13 Radians   351.01 Degrees

The heading values fluctuate approximately from 350 -> 360 and between 10 and 30 degrees but never anything outside of this. It appears that the x value (col one above) never becomes negative (you would expect it be be negative for 50% of the time) assuming an even rotation.
Has anyone seen this behaviour before? Can anyone think of why this might happen?

Magnetometers need to be calibrated or the results will be nonsense. Below are links to two procedures (the second is much better). Also make sure that no magnets or iron objects are nearby.

Some boards have incorrectly marked axis.

Hi jremington,

I need to calibrate my compass and want to use the mag cal software. Dialog box requires the "Norm of the earth magnetic field (Hm) which is calculated in the link that is provided in the help button. But the link is broken and don't know where else to find that parameter. Would you please advice?

best regards

Just enter 1.0 for Hm.

Ideally Hm would be used to calibrate the magnetometer in absolute units, which is irrelevant for a compass. However, the MagCal GUI seems to allow only a limited range of numbers.

My magnetometers output values that are typically between 100 and 1000, with an average of about 500, which is what I would want to enter for Hm. In that case, the correction matrix would have diagonal entries of about 1.0 and small off-diagonal terms.

I prefer "Magneto" from the sailboatinstruments site.

Thank you,

Now I have these results and want to know how to adjust the magnetometer. Would you please advice? Is there a tutorial?

The hard iron bias equals:

87.2125 -225.9660 -72.8792

The combined matrix equals:

516.2249 -5.2648 -9.8155
-5.2648 537.0403 -2.8799
-9.8155 -2.8799 417.1689

For each set of measurements (mx, my, mz) subtract the "hard iron bias" and multiply by the combined matrix.

If you don't know how to do that, look up on the web how to multiply a matrix and a vector in C/C++.

I would first divide every term in the combined matrix by 537.0403 so that the numbers come out on the same scale as the measurements.