从四元数到欧拉角和背面的转换不正确

时间:2013-02-24 00:48:44

标签: math rotation angle quaternions

我正在将角度轴表示转换为欧拉角度。我决定检查并确保从转换中得到的欧拉角会回到原来的轴角。我打印出值,但它们不匹配!我在此网站上已阅读http://forum.onlineconversion.com/showthread.php?t=5408http://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles以及类似的转换问题。

在下面的代码中,我从角度'angle'和轴(rx,ry,rz)开始,然后我将其转换为四元数(q0,q1,q2,q3)。我将四元数转换为欧拉角(滚动,俯仰,偏航)。然后检查它,我将(滚动,俯仰,偏航)转换回轴角度为cAngle和(cRx,cRy,cRz)。然后,我做了一些检查(滚动,俯仰,偏航)的边界,以保持-pi和pi之间的数字,然后我打印出来。它应该是cAngle = angle和(cRx,cRy,cRz)=(rx,ry,rz),但这些都是错误的。

我认为旋转按照常见的Z * Y * X顺序进行。我的数学有问题吗?我计划最终添加特殊情况,如音高为0或PI,如同http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToEuler/,但现在我认为问题是分开的。

        //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);

2 个答案:

答案 0 :(得分:4)

我没有(我不会)检查你的代码。 即使您的代码是正确的,您的测试也会因至少两个原因而失败。

也就是说,即使您的转化正确,您也可以获得其他代表,而不是您开始使用的代表。无论你是从欧拉角还是四元数开始都没关系。


如果您想测试代码,我建议检查单位基础向量的正交旋转。例如,适当地旋转[1, 0, 0] 90度以获得[0, 1, 0]。检查您是否真的得到了预期的[0, 1, 0]等。 如果您获得了所有3个基矢量的旋转,那么您的代码很可能是正确的。

此测试具有明确的优点,如果您搞砸了某些内容(例如公式中的符号),此测试可以帮助您找到错误。


我不会将欧拉角用作they screw up the stability of your application。它们也是not very handy

答案 1 :(得分:0)

使用四元数不正确。

我想添加到此答案。人们习惯上使用四元数,即使应用程序不正确,这也很重要。

如果旋转主题无法滚动,则使用四元数表示旋转是不正确的。四元数将旋转的三个维度编码到系统中,如果您的系统只有两个,则表示不匹配且不正确。

四元数是用于固定万向节锁定的旋转的过于复杂的表示,并且仅对于涉及俯仰,偏航和侧倾的旋转提供更好的可组合性。

如果只有俯仰和偏航。四元数转换可以为您提供涉及滚动的答案,这从根本上是不正确的。调零侧倾角不会阻止变换具有侧倾值。四元数没有用没有旋转的旋转概念编码,因此在此处使用它是不正确的。

对于只能倾斜和偏航而不能滚动的事物,请使用不涉及“滚动”概念的实体,例如3D笛卡尔坐标或球坐标(不是欧拉角)。这是足够的,更正确的。在这种情况下,您将不会遭受万向节锁定的困扰……使用四元数不仅可以杀死敌人,而且会出错。

相关问题