Here is what I did (and all of these results are on the attached image):
I placed the (raw) digital compass pointed in the same direction as my hand compass, and took the x.y readings at 0, 90, 180, 270.
Then, I looked at the offsets for the x readings at 0 and 180, and again at 90 and 270. (I did the same for the y.)
I then took the absolute value the readings, and took the average these results to arrive at an offset. In pseudo code as an example:
0,180
x-value = [abs(x_180) – abs(x_0)] / 2
y-value = [abs(y_180) – abs(y_0)] / 2
Note:
(1) x-dir is more neg than positive, x_180 = -34.82 vs. x_0 = 27.36, thus need to ADD to event.x.
(2) At y_180, y_0, both are neg.
90, 270
x-value = [abs(x_270) – abs(x_90)] / 2
y-value = [abs(y_270) – abs(y_90)] / 2
Notes:
(1) y-dir is more neg than positive, y_270 = -26.73 vs. y_90 = 22.36, thus need to ADD to event.y.
(2) (At x_270, x_90, both are neg.)
For the magnetic offset correction amounts, I noticed that offset value in the x-direction is somewhere between 0.275 – 3.73, so I did 3.73 – 0.275 = 3.455
I did similar for the y-direction, noticing that the value was between 0.14 – 2.185, so 2.185 – 0.14 = 2.045.
Summary for calibrating:
event.magnetic.y = event.magnetic.y + 2.045
event.magnetic.x = event.magnetic.x + 3.455
As you can see from the column, “Calibrated”, after the calibration, I redid the measurements at the 0, 90, 180, 270 hand compass markings, and the results appeared closer to what the compass read.
Only then after this, did I use the angle of declination. Being on the east coast of the USA, my angle of declination is negative, so converted this to radians, and updated my compass readings with it.
Then, this was converted to degrees for readability on a circle.
Here are compass code parts:
// Compass Libraries
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_HMC5883_U.h>
// Math Library
#include <math.h>
// I2C - Compass
/* Assign a unique ID to this sensor at the same time */
Adafruit_HMC5883_Unified mag = Adafruit_HMC5883_Unified(12345);
/****************************************
Compass Functions
****************************************/
int compass_delay = 1000; // delay time for compass readings output
float headingDegrees;
void displaySensorDetails(void)
{
sensor_t sensor;
mag.getSensor(&sensor);
Serial.println("------------------------------------");
Serial.print ("Sensor: "); Serial.println(sensor.name);
Serial.print ("Driver Ver: "); Serial.println(sensor.version);
Serial.print ("Unique ID: "); Serial.println(sensor.sensor_id);
Serial.print ("Max Value: "); Serial.print(sensor.max_value); Serial.println(" uT");
Serial.print ("Min Value: "); Serial.print(sensor.min_value); Serial.println(" uT");
Serial.print ("Resolution: "); Serial.print(sensor.resolution); Serial.println(" uT");
Serial.println("------------------------------------");
Serial.println("");
delay(500);
}
void compass(void)
{
/* Get a new sensor event */
sensors_event_t event;
mag.getEvent(&event);
/*
// Display the results (magnetic vector values are in micro-Tesla (uT))
Serial.print("X: "); Serial.print(event.magnetic.x); Serial.print(" ");
Serial.print("Y: "); Serial.print(event.magnetic.y); Serial.print(" ");
Serial.print("Z: "); Serial.print(event.magnetic.z); Serial.print(" ");Serial.println("uT");
*/
// Hold the module so that Z is pointing 'up' and you can measure the heading with x&y
// Calculate heading when the magnetometer is level, then correct for signs of axis.
// Note: This has been calibrated
float heading = atan2(event.magnetic.y + 2.045, event.magnetic.x + 3.455);
// 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/ (Note - NOT USED)
// NOTE: I used this website: http://www.ngdc.noaa.gov/geomag-web/#declination
float declinationAngle = (M_PI/180) * (- 10.85); // this will vary based on your GPS location and be in Radians
// this converts Degrees to Radians
heading += 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);
headingDegrees = (heading * 180/M_PI);
Serial.print("Compass Heading (degrees): ");
Serial.println(headingDegrees);
delay(compass_delay);
