HMC6352 2D magnetometer revisited

While most of use have moved on to 3D accelerometer/magnetometer compasses or even IMUs for our robots, there are still interesting uses for the HMC6352 2D magnetometer. I wanted to make a high resolution frictionless shaft position indicator out of mine (http://www.sparkfun.com/products/7915). Fortunately, I have an earlier version of the linked Spark Fun breakout board, which has pads for adding resistors to reduce the amplifier gain so that a magnet can be used to drive the compass. This feature has been removed from the latest board, which was not a wise move. My particular board also has the North arrow incorrectly pointing West, as found by experiment and in agreement with the chip orientation on the breakout board.

With the stock amplifier gain, when exposed to even modest magnetic fields, the chip undergoes some sort of automatic adjustment which can result in lockup and/or wildly incorrect output. Cycling the power does not help. The solution is to send the “reset S/R bridge offset” command, the effect of which is not explained in the datasheet. The S/R reset does not affect the results of the built-in “user calibration procedure”, which is also poorly documented.

So, I looked closer, examining the raw magnetometer data and the result of the user calibration command. The raw magnetometer data are positive integers, i.e. the ADC results, and the result of the user calibration procedure is just to calculate and subtract an average offset in the X and Y measurements. In my HMC6352, the gains of the X and Y amplifiers are significantly different, which seems to be true for all inexpensive magnetometers and this leads to magnetic bearings that are far less accurate than the data sheet claims.

Inspired by various efforts to extract the best possible data out of 3D magnetometer/accelerometers, I wrote a 2D version of the procedure described in http://sailboatinstruments.blogspot.com … ation.html for the HMC6352. As is usual I fit an ellipse to the data and rotate/rescale the ellipse to a circle. This makes a big difference, up to 5 degrees, in the accuracy of the reported angle of the magnetic field vector.

The output of the code posted below, on data collected from the HMC6352 in the Earth’s magnetic field (after using the built-in user calibration procedure) was the following matrix and offset vector. As you can see, the correction is about 9% in magnitude for the X axis with a significant rotational component.

scaled rotation matrix and vector to apply: Q*(XY-XY0)

(1.0886 0.0407)*(X - ( -1.4))

(0.0407 1.0187)*(Y - ( -8.0))

The figure below shows the raw data for two complete revolutions of the compass, while held level (blue circles) and the rescaled data points (green circles). The fitted ellipse is the solid line.

The figure below shows the difference in magnetic bearings in degrees, obtained from the data before and after calibration by using the atan2 function.

The current code is written for MATLAB. If there is sufficient interest, I could write a version in C.

Caveat: this code has not been thoroughly tested and will probably fail in pathological cases!

%
% File: magcal_2d.m
% This MATLAB program calculates the calibration parameters for a 2D magnetometer.
% As is customary, data for one or two complete revolutions of the magnetometer
% should be collected while held level, points closely spaced if possible. 
%
% uses published Matlab function EllipseDirectFit.m
% http://www.mathworks.com/matlabcentral/fileexchange/22684-ellipse-fit-direct-method
%
% First step: collect data and produce a CSV file (comma separated values) of
% magnetometer X and Y values (can be raw).
% 
% Second step: from Matlab File Menu, import CSV file of (max, magy)
% measurements into array magxy.
%
% Third step: execute magcal_2d.m
%
% This work was inspired by the 3D procedure described in: 
% http://sailboatinstruments.blogspot.com/2011/08/improved-magnetometer-calibration.html
%

A = EllipseDirectFit(magxy);

% modified coefficients of equation for ellipse
% from http://mathworld.wolfram.com/Ellipse.html

a = A(1);
b = A(2)/2;
c = A(3);
d = A(4)/2;
f = A(5)/2;
g = A(6);

% X0, Y0 offset (centroid of ellipse)

x0 = (c*d - b*f)/(b^2 - a*c);
y0 = (a*f - b*d)/(b^2 - a*c);

% semimajor and semiminor axes 

numer = 2*(a*f*f+c*d*d+g*b*b-2*b*d*f-a*c*g);
denom1 = (b*b-a*c)*( sqrt((a-c)^2 + 4*b*b) - (a+c));
denom2 = (b*b-a*c)*(-sqrt((a-c)^2 + 4*b*b) - (a+c));
a_axis = sqrt(numer/denom1);
b_axis = sqrt(numer/denom2);

% angle of ellipse semimajor axis wrt X-axis

if (a < c) theta =        0.5*acotd((a-c)/(2*b));
else       theta = 90.0 + 0.5*acotd((a-c)/(2*b));
end

s=sprintf('x0 = %5.2f y0 = %5.2f a = %5.2f, b= %5.2f, theta(d) = %4.1f', ...
         x0,y0,a_axis,b_axis, theta);
disp(s);

% rotation matrix to align semimajor axis to X-axis

ct=cosd(theta);
st=sind(theta);
R = [ct st; -st ct];
xy0 = [x0 y0];

%rescale vector, correct for difference in magnetometer X & Y gains

scale = [b_axis/a_axis,1];

% final result: matrix to align ellipse axes wrt coordinates system, normalize X and Y gains and rotate back.

Q = R^-1*([scale(1) 0; 0, scale(2)]*R);

% correct the input data

for i = 1 :  length(magxy)
xy(i,:) = ( Q*(magxy(i,:)-xy0)' )';
end

% replot scaled data. Set "hold on" in EllipseDirectFit.m
scatter(xy(:,1),xy(:,2));

% residual plot

figure;

p1 = (180./3.14159).*atan2(magxy(:,2),magxy(:,1));
p2 = (180./3.14159).*atan2(xy(:,2),xy(:,1));
xp = 1:length(magxy);
hold on
title('Residual bearings in degrees after rescaling');
plot(xp,p1-p2,'-g');

disp(' ');
disp('scaled rotation matrix and vector to apply: Q*(XY-XY0)');
s = sprintf('(%6.4f %6.4f)*(X - (%5.1f))',Q(1,1),Q(1,2),x0);
disp(s);
s = sprintf('(%6.4f %6.4f)*(Y - (%5.1f))',Q(2,1),Q(2,2),y0);
disp(s);

jremington:
As is usual I fit an ellipse to the data and rotate/rescale the ellipse to a circle. This makes a big difference, up to 5 degrees, in the accuracy of the reported angle of the magnetic field vector.

Just to understand (or not) ... you fit to an ellipse because the gains aren't equal. Then when the fitting is done and the rotation is correct, you account for the unequal gains and so make the circle I would expect ?

How far above the sensor were you able to place the magnet ? I’d expect the closer the better, from a field alignment viewpoint but overloading the sensor (and thus elliciting non-linear data) might be a problem. I’d expect some “sweet zone” as a result. Comments ??

Your understanding is correct regarding the ellipse. In a bit more detail, the procedure is to fit an ellipse to the data and calculate the angle of one of the ellipse axes with respect to the X-axis (in the case above it is actually the semiminor axis). Then the ellipse is rotated to align that axis with X. To correct for the difference in gains you multiply the rotated X coordinates by the ellipse axial ratio. Then everything has to be rotated back to the original orientation.

In the example above the angle of the semiminor axis to X was about 24 degrees, but I don’t understand where that angle comes from. Maybe there is some interaction between the magnetometers, but such a large angle is commonly reported! In the 3D magnetometer case the procedure is the same except that you have to fit an ellipsoid and align two of its axes to the coordinate system before rescaling. After replotting the rescaled data, a nice circle or sphere appears. The use of trig functions to calculate vector directions assumes circular or spherical symmetry.

These magnetometers are incredibly sensitive and detect a weak bar magnet a couple of feet away (weak as in “does not stick to refrigerator strongly”). If you bring the magnet within a couple of inches the chip goes wild and has to be reset. There is indeed a sweet spot where the chip output follows the orientation of the magnet, but for my shaft position detector it will clearly necessary to reduce the amplifier gain by a factor of 10 or so. I’m glad that the chip designers foresaw the need and brought out the connections! The project isn’t finished, but I thought this intermediate result would be useful to others.

jremington:
… but I don’t understand where that angle comes from. Maybe there is some interaction between the magnetometers, but such a large angle is commonly reported! In the 3D magnetometer case the procedure is the same except that you have to fit an ellipsoid and align two of its axes

I can only think of 2 causes; either there's a misalignment btw the sensor and it's physical casing as it comes from the factory or (really and/or) the metal in the traces of the PCB alter the magnetic field enough to distort it's direction. The latter is common in boat compasses (due to metal and wiring near the compass) and good ones will allow you to correct for deviation. In any case so long as your correction holds over time, it's all good but people should be aware that such a calibration is needed for applications that need some degree of absolute accuracy.

You may be right that currents in the PCB are causing the ellipse rotation (the so called “soft iron” distortion).

I’ll check to see if the distortion changes with time. It certainly does change with environment.

It is very quick on a PC to do the calibration but unless someone can come up with a clever algorithm to do away with the heavy duty matrix math, it is unlikely that this procedure could be implemented on a typical 8-bit micro, i.e. as a built-in feature. In any case, calibration is clearly required for reasonable accuracy, and is best performed after building the magnetometer into its final resting place.