I'm trying to obtain the angle between the upperarm en lowerarm using two IMU's respectively. I calibrate both imu's and use Quaternions to get global orientation of the upperarm and lowerarm object in Unity 3D.
Qimu1 = Quaternion from the imu located on the lowerarm
Qimu2 = Quaternion from the imu located on upperarm.
I made two objects in Unity representing the upperarm en lowerarm. Where the lowerarm is a child object of the upperarm and is connected to the upperarm using Character joint.
This is the script for the upperarm:
if (Input.GetKeyDown(KeyCode.Space))
{
Qstart2 = Qimu2;
}
transform.localRotation = Qstart2 * Quaternion.Inverse(Qimu2);
Lowerarm script:
if (Input.GetKeyDown(KeyCode.Space))
{
Qstart1 = Qimu1;
}
Qimu1new = Qstart1 * Quaternion.Inverse(Qimu1);
Quaternion Qdiff = Quaternion.Inverse(Qimu1new) * Qimu2;
transform.localRotation = Qdiff;
What i would like to acquire is a visual representation of arm movement in Unity3D using 2 IMU's. Now if i keep my elbow extended the script works. But as soon as i start to flex my elbow the lowerarm object starts to continuously rotate around the same axis.
We can use some algebra to find the calculation for the lower arm transform's relative rotation:
The formula Qstartx * Quaternion.Inverse(Qimux)
gives you a rotation for that part relative to the body:
upper arm's rotation relative to body = Qstart2 * Quaternion.Inverse(Qimu2)
lower arm's rotation relative to body = Qstart1 * Quaternion.Inverse(Qimu1)
We know that since lower arm is a child of the upper arm:
lower arm's rotation relative to body
= upper arm's rotation relative to body * lowerArmTransform.relativeRotation
With substitution, we can determine:
Qstart1 * Quaternion.Inverse(Qimu1)
= (Qstart2 * Quaternion.Inverse(Qimu2)) * lowerArmTransform.relativeRotation
Multiply both sides on the left by Quaternion.Inverse(Qstart2 * Quaternion.Inverse(Qimu2))
:
Quaternion.Inverse(Qstart2 * Quaternion.Inverse(Qimu2)) * Qstart1
* Quaternion.Inverse(Qimu1)
= Quaternion.Inverse(Qstart2 * Quaternion.Inverse(Qimu2))
* ( Qstart2 * Quaternion.Inverse(Qimu2) )
* lowerArmTransform.relativeRotation
Quaternion.Inverse(Qstart2 * Quaternion.Inverse(Qimu2)) * ( Qstart2 * Quaternion.Inverse(Qimu2) )
cancel out:
Quaternion.Inverse(Qstart2 * Quaternion.Inverse(Qimu2)) * Qstart1
* Quaternion.Inverse(Qimu1)
= lowerArmTransform.relativeRotation
Since Qimu1new = Qstart1 * Quaternion.Inverse(Qimu1);
, we can conclude:
lowerArmTransform.relativeRotation = Quaternion.Inverse(Qstart2 * Quaternion.Inverse(Qimu2)) * Qimu1new;