2025-05-11 9:40 PM
Hello STM32 Community,
I'm working with the LSM303AGR magnetometer/accelerometer sensor on an STM32L4 microcontroller. I'm trying to compute a tilt-compensated heading, based on the method described in ST's application note DT0058.
However, I'm running into a problem: the heading value changes significantly when the sensor is tilted, even when the actual orientation toward magnetic north doesn't change. I expect the heading to stay consistent regardless of tilt, thanks to tilt compensation — but this is not happening.
Below is the code I'm currently using to compute the heading:
uint8_t lsm303agr_heading_read(float* heading) {
float magx_out, magy_out, magz_out;
float accx_out, accy_out, accz_out;
// Read sensor data
if (lsm303agr_acc_data_read(&accx_out, &accy_out, &accz_out, 10) != 0)
return 1;
if (lsm303agr_m_data_read(&magx_out, &magy_out, &magz_out, 10) != 0)
return 1;
// Normalize accelerometer readings
float acc_norm = sqrt(accx_out * accx_out + accy_out * accy_out + accz_out * accz_out);
if (acc_norm == 0) return 1;
accx_out /= acc_norm;
accy_out /= acc_norm;
accz_out /= acc_norm;
// Normalize magnetometer readings
float mag_norm = sqrt(magx_out * magx_out + magy_out * magy_out + magz_out * magz_out);
if (mag_norm == 0) return 1;
magx_out /= mag_norm;
magy_out /= mag_norm;
magz_out /= mag_norm;
// Compute roll and pitch
double roll = atan2(accy_out, accz_out);
double acc_z2 = accy_out * sin(roll) + accz_out * cos(roll);
double theta = atan(-accx_out / acc_z2);
// Tilt-compensated magnetometer
double mag_y2 = magz_out * sin(roll) - magy_out * cos(roll);
double mag_z2 = magy_out * sin(roll) + magz_out * cos(roll);
double mag_x3 = magx_out * cos(theta) + mag_z2 * sin(theta);
// Compute heading
double heading_rad = atan2(mag_y2, mag_x3);
double heading_deg = heading_rad * (180.0 / 3.14159);
if (heading_deg < 0)
heading_deg += 360.0;
*heading = (float)heading_deg;
return 0;
}
The heading value is correct when the sensor is flat (horizontal).
When the sensor is tilted (e.g., rotated along X or Y), the heading becomes inaccurate.
I am following the tilt-compensation steps from ST’s DT0058, but they don’t seem to work as expected.
Is there any mistake in my tilt-compensation math?
Is DT0058 accurate for the LSM303AGR, or are there better alternatives?
Do I need to apply any additional corrections (like hard-iron or soft-iron calibration)?
Can anyone please provide a working example code that gives consistent heading regardless of tilt?
Any help or guidance would be highly appreciated.
Thank you!