I have been using a BNO055 sensor (9° dof IMU) for a project which will use angular velocity to the mouse cursor on screen.
So far, I have gotten quaternion output from the sensor and been able to convert it to angular velocity in a couple of ways. The first, multiplying 1 quaternion sample by its conjugate in the next sample, and then converting the quaternion Delta in Euler angles. The second, converting from quaternions to Euler angles and then finding the change in those between samples.
Both methods result in angular velocity measurement, but each with their advantages and disadvantages. E.g. Quaternion Delta between samples does not suffer from gimbal lock, but it's difficult to isolate y-axis from z-axis movement.
I know that you can ask the sensor for angular velocity data directly, but apparently that's less precise due to the Gyro drift and it's relative orientation only, which is why I opted to work with quaternions.
Is there a better way to go about this?
My code included below for reference with the 2 approaches in case it's helpful/interesting. It uses the Adafruit repository, doing the standard stuff in setup function and then calling the function below in loop.
void quaternion_Delta () {
// Quaternion data 1
imu::Quaternion quat = bno.getQuat();
// Euler 1
imu::Vector<3> euler_one = quat.toEuler();
//delay between samples
delay(BNO055_SAMPLERATE_DELAY_MS);
// Quaternion data 2
imu::Quaternion quat_two = bno.getQuat();
// Euler 2
imu::Vector<3> euler_two = quat_two.toEuler();
// quaternion comparison
imu::Quaternion quatDelta = quat_two * quat.conjugate ();
imu::Vector<3> euler = quatDelta.toEuler();
Serial.print(" X: ");
Serial.print(euler.x()*radius_to_degrees, 2);
Serial.print(" Y: ");
Serial.print(euler.y()*radius_to_degrees, 2);
Serial.print(" Z: ");
Serial.print(euler.z()*radius_to_degrees, 2);
Serial.print("\t\t");
// Euler comparison
imu::Vector<3> euler_comparison = euler_two - euler_one;
Serial.print(" x: ");
Serial.print(euler_comparison.x()*radius_to_degrees, 2);
Serial.print(" y: ");
Serial.print(euler_comparison.y()*radius_to_degrees, 2);
Serial.print(" z: ");
Serial.print(euler_comparison.z()*radius_to_degrees, 2);
Serial.print("\n");
}