Best way to get angular velocity data from a IMU 9 DoF sensor

I have been using a BNO055 sensor (9° dof IMU) for a project which will use angular velocity to move the mouse cursor on a PC 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.

My question is, is there anything fundamentally wrong with my approach? Is there a better way to go about this? I'm afraid my lack of understanding of the underlying maths may make me blind to some issue.

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");
  }

Which Y and Z axes?

The rate gyro measures rotation rates relative to the sensor axes. Once you have subtracted the offsets, you can't do better than that.

The quaternion represents the transformation from sensor reference frame to Earth frame, and rotations measured relative to the Earth have additional errors due to the other sensors, and suffer from the interaction of the Euler angles.

It would help if you explained what you are actually trying to do.

Thanks for your response. I'm trying to find the best way to measure angular velocity, which I will then translate into mouse movement of the cursor on a computer screen.

Basically I'm wondering if it's going to be more accurate to use the gyroscope only, or poll the sensor for quaternions, from which I can then calculate the angular velocity.

Have you considered using ML (machine learning) along with your MPU measurements?

You can train Linear Regression models to learn what a particular mouse movement is, from MPU movement readings, and use those trained models to do the thing.

Interesting. I can do some research, but since I want the MPU to basically allow me to control the mouse full-time, as a mouse replacement perhaps that would not be appropriate?

It was just a suggestion. Good luck.

1 Like

Reviving topic hoping for some more advice.

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.