【万向死锁问题】:旋转矩阵推导解释万向死锁问题、欧拉角的本质、万向死锁的本质、欧拉角表示最佳替代方案——四元数表示

922 阅读5分钟

@TOC


前言

个人认为 ==万向死锁== 是在三维计算机图形学和机器人学等领域中一个独特且充满趣味性的问题。特别是在处理旋转和平移的组合变换时,如,在计算机图形学中使用欧拉角表示旋转时,由于万向节死锁的存在,可能会导致在特定情况下无法准确地表示物体的旋转状态,从而影响到图形的渲染效果。机器人学中,机器人的关节运动可能会受到万向节死锁的影响,使得机器人在某些姿态下无法进行特定的运动。

~~噢,NO~~~ xyzxyz 轴变换如此常用,从我们小学就开始学习,但为什么还有这么多问题?

实际上,工程应用中上为了避免 ==欧拉角表示法== 中可能出现的万向节死锁而引入计算效率高插值平滑的 ==四元数==

本文将会在引入 万向死锁 问题后,通过矩阵变换计算的方式从数学理解万向死锁问题,并且借由万向死锁这一问题理解 矩阵 的本质—— 变换 的表示工具。然后快速学习欧拉角表示的最佳替代方案——四元数表示,帮助大家解决眼前的实际开发问题。

  • 当然,如果想要无伤【不涉及数学知识】理解 ==万向死锁问题== 、==欧拉角表示的是变换而非“旋转”这一运动== 请移步: 【无伤理解欧拉角中的“万向死锁”现象 => BiliBili】
  • 该博主从欧拉角定义本身通俗易懂的帮助大家认识万向死锁问题发生的根本 以下是本篇文章正文内容,如果觉得有用还请点赞收藏下哦

一、万向死锁是什么?

大家对 欧拉角 肯定不陌生: 欧拉角是用来描述三维空间中刚体旋转的一种方法。它通过三个角度来确定刚体的旋转状态,通常这三个角度分别被称为 偏航角(yaw)、俯仰角(pitch)和滚转角(roll)。【==直观理解成与 xyzxyz 轴的夹角即可==】 在这里插入图片描述

==万向死锁:== 简单说就是欧拉角 3次旋转过程中产生了1次旋转轴的重合,导致原来的 3个旋转自由度实际退化成为2个有效的自由度,==这导致了一个物体姿态表示自由度的丢失!== 假设 :你编写一个飞机的遥控系统,具备 XYZX-Y-Z 三个轴的角度变换拖拽条,当你先将 YY 轴拖拽到 90°90° 时,你会发现 XXZZ 轴的角度旋转效果相同【XX轴的变换效果消失,表现为与 ZZ 轴变换的效果相同,此时飞机无法进行 XX 轴角度变换】 ==确实头秃!== 在这里插入图片描述 ==令人麻爪万向死锁=>==在这里插入图片描述

还看不懂?没关系! ==超简单的理解方法:==

  1. 站起来,y轴朝天,x轴两臂(左臂),z轴朝前 理解?

  2. 顺序:Y=>X=>ZY=>X=>Z 沿Y轴转,就是转身 沿X轴转,就是抬头 沿Z轴转,就是保持脸的朝向不变,歪头 理解?

  3. 那么接下来按照以下顺序转:转身转过随便一个角度,然后抬头90度直朝天,然后再随便歪头歪一个角度 (注意1:歪头时脸的朝向是不变的) (注意2:把视线方向作为你的旋转效果) 那么你就会发现,歪头的效果跟开始转身的效果是一样的

  4. 如果歪头的角度和转身的角度相等但是方向相反,那么就可以相互抵消[礼貌微笑][好奇探头][手动狗头]


二、万向死锁问题的旋转矩阵推导【数学角度进行理解】

万向节死锁(万向死锁)发生时的旋转矩阵推导过程如下:

    1. 明确旋转顺序及旋转矩阵表示:

    通常我们考虑按某一顺序(比如先绕 zz 轴,再绕 yy 轴,最后绕 xx 轴旋转)来构建旋转矩阵。

    • zz 轴旋转 αα 角度的旋转矩阵 Rz(α)R_z(α) 为:
    Rz(α)=[1000cosαsinα0sinαcosα]R_z(α) = \begin{bmatrix} 1 & 0 & 0 \\ 0 & \cosα & -\sinα \\ 0 & \sinα & \cosα \end{bmatrix}
    • yy 轴旋转 ββ 角度的旋转矩阵 Ry(β)R_y(β) 为:
    Ry(β)=[cosβ0sinβ010sinβ0cosβ]R_y(β) = \begin{bmatrix} \cosβ & 0 & \sinβ \\ 0 & 1 & 0 \\ -\sinβ & 0 & \cosβ \end{bmatrix}
    • xx 轴旋转 γγ 角度的旋转矩阵 Rx(γ)R_x(γ) 为:
    Rx(γ)=[cosγsinγ0sinγcosγ0001]R_x(γ) = \begin{bmatrix} \cosγ & -\sinγ & 0 \\ \sinγ & \cosγ & 0 \\ 0 & 0 & 1 \end{bmatrix}
    1. 按顺序相乘得到复合旋转矩阵:

    按照规定的旋转顺序相乘,得到复合旋转矩阵 R复合R_{\text{复合}},即:

    R复合=Rx(γ)Ry(β)Rz(α)R_{\text{复合}} = R_x(γ)R_y(β)R_z(α)

    具体计算过程为:

    R复合=[cosγsinγ0sinγcosγ0001][cosβ0sinβ010sinβ0cosβ][1000cosαsinα0sinαcosα]R_{\text{复合}} = \begin{bmatrix} \cosγ & -\sinγ & 0 \\ \sinγ & \cosγ & 0 \\ 0 & 0 & 1 \end{bmatrix} \begin{bmatrix} \cosβ & 0 & \sinβ \\ 0 & 1 & 0 \\ -\sinβ & 0 & \cosβ \end{bmatrix} \begin{bmatrix} 1 & 0 & 0 \\ 0 & \cosα & -\sinα \\ 0 & \sinα & \cosα \end{bmatrix}
    [cosγcosβcosγsinβsinαsinγcosαcosγsinβcosα+sinγsinαsinγcosβsinγsinβsinα+cosγcosαsinγsinβcosαcosγsinαsinβcosβsinαcosβcosα]\begin{bmatrix} \cosγ \cosβ & \cosγ \sinβ \sinα - \sinγ \cosα & \cosγ \sinβ \cosα + \sinγ \sinα \\ \sinγ \cosβ & \sinγ \sinβ \sinα + \cosγ \cosα & \sinγ \sinβ \cosα - \cosγ \sinα \\ -\sinβ & \cosβ \sinα & \cosβ \cosα \end{bmatrix}
    1. 分析万向节死锁发生的条件及矩阵变化:

    • 万向死锁发生条件:中间轴 (这里是y轴)旋转90°时,即β = 90°。此时cosβ = 0,sinβ = 1。

    • 将其代入上述复合旋转矩阵中,得到:

    Rxyz=[cosγ×0cosγ×1×sinα+sinγ×cosαsinγ×sinα+cosγ×cosαsinγ×0sinγ×1×sinα+cosγ×cosαsinγ×cosαcosγ×sinα10×sinα0×cosα]R_{xyz} = \begin{bmatrix} \cosγ \times 0 & -\cosγ \times 1 \times \sinα + \sinγ \times \cosα & \sinγ \times \sinα + \cosγ \times \cosα \\ \sinγ \times 0 & \sinγ \times 1 \times \sinα + \cosγ \times \cosα & \sinγ \times \cosα - \cosγ \times \sinα \\ -1 & 0 \times \sinα & 0 \times \cosα \end{bmatrix}
    [0cosγsinα+sinγcosαsinγsinα+cosγcosα0sinγsinα+cosγcosαsinγcosαcosγsinα100]\begin{bmatrix} 0 & -\cosγ \sinα + \sinγ \cosα & \sinγ \sinα + \cosγ \cosα \\ 0 & \sinγ \sinα + \cosγ \cosα & \sinγ \cosα - \cosγ \sinα \\ -1 & 0 & 0 \end{bmatrix}
    • 进一步 ==化简== 可得:
    Rxyz=[0sin(γ+α)cos(γ+α)0cos(γ+α)sin(γ+α)100]R_{xyz} = \begin{bmatrix} 0 & -\sin(γ + α) & \cos(γ + α) \\ 0 & \cos(γ + α) & \sin(γ + α) \\ -1 & 0 & 0 \end{bmatrix}
    • 可以发现,此时旋转矩阵中原本独立的 XYZX、Y、Z 轴的旋转信息发生了 耦合。原本我们可以通过独立地改变 αβγα、β、γ 三个角度实现不同的旋转效果。但在这种情况下,由于 yy 轴旋转 90°90°,导致 zz 轴和原来的 xx 轴重叠了重合(从矩阵的角度来看,绕 xx 轴的旋转和绕 zz 轴的旋转产生了 等效),从而丢失了一个自由度( ββ 旋转效果被抵消,即在最后的旋转效果矩阵中不被表示),这就是万向死锁现象。

三、欧拉角的本质【万向死锁问题发生的本质原因(这里我们仅讨论动态欧拉角)】

  • 有的朋友已经发现了,万向死锁的发生条件是欧拉角旋转变换的 中间轴旋转 90°90° 发生的
  • 这体现了一个关键 => 三个轴的变换需要按照一定顺序,不同顺序会导致不同结果

==why?== 要理解万向死锁发生的本质我们需要深刻体会一件事情: 在这里插入图片描述

关键就是 “旋转变换” 不满足 “交换律” ,每一次旋转的结果都基于当前姿态情况。 ==【矩阵乘法不满足交换律一样也是同理,矩阵是表示变换的工具,它并不记载中间的运动过程】==

初学者接触欧拉角描述很容易拿去跟直角坐标位置描述去对比,就很容易陷入 ==思维误区==。 这个思维误区就是将欧拉角的 “旋转变换” 当成了 “转动”

例如:飞机从初始姿态,先绕 XX 轴旋转变换 10°10°,再绕 YY 轴变换 90°90°,最后绕 ZZ 轴变换 0°,前三个变换共同组成一个 “整体变换”,“啪” 一下将飞机从初始姿态 “直接” 变为了结果姿态。

【三个变换被放到黑箱中,其中两个轴旋转变换信息产生 “耦合”,飞机接受的是黑箱 整体变换信息直接 做出变换,而非是简单的 “旋转运动”,旋转运动是当拖拽旋转拉条时 大量单次 1° 变换后的结果姿态 组成的连续帧动画产生的幻觉】

  • 所谓的万向死锁,这个名字很具有 ==“误导性”==,听起来像是欧拉角这种描述方式存在巨大缺陷一样。

  • 但其本质就是: ==物体角度状态与欧拉角坐标并非一一对应关系。== 某些位置状态并不唯一确定一组欧拉角坐标 【在上面飞机的例子就是在中间轴旋转 90°90°xxzz 的角度是等效的】

  • 这并不是什么大问题。空间中的任何状态都能通过欧拉角变换得到,只是某些状态坐标不唯一而已。这是由于采用自身坐标系引起的:多种旋转方式(对应多种欧拉角坐标)都能得到同一种最终状态。采用自身坐标系的优势是直观方便操控,如果想要唯一确定坐标直接用世界坐标系就行了。

【更进一步理解,非数学精通可以不看】:从更进一步的数学角度看,欧拉角可以看作是一种从三维空间的角度参数到三维空间旋转群的映射。这种映射在除了一些特殊情况(如某些角度组合会导致奇点问题)外,在局部是光滑同胚的。也就是说,在大部分情况下,微小的角度变化会导致刚体姿态的平滑变化,但在一些特殊角度下,这种映射关系会出现退化或不连续的情况,也就是这个万向死锁问题。


四、四元数表示——欧拉角表示最佳替代方案

四元数由威廉·罗恩·哈密顿于1843年引入,作为一种允许他对向量进行乘法和除法、旋转和拉伸的方法,避免了欧拉角的奇异性。 ==【以下内容仅做基础说明,深入研究请移步末尾的更进一步的学习文章】==

  • 四元数是一个向量,定义为:

    q=w+xi+yj+zkq = w + xi + yj + zk

    其中,ww 是实数部分,xyzx、y、z 是虚数部分。四元数可以被表示为:

    q=(w,x,y,z)q = (w, x, y, z)
    • ww:实数部分
    • x,y,zx, y, z:虚数部分
  • 我们将一个四元数的实部看作在一个三维空间上的旋转角度(角度值用余弦表示),虚部则为旋转轴方向的向量


例如,单位四元数表示一个旋转:

q=(cos(θ/2),n^sin(θ/2))q = (\cos(\theta/2), \hat{n} \cdot \sin(\theta/2))

其中,n^\hat{n} 是旋转轴,θ\theta 是旋转角度。

  • ==点积==
ab=abcos(θ)a \cdot b = |a||b|\cos(\theta)
  • 几何上,点积定义了两个向量之间的夹角,若点积为0,两个向量正交。
  • ==叉积==
a×b=absin(θ)n^a \times b = |a||b|\sin(\theta)\hat{n}
  • 叉积生成一个与向量 aabb 正交的向量 n^\hat{n}

考虑单位矢量的旋转问题。在3D空间中,一个单位四元数可以用于描述一个矢量 v\vec{v} 的旋转。 设定旋转轴 n^\hat{n},并设 θ\theta 为旋转角度。使用四元数旋转可以描述为:

q=qvq1q' = qvq^{-1}

其中q是四元数,q'是旋转后的四元数。


四元数矩阵表示

四元数可转换为矩阵形式,以便进行旋转运算。旋转矩阵表示为:

R(q)=[12(y2+z2)2(xyzw)2(xz+yw)2(xy+zw)12(x2+z2)2(yzxw)2(xzyw)2(yz+xw)12(x2+y2)]R(q) = \begin{bmatrix} 1 - 2(y^2 + z^2) & 2(xy - zw) & 2(xz + yw) \\ 2(xy + zw) & 1 - 2(x^2 + z^2) & 2(yz - xw) \\ 2(xz - yw) & 2(yz + xw) & 1 - 2(x^2 + y^2) \end{bmatrix}

该矩阵用于将四元数转化为旋转矩阵。


四元数乘法

四元数乘法并不是交换的,它定义了旋转复合。两个四元数q1和q2的乘法如下:

q1×q2=(w1,x1,y1,z1)×(w2,x2,y2,z2)q1 \times q2 = (w_1, x_1, y_1, z_1) \times (w_2, x_2, y_2, z_2)

对于复合旋转,四元数的乘法满足以下公式:

q=q1q2q' = q_1q_2

四元数广泛应用于计算机图形学、物理学等领域,用于高效地处理旋转问题,避免万向节死锁现象。


更多欧拉角与四元数相互转换与学习文章请参考:


五、欧拉角表示 VS 四元数表示

[AI内容]

==四元数:==

  • 优点: > - 计算效率高:四元数进行旋转计算时,相比旋转矩阵所需的计算量更小,尤其是在频繁进行旋转操作的场景下。如动画、游戏物理模拟等,能显著提高计算速度。
    • 不存在方向奇异问题:四元数在存在旋角时(如俯仰角为 ±90°)时会出现万向节锁,导致失去一个旋转自由度,而四元数由于使用单位四元数(即保持单位模长的四元数),可避免这种通过本旋转。
    • 转插值:在进行旋转插值时,四元数旋转能使得平滑的过渡效果,适用于需要在不同旋转状态间平滑过渡的应用场景。比如动画、游戏开发中的旋转速度效果。
    • 存储空间小:四元数只需四个数值(一个实部和三个虚部)表示旋转,相比旋转矩阵(需要9个元素),占用的存储空间更少。
  • 缺点: > - 不直观:四元数的数学表达对大部分人而言并不直接,对人们理解的角度较低,难以像欧拉角那样容易理解和计算,同时四元数的运算规则较为复杂,学习起来不友好。
    • 单个四元数不能表示超过180度的旋转:虽然可以通过一些方法解决这个问题,但使用四元数表示大于一定的方向变化的旋转并不优雅。

==欧拉角:==

  • 优点:
    • 直观:欧拉角表示旋转直观且易于理解,对于大部分人来说,旋转角度的概念容易掌握。对三维图形操作中的旋转而言,欧拉角是一种直接的表示方法,尤其是在旋转过程中相对简单的情况。
    • 可表示大于180度的旋转:能直接表示从一个方向到另一个方向旋转大于180度的角度,在需要表示大范围旋转的场景下有优势。
  • 缺点:
    • 万向节锁问题:当俯仰角为±90°时,会出现方向奇异现象(被称为万向节锁),导致失去一个自由度,导致在某些情况下旋转无法完成,且可能引发计算结果不准确的情况。在一些对旋转精度要求较高的应用中不适用。
    • 旋转顺序影响最终结果不统一:欧拉角的旋转顺序非常重要,得到的最终旋转结果可能截然不同。而在不同的应用场景中可能会使用不同的旋转顺序,这使得欧拉角在某些复杂情况下不容易处理。
    • 插值结果不直观:由于欧拉角分别影响三个独立的旋转轴,在进行旋转插值时很难获得光滑且自然的过渡效果。 -角度范围受限无法解决同角度问题:旋转的范围通常受限在 ±180° 或 0°-360° 之间,超过这个范围时会出现角度计算问题。例如:无法轻松解决在旋转过程中超出这些角度范围的问题。