用一个机器人关节旋转示例串讲欧拉角、四元数、万向锁与Slerp/Lerp插值
导语:在三维旋转处理中,四元数、万向锁、Lerp和Slerp是四个紧密关联的概念。通过一个具体的机器人关节旋转示例,将这四个概念串联起来,深入浅出地解析其原理。最后以问答形式巩固理解。
一、 场景:机器人肩关节的旋转任务
假设我们有一个网球AI教练系统中的机器人,其肩关节需要从初始姿态 AAA 旋转到目标姿态 BBB,以完成一个发球动作。
- 姿态 A:机器人手臂自然下垂,朝向正前方。
- 姿态 B:手臂抬起,同时向外旋转一定角度。
我们需要解决三个问题:
- 如何用数学描述这两个姿态?(引入欧拉角与四元数)
- 为什么直接对角度进行插值会导致动作突变?(揭示万向锁)
- 如何实现平滑、恒定的旋转动画?(对比 Lerp 与 Slerp)
如图所示的三轴陀螺仪,若旋转红圈过程中,恰巧旋转到了图二所示状态,然后进行步骤3时会发现,旋转蓝圈与绿圈效果一样。也就是这种状态下,旋转Y或Z轴效果一样了,都只能使飞机左右倾斜,而不能再俯视或仰视(它只能头朝天),这下坏了,飞机操作失灵了,只能向上直冲。这就所谓的万向节死锁(gimbal lock)
二、 欧拉角(Euler Angles):直观的旋转表示
1. 什么是欧拉角?
欧拉角是描述三维刚体取向的一种直观方法,它将任意旋转分解为绕三个坐标轴的一系列旋转。通常这三个轴对应:
- 偏航(Yaw):绕垂直轴(通常为Y轴或Z轴)的旋转,如摇头。
- 俯仰(Pitch):绕水平横向轴(通常为X轴)的旋转,如点头。
- 滚转(Roll):绕前后纵深轴(通常为Z轴或X轴)的旋转,如翻滚。

2. 旋转顺序与约定
由于三维旋转不满足交换律(先绕X转再绕Y转 ≠ 先绕Y转再绕X转),必须约定旋转顺序。常见的约定有:
- 航空约定(ZYX):先偏航(Z),再俯仰(Y),最后滚转(X)。
- 机器人学常用(XYZ 或 ZYZ):根据具体关节设计而定。
在示例中,我们假设使用 ZYX 顺序(偏航-俯仰-滚转)。姿态 A 对应 (0∘,0∘,0∘)(0^\circ, 0^\circ, 0^\circ)(0∘,0∘,0∘),姿态 B 对应 (45∘,90∘,45∘)(45^\circ, 90^\circ, 45^\circ)(45∘,90∘,45∘)。
3. 欧拉角的优点与隐患
- 优点:极其直观,人类容易理解和调试(“俯仰角30度”一听就懂)。
- 隐患:当中间轴(如俯仰轴)旋转到特定角度(如 ±90∘\pm 90^\circ±90∘)时,会触发万向锁(Gimbal Lock),导致自由度丢失。
三、 万向锁(Gimbal Lock):欧拉角的阿喀琉斯之踵
1. 通俗理解:三轴陀螺仪
想象一个机械三轴陀螺仪,有三个嵌套的金属环,分别控制偏航、俯仰、滚转。正常情况下,三个环互不干扰,提供三个自由度。
但是,当中间的俯仰环旋转到 90° 时,最外层的偏航环和最内层的滚转环会共面,它们的旋转轴完全重合。此时,转动偏航或滚转,手臂只能在同一个平面上画圈,系统丢失了一个自由度——这就是万向锁。


2. 数学本质
万向锁的本质是参数化奇异性。在俯仰角为 90∘90^\circ90∘ 时,旋转矩阵退化为:
R=Rz(α)Ry(90∘)Rx(γ)=Rz(α+γ)Ry(90∘)
R = R_z(\alpha) R_y(90^\circ) R_x(\gamma) = R_z(\alpha+\gamma) R_y(90^\circ)
R=Rz(α)Ry(90∘)Rx(γ)=Rz(α+γ)Ry(90∘)
此时 α\alphaα 和 γ\gammaγ 无法被独立解耦,它们被“捆绑”成一个角度。数学上,雅可比矩阵在该点秩亏,无法求逆。
3. 在示例中的危害
如果我们的目标姿态 B 是 (45∘,90∘,45∘)(45^\circ, 90^\circ, 45^\circ)(45∘,90∘,45∘),俯仰角正好 90∘90^\circ90∘。若使用欧拉角插值(从 0∘0^\circ0∘ 到 90∘90^\circ90∘ 逐渐增加俯仰),当俯仰接近 90∘90^\circ90∘ 时,偏航和滚转会瞬间耦合,机械臂末端轨迹会出现非预期的剧烈抖动,甚至触发电机保护。
四、 四元数(Quaternion):无奇异的旋转表示
1. 为什么需要四元数?
为了彻底避开万向锁,数学家发明了四元数。它是复数的四维扩展,形式为:
q=w+xi+yj+zk
q = w + xi + yj + zk
q=w+xi+yj+zk
其中 i2=j2=k2=ijk=−1i^2 = j^2 = k^2 = ijk = -1i2=j2=k2=ijk=−1。在机器人学中,我们使用单位四元数(模长为1)来表示旋转。
2. 几何意义:轴角表示
任意一个三维旋转都可以理解为绕某个单位轴 (x,y,z)(x, y, z)(x,y,z) 旋转 θ\thetaθ 角度。四元数完美封装了这两者:
- w=cos(θ/2)w = \cos(\theta/2)w=cos(θ/2)
- (x,y,z)=sin(θ/2)⋅旋转轴(x, y, z) = \sin(\theta/2) \cdot \text{旋转轴}(x,y,z)=sin(θ/2)⋅旋转轴
为什么是 θ/2\theta/2θ/2? 因为四元数旋转通过两次乘法实现:q⋅p⋅q−1q \cdot p \cdot q^{-1}q⋅p⋅q−1,一次乘法贡献一半旋转,两次刚好完成 θ\thetaθ 旋转。
3. 四元数如何解决万向锁?
四元数直接在一个四维超球面上描述旋转,不存在“依次旋转的三个轴”,因此天然没有奇点。无论旋转路径如何,它都能平滑过渡。在示例中,我们将姿态 A 和 B 转换为四元数 qAq_AqA 和 qBq_BqB,完全避开了欧拉角的陷阱。
五、 Slerp 与 Lerp 插值:平滑旋转的保证
现在我们需要在 qAq_AqA 和 qBq_BqB 之间生成中间帧,让机器人手臂平滑运动。
1. Lerp(线性插值)
Lerp 在两点间沿直线插值:v(t)=(1−t)v0+tv1v(t) = (1-t)v_0 + t v_1v(t)=(1−t)v0+tv1。
- 问题1:角速度不均匀。直线切割单位球面,导致在起点和终点附近角速度慢,中间快。手臂动作会“一顿一顿”。
- 问题2:向量缩水。插值结果模长小于1,需要额外归一化(Nlerp),且当 qAq_AqA 与 qBq_BqB 夹角接近 180∘180^\circ180∘ 时,中间向量趋近零,数值不稳定。
2. Slerp(球面线性插值)
Slerp 在单位球面上沿**最短圆弧(大圆)**插值:
Slerp(q0,q1,t)=sin((1−t)Ω)sinΩq0+sin(tΩ)sinΩq1
\text{Slerp}(q_0, q_1, t) = \frac{\sin((1-t)\Omega)}{\sin\Omega} q_0 + \frac{\sin(t\Omega)}{\sin\Omega} q_1
Slerp(q0,q1,t)=sinΩsin((1−t)Ω)q0+sinΩsin(tΩ)q1
其中 Ω=arccos(q0⋅q1)\Omega = \arccos(q_0 \cdot q_1)Ω=arccos(q0⋅q1) 是两四元数的夹角。
Slerp 的优势:
- 恒定角速度:参数 ttt 线性对应旋转角度,运动丝滑。
- 天然单位长度:结果始终在球面上,无需归一化。
- 数值稳定:只要 q0q_0q0 和 q1q_1q1 不互为反向,公式始终有效。
在示例中,使用 Slerp 能让机器人手臂以恒定速度从 A 旋转到 B,完美完成发球动作。
import numpy as np
# 1. 欧拉角转四元数(示例:ZYX顺序)
def euler_to_quat(yaw, pitch, roll):
cy = np.cos(yaw * 0.5)
sy = np.sin(yaw * 0.5)
cp = np.cos(pitch * 0.5)
sp = np.sin(pitch * 0.5)
cr = np.cos(roll * 0.5)
sr = np.sin(roll * 0.5)
w = cr * cp * cy + sr * sp * sy
x = cr * sp * sy - sr * cp * cy
y = cr * sp * cy + sr * cp * sy
z = sr * sp * cy - cr * cp * sy
return np.array([w, x, y, z])
# 2. 定义姿态
q_A = euler_to_quat(0, 0, 0) # 初始姿态
q_B = euler_to_quat(np.pi/4, np.pi/2, np.pi/4) # 目标姿态(含90°俯仰)
# 3. Slerp 插值
def slerp(q0, q1, t):
dot = np.dot(q0, q1)
if dot < 0: # 走最短路径
q1 = -q1
dot = -dot
dot = np.clip(dot, -1, 1)
Omega = np.arccos(dot)
if Omega < 1e-6:
return (1-t)*q0 + t*q1
sin_Omega = np.sin(Omega)
return (np.sin((1-t)*Omega)/sin_Omega)*q0 + (np.sin(t*Omega)/sin_Omega)*q1
# 4. 生成平滑轨迹
trajectory = []
for t in np.linspace(0, 1, 30):
q_interp = slerp(q_A, q_B, t)
trajectory.append(q_interp)
七、 原理解析
Q1: 欧拉角为什么需要约定旋转顺序?
A: 三维空间中的旋转是不可交换的。先绕X轴转30°再绕Y轴转30°,与先绕Y轴转30°再绕X轴转30°,最终姿态完全不同。因此必须严格约定顺序(如ZYX),否则同一个 (α,β,γ)(α, β, γ)(α,β,γ) 会对应无数种姿态。
Q2: 万向锁是机械结构的故障吗?
A: 不是。它是欧拉角数学表示的固有缺陷。当中间轴旋转到90°时,第一轴和第三轴的旋转轴在数学上重合,导致自由度丢失。即使是最完美的机械陀螺仪,只要使用欧拉角描述,就会遇到这个问题。
Q3: 四元数旋转为什么要用 θ/2\theta/2θ/2?
A: 四元数旋转操作是 q⋅p⋅q−1q \cdot p \cdot q^{-1}q⋅p⋅q−1,这是一个共轭乘法。代数上可以证明,这种双重乘法会将旋转角度加倍。因此,为了最终得到 θ\thetaθ 的旋转,四元数本身必须存储 θ/2\theta/2θ/2。
Q4: 为什么 Slerp 能保证恒定角速度?
A: Slerp 的公式是从球面几何推导出来的。它使得插值参数 ttt 与球面上的弧长成严格正比,而弧长对应旋转角度。因此,匀速变化的 ttt 直接对应匀速旋转,角速度自然恒定。
Q5: 在什么情况下可以用 Lerp 代替 Slerp?
A: 当两个四元数夹角非常小(如小于 5°)时,直线(弦)和圆弧(大圆)几乎重合,此时 Lerp 归一化(Nlerp)的计算量远小于 Slerp,且视觉上难以区分。但在大角度或高精度机器人控制中,必须使用 Slerp。
八、 总结
通过机器人肩关节旋转的示例,我们串联了四个核心概念:
- 欧拉角:直观但存在万向锁隐患。
- 万向锁:欧拉角在中间轴90°时的自由度丢失,是数学奇异性。
- 四元数:用四维向量无奇点地表示旋转,彻底避开万向锁。
- Slerp/Lerp:Slerp 在单位球面上沿圆弧插值,保证恒定角速度;Lerp 走直线,仅适用于小角度。
理解这些概念及其内在联系,是掌握三维旋转处理、动作捕捉与机器人轨迹规划的关键。
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐


所有评论(0)