summaryrefslogtreecommitdiff
path: root/debug/IMU_comp/IMU_comp.ino
diff options
context:
space:
mode:
Diffstat (limited to 'debug/IMU_comp/IMU_comp.ino')
-rw-r--r--debug/IMU_comp/IMU_comp.ino104
1 files changed, 86 insertions, 18 deletions
diff --git a/debug/IMU_comp/IMU_comp.ino b/debug/IMU_comp/IMU_comp.ino
index 0c3928d..fc35244 100644
--- a/debug/IMU_comp/IMU_comp.ino
+++ b/debug/IMU_comp/IMU_comp.ino
@@ -1,8 +1,33 @@
+/*
+This sketch combines magnetometer readings from an LIS3MDL and accelerometer
+readings from an LSM6 to calculate a tilt-compensated magnetic heading. It
+requires Pololu's LSM6 Arduino library to be installed:
+
+https://github.com/pololu/lsm6-arduino
+
+This program can be used with a board that includes both sensors, like the
+Pololu MinIMU-9 v5 and AltIMU-10 v5, or with separate carrier boards for the two
+sensors, both connected to the same I2C bus. If you are using separate boards,
+make sure the axes are oriented the same way on both (i.e. the X, Y, and Z axes
+of both boards should point in the same direction, and the surfaces of the
+boards should be as close to parallel as possible).
+*/
+
#include <Wire.h>
#include <LIS3MDL.h>
-#include <math.h>
+#include <LSM6.h>
LIS3MDL mag;
+LSM6 imu;
+int front = 0;
+
+/*
+Calibration values; the default values of +/-32767 for each axis
+lead to an assumed magnetometer bias of 0. Use the Calibrate example
+program to determine appropriate values for your particular unit.
+*/
+LIS3MDL::vector<int16_t> m_min = {+942, +3436, -3323};
+LIS3MDL::vector<int16_t> m_max = {+1053, +3559, -3142};
void setup()
{
@@ -11,35 +36,78 @@ void setup()
if (!mag.init())
{
- Serial.println("Failed to detect and initialize magnetometer!");
+ Serial.println("Failed to detect and initialize LIS3MDL magnetometer!");
while (1);
}
-
mag.enableDefault();
+
+ if (!imu.init())
+ {
+ Serial.println("Failed to detect and initialize LSM6 IMU!");
+ while (1);
+ }
+ imu.enableDefault();
+
+ //get start heading
+ mag.read();
+ imu.read();
+ float heading = computeHeading();
+ front = heading;
+ Serial.println(heading);
+
}
void loop()
{
mag.read();
+ imu.read();
- // Calculate heading
- float heading = atan2(mag.m.y, mag.m.x);
- if (heading < 0)
- heading += 2 * PI; // Normalize heading to positive angles
- // Convert from radians to degrees
- float headingDegrees = heading * 180.0 / PI;
+ float heading = computeHeading();
+ int offset = front - heading;
+
+ Serial.print("heading: ");
+ Serial.print(heading);
+ Serial.print(", goal location: ");
+ Serial.print(front);
+ Serial.print(", offset: ");
+
+ Serial.println(offset);
- // Adjust for magnetic declination if needed
- // headingDegrees += magneticDeclination;
+ delay(100);
+}
- // Normalize headingDegrees to [0, 360) range
- if (headingDegrees >= 360.0)
- headingDegrees -= 360.0;
+template <typename T> float computeHeading(LIS3MDL::vector<T> from)
+{
+ LIS3MDL::vector<int32_t> temp_m = {mag.m.x, mag.m.y, mag.m.z};
- // Print heading
- Serial.print("Heading: ");
- Serial.println(headingDegrees);
+ // copy acceleration readings from LSM6::vector into an LIS3MDL::vector
+ LIS3MDL::vector<int16_t> a = {imu.a.x, imu.a.y, imu.a.z};
- delay(100);
+ // subtract offset (average of min and max) from magnetometer readings
+ temp_m.x -= ((int32_t)m_min.x + m_max.x) / 2;
+ temp_m.y -= ((int32_t)m_min.y + m_max.y) / 2;
+ temp_m.z -= ((int32_t)m_min.z + m_max.z) / 2;
+
+ // compute E and N
+ LIS3MDL::vector<float> E;
+ LIS3MDL::vector<float> N;
+ LIS3MDL::vector_cross(&temp_m, &a, &E);
+ LIS3MDL::vector_normalize(&E);
+ LIS3MDL::vector_cross(&a, &E, &N);
+ LIS3MDL::vector_normalize(&N);
+
+ // compute heading
+ float heading = atan2(LIS3MDL::vector_dot(&E, &from), LIS3MDL::vector_dot(&N, &from)) * 180 / PI;
+ if (heading < 0) heading += 360;
+ return heading;
+}
+
+/*
+Returns the angular difference in the horizontal plane between a
+default vector (the +X axis) and north, in degrees.
+*/
+float computeHeading()
+{
+ return computeHeading((LIS3MDL::vector<int>){1, 0, 0});
}