3、四元数基础:数学定义、旋转与基本运算
各位同学,欢迎来到第三讲。今天咱们聊聊四元数。
说实话,我第一次接触四元数的时候,头都是大的。什么虚部实部,什么i、j、k,感觉像在学天书。但后来在飞控项目里被欧拉角狠狠坑过一次——万向锁导致无人机直接翻了个跟头——从那以后,我就老老实实把四元数啃下来了。
你想想看,一个能在三维空间里自由旋转、还没有死角的数学工具,它不香吗?
3.1 四元数的数学定义
四元数,说白了就是一个超复数。它由一个实部和三个虚部组成:
q = w + xi + yj + zk
其中w是实部,x、y、z是虚部。i、j、k是三个虚数单位,它们满足一个很有意思的关系:
i² = j² = k² = ijk = -1
嗯,这里要注意,i、j、k之间不满足交换律。也就是说:
i × j = k
j × i = -k
这个特性很重要,后面讲旋转的时候会用到。
我们通常把四元数写成向量形式:
q = [w, x, y, z]ᵀ
或者更规范一点:
q = [w, v] 其中 v = (x, y, z)
核心要点:四元数本质上是一个四维向量,但它能优雅地表示三维空间中的旋转。
3.2 四元数与旋转
为什么四元数能表示旋转?我当年也困惑了很久。
其实道理很简单:任何一个三维旋转,都可以用一个单位四元数来表示。假设我们要绕单位向量 n = (nx, ny, nz) 旋转 θ 角度,那么对应的四元数是:
q = cos(θ/2) + sin(θ/2) · (nx·i + ny·j + nz·k)
写成向量形式:
q = [cos(θ/2), sin(θ/2)·nx, sin(θ/2)·ny, sin(θ/2)·nz]
举个例子,绕Z轴旋转90度:
θ = 90°, n = (0, 0, 1)
q = [cos45°, 0, 0, sin45°] = [0.707, 0, 0, 0.707]
个人经验:我在做IMU姿态解算时,经常用这个公式把角度转换成四元数。记住,角度一定要用半角,这是初学者最容易犯错的地方。
3.3 四元数的基本运算
好了,理论讲完了,咱们来点实在的。四元数的运算其实不复杂,我给大家梳理一下。
3.3.1 加法
两个四元数相加,就是对应分量相加:
q₁ = [w₁, x₁, y₁, z₁]
q₂ = [w₂, x₂, y₂, z₂]
q₁ + q₂ = [w₁+w₂, x₁+x₂, y₁+y₂, z₁+z₂]
这个很简单,没什么好说的。
3.3.2 乘法
四元数乘法就有点意思了。它不满足交换律,所以顺序很重要。
假设:
q₁ = [w₁, v₁] 其中 v₁ = (x₁, y₁, z₁)
q₂ = [w₂, v₂] 其中 v₂ = (x₂, y₂, z₂)
那么:
q₁ × q₂ = [w₁w₂ - v₁·v₂, w₁v₂ + w₂v₁ + v₁×v₂]
展开成标量形式:
w = w₁w₂ - x₁x₂ - y₁y₂ - z₁z₂
x = w₁x₂ + x₁w₂ + y₁z₂ - z₁y₂
y = w₁y₂ - x₁z₂ + y₁w₂ + z₁x₂
z = w₁z₂ + x₁y₂ - y₁x₂ + z₁w₂
我曾经踩过的坑:在C语言里实现四元数乘法时,一定要注意不能原地更新。比如 q1 = q1 * q2,如果你先更新了w分量,后面计算x、y、z时用的w就已经变了。正确的做法是用临时变量。
3.3.3 共轭
四元数的共轭,就是把虚部取反:
q = [w, x, y, z]
q* = [w, -x, -y, -z]
共轭有什么用?它和逆四元数关系密切。对于单位四元数,它的逆就等于共轭:
q⁻¹ = q* (当 ||q|| = 1时)
这个性质在姿态解算中太常用了。比如我们要把一个向量从机体坐标系转到世界坐标系,就是用共轭四元数去乘。
3.3.4 模长
四元数的模长,就是它的范数:
||q|| = √(w² + x² + y² + z²)
单位四元数的模长为1。为什么叫单位四元数?因为它模长是1,就像单位向量一样。
重要提醒:在飞控代码里,每次更新完四元数后,我建议都做一次归一化。因为数值计算会引入误差,导致模长偏离1。不归一化的话,旋转会变形,姿态会漂移。
3.4 实战:用四元数旋转一个向量
说了这么多,咱们来点实际的。怎么用四元数旋转一个三维向量?
假设有一个向量 p = (px, py, pz),我们把它写成纯四元数形式:
p_quat = [0, px, py, pz]
然后用旋转四元数 q 去旋转它:
p_rotated = q × p_quat × q*
注意顺序:先左乘q,再右乘q的共轭。结果p_rotated的虚部就是旋转后的向量。
举个例子:
// 绕Z轴旋转90度
q = [0.707, 0, 0, 0.707]
p = [0, 1, 0, 0] // 指向X轴正方向
// 计算 p_rotated = q * p * q*
// 结果应该是 [0, 0, 1, 0],指向Y轴正方向
我的习惯:在代码里,我会把四元数旋转封装成一个函数。输入是四元数和三维向量,输出是旋转后的三维向量。这样调用起来特别清爽,不容易出错。
3.5 本章小结
来,咱们捋一捋今天的内容:
- 四元数定义:一个实部加三个虚部,q = w + xi + yj + zk
- 旋转表示:绕轴n转θ,对应q = [cos(θ/2), sin(θ/2)·n]
- 基本运算:加法对应分量相加,乘法注意顺序,共轭虚部取反,模长是平方和开根
- 向量旋转:p_rotated = q × p_quat × q*
下一讲,咱们会深入四元数在姿态解算中的具体应用。到时候我会分享一些实际项目中的代码和调试经验,敬请期待。
记住,四元数这东西,刚开始觉得绕,用多了就顺了。我在项目里已经离不开它了,希望你也是。