Posted on
• # Using a 3-Axis Magnetometer as a compass.

• Vertical axis is the Yaw axis
This leaves two remaining axis
• The heading or roll axis points in the direction of travel
• The remaining horizontal axis is the pitch axis that points left and right from the heading axis.
• To get a heading we use the atan2 function and then adjust to a 0 to 360 degree range
• If(ww<0) ww+=360
• Atan2 produces values in radians so we define pirate= 180/pi to get degrees
57.29577951
• In the following table pay attention to the sign of the axis values

North 1 0 0 0
NorthEast 1 1 45 45
East 0 1 90 90
SouthEast -1 1 135 135
South -1 0 180 180
SouthWest -1 -1 -135 225
West 0 -1 -90 270
NorthWest 1 -1 -45 315

*Magnetometer axis usually have an offset that needs to be corrected so that no field produces a zero value. x1= x - xoffset, y1= y-yoffset, z1= z-zoffset;

• You must assign the X,Y, and Z axis to the Roll, Pitch and Yaw axis based on the mounting of the magnetometer.
• The roll or pitch readings from the mgnetometer may need to be negated to get the proper heading, as the direction of the assigned axis may be reversed from the Roll, Pith and Yaw axis as define in the table.

Use the attached trycompass.js file as a starting point. Attention Puck experimenters!
(still puzzling as to why the markdown table above doesn't display correctly?)

1 Attachment

• still puzzling as to why the markdown table above doesn't display correctly?

...autodetect of text of numbers does left and right alignment in table cell... :/ ...so much does autoXyz do any good...

• # Using a 3-Axis Magnetometer as a compass.

## An example:

### First Zero the magnetometer

For each axis X, Y and Z point the axis North and take a reading R1, then turn the magnetometer 180 degrees and take reading R2. Take the average of the two readings as the offset for that axis.
Your code will then take a reading and subtract the offset for each axis. X= Xraw- Xoffset, Y= Yraw- Yoffset, Z= Zraw- Zoffset.
Use the resulting Z, Y and Z values in all calculations that follow. If you repeat the North and then rotate proceedure then
Xn =-Xs, Yn=-Yz, and Zn=-Zs, where the subscripts s and n stanf for North and South.

### Example

• Assign the Z axis to the Yaw axis.
• Assign the X axis to the roll (heading) axis.
• Assign the Y axis to the pitch axis.
• With the X and Y axis level and the Z axis pointing in the position for use ( Think the model airplane is not inverted):
• Point the roll (X) axis North and note the sign of the X axis reading. If it is negative, you need to multiply X by -1 in the assignment statement of the code
• Point the roll (X) axis East and note the sign of the Y axis. The reading should be negative, if not you need to multiply Y by -1 in the assignment statement of the code
• The yaw axis should be positive in the Northern hemisphere and negative in the Southern menisphere. If not negate it.

``````var X=1,Y=-1,Z=1;
var X1,Y1,Z1;
var Xoffset=0,Yoffset=0,Zoffset=0;
//Read the magnetometer X,Y, and Z

//Subtract the offsets
X1=X-Xoffset; Y1=Y-Yoffset; Z1=Z-Zoffset;
//Assign the XYZ to roll pitch and yaw axis
var Sroll=1; var Spitch=-1; var Syaw=1;
roll=Sroll*X1; pitch=Spitch*Y1; yaw=Syaw*Z1;
dip=180/Math.PI*Math.atan(Math.sqrt(roll­*roll+pitch*pitch),yaw);
console.log("Dip= ",dip);
``````

Note the change in the argument order of the atan2 function from the orignal post.

• Try it out to see that 90 degree heading is East, 180 is South, 270 is West and 0 is North.
• Repeat using the Y axis as the roll axis and the X axis as pitch.

https://en.wikipedia.org/wiki/Magnetic_d­ip

https://www.ngdc.noaa.gov/geomag-web/#ig­rfwmm

https://en.wikipedia.org/wiki/Magnetic_d­eclination

• For dip try this instead:

``````dip=180/Math.PI*Math.atan(yaw/Math.sqrt(­roll*roll+pitch*pitch));
``````

dip is positive in Northern and negative in Southern hemispheres.
It ranges from -90 to +90.

• Thanks!

If we could think of a nice way of automatically doing calibration this could make a really interesting module

• ### Thoughts on magnetometer calibrations.

• Use a min/max program to find the minimum and maximum readings for each axis and then average the minimum and maximum to obtain the offset for each axis.
Point both ends of each axis towards the magnetic pole. Remember the pole is actually below the horizontal by the dip angle.

``````//Cal_idea.js
//5 Jan 2017

function minmax(){
this.min=[0,0,0];
this.max=[0,0,0];
this.avg=[0,0,0];
}

minmax.prototype.process=function(A){
var i;
for(i=0;i<3;i++){
if(A[i]>this.max[i])this.max[i]=A[i];
if(A[i]<this.min[i])this.min[i]=A[i];
this.avg[i]=(this.min[i]+this.max[i])/2;­
}
console.log("max= ",this.max);
console.log("min= ",this.min);
console.log("avg= ",this.avg);
};

var i;
var T=new minmax();
for(i=-4;i<4;i++){
//fake some data for demo
//process data while moving the magnetometer
// until the max and min for each axis is at the limit
//use the average as the offset value
}//next i
``````
• In the module MAG3110.js, does the Puck use this function?
http://www.espruino.com/modules/MAG3110.­js

``````/**
* Performs a manual magnetic sensor reset (One-Shot).
* Initiates a magnetic sensor reset cycle that will restore correct operation after exposure to an excessive magnetic
* field wich exceeds the Full Scale Range of +/-1000ÂµT, e.g. near a speaker magnet.
*/
MAG3110.prototype.magneticReset = function () {
value |= 0x10; // set Mag_RST
this.write8(MAG3110.CTRL_REG2, value);
};
``````
• Finding the best fit sphere regression using Solver in Excel

http://forum.espruino.com/conversations/­297875/

1 Attachment

• The Puck uses something very similar to that JS module, but it's written in C to try and get it running as fast as possible, without using up any JS code space.

• Post a reply