Question

I have a 3D unit quaternion = {w,x,y,z} coming from a sensor device. I want to get the amount of angles(ax,ay,az) about X, Y and Z axes ( But the angles should be independent, one should not change when the other changes). I have come across, Quaternion to Euler angle conversion, they have gimbal lock problem & they are dependents. So I'm thinking to take different approach.

Take 3D vectors x = [1,0,0], y = [0,1,0] and z = [0,0,1]. If I rotate these vectors x, y and z by quaternion, we get 3 vectors xx, yy and zz. Then calculate the angle between x, xx vectors. Similarly angle between y, yy and z, zz. This also seems to be not working. The following is the C# code I've written. The angle range should be -180 to 180 or 0 to 360deg. acos is not preferred as it has precision problems.

How to get this done ? Are there standard approaches ? How to decompose a 3D quaternion into 3 quaternions for individual X, Y and Z axes ?

Vector3D rotVecX = QuatVecRotation(Quaternion, new Vector3D(1,0,0));
Vector3D rotVecY = QuatVecRotation(Quaternion, new Vector3D(0,1,0));
Vector3D rotVecZ = QuatVecRotation(Quaternion, new Vector3D(0,0,1));                
float aX = (float)GetXangle(new Vector3D(1, 0, 0), rotVec1);
float aY = (float)GetYangle(new Vector3D(0, 1, 0), rotVec2);
float aZ = (float)GetZangle(new Vector3D(0, 0, 1), rotVec3); 

Vector3D QuatVecRotation(Quaternion quat, Vector3D vec)
    {            
        Quaternion Qvec = new Quaternion(0,vec.X,vec.Y,vec.Z);              
        Quaternion QvecR = Quaternion.Multiply(quat, Qvec);
        Quaternion Qinv = new Quaternion( quat.W, -quat.X, -quat.Y, -quat.Z); // conjugate or Inverse
        Quaternion Qr = Quaternion.Multiply(QvecR, Qinv);
        Vector3D resultVec = new Vector3D(Qr.X, Qr.Y, Qr.Z);
        resultVec.Normalize();
        return resultVec;
    }
    public double GetXangle(Vector3D vec1, Vector3D vec2)
    {            
        Vector3D axis = Vector3D.CrossProduct(vec1, vec2);
        double angle = Rad2Deg((float)Math.Atan2(axis.Length, Vector3D.DotProduct(vec1, vec2)));            
        double dir = Vector3D.DotProduct(Vector3D.CrossProduct(axis, vec1), new Vector3D(0, 1, 1));
        if(dir<0)
            angle = angle * Math.Sign(dir);            
        return angle;
    }
Était-ce utile?

La solution 2

If the Euler angles obtained from a quaternion becomes bigger, then we will experience gimbal-lock problem, if they are smaller ( between two successive quaternions), then there should be no problem. We may just add the present angles to the previous ones & is possible to get them in desired ranges.

Autres conseils

use dot product:

x·xx = |x||xx|cos(angle)

so:

angle = acos( x·xx / ( |x||xx| ) )

I would suggest calculating the Rodriguez rotation first. This is quite simple

Considering you have two vectors a and b.

The rotation axis will be defined by their cross product N=axb.

The rotation angle will be defined by their normalized dot product cos(theta) = a * b/(||a|| ||b||)

The formula to convert between the Rodriguez rotation and it's Quaternion is here

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top