Hello, I read a previous thread about a tilt-compensated compass, however, it wasn't of much help to me.
I have a LSM303DLHC accelerometer and magnetometer. I want to be able to tell the compass heading (azimuth/yaw) and the altitude angle (elevation/pitch) at the same time. However, although the altitude reading works fine at all times, the compass heading gets thrown way off when not perfectly flat/horizontal. Therefore, for it to work, I would have to have the altitude be 0 for the heading to be accurate. This is not ideal. Does anyone else have a suggestion? Could it be converted using math?
P.S. I have 2 of these sensors, do you think they would work separately on one arduino (uno)? Also, I have the Adafruit Precision NXP 9-DOF sensor board that works decently well, but I don't think the hassle of working with it is worth it.
You must calibrate the magnetometer before it will be useful as a compass. Overview here.
Pololu has simple code for implementing a tilt compensated compass with previous versions of that sensor - slight modifications may be required. Check their site for the code.
I tried the above suggestions and input the guy's formula for a tilt compensated compass (see below). The roll and pitch seem to work just fine, but the compass heading prints a number like -45 for what i believe to be due north, and only seems to range from -90 to 90 as it is spun around in all axis directions.
P.S. I didn't calibrate the magnetic sensor because from my understanding it doesn't matter for just a simple test. Also, doesn't it come factory calibrated?
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_LSM303_U.h>
#include <math.h>
float Altitude=0;
float heading=0;
float xh=0;
float yh=0;
float Roll=0;
/* Assign a unique ID to this sensor at the same time */
Adafruit_LSM303_Accel_Unified accel = Adafruit_LSM303_Accel_Unified(54321);
Adafruit_LSM303_Mag_Unified mag = Adafruit_LSM303_Mag_Unified(12345);
void displaySensorDetails(void)
{
sensor_t sensor;
accel.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(" m/s^2");
Serial.print ("Min Value: "); Serial.print(sensor.min_value); Serial.println(" m/s^2");
Serial.print ("Resolution: "); Serial.print(sensor.resolution); Serial.println(" m/s^2");
Serial.println("------------------------------------");
Serial.println("");
delay(500);
}
void setup(void)
{
#ifndef ESP8266
while (!Serial);
#endif
Serial.begin(9600);
Serial.println("Accelerometer Test"); Serial.println("");
if(!accel.begin())
{
/* There was a problem detecting the ADXL345 ... check your connections */
Serial.println("Ooops, no LSM303 detected ... Check your wiring!");
while(1);
}
displaySensorDetails();
}
void loop(void)
{
/* Get a new sensor event */
sensors_event_t event;
accel.getEvent(&event);
Altitude = (atan(event.acceleration.x/event.acceleration.z));//*180/PI;
Roll = atan(event.acceleration.y/event.acceleration.z);
mag.getEvent(&event);
xh=event.magnetic.x*cos(Altitude)+event.magnetic.z*sin(Altitude);
yh=event.magnetic.x*sin(Roll)*sin(Altitude)+event.magnetic.y*cos(Roll)-event.magnetic.z*sin(Roll)*cos(Altitude);
heading=atan(yh/xh)*180/PI;
Serial.print("Altitude: ");;
Serial.println(Altitude*180/PI);
Serial.print("Roll: ");
Serial.println(Roll*180/PI);
Serial.print("Direction from North: ");
Serial.println(heading);
delay(1000);
}
That was your mistake, which explains the following:
The compass heading prints a number like -45 for what i believe to be due north, and only seems to range from -90 to 90 as it is spun around in all axis directions.
You also have to correct for the local magnetic declination, in order to determine true North.