4

I am converting angles-axis representation to Euler angles. I decided to check and make sure that the Euler angles I got from the conversion would lead back to the original axis-angle. I print out the values, but they do not match! I have read http://forum.onlineconversion.com/showthread.php?t=5408 and http://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles as well as similar conversion questions on this website.

In the code below I start with angle 'angle' and axis (rx,ry,rz), then I convert it to quaternions (q0,q1,q2,q3). I convert the quaternions to euler angles (roll, pitch, yaw). Then to check it, I convert (roll,pitch,yaw) back to axis-angle as cAngle and (cRx,cRy,cRz). I then do some bounds checking on (roll, pitch,yaw) to keep the numbers between -pi and pi, and then I print them out. It should be that cAngle=angle and (cRx,cRy,cRz)=(rx,ry,rz), but these are both wrong.

The rotations are in order Z*Y*X as is common, I believe. Is there someting wrong with my math? I plan on eventually adding special cases for when pitch is 0 or PI as in http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToEuler/ but right now I think the problem is separate.

        //input is angle 'angle' and axis '(rx,ry,rz)'

        //convert rx,ry,rz, angle, into roll, pitch, yaw
        double q0 = Math.Cos(angle / 2);
        double q1 = Math.Sin(angle / 2) *Math.Cos(rx);
        double q2 = Math.Sin(angle / 2) * Math.Cos(ry);
        double q3 = Math.Sin(angle / 2) * Math.Cos(rz);
        double roll = Math.Atan2(2 * (q0 * q1 + q2 * q3), 1 - 2 * (q1 * q1 + q2 * q2));
        double pitch = Math.Asin(2 * (q0 * q2 - q3 * q1));
        double yaw = Math.Atan2(2 * (q0 * q3 + q1 * q2), 1 - 2 * (q2 * q2 + q3 * q3));

        //convert back to angle axis
        double cAngle = 2 * Math.Cos(Math.Cos(roll / 2) * Math.Cos(pitch / 2) * Math.Cos(yaw / 2) + Math.Sin(roll / 2) * Math.Sin(pitch / 2) * Math.Sin(yaw / 2));
        double cRx = Math.Acos((Math.Sin(roll / 2) * Math.Cos(pitch / 2) * Math.Cos(yaw / 2) - Math.Cos(roll / 2) * Math.Sin(pitch / 2) * Math.Sin(yaw / 2)) / Math.Sin(cAngle / 2));
        double cRy = Math.Acos((Math.Cos(roll / 2) * Math.Sin(pitch / 2) * Math.Cos(yaw / 2) + Math.Sin(roll / 2) * Math.Cos(pitch / 2) * Math.Sin(yaw / 2)) / Math.Sin(cAngle / 2));
        double cRz = Math.Acos((Math.Cos(roll / 2) * Math.Cos(pitch / 2) * Math.Sin(yaw / 2) - Math.Sin(roll / 2) * Math.Sin(pitch / 2) * Math.Cos(yaw / 2)) / Math.Sin(cAngle / 2));

        //stay within +/- PI of 0 to keep the number small
        if (roll > 3.1416) roll = -Math.PI + (roll - Math.PI);
        if (roll < -3.1416) roll = Math.PI + (roll - (-1) * Math.PI);
        if (pitch > 3.1416) pitch = -Math.PI + (pitch - Math.PI);
        if (pitch < -3.1416) pitch = Math.PI + (pitch - (-1) * 3.1416F);
        if (yaw > 3.1416) yaw = -Math.PI + (yaw - Math.PI);
        if (yaw < -3.1416) yaw = Math.PI + (yaw - (-1) * Math.PI);

        Console.WriteLine("original angle, axis " + angle + ": " + rx + ", " + ry + ", " + rz);
        Console.WriteLine("converted angle, axis " + cAngle + ": " + cRx + ", " + cRy + ", " + cRz);
        Console.WriteLine("quats " + q0 + ", " + q1 + ", " + q2 + ", " + q3);
        Console.WriteLine("roll,pitch,yaw:  " + roll + ", " + pitch + ", " + yaw);
AAB
  • 674
  • 3
  • 14
  • 27
  • 2
    +1. I finally know what a quaternion is. more info in a minute than days of Google. Hope you get your answer. – Kaliber64 Feb 24 '13 at 00:55

2 Answers2

5

I didn't (and I won't) check your code. Even if your code is correct, your test fails for at least 2 reasons.

That is, even if your conversions are correct, you can get the other representation and not the one you started with. It doesn't matter whether you started with Euler angles or quaternions.


If you want to test your code, I suggest checking orthogonal rotations of the unit basis vectors. For example rotate [1, 0, 0] with 90 degrees appropriately to get [0, 1, 0]. Check whether you really get the expected [0, 1, 0], etc. If you got the rotations of all 3 basis vectors right then your code is most likely correct.

This test has the advantage of being unambiguous and if you mess up something (for example a sign in a formula) this test helps you a lot in finding your mistake.


I wouldn't use Euler angles as they screw up the stability of your application. They are not very handy either.

Community
  • 1
  • 1
Ali
  • 56,466
  • 29
  • 168
  • 265
  • Thank you so much for this complete explanation. I think I will avoid euler angles now, I had a bad idea of using them as intermediaries to compose rotation matrices. If I turn quaternions directly into a rotation matrix and back (as in http://www.cg.info.hiroshima-cu.ac.jp/~miyazaki/knowledge/teche52.html ) will I have the same problem, or will I be able to correctly test values other than basis vectors? Also, is it possible to write a special case to avoid gimbal lock if pitch angle is obscured by this method? – AAB Feb 24 '13 at 18:53
  • 1
    You will have the same problem as long as you convert back and forth: quaternions have the double cover property. If you test the way I suggest then you **won't have** this problem. You don't have to test the unit basis vectors, it was just a suggestion. You can test whatever vector you like as long as you can somehow calculate what to expect (you can easily calculate that in your had for the unit vectors, that's why I suggested them). Neither rotation matrices nor quaternions suffer from the gimbal lock. So if you get rid of the Euler angles you also get rid of the gimbal lock issue as well. – Ali Feb 24 '13 at 19:01
  • Ok I see now. Thank you so much. I'll make sure I understand double cover more properly. Thanks for the testing suggestions. – AAB Feb 24 '13 at 19:06
  • 1
    I have seen problems where rotations about individual axes look OK, but combined roll-pitch-yaw rotations have problems; thus you should not _only_ rely on verifying the rotations of the unit vectors. – Dave Jan 14 '14 at 18:22
  • @Dave Yes, I know, thanks. That's why I said *"likely"*. It's a very simple test catching many of the bugs early, although it won't guard you against all possible bugs. I had other, more complicated tests in my code where I derived the expected outcome analytically. – Ali Jan 14 '14 at 19:08
0

Using quaternions are incorrect.

I want to add to this answer. People use quaternions by convention even when the application is incorrect so this is important.

If your subject of rotation cannot roll then using quaternions to represent your rotation is Incorrect. Quaternions encode 3 dimensions of rotation into the system and if your system has only two the representation is mismatched and incorrect.

Quaternions are an over complicated representation of rotation used to fix gimbal lock and provide better composability ONLY for rotations that involve pitch, yaw AND roll.

If you only have pitch and yaw. Quaternion transformations can give you an answer involving roll which is fundamentally incorrect. Zeroing the roll angle does not prevent your transformations from having a roll value. The Quaternion is not encoded with the concept of rotations Without a roll so it is incorrect to use it here.

For things that can only pitch and yaw and NOT roll, use entities that do not involve the concept of "rolling" like 3D Cartesian coordinates or spherical coordinates (not euler angles). That is enough and more correct. You will not suffer from gimbal lock under these conditions... using quaternions for this is not just over kill but WRONG.

Brian Yeh
  • 3,119
  • 3
  • 26
  • 40