Can't get compass heading to work with LSM9DS1
banjo
Posts: 447
For my outdoor robot project I'm trying to use the LSM9DS1 as a compass.
The module is connected similarly as on the learn site. The code below is copied from the c-file coming with the SimpleIDE library.
The module seems to work ok as such as I get readings from it, the issue is that I'm not able to turn the magnetic readings into a correct compass heading 0-360. Depending on the code and calibration, I get different results, e.g. between 12 and 41 with the code below, but never something that is even close to 0-360
I've run the calibration code (function imu_calibrateMag() below), this is though quite tricky as it always finishes within ~3 seconds (regardless if I do something or not). During these ~3 seconds I'm supposed to slowly rotate the module around its' 3 axis...this seems contradicting to me.
I've used Blockly code to find different options related to the x,y and z axis but while the compass headings change, I'm not able to get a consistent 0-360 heading. Also, it seems that there's no tilt-compensation as the module is very sensitive when it comes to rotation in all 3 axis. I however assume tilt-compensation is possible as this module is used in the Parallax quadcopters.
Has someone else been able to use the module as a compass? Any other suggestions?
The module is connected similarly as on the learn site. The code below is copied from the c-file coming with the SimpleIDE library.
The module seems to work ok as such as I get readings from it, the issue is that I'm not able to turn the magnetic readings into a correct compass heading 0-360. Depending on the code and calibration, I get different results, e.g. between 12 and 41 with the code below, but never something that is even close to 0-360
I've run the calibration code (function imu_calibrateMag() below), this is though quite tricky as it always finishes within ~3 seconds (regardless if I do something or not). During these ~3 seconds I'm supposed to slowly rotate the module around its' 3 axis...this seems contradicting to me.
I've used Blockly code to find different options related to the x,y and z axis but while the compass headings change, I'm not able to get a consistent 0-360 heading. Also, it seems that there's no tilt-compensation as the module is very sensitive when it comes to rotation in all 3 axis. I however assume tilt-compensation is possible as this module is used in the Parallax quadcopters.
Has someone else been able to use the module as a compass? Any other suggestions?
/** * @file libLSM9DS1.c * * @author Matthew Matz * * @version 0.6 * * @copyright * Copyright (C) Parallax, Inc. 2016. All Rights MIT Licensed. * * @brief Test harness for the Propeller C library for the Parallax 9-axis IMU Sensor, based * on the STMicroelectronics LSM9DS1 inertial motion sensor chip. */ #include "simpletools.h" #include "lsm9ds1.h" #define TEST_HARNESS 1 float gx, gy, gz; // x, y, and z axis readings of the gyroscope float ax, ay, az; // x, y, and z axis readings of the accelerometer float mx, my, mz; // x, y, and z axis readings of the magnetometer float tmp; int main() { #ifdef TEST_HARNESS int whoAmI = imu_init(6, 7, 8, 9); print("Who Am I? %x\r", whoAmI); pause(1500); high(26); high(27); imu_calibrateMag(); low(26); low(27); while(1) { imu_readGyroCalculated(&gx, &gy, &gz); print("Gyro:\t%.2f\t%.2f\t%.2f\r", gx, gy, gz); imu_readAccelCalculated(&ax, &ay, &az); print("Accel:\t%.2f\t%.2f\t%.2f\r", ax, ay, az); imu_readMagCalculated(&mx, &my, &mz); print("Mag:\t%.2f\t%.2f\t%.2f\r", mx, my, mz); imu_readTempCalculated(&tmp, CELSIUS); print("Temp:\t%.2f\r\r", tmp); float heading = atan2(mx, mz) * 180.0 / PI; if(heading < 0.0) // Convert -180...+180 to 0...360 heading = (360.0 + heading); print("heading = %.0f, \n", // Display raw compass values heading); pause(500); } #endif } /** * TERMS OF USE: MIT License * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */
Comments
The mag will return 3 readings that make a 3d vector. If you rotate the mag all over the place and plot the readings, you should get something that looks like a sphere, but not centered at the origin, and possibly squished. If you can determine where the center of your readings are, you can offset the readings by that amount to put the center of the sphere at 0,0,0, and then the atan2() function should start giving you proper results.
Check to make sure that the numbers you're getting back aren't clamped or doing anything strange - you should be able to plot mx,mz and get something that mostly looks like a circle, and mx,my,mz plotted should produce a sphere. If they don't, you may not have the measurement range configured properly, you might have a magnet or hard iron source too close to the device, etc, etc.
I have code that gets a heading from it, but it's all wound into the IMU code of the flight controller, so it likely won't be a ton of help to you. The IMU keeps track of its orientation as a quaternion, and uses that to re-orient the vector from the mag sensor before "flattening" and computing the heading.
This might help, or make life harder, depending on how current your math is:
https://cache.freescale.com/files/sensors/doc/app_note/AN4248.pdf
There's sample C# code that uses the accel and mag together to figure out heading that might work for you. It's subject to noise, but it's pretty good. If you need it to be more stable and tilt compensated, you might need a full IMU.
My math is not current at all... but the C# code seems to help more. I'd accept some noise and a heading +/- approx. 10 degrees. Related to the tilt compensation, this is a rover (WildThumper) moving on a relatively flat but not always horizontal lawn. The max gradient would perhaps be around +/- 15 degrees.
I also have a compass (HMC5883L) I could try, if I remember correctly I had similar issues when it was not leveled.
Then, rotate and look at readings. Maybe if you compare to real compass heading, you could see what it's doing.
Then, you'd need to figure out how to do arc-tangent, like Jason said to turn two values into an angle...
This is actually what I tried, but the readings were very inconsistent, I re-calibrated over 20 times in trying to find something to work on. I'll however try a few times more and make the Activity Board self-sufficient to make it possible to move away from the laptop and external monitor which might have interfered with the magnetic readings. I'll then need to use a LCD for displaying the headings