Hello,
I teach a high school project course which used the LSM303 as a simple compass. The LSM303 has been discontinued, so we are looking at alternatives- the first one we are trying is the MinIMU-9 v5. The old LSM303 library had an example called heading that generated a single angle, which is meant to be the heading compared to North. This uses both the magnetometer and accelerometer functions, as well as a simple calibration based off scaling.
The MinIMU-9 v5 does not have a similar built-in example. I am trying to create a substitute, but I am encountering issues integrating the LIS3MDL magnetometer readings and the LSM6 accelerometer readings in a way that matches what heading does. I have made an attempt at a calibration using only the magnetometer min and max values from the LS3MDL calibrate sketch, but this creates a poor calibration.
Has anyone already made a sketch that does what heading does- generating a single angle measure, such that you can control which axis is used as the reference- but for the MiniMU-9? Alternatively, is there another chip that has this functionality already available? If I could get a handle on how to do the vector math portions in a sketch (rather than a library), I could try that as well. I need a single sketch I can hand over to students who have not touched C++ before and not ask much beyond changing calibration values, so Heading was wonderful, and we sorely miss its loss.
This is Heading from the LSM303 library:
/*
Returns the angular difference in the horizontal plane between the
"from" vector and north, in degrees.
Description of heading algorithm:
Shift and scale the magnetic reading based on calibration data to find
the North vector. Use the acceleration readings to determine the Up
vector (gravity is measured as an upward acceleration). The cross
product of North and Up vectors is East. The vectors East and North
form a basis for the horizontal plane. The From vector is projected
into the horizontal plane and the angle between the projected vector
and horizontal north is returned.
*/
template <typename T> float LSM303::heading(vector<T> from)
{
vector<int32_t> temp_m = {m.x, m.y, m.z};
// 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
vector<float> E;
vector<float> N;
vector_cross(&temp_m, &a, &E);
vector_normalize(&E);
vector_cross(&a, &E, &N);
vector_normalize(&N);
// compute heading
float heading = atan2(vector_dot(&E, &from), vector_dot(&N, &from)) * 180 / PI;
if (heading < 0) heading += 360;
return heading;
}
template <typename Ta, typename Tb, typename To> void LSM303::vector_cross(const vector<Ta> *a, const vector<Tb> *b, vector<To> *out)
{
out->x = (a->y * b->z) - (a->z * b->y);
out->y = (a->z * b->x) - (a->x * b->z);
out->z = (a->x * b->y) - (a->y * b->x);
}
template <typename Ta, typename Tb> float LSM303::vector_dot(const vector<Ta> *a, const vector<Tb> *b)
{
return (a->x * b->x) + (a->y * b->y) + (a->z * b->z);
}