Joint angle calculation using ICM-20948

Good afternoon,

I'm involved in a project in which I have to be able to measure a joint angle while doing flexion/extension using two SparkFun 9DoF IMU Breakout - ICM-20948 IMU's and a ESP32 W-ROOM 32D microcontroller.

I'm not familiar to working with IMUs and quaternions, hence I've been struggling a bit to understand what is necessary mathmatical wise.
In my understanding of the problem, I require the Pitch provided by the IMU which sits on top of the limb that is moving (while the other limb that is connected to the joint is stationary).

I've started working from the DMP_Quat6 example by Sparkfun's library using DMP sensor fusion to obtain the quaternions (using the option INV_ICM20948_SENSOR_ROTATION_VECTOR) and had some realistic readings in terms of the pitch angle being measured.

Though since the limb might be in horizontal or vertical position, the origin of the readings have to change from horizontally to vertically (not sure if I'm being clear), if for example I'm trying to read the flexion angle of the arm in regards to the elbow joint, if my arm is laying flat on a table the readings should be 0, but if I'm standing up with my arm down, here the readings should also be 0.

Is this the right way to approach this or should I consider an alternative? I've tried doing a rotation on the quaternion readings provided by the IMU following some quaternion formulas I've researched.

Any help or guidance is appreciated.
Best regards,
normie

      double q1 = ((double)data.Quat9.Data.Q1) / 1073741824.0; // Convert to double x 
      double q2 = ((double)data.Quat9.Data.Q2) / 1073741824.0; // y 
      double q3 = ((double)data.Quat9.Data.Q3) / 1073741824.0; // z  
      Quaternion PointIn = { 0,q2,0,0 };
      Quaternion Rotation = { 0, SIN_45, 0, COS_45 };
      Quaternion ConjugRotation = ConjugateQuaternion(Rotation);

      Quaternion PointOut = MultiplyQuaternions(MultiplyQuaternions(Rotation,PointIn),ConjugRotation);

Quaternion ConjugateQuaternion(Quaternion quat){
  Quaternion res;
  
  res.x = -quat.x;
  res.y = -quat.y;
  res.z = -quat.z;
  res.w = quat.w;

  return res;
}

Quaternion MultiplyQuaternions(Quaternion quat1, Quaternion quat2){
  Quaternion res;
  
  res.x = (quat1.w * quat2.x) + (quat1.x * quat2.w) + (quat1.y * quat2.z) + (-quat1.z * quat2.y);
  res.y = (quat1.w * quat2.y) + (-quat1.x * quat2.z) + (quat1.y * quat2.w) + (quat1.z * quat2.x);
  res.z = (quat1.w * quat2.z) + (quat1.x * quat2.y) + (-quat1.y * quat2.x) + (quat1.z * quat2.w);
  res.w = (quat1.w * quat2.w) + (-quat1.x * quat2.x) + (-quat1.y * quat2.y) + (-quat1.z * quat2.z);

  return res;
}


Hi there,
Let's consider two segments A and B forming a pivot joint, with an IMU attached to B.
You cannot measure the angle between A and B with a single IMU. Unless A is fixed in space.
To achieve what you described in your post you will need two IMUs. One attached to each segment of your joint (ex: forearm and upper arm).
After positioning the IMUs properly and initialising the system (standing + arm stretched), the computation of flexion angle should be straightforward.

1 Like

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