赞
踩
描述坐标系{B}相对于参考坐标系{A}的姿态有两种方式。第一种是绕固定(参考)坐标轴旋转:假设开始两个坐标系重合,先将{B}绕{A}的X轴旋转,然后绕{A}的Y轴旋转,最后绕{A}的Z轴旋转,就能旋转到当前姿态。可以称其为X-Y-Z fixed angles或RPY角(Roll, Pitch, Yaw)。
Roll:横滚
Pitch: 俯仰
Yaw: 偏航(航向)
由于是绕固定坐标系旋转,则旋转矩阵为( is shorthand for , is shorthand for ,and so on.)
另一种姿态描述方式是绕自身坐标轴旋转:假设开始两个坐标系重合,先将{B}绕自身的Z轴旋转,然后绕Y轴旋转,最后绕X轴旋转,就能旋转到当前姿态。称其为Z-Y-X欧拉角,由于是绕自身坐标轴进行旋转,则旋转矩阵为:
可以发现这两种描述方式得到的旋转矩阵是一样的,即绕固定坐标轴X-Y-Z旋转和绕自身坐标轴Z-Y-X旋转的最终结果一样,只是描述的方法有差别而已。In gerenal: three rotations taken about fixed axes yield the same final orientation as the same three rotations taken in opposite order about the axes of the moving frame.
绕坐标轴的多次旋转可以等效为绕某一转轴旋转一定的角度。假设等效旋转轴方向向量为,等效旋转角为,则四元数,其中:
且有
即四元数存储了旋转轴和旋转角的信息,它能方便的描述刚体绕任意轴的旋转。
四元数转换为旋转矩阵:
已知旋转矩阵为:
则对应的四元数为:
定义两个四元数:
四元数加法:
四元数乘法:
四元数的乘法的意义类似于矩阵的乘法,可以表示旋转的合成。当有多次旋转操作时,使用四元数可以获得更高的计算效率。
<<Quaternions` (* This loads the package *) Quaternion[2, 1, 1, 3] ** Quaternion[2, 1, 1, 0] ** Quaternion[1, 1, 1, 1] (* Be sure to use ** rather than * when multiplying quaternions *)
计算结果为:Quaternion[-12, 4, 14, 2]
θ = ATan(y / x)求出的θ取值范围是[-PI/2, PI/2];
θ = ATan2(y, x)求出的θ取值范围是[-PI, PI]。
当 (x, y) 在第一象限, 0 < θ < PI/2
当 (x, y) 在第二象限 PI/2 < θ≤PI
当 (x, y) 在第三象限, -PI < θ < -PI/2
当 (x, y) 在第四象限, -PI/2 < θ < 0
enum RotSeq{zyx, zyz, zxy, zxz, yxz, yxy, yzx, yzy, xyz, xyx, xzy,xzx};
上面的代码存在一个问题,即奇异性没有考虑。下面看一种特殊的情况(参考Maths - Conversion Quaternion to Euler):假设一架飞机绕Y轴旋转了90°(俯仰角pitch=90),机头垂直向上,此时如何计算航向角和横滚角?
这时会发生自由度丢失的情况,即Yaw和Roll会变为一个自由度。此时再使用上面的公式根据四元数计算欧拉角会出现问题:
的定义域为,因此,当时(在程序中浮点数不能直接进行等于判断,要使用合理的阈值),俯仰角为90°,将其带入正向公式计算出四元数,然后可以发现逆向公式中atan2函数中的参数全部为0,即出现了的情况!无法计算。
时,,将其带入公式中有
则,于是有
通常令,这时。可以进行验证:当四元数为(w,x,y,z)=(0.653,-0.271,0.653,0.271)时,根据这些规则计算出来的ZYX欧拉角为α=0°,β=90°,γ=45°
当俯仰角为-90°,即机头竖直向下时的情况也与之类似,可以推导出奇异姿态时的计算公式。比较完整的四元数转欧拉角(Z-Y-X order)的代码如下:
CameraSpacePoint QuaternionToEuler(Vector4 q) // Z-Y-X Euler angles { CameraSpacePoint euler = { 0 }; const double Epsilon = 0.0009765625f; const double Threshold = 0.5f - Epsilon; double TEST = q.w*q.y - q.x*q.z; if (TEST < -Threshold || TEST > Threshold) // 奇异姿态,俯仰角为±90° { int sign = Sign(TEST); euler.Z = -2 * sign * (double)atan2(q.x, q.w); // yaw euler.Y = sign * (PI / 2.0); // pitch euler.X = 0; // roll } else { euler.X = atan2(2 * (q.y*q.z + q.w*q.x), q.w*q.w - q.x*q.x - q.y*q.y + q.z*q.z); euler.Y = asin(-2 * (q.x*q.z - q.w*q.y)); euler.Z = atan2(2 * (q.x*q.y + q.w*q.z), q.w*q.w + q.x*q.x - q.y*q.y - q.z*q.z); } return euler; }
在DirectXMath Library中有许多与刚体姿态变换相关的函数可以直接调用:
下面的代码中坐标系绕X轴旋转90°(注意这里不是按照右手定则的方向,而是沿着坐标轴向原点看过去以顺时针方式旋转,因此与传统的右手定则刚好方向相反),来进行变换:
结果如下图所示:
参考:
DirectXMath Library Quaternion Functions
Convert quaternion to euler rotations
Conversion between quaternions and Euler angles
Maths - Conversion Quaternion to Euler
Coordinate Transformations in Robotics—MATLAB
Introduction to Robotics - Mechanics and Control. Chapter 2 Spatial descriptions and transformations
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。