我正在将角度轴表示转换为欧拉角度。我决定检查并确保从转换中得到的欧拉角会回到原来的轴角。我打印出值,但它们不匹配!我在此网站上已阅读http://forum.onlineconversion.com/showthread.php?t=5408和http://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);
答案 0 :(得分:4)
我没有(我不会)检查你的代码。 即使您的代码是正确的,您的测试也会因至少两个原因而失败。
There are 2 ways用欧拉角表示相同的旋转。另请参阅Euler angle to Quaternion then Quaternion to euler angle,该问题基本上与您遇到的问题有关。
四元数具有所谓的double covering属性:两个单位四元数对应于每个旋转。
也就是说,即使您的转化正确,您也可以获得其他代表,而不是您开始使用的代表。无论你是从欧拉角还是四元数开始都没关系。
如果您想测试代码,我建议检查单位基础向量的正交旋转。例如,适当地旋转[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笛卡尔坐标或球坐标(不是欧拉角)。这是足够的,更正确的。在这种情况下,您将不会遭受万向节锁定的困扰……使用四元数不仅可以杀死敌人,而且会出错。