Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: mbed-dev
Fork of Adafruit9-DOf_AHRS_Regler_Discrete by
Source/Adafruit_9DOF.cpp
- Committer:
- rtlabor
- Date:
- 2018-09-20
- Revision:
- 3:bd353b8184cc
- Parent:
- 0:772bf4786416
File content as of revision 3:bd353b8184cc:
/***************************************************************************
This is a library for the Adafruit 9DOF Breakout
Designed specifically to work with the Adafruit 9DOF Breakout:
http://www.adafruit.com/products/1714
These displays use I2C to communicate, 2 pins are required to interface.
Adafruit invests time and resources providing this open source code,
please support Adafruit andopen-source hardware by purchasing products
from Adafruit!
Written by Kevin Townsend for Adafruit Industries.
BSD license, all text above must be included in any redistribution
***************************************************************************/
#include <math.h>
#include "Adafruit_9DOF.h"
#define PI (3.14159265F);
/***************************************************************************
PRIVATE FUNCTIONS
***************************************************************************/
/***************************************************************************
CONSTRUCTOR
***************************************************************************/
/**************************************************************************/
/*!
@brief Instantiates a new Adafruit_9DOF class
*/
/**************************************************************************/
Adafruit_9DOF::Adafruit_9DOF(void)
{
}
/***************************************************************************
PUBLIC FUNCTIONS
***************************************************************************/
/**************************************************************************/
/*!
@brief Setups the HW
*/
/**************************************************************************/
bool Adafruit_9DOF::begin()
{
// Enable I2C
return true;
}
/**************************************************************************/
/*!
@brief Populates the .pitch/.roll fields in the sensors_vec_t struct
with the right angular data (in degree)
@param event The sensors_event_t variable containing the
data from the accelerometer
@param orientation The sensors_vec_t object that will have it's
.pitch and .roll fields populated
@return Returns true if the operation was successful, false if there
was an error
@code
bool error;
sensors_event_t event;
sensors_vec_t orientation;
...
lsm303accelGetSensorEvent(&event);
error = accelGetOrientation(&event, &orientation);
@endcode
*/
/**************************************************************************/
bool Adafruit_9DOF::accelGetOrientation(sensors_event_t *event, sensors_vec_t *orientation)
{
/* Make sure the input is valid, not null, etc. */
if (event == NULL) return false;
if (orientation == NULL) return false;
float t_pitch;
float t_roll;
float signOfZ = event->acceleration.z >= 0 ? 1.0F : -1.0F;
/* roll: Rotation around the longitudinal axis (the plane body, 'X axis'). -90<=roll<=90 */
/* roll is positive and increasing when moving downward */
/* */
/* y */
/* roll = atan(-----------------) */
/* sqrt(x^2 + z^2) */
/* where: x, y, z are returned value from accelerometer sensor */
t_roll = event->acceleration.x * event->acceleration.x + event->acceleration.z * event->acceleration.z;
orientation->roll = (float)atan2(event->acceleration.y, sqrt(t_roll)) * 180 / PI;
/* pitch: Rotation around the lateral axis (the wing span, 'Y axis'). -180<=pitch<=180) */
/* pitch is positive and increasing when moving upwards */
/* */
/* x */
/* roll = atan(-----------------) */
/* sqrt(y^2 + z^2) */
/* where: x, y, z are returned value from accelerometer sensor */
t_pitch = event->acceleration.y * event->acceleration.y + event->acceleration.z * event->acceleration.z;
orientation->pitch = (float)atan2(event->acceleration.x, signOfZ * sqrt(t_pitch)) * 180 / PI;
return true;
}
/**************************************************************************/
/*!
@brief Utilize the sensor data from an accelerometer to compensate
the magnetic sensor measurements when the sensor is tilted
(the pitch and roll angles are not equal 0�)
@param axis The given axis (SENSOR_AXIS_X/Y/Z) that is
parallel to the gravity of the Earth
@param mag_event The raw magnetometer data to adjust for tilt
@param accel_event The accelerometer event data to use to determine
the tilt when compensating the mag_event values
@code
// Perform tilt compensation with matching accelerometer data
sensors_event_t accel_event;
error = lsm303accelGetSensorEvent(&accel_event);
if (!error)
{
magTiltCompensation(SENSOR_AXIS_Z, &mag_event, &accel_event);
}
@endcode
*/
/**************************************************************************/
bool Adafruit_9DOF::magTiltCompensation(sensors_axis_t axis, sensors_event_t *mag_event, sensors_event_t *accel_event)
{
/* Make sure the input is valid, not null, etc. */
if (mag_event == NULL) return false;
if (accel_event == NULL) return false;
float accel_X, accel_Y, accel_Z;
float *mag_X, *mag_Y, *mag_Z;
switch (axis)
{
case SENSOR_AXIS_X:
/* The X-axis is parallel to the gravity */
accel_X = accel_event->acceleration.y;
accel_Y = accel_event->acceleration.z;
accel_Z = accel_event->acceleration.x;
mag_X = &(mag_event->magnetic.y);
mag_Y = &(mag_event->magnetic.z);
mag_Z = &(mag_event->magnetic.x);
break;
case SENSOR_AXIS_Y:
/* The Y-axis is parallel to the gravity */
accel_X = accel_event->acceleration.z;
accel_Y = accel_event->acceleration.x;
accel_Z = accel_event->acceleration.y;
mag_X = &(mag_event->magnetic.z);
mag_Y = &(mag_event->magnetic.x);
mag_Z = &(mag_event->magnetic.y);
break;
case SENSOR_AXIS_Z:
/* The Z-axis is parallel to the gravity */
accel_X = accel_event->acceleration.x;
accel_Y = accel_event->acceleration.y;
accel_Z = accel_event->acceleration.z;
mag_X = &(mag_event->magnetic.x);
mag_Y = &(mag_event->magnetic.y);
mag_Z = &(mag_event->magnetic.z);
break;
default:
return false;
}
float t_roll = accel_X * accel_X + accel_Z * accel_Z;
float rollRadians = (float)atan2(accel_Y, sqrt(t_roll));
float t_pitch = accel_Y * accel_Y + accel_Z * accel_Z;
float pitchRadians = (float)atan2(accel_X, sqrt(t_pitch));
float cosRoll = (float)cos(rollRadians);
float sinRoll = (float)sin(rollRadians);
float cosPitch = (float)cos(-1*pitchRadians);
float sinPitch = (float)sin(-1*pitchRadians);
/* The tilt compensation algorithm */
/* Xh = X.cosPitch + Z.sinPitch */
/* Yh = X.sinRoll.sinPitch + Y.cosRoll - Z.sinRoll.cosPitch */
*mag_X = (*mag_X) * cosPitch + (*mag_Z) * sinPitch;
*mag_Y = (*mag_X) * sinRoll * sinPitch + (*mag_Y) * cosRoll - (*mag_Z) * sinRoll * cosPitch;
return true;
}
/**************************************************************************/
/*!
@brief Populates the .heading fields in the sensors_vec_t
struct with the right angular data (0-359�)
Heading increases when measuring clockwise
@param axis The given axis (SENSOR_AXIS_X/Y/Z)
@param event The raw magnetometer sensor data to use when
calculating out heading
@param orientation The sensors_vec_t object where we will
assign an 'orientation.heading' value
@code
magGetOrientation(SENSOR_AXIS_Z, &mag_event, &orientation);
@endcode
*/
/**************************************************************************/
bool Adafruit_9DOF::magGetOrientation(sensors_axis_t axis, sensors_event_t *event, sensors_vec_t *orientation)
{
/* Make sure the input is valid, not null, etc. */
if (event == NULL) return false;
if (orientation == NULL) return false;
switch (axis)
{
case SENSOR_AXIS_X:
/* Sensor rotates around X-axis */
/* "heading" is the angle between the 'Y axis' and magnetic north on the horizontal plane (Oyz) */
/* heading = atan(Mz / My) */
orientation->heading = (float)atan2(event->magnetic.z, event->magnetic.y) * 180 / PI;
break;
case SENSOR_AXIS_Y:
/* Sensor rotates around Y-axis */
/* "heading" is the angle between the 'Z axis' and magnetic north on the horizontal plane (Ozx) */
/* heading = atan(Mx / Mz) */
orientation->heading = (float)atan2(event->magnetic.x, event->magnetic.z) * 180 / PI;
break;
case SENSOR_AXIS_Z:
/* Sensor rotates around Z-axis */
/* "heading" is the angle between the 'X axis' and magnetic north on the horizontal plane (Oxy) */
/* heading = atan(My / Mx) */
orientation->heading = (float)atan2(event->magnetic.y, event->magnetic.x) * 180 / PI;
break;
default:
return false;
}
/* Normalize to 0-359� */
if (orientation->heading < 0)
{
orientation->heading = 360 + orientation->heading;
}
return true;
}
/**************************************************************************/
/*!
@brief Populates the .roll/.pitch/.heading fields in the sensors_vec_t
struct with the right angular data (in degree).
The starting position is set by placing the object flat and
pointing northwards (Z-axis pointing upward and X-axis pointing
northwards).
The orientation of the object can be modeled as resulting from
3 consecutive rotations in turn: heading (Z-axis), pitch (Y-axis),
and roll (X-axis) applied to the starting position.
@param accel_event The sensors_event_t variable containing the
data from the accelerometer
@param mag_event The sensors_event_t variable containing the
data from the magnetometer
@param orientation The sensors_vec_t object that will have it's
.roll, .pitch and .heading fields populated
*/
/**************************************************************************/
bool Adafruit_9DOF::fusionGetOrientation(sensors_event_t *accel_event, sensors_event_t *mag_event, sensors_vec_t *orientation)
{
/* Make sure the input is valid, not null, etc. */
if ( accel_event == NULL) return false;
if ( mag_event == NULL) return false;
if ( orientation == NULL) return false;
float const PI_F = 3.14159265F;
/* roll: Rotation around the X-axis. -180 <= roll <= 180 */
/* a positive roll angle is defined to be a clockwise rotation about the positive X-axis */
/* */
/* y */
/* roll = atan2(---) */
/* z */
/* */
/* where: y, z are returned value from accelerometer sensor */
orientation->roll = (float)atan2(accel_event->acceleration.y, accel_event->acceleration.z);
/* pitch: Rotation around the Y-axis. -180 <= roll <= 180 */
/* a positive pitch angle is defined to be a clockwise rotation about the positive Y-axis */
/* */
/* -x */
/* pitch = atan(-------------------------------) */
/* y * sin(roll) + z * cos(roll) */
/* */
/* where: x, y, z are returned value from accelerometer sensor */
if (accel_event->acceleration.y * sin(orientation->roll) + accel_event->acceleration.z * cos(orientation->roll) == 0)
orientation->pitch = accel_event->acceleration.x > 0 ? (PI_F / 2) : (-PI_F / 2);
else
orientation->pitch = (float)atan(-accel_event->acceleration.x / (accel_event->acceleration.y * sin(orientation->roll) + \
accel_event->acceleration.z * cos(orientation->roll)));
/* heading: Rotation around the Z-axis. -180 <= roll <= 180 */
/* a positive heading angle is defined to be a clockwise rotation about the positive Z-axis */
/* */
/* z * sin(roll) - y * cos(roll) */
/* heading = atan2(--------------------------------------------------------------------------) */
/* x * cos(pitch) + y * sin(pitch) * sin(roll) + z * sin(pitch) * cos(roll)) */
/* */
/* where: x, y, z are returned value from magnetometer sensor */
orientation->heading = (float)atan2(mag_event->magnetic.z * sin(orientation->roll) - mag_event->magnetic.y * cos(orientation->roll), \
mag_event->magnetic.x * cos(orientation->pitch) + \
mag_event->magnetic.y * sin(orientation->pitch) * sin(orientation->roll) + \
mag_event->magnetic.z * sin(orientation->pitch) * cos(orientation->roll));
/* Convert angular data to degree */
orientation->roll = orientation->roll * 180 / PI_F;
orientation->pitch = orientation->pitch * 180 / PI_F;
orientation->heading = orientation->heading * 180 / PI_F;
return true;
}
