对了,我最近开通了微信公众号,计划是两边会同步更新,并逐步的会将博客上的文章同步至公众号中。
感兴趣的朋友可以扫描下方的二维码或者搜索“里先森sements”来关注,欢迎来玩~!
欧拉角与自由度缺失是一个头疼却又讲不明白的问题,本篇是个人的学习笔记,提前感谢各位指正文中错误。
本文中的部分参考文献如下:
- 欧拉角 - 维基百科,自由的百科全书: https://zh.wikipedia.org/wiki/%E6%AC%A7%E6%8B%89%E8%A7%92
- Euler angles - Wikipedia: https://en.wikipedia.org/wiki/Euler_angles
- 环架锁定 - 维基百科,自由的百科全书: https://zh.wikipedia.org/wiki/%E7%92%B0%E6%9E%B6%E9%8E%96%E5%AE%9A
- Gimbal lock - Wikipedia: https://en.wikipedia.org/wiki/Gimbal_lock#Loss_of_a_degree_of_freedom_with_Euler_angles
- Active and passive transformation - Wikipedia: https://en.wikipedia.org/wiki/Active_and_passive_transformation
- unity 旋转欧拉角 万向锁 解释_fengya1的专栏-CSDN博客_unity 万向锁: https://blog.csdn.net/fengya1/article/details/50721768
- 无人机理论(一):坐标转换与姿态描述 - 知乎: https://zhuanlan.zhihu.com/p/73406793
- 欧拉角细节/旋转顺序/内旋外旋 - 知乎: https://zhuanlan.zhihu.com/p/85108850
先介绍一下接下来讲述所需要用到的几种坐标系:世界坐标系、惯性坐标系以及载体坐标系。世界坐标系或者说导航坐标系不难理解,我们的目的最终是求得载体在世界坐标系中的位置以及姿态;载体坐标系是固连在载体上的坐标系,通过它记录了模型各个顶点之间的位置关系,其随载体在世界坐标系中的位置与姿态的变换而变换;惯性坐标系与载体坐标系的原点一致,同样会随载体在世界坐标系中的运动而移动,但坐标轴的方向始终与世界坐标系相同。
1 外旋与内旋
欧拉角中绕三个轴的基本旋转有两种:
- 静态:即绕惯性坐标系的三个轴的旋转,由于物体旋转过程中坐标轴始终保持静止,所以称为静态。(亦或者称为外旋 extrinsic rotations:https://en.wikipedia.org/wiki/Euler_angles#Conventions_by_extrinsic_rotations)
- 动态:绕载体坐标系的三个轴的旋转,由于物体旋转过程中坐标轴随着物体做相同的转动,所以称为动态。(亦或者称为内旋 intrinsic rotations:https://en.wikipedia.org/wiki/Euler_angles#Conventions_by_intrinsic_rotations)
2 表达方式
欧拉角还有两类表达方式,Proper Euler angles 与 Tait–Bryan angles。两个大类都使用三个变量描述了三次旋转过程中的三个旋转角度,最大的差别在于,Proper Euler angles 只涉及了两个转轴,而 Tait–Bryan angles 则涉及三个转轴。Tait–Bryan angles 通常用于航空航天应用。下表[2]展示了两类表达方式的旋转次序,以及对应的主动旋转[5]得到的旋转矩阵,其中X、Y、Z分别表示当前绕坐标系的哪个轴旋转,下标1、2、3分别表示对应于绕第一、第二以及第三个轴的旋转角度, s s s代表正弦 c c c代表余弦(例如 s 2 s_2 s2代表了所绕第二个轴旋转角度的正弦值)。
Proper Euler angles | Tait–Bryan angles |
---|---|
X 1 Y 2 X 3 = [ c 2 − c 3 s 2 s 2 s 3 c 1 s 2 c 1 c 2 c 3 − s 1 s 3 − c 3 s 1 − c 1 c 2 s 3 s 1 s 2 c 1 s 3 + c 2 c 3 s 1 c 1 c 3 − c 2 s 1 s 3 ] X_1Y_2X_3=\begin{bmatrix}c_2&-c_3s_2&s_2s_3\\c_1s_2&c_1c_2c_3-s_1s_3&-c_3s_1-c_1c_2s_3\\s_1s_2&c_1s_3+c_2c_3s_1&c_1c_3-c_2s_1s_3\end{bmatrix} X1Y2X3=⎣⎡c2c1s2s1s2−c3s2c1c2c3−s1s3c1s3+c2c3s1s2s3−c3s1−c1c2s3c1c3−c2s1s3⎦⎤ | X 1 Z 2 Y 3 = [ c 2 c 3 − s 2 c 2 s 3 s 1 s 3 + c 1 c 3 s 2 c 1 c 2 c 1 s 2 s 3 − c 3 s 1 c 3 s 1 s 2 − c 1 s 3 c 2 s 1 c 1 c 3 + s 1 s 2 s 3 ] X_1 Z_2 Y_3 = \begin{bmatrix} c_2 c_3 & - s_2 & c_2 s_3 \\ s_1 s_3 + c_1 c_3 s_2 & c_1 c_2 & c_1 s_2 s_3 - c_3 s_1 \\ c_3 s_1 s_2 - c_1 s_3 & c_2 s_1 & c_1 c_3 + s_1 s_2 s_3 \end{bmatrix} X1Z2Y3=⎣⎡c2c3s1s3+c1c3s2c3s1s2−c1s3−s2c1c2c2s1c2s3c1s2s3−c3s1c1c3+s1s2s3⎦⎤ |
X 1 Y 2 X 3 = [ c 2 s 2 s 3 c 3 s 2 s 1 s 2 c 1 c 3 − c 2 s 1 s 3 − c 1 s 3 − c 2 c 3 s 1 − c 1 s 2 c 3 s 1 + c 1 c 2 s 3 c 1 c 2 c 3 − s 1 s 3 ] X_1 Y_2 X_3 = \begin{bmatrix} c_2 & s_2 s_3 & c_3 s_2 \\ s_1 s_2 & c_1 c_3 - c_2 s_1 s_3 & - c_1 s_3 - c_2 c_3 s_1 \\ - c_1 s_2 & c_3 s_1 + c_1 c_2 s_3 & c_1 c_2 c_3 - s_1 s_3 \end{bmatrix} X1Y2X3=⎣⎡c2s1s2−c1s2s2s3c1c3−c2s1s3c3s1+c1c2s3c3s2−c1s3−c2c3s1c1c2c3−s1s3⎦⎤ | X 1 Y 2 Z 3 = [ c 2 c 3 − c 2 s 3 s 2 c 1 s 3 + c 3 s 1 s 2 c 1 c 3 − s 1 s 2 s 3 − c 2 s 1 s 1 s 3 − c 1 c 3 s 2 c 3 s 1 + c 1 s 2 s 3 c 1 c 2 ] X_1 Y_2 Z_3 = \begin{bmatrix} c_2 c_3 & - c_2 s_3 & s_2 \\ c_1 s_3 + c_3 s_1 s_2 & c_1 c_3 - s_1 s_2 s_3 & - c_2 s_1 \\ s_1 s_3 - c_1 c_3 s_2 & c_3 s_1 + c_1 s_2 s_3 & c_1 c_2 \end{bmatrix} X1Y2Z3=⎣⎡c2c3c1s3+c3s1s2s1s3−c1c3s2−c2s3c1c3−s1s2s3c3s1+c1s2s3s2−c2s1c1c2⎦⎤ |
Y 1 X 2 Y 3 = [ c 1 c 3 − c 2 s 1 s 3 s 1 s 2 c 1 s 3 + c 2 c 3 s 1 s 2 s 3 c 2 − c 3 s 2 − c 3 s 1 − c 1 c 2 s 3 c 1 s 2 c 1 c 2 c 3 − s 1 s 3 ] Y_1 X_2 Y_3 = \begin{bmatrix}c_1 c_3 - c_2 s_1 s_3 & s_1 s_2 & c_1 s_3 + c_2 c_3 s_1 \\ s_2 s_3 & c_2 & - c_3 s_2 \\ - c_3 s_1 - c_1 c_2 s_3 & c_1 s_2 & c_1 c_2 c_3 - s_1 s_3 \end{bmatrix} Y1X2Y3=⎣⎡c1c3−c2s1s3s2s3−c3s1−c1c2s3s1s2c2c1s2c1s3+c2c3s1−c3s2c1c2c3−s1s3⎦⎤ | Y 1 X 2 Z 3 = [ c 1 c 3 + s 1 s 2 s 3 c 3 s 1 s 2 − c 1 s 3 c 2 s 1 c 2 s 3 c 2 c 3 − s 2 c 1 s 2 s 3 − c 3 s 1 c 1 c 3 s 2 + s 1 s 3 c 1 c 2 ] Y_1 X_2 Z_3 = \begin{bmatrix} c_1 c_3 + s_1 s_2 s_3 & c_3 s_1 s_2 - c_1 s_3 & c_2 s_1 \\ c_2 s_3 & c_2 c_3 & - s_2 \\ c_1 s_2 s_3 - c_3 s_1 & c_1 c_3 s_2 + s_1 s_3 & c_1 c_2 \end{bmatrix} Y1X2Z3=⎣⎡c1c3+s1s2s3c2s3c1s2s3−c3s1c3s1s2−c1s3c2c3c1c3s2+s1s3c2s1−s2c1c2⎦⎤ |
Y 1 Z 2 Y 3 = [ c 1 c 2 c 3 − s 1 s 3 − c 1 s 2 c 3 s 1 + c 1 c 2 s 3 c 3 s 2 c 2 s 2 s 3 − c 1 s 3 − c 2 c 3 s 1 s 1 s 2 c 1 c 3 − c 2 s 1 s 3 ] Y_1 Z_2 Y_3 = \begin{bmatrix} c_1 c_2 c_3 - s_1 s_3 & - c_1 s_2 & c_3 s_1 + c_1 c_2 s_3 \\ c_3 s_2 & c_2 & s_2 s_3 \\ - c_1 s_3 - c_2 c_3 s_1 & s_1 s_2 & c_1 c_3 - c_2 s_1 s_3 \end{bmatrix} Y1Z2Y3=⎣⎡c1c2c3−s1s3c3s2−c1s3−c2c3s1−c1s2c2s1s2c3s1+c1c2s3s2s3c1c3−c2s1s3⎦⎤ | Y 1 Z 2 X 3 = [ c 1 c 2 s 1 s 3 − c 1 c 3 s 2 c 3 s 1 + c 1 s 2 s 3 s 2 c 2 c 3 − c 2 s 3 − c 2 s 1 c 1 s 3 + c 3 s 1 s 2 c 1 c 3 − s 1 s 2 s 3 ] Y_1 Z_2 X_3 = \begin{bmatrix} c_1 c_2 & s_1 s_3 - c_1 c_3 s_2 & c_3 s_1 + c_1 s_2 s_3 \\ s_2 & c_2 c_3 & - c_2 s_3 \\ - c_2 s_1 & c_1 s_3 + c_3 s_1 s_2 & c_1 c_3 - s_1 s_2 s_3 \end{bmatrix} Y1Z2X3=⎣⎡c1c2s2−c2s1s1s3−c1c3s2c2c3c1s3+c3s1s2c3s1+c1s2s3−c2s3c1c3−s1s2s3⎦⎤ |
Z 1 Y 2 Z 3 = [ c 1 c 2 c 3 − s 1 s 3 − c 3 s 1 − c 1 c 2 s 3 c 1 s 2 c 1 s 3 + c 2 c 3 s 1 c 1 c 3 − c 2 s 1 s 3 s 1 s 2 − c 3 s 2 s 2 s 3 c 2 ] Z_1 Y_2 Z_3 = \begin{bmatrix} c_1 c_2 c_3 - s_1 s_3 & - c_3 s_1 - c_1 c_2 s_3 & c_1 s_2 \\ c_1 s_3 + c_2 c_3 s_1 & c_1 c_3 - c_2 s_1 s_3 & s_1 s_2 \\ - c_3 s_2 & s_2 s_3 & c_2 \end{bmatrix} Z1Y2Z3=⎣⎡c1c2c3−s1s3c1s3+c2c3s1−c3s2−c3s1−c1c2s3c1c3−c2s1s3s2s3c1s2s1s2c2⎦⎤ | Z 1 Y 2 X 3 = [ c 1 c 2 c 1 s 2 s 3 − c 3 s 1 s 1 s 3 + c 1 c 3 s 2 c 2 s 1 c 1 c 3 + s 1 s 2 s 3 c 3 s 1 s 2 − c 1 s 3 − s 2 c 2 s 3 c 2 c 3 ] Z_1 Y_2 X_3 = \begin{bmatrix} c_1 c_2 & c_1 s_2 s_3 - c_3 s_1 & s_1 s_3 + c_1 c_3 s_2 \\ c_2 s_1 & c_1 c_3 + s_1 s_2 s_3 & c_3 s_1 s_2 - c_1 s_3 \\ - s_2 & c_2 s_3 & c_2 c_3 \end{bmatrix} Z1Y2X3=⎣⎡c1c2c2s1−s2c1s2s3−c3s1c1c3+s1s2s3c2s3s1s3+c1c3s2c3s1s2−c1s3c2c3⎦⎤ |
Z 1 X 2 Z 3 = [ c 1 c 3 − c 2 s 1 s 3 − c 1 s 3 − c 2 c 3 s 1 s 1 s 2 c 3 s 1 + c 1 c 2 s 3 c 1 c 2 c 3 − s 1 s 3 − c 1 s 2 s 2 s 3 c 3 s 2 c 2 ] Z_1 X_2 Z_3 = \begin{bmatrix} c_1 c_3 - c_2 s_1 s_3 & - c_1 s_3 - c_2 c_3 s_1 & s_1 s_2 \\ c_3 s_1 + c_1 c_2 s_3 & c_1 c_2 c_3 - s_1 s_3 & - c_1 s_2 \\ s_2 s_3 & c_3 s_2 & c_2 \end{bmatrix} Z1X2Z3=⎣⎡c1c3−c2s1s3c3s1+c1c2s3s2s3−c1s3−c2c3s1c1c2c3−s1s3c3s2s1s2−c1s2c2⎦⎤ | Z 1 X 2 Y 3 = [ c 1 c 3 − s 1 s 2 s 3 − c 2 s 1 c 1 s 3 + c 3 s 1 s 2 c 3 s 1 + c 1 s 2 s 3 c 1 c 2 s 1 s 3 − c 1 c 3 s 2 − c 2 s 3 s 2 c 2 c 3 ] Z_1 X_2 Y_3 = \begin{bmatrix} c_1 c_3 - s_1 s_2 s_3 & - c_2 s_1 & c_1 s_3 + c_3 s_1 s_2 \\ c_3 s_1 + c_1 s_2 s_3 & c_1 c_2 & s_1 s_3 - c_1 c_3 s_2 \\ - c_2 s_3 & s_2 & c_2 c_3 \end{bmatrix} Z1X2Y3=⎣⎡c1c3−s1s2s3c3s1+c1s2s3−c2s3−c2s1c1c2s2c1s3+c3s1s2s1s3−c1c3s2c2c3⎦⎤ |
因此,在我们使用欧拉角进行旋转描述时,不仅仅要注明使用的表达方式是 Proper Euler angles 还是 Tait–Bryan angles(这通常可以从顺规描述中看出)、使用了哪种顺序规定以及是静态(外旋)还是动态(内旋)。
3 举一个例子
通常我们可以选择自己喜欢或领域内常用的旋转顺规,例如,XYZ顺规,是按照X->Y->Z的顺序来进行旋转的,而ZYX顺规是按照Z->Y->X的顺序来进行旋转。以ZYX顺规为例进行讨论,我们设旋转过程中偏航角为ψ,俯仰角为θ,滚转角为Φ。下图[7]中的飞机演示了ZYX顺规下动态欧拉角的内旋运动,标注出的坐标系便是惯性坐标系,机头-机尾轴向为载体坐标系的x轴,左翼-右翼轴向为载体坐标系的y轴,机背-机底轴向为载体坐标系的z轴,请注意不要混淆。
绕三个轴的旋转虽然都在三维笛卡尔直角坐标系下进行,但每个旋转的步骤内都是平面旋转,用旋转矩阵可以分别表示为[7]:
R
ψ
=
[
cos
ψ
sin
ψ
0
−
sin
ψ
cos
ψ
0
0
0
1
]
R_ψ=\begin{bmatrix}\cosψ&\sinψ&0\\-\sinψ&\cosψ&0\\0&0&1\end{bmatrix}
Rψ=⎣⎡cosψ−sinψ0sinψcosψ0001⎦⎤
R θ = [ cos θ 0 − sin θ 0 1 0 sin θ 0 cos θ ] R_θ=\begin{bmatrix}\cosθ&0&-\sinθ\\0&1&0\\\sinθ&0&\cosθ\end{bmatrix} Rθ=⎣⎡cosθ0sinθ010−sinθ0cosθ⎦⎤
R Φ = [ 1 0 0 0 cos Φ sin Φ 0 − sin Φ cos Φ ] R_Φ=\begin{bmatrix}1&0&0\\0&\cosΦ&\sinΦ\\0&-\sinΦ&\cosΦ\end{bmatrix} RΦ=⎣⎡1000cosΦ−sinΦ0sinΦcosΦ⎦⎤
即:
R
=
R
Φ
R
θ
R
ψ
=
[
cos
θ
cos
ψ
cos
θ
sin
ψ
−
sin
θ
sin
Φ
sin
θ
cos
ψ
−
cos
Φ
sin
ψ
sin
Φ
sin
θ
sin
ψ
+
cos
Φ
cos
ψ
sin
Φ
cos
θ
cos
Φ
sin
θ
cos
ψ
+
sin
Φ
sin
ψ
cos
Φ
sin
θ
sin
ψ
−
sin
Φ
cos
ψ
cos
Φ
cos
θ
]
R=R_ΦR_θR_ψ=\begin{bmatrix}\cosθ\cosψ&\cosθ\sinψ&-\sinθ\\\sinΦ\sinθ\cosψ-\cosΦ\sinψ&\sinΦ\sinθ\sinψ+\cosΦ\cosψ&\sinΦ\cosθ\\\cosΦ\sinθ\cosψ+\sinΦ\sinψ&\cosΦ\sinθ\sinψ-\sinΦ\cosψ&\cosΦ\cosθ\end{bmatrix}
R=RΦRθRψ=⎣⎡cosθcosψsinΦsinθcosψ−cosΦsinψcosΦsinθcosψ+sinΦsinψcosθsinψsinΦsinθsinψ+cosΦcosψcosΦsinθsinψ−sinΦcosψ−sinθsinΦcosθcosΦcosθ⎦⎤
由于此处旋转矩阵使用的是被动旋转的表示方法,你可以发现
R
R
R与上表中ZYX顺规主动旋转的得到的结果互为转置,这并不影响我们后面的分析。
To change the formulas for passive rotations (or find reverse active rotation), transpose the matrices (then each matrix transforms the initial coordinates of a vector remaining fixed to the coordinates of the same vector measured in the rotated reference system; same rotation axis, same angles, but now the coordinate system rotates, rather than the vector).[2]
4 自由度的缺失
在上式中,当我们在Y轴方向,也就是俯仰角θ取±90度时,公式变成了:
R
=
R
Φ
R
θ
R
ψ
=
[
0
0
−
1
sin
(
Φ
−
ψ
)
cos
(
Φ
−
ψ
)
0
cos
(
Φ
−
ψ
)
−
sin
(
Φ
−
ψ
)
0
]
R=R_ΦR_θR_ψ=\begin{bmatrix}0&0&-1\\\sin(Φ-ψ)&\cos(Φ-ψ)&0\\\cos(Φ-ψ)&-\sin(Φ-ψ)&0\end{bmatrix}
R=RΦRθRψ=⎣⎡0sin(Φ−ψ)cos(Φ−ψ)0cos(Φ−ψ)−sin(Φ−ψ)−100⎦⎤
在这种情况下,无论你如何改变偏航角ψ与滚转角Φ,也无法改变矩阵第一行与最后一列的结果,这就是自由度上的缺失。自由度缺失的根本原因是载体坐标系的旋转,即在绕第二旋转轴运动后,第三旋转轴的轴向与初始状态下第一旋转轴的轴向一致。
我们可以做一个试验,将手机的底边作为x轴,左长边作为y轴,手机左下角为原点,从手机底部向屏幕方向为z轴。自由度缺失的判定很简单,我们取第二旋转轴上的一个顶点,观察其在第一次旋转过程中与第三次旋转过程中是否处于同一个旋转平面即可。例如我们按照XYZ顺序进行运动时,可取手机左上角为观测点,第一步绕x轴运动45°时,观测点在惯性坐标系的y-z平面内运动,第二步绕y轴运动90度达成奇异点,第三步无论绕z轴如何运动,观测点始终还是在y-z平面内运动。这便是自由度的缺失,这个现象在万向节中也被称为万向锁(Gimbal lock),但部分现有的教程在解释欧拉角的缺陷时无脑丢出万向锁进行解释可能容易让人摸不着头脑。
对于 Tait–Bryan angles,自由度缺失只存在于动态,也即内旋之中,由于外旋时旋转的参考为惯性坐标系,惯性坐标系并不会随着载体坐标系的旋转而发生运动,也就不存在轴向变化的问题。
对于 Proper Euler angles,我们在ZYZ顺规中,Y轴方向的旋转角度取0或180度时,公式变成了:
Z
1
Y
2
Z
3
=
[
c
1
c
3
−
s
1
s
3
−
c
3
s
1
−
c
1
s
3
0
c
1
s
3
+
c
3
s
1
c
1
c
3
−
s
1
s
3
0
0
0
1
]
Z_1 Y_2 Z_3 = \begin{bmatrix} c_1 c_3 - s_1 s_3 & - c_3 s_1 - c_1 s_3 & 0 \\ c_1 s_3 + c_3 s_1 & c_1 c_3 - s_1 s_3 & 0 \\ 0 & 0 & 1 \end{bmatrix}
Z1Y2Z3=⎣⎡c1c3−s1s3c1s3+c3s10−c3s1−c1s3c1c3−s1s30001⎦⎤
其同样也存在自由度缺失的现象,只不过这种情况下的触发条件为俯仰角取0或180度。值得注意的是,对于 Proper Euler angles,无论是内旋还是外旋,均存在着自由度缺失的情况。