2013-02-24 141 views
4

我将角轴表示转换为欧拉角。我决定检查并确保从转换中得到的欧拉角度会回到原来的轴角度。我打印出这些值,但它们不匹配!我已阅读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 =角度和(cRx,cRy,cRz)=(rx,ry,rz),但这些都是错误的。

我相信旋转的顺序是Z * Y * X。我的数学有什么问题吗?我打算最终在pitch为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); 
+1

+1。我终于知道四元数是什么。更多信息在一分钟内比谷歌天。希望你得到你的答案。 – Kaliber64 2013-02-24 00:55:43

回答

4

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

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


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

此测试的优点是明确,如果你搞砸了某些东西(例如公式中的符号),这个测试可以帮助你找到你的错误。


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

+0

非常感谢您提供完整的解释。我想我现在会避免使用欧拉角度,我不想使用它们作为中介组成旋转矩阵。如果我将四元数直接转换为旋转矩阵并返回(如http://www.cg.info.hiroshima-cu.ac.jp/~miyazaki/knowledge/teche52.html),我是否也会遇到同样的问题,或者会我能够正确地测试基向量以外的值吗?另外,如果用这种方法遮掩俯仰角,是否可以写一个特殊情况来避免万向节锁定? – AAB 2013-02-24 18:53:59

+1

只要您来回转换,您将遇到同样的问题:四元数具有双重封面属性。如果你测试我建议的方式,那么你**不会有**这个问题。你不必测试单位基础矢量,这只是一个建议。你可以测试任何你喜欢的矢量,只要你可以计算出预期的结果(你可以很容易地计算出你的单位矢量的那个,这就是为什么我建议他们)。旋转矩阵和四元数都不受万向节锁的影响。所以如果你摆脱了欧拉角,你也可以摆脱万向节锁问题。 – Ali 2013-02-24 19:01:32

+0

好吧,我现在看到。非常感谢。我会确保我更理解双封面。感谢您的测试建议。 – AAB 2013-02-24 19:06:50