HMC5883L & ADXL345 with Adafruit Libraries (Tilt Compensation Issue)

Dear Friends,

I have built below codes for Tilt Compensated Compass (based on HMC5883L and ADXL345) with help of Adafruit Libraries (see attached) :

// Adafruit Accel & Compass for Tilt Compensated

#include "Wire.h"
#include "Adafruit_Sensor.h"
#include "Adafruit_ADXL345_U.h"
#include "Adafruit_HMC5883_U.h"

Adafruit_ADXL345_Unified accel = Adafruit_ADXL345_Unified(12345);
Adafruit_HMC5883_Unified mag = Adafruit_HMC5883_Unified(12345);

float magHeadingX, magHeadingY;
float magHeadingAbsolute = 0.0;

void magnetometer(void) {
sensors_event_t event;
mag.getEvent(&event);
  sensor_t sensor;
  mag.getSensor(&sensor);
Serial.print("MX: "); Serial.print(event.magnetic.x); Serial.print("  ");
Serial.print("MY: "); Serial.print(event.magnetic.y); Serial.print("  ");
Serial.print("MZ: "); Serial.print(event.magnetic.z); Serial.print("  ");Serial.println("uT");
  delay(1000); }

void accelerometer(void) {
sensors_event_t event;
accel.getEvent(&event);
  sensor_t sensor;
  accel.getSensor(&sensor);
Serial.print("AX: "); Serial.print(event.acceleration.x); Serial.print("  ");
Serial.print("AY: "); Serial.print(event.acceleration.y); Serial.print("  ");
Serial.print("AZ: "); Serial.print(event.acceleration.z); Serial.print("  ");Serial.println("m/s^2 ");
  delay(1000); }
  
void heading(void) {
sensors_event_t event;
mag.getEvent(&event);
  sensor_t sensor;
  mag.getSensor(&sensor);
  float heading = atan2(event.magnetic.y, event.magnetic.x);
  float declinationAngle = 0.0766;
  heading -= declinationAngle;
  if(heading < 0)
    heading += 2*PI;
  if(heading > 2*PI)
    heading -= 2*PI;
  float headingDegrees = heading * 180/M_PI; // Radians to Degrees 
Serial.print("Heading (degrees): "); Serial.println(headingDegrees);
  delay(1000); }

void tcheading(void) {
sensors_event_t event;
mag.getEvent(&event);
  sensor_t sensor;
  mag.getSensor(&sensor);

  float cosRoll = cos(event.magnetic.x);
  float sinRoll = sin(event.magnetic.x);
  float cosPitch = cos(event.magnetic.y);
  float sinPitch = sin(event.magnetic.y);

  float magX, magY;
    magX = event.magnetic.x * cosPitch * event.magnetic.z * sinPitch;
    magY = event.magnetic.x * sinRoll * sinPitch + event.magnetic.y * cosRoll - event.magnetic.z * sinRoll * cosPitch;
  
  float norm = sqrt(magX * magX + magY * magY);
  magHeadingX = magX / norm;
  magHeadingY = -magY / norm;
  magHeadingAbsolute = atan2(magHeadingY, magHeadingX);
  float declinationAngle = 0.0766;
  magHeadingAbsolute -= declinationAngle;
  if(magHeadingAbsolute < 0)
    magHeadingAbsolute += 2*PI;
  if(magHeadingAbsolute > 2*PI)
    magHeadingAbsolute -= 2*PI;
  float headingDegrees = magHeadingAbsolute * 180/M_PI; // Radians to Degrees 
Serial.print("Compensated Heading (degrees): "); Serial.println(headingDegrees);
  delay(1000); } 
  
void setup(void) {
Serial.begin(9600);
accel.begin();
accel.setRange(ADXL345_RANGE_2_G);
mag.begin();
mag.setMagGain(HMC5883_MAGGAIN_1_3);
}

void loop(void) {
magnetometer();
accelerometer();
heading();
tcheading();
}

The result from serial have strange output as below :

...
MX: 1.91 MY: -3.64 MZ: 63.88 uT
AX: 4.59 AY: 0.51 AZ: -9.45 m/s^2
Heading (degrees): 282.31
Compensated Heading (degrees): 356.49
MX: 19.09 MY: -5.18 MZ: 59.29 uT
AX: 0.31 AY: 0.39 AZ: -10.24 m/s^2
Heading (degrees): 341.51
Compensated Heading (degrees): 325.76
MX: 19.73 MY: -4.73 MZ: 59.08 uT
AX: 0.27 AY: 0.35 AZ: -10.28 m/s^2
Heading (degrees): 341.89
Compensated Heading (degrees): 352.25
MX: 19.64 MY: -4.82 MZ: 59.08 uT
AX: 0.24 AY: 0.35 AZ: -10.28 m/s^2
Heading (degrees): 342.01
Compensated Heading (degrees): 226.55
MX: 7.00 MY: -2.45 MZ: 63.16 uT
AX: 3.45 AY: 0.51 AZ: -9.77 m/s^2
Heading (degrees): 324.49
Compensated Heading (degrees): 22.14
....

When i tilt or roll the module, the Heading changes as seen above, but on the other side Tilt Compensated Heading output changes a lot instead of compensating :frowning:

Any i ideas ?

Adafruit Libraries.zip (22.7 KB)

It is essential to calibrate the magnetometer. Have you done that?
I don't see where the accelerometer data are used for tilt compensation. You might want to take a look at this application note describing the approach: http://cache.freescale.com/files/sensors/doc/app_note/AN4248.pdf

Dear jremington,

Just read from http://hobbylogs.me.pn/?p=17 and used to code, below are results :


End Debug -- (Offset Calibration)


Offset x = -21.97 mG
Offset y = 91.83 mG
Offset z = -858.69 mG

Where do i need to add them into my code ?

Just another try with same calibration code :


End Debug -- (Offset Calibration)


Offset x = 1.12 mG
Offset y = 56.26 mG
Offset z = -550.21 mG

Everything is same on bench, but give such different values :frowning: Don't know why.

This method of calibration will work much better: Sailboat Instruments: Improved magnetometer calibration (Part 1)

I don't think your code actually does tilt compensation.

Dear jremington,

Thanks for your weblink and document but it's not for me as it looks like rocket science at this level :frowning:

I definitely look for a quick'n'dirty method. Thanks again.

Regards

as it looks like rocket science at this level

You make some measurements and feed them into a program, which publishes a correction. Hardly rocket science, and only slightly more complicated than tilt compensation.

Hi Newbie_Led

I just went through what felt like a reasonably steep learning curve on compass calibration, and since it took me a while to get the hang of it I posted the whole process on my blog: (warning: the post is really long)

I followed the advice of many on these forums (including jremington) and tried the SailboatInstruments Magneto application. I also tried out Varesano's FreeIMU tools in manual mode (without the python GUI). I found that each program had a few things that you had to be aware of before they worked properly and I have noted these in some detail.

The good thing is that the same software that calibrates your compass, also calibrates your accelerometer. So you kind of get that for free once you work your way through it. I think I had trouble at the beginning simply by being overwhelmed by all the different approaches and information that I found when google searching. It was hard to know where to start and it seems like I am in the same place again now that I am trying to to get tilt compensation to work.

P.S. I was using data from an LM303 in the examples, but the both applications are pretty generic, and should work with almost any compass/accelerometer.