从四元数到欧拉角的转换不正确,反之亦然

5
我正在将角度轴表示法转换为欧拉角。我决定检查并确保从转换得到的欧拉角会回到原始的角度轴。我输出了值,但它们不匹配!我已经阅读了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)。我将四元数转换为欧拉角(roll,pitch,yaw)。然后为了检查它,我将(roll,pitch,yaw)转换回角度轴作为cAngle和(cRx,cRy,cRz)。然后我对(roll,pitch,yaw)进行一些边界检查,以使数字保持在- 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
+1. 我终于知道什么是四元数了,比起谷歌搜寻几天的信息得到更多。希望你能得到你的答案。 - Kaliber64
2个回答

5
我没有检查过你的代码,也不会去检查。即使你的代码正确,你的测试至少有两个失败原因。

也就是说,即使你的转换是正确的,你也可以得到其他表示而不是你开始的那个。无论你是从欧拉角还是从四元数开始的都没关系。


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

这个测试具有明确性,如果你弄错了什么(例如公式中的符号),这个测试会帮助你找到错误。


我不会使用欧拉角作为它们会破坏你的应用程序的稳定性。它们也不太方便


非常感谢这个完整的解释。我想现在我会避免欧拉角,我原本错误地打算将它们用作合成旋转矩阵的中间介质。如果我直接将四元数转换为旋转矩阵并返回(如http://www.cg.info.hiroshima-cu.ac.jp/~miyazaki/knowledge/teche52.html中所示),我是否会遇到同样的问题,还是能够正确测试除基向量以外的值?此外,是否可能编写一个特殊情况来避免万向锁,如果俯仰角被这种方法遮挡了? - AAB
1
只要你来回转换,就会遇到同样的问题:四元数具有双重覆盖属性。如果按照我建议的方式进行测试,那么你将不会遇到这个问题。你不必测试单位基向量,那只是一个建议。只要你能够以某种方式计算出期望值(对于单位向量,你可以很容易地在脑海中计算出来,这就是我建议使用它们的原因),你可以测试任何向量。旋转矩阵和四元数都不会受到万向节锁定的影响。因此,如果你摆脱了欧拉角,也就同时解决了万向节锁定问题。 - Ali
好的,我现在明白了。非常感谢你。我会确保更好地理解双覆盖。感谢你提供的测试建议。 - AAB
1
我曾经遇到过这样的问题,单独绕各个轴旋转看起来没问题,但是组合的横滚-俯仰-偏航旋转就有问题;因此你不应该仅仅依赖于验证单位向量的旋转。 - Dave
@Dave 是的,我知道,谢谢。这就是为什么我说“可能”。这是一个非常简单的测试,可以尽早捕捉到许多错误,尽管它不能保护您免受所有可能的错误。我在我的代码中有其他更复杂的测试,我从中分析出了预期的结果。 - Ali

-1

使用四元数是不正确的。

我想要补充一下这个答案。人们通常会按照惯例使用四元数,即使应用是不正确的,所以这很重要。

如果你的旋转对象不能滚动,那么使用四元数来表示你的旋转是不正确的。四元数将三维旋转编码到系统中,如果你的系统只有两个维度,则表示不匹配且不正确。

四元数是旋转的过于复杂的表示形式,仅用于修复万向节锁定并提供更好的组合性,仅适用于涉及俯仰、偏航和横滚的旋转。

如果你只有俯仰和偏航。四元数变换可能会给出一个涉及横滚的答案,这在根本上是不正确的。将横滚角度归零并不能防止你的变换具有横滚值。四元数没有编码旋转无横滚的概念,因此在这里使用它是不正确的。

对于只能俯仰和偏航而不能滚动的物体,请使用不涉及“滚动”概念的实体,如三维笛卡尔坐标或球坐标(而不是欧拉角)。这已经足够且更正确。在这些条件下,你不会遭受万向节锁定的影响...在这种情况下使用四元数不仅过度,而且是错误的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接