SLAM 中关于姿态导数的计算

在学习SLAM的过程中,不可避免地会遇到需要对姿态求导的场景。姿态分别有:旋转向量、旋转矩阵、欧拉角、四元数四种表示方法。旋转矩阵适合对坐标进行坐标变换,即将某一个坐标系下的坐标转换至另一个坐标系;欧拉角适合直观的描述载体当前的姿态,便于人们感受姿态;四元数适合更新姿态,只要我们记着及时将四元数归一化;而旋转向量更适合在求导中使用,下面我将试图说清楚旋转向量在求导中的使用。讲清楚此部分内容可能需要较多角标符号,所以请大家仔细分辨这些符号,可能我自己都分辨不清楚。由于本人能力有限,难免会有出错,请大家多多指正。

符号约定

为避免符号约定的歧义,在此说明,在本文中:

对于旋转矩阵 RbwR_{b}^{w}Rbw​,其表示将坐标系b中的坐标旋转至坐标系 w 中的坐标变换矩阵,即若存在一个 b 系下的坐标 pb=[xb yb zb]Tp^{b}=\left[x^{b}\ y^{b}\ z^{b}\right]^{T}pb=[xb yb zb]T,那么有 pw=Rbwpbp^{w}=R_{b}^{w}p^{b}pw=Rbw​pb。这里的 b 系,我们通常认为是载体系,w 系通常认为是世界系。

四元数 qwbq_{w}^{b}qwb​ 在表示坐标变换时,与 RbwR_{b}^{w}Rbw​ 表达的含义相反,但与 RwbR_{w}^{b}Rwb​ 的含义相同,四元数具体的坐标转换方式见SLAM14 讲第二版3.4.3 节。我习惯称 qwb/Rwbq_{w}^{b}/R_{w}^{b}qwb​/Rwb​ 形式的姿态为 w 系在 b 系下的姿态。

旋转向量 ϕbwb\phi_{bw}^{b}ϕbwb​,令其为 ϕbwb=θab\phi_{bw}^{b}=\theta a^{b}ϕbwb​=θab,θ 为标量表示旋转向量转过的角度,aba^{b}ab 是 3 维单位向量,位于 b 系。那么 ϕbwb\phi_{bw}^{b}ϕbwb​ 的完整含义为:按右手定则,让 b 系绕 aba^{b}ab 轴转动 θ 角度,即可让 b 系三轴与 w 系三轴重合,这里说的重合,是指 b 系的 x、y、z 轴依次与 w 系的 x、y、z 轴重合。

各姿态表示之间的一些必要转换

首先对于旋转向量有:

−ϕbwb=ϕwbw-\phi_{bw}^{b}=\phi_{wb}^{w}−ϕbwb​=ϕwbw​

如果 R3×3(ϕ)R_{3\times3}(\phi)R3×3​(ϕ) 表示用罗德里格斯公式将旋转向量转化为旋转矩阵,那么有下式:

R3×3(ϕbwb)=cos⁡(θ)I+(1−cos⁡(θ))ab(ab)T+sin⁡θ(ab×)R_{3\times 3}\left(\phi_{bw}^{b}\right)=\cos(\theta)I+\left(1-\cos(\theta)\right)a^{b}\left(a^{b}\right)^{T}+\sin\theta\left(a^{b}\times\right)R3×3​(ϕbwb​)=cos(θ)I+(1−cos(θ))ab(ab)T+sinθ(ab×)

R3×3(ϕbwb)R_{3\times 3}(\phi_{bw}^{b})R3×3​(ϕbwb​) 表示的其实是RwbR_{w}^{b}Rwb​,R3×3(−ϕbwb)R_{3\times3}(-\phi_{bw}^{b})R3×3​(−ϕbwb​) 表示 RbwR_{b}^{w}Rbw​。当 θ 为小量时:

Rwb≈I−ϕwbw×=I+ϕbwb×R_{w}^{b}\approx I-\phi_{wb}^{w}\times =I+\phi_{bw}^{b}\timesRwb​≈I−ϕwbw​×=I+ϕbwb​×

Rbw≈I+ϕwbw×=I−ϕbwb×R_{b}^{w}\approx I+\phi_{wb}^{w}\times =I-\phi_{bw}^{b}\timesRbw​≈I+ϕwbw​×=I−ϕbwb​×

“×”符号在这里表示取左侧向量的反对称阵。
对于 qwbq_{w}^{b}qwb​ 与 ϕbwb\phi_{bw}^{b}ϕbwb​,我们有如下转化关系:

qwb=[cos⁡(∣ϕbwb∣2)ϕbwb∣ϕbwb∣sin⁡(∣ϕbwb∣2)]=[cos⁡(∣−ϕwbw∣2)−ϕwbw∣−ϕwbw∣sin⁡(∣−ϕwbw∣2)]q_{w}^{b}=\left[\begin{array}{c}\cos\left(\frac{\left|\phi_{bw}^{b}\right|}{2}\right)\\ \frac{\phi_{bw}^{b}}{\left|\phi_{bw}^{b}\right|}\sin\left(\frac{\left|\phi_{bw}^{b}\right|}{2}\right)\end{array}\right]=\left[\begin{array}{c}\cos\left(\frac{\left|-\phi_{wb}^{w}\right|}{2}\right)\\ \frac{-\phi_{wb}^{w}}{\left|-\phi_{wb}^{w}\right|}\sin\left(\frac{\left|-\phi_{wb}^{w}\right|}{2}\right)\end{array}\right]qwb​=​cos(2∣ϕbwb​∣​)∣ϕbwb​∣ϕbwb​​sin(2∣ϕbwb​∣​)​​=​cos(2∣−ϕwbw​∣​)∣−ϕwbw​∣−ϕwbw​​sin(2∣−ϕwbw​∣​)​​

当 θ 为小量时,有:

qwb≈[1ϕbwb2]=[1−ϕwbw2]q_{w}^{b}\approx\left[\begin{array}{c}1\\ \frac{\phi_{bw}^{b}}{2}\end{array}\right]=\left[\begin{array}{c}1\\ \frac{-\phi_{wb}^{w}}{2}\end{array}\right]qwb​≈[12ϕbwb​​​]=[12−ϕwbw​​​]

我习惯称 ϕbwb\phi_{bw}^{b}ϕbwb​ 对应的旋转向量和四元数为:RwbR_{w}^{b}Rwb​ 和 qwbq_{w}^{b}qwb​,那么 ϕwbw\phi_{wb}^{w}ϕwbw​ 就与 RbwR_{b}^{w}Rbw​ 和 qbwq_{b}^{w}qbw​ 对应。

姿态如何累积

各种姿态的表示方法都不满足普通的加法,我们需要使用以下方法将姿态累积起来:

Rbw=Rw1wRbw1R_{b}^{w}=R_{w1}^{w}R_{b}^{w1}Rbw​=Rw1w​Rbw1​

qbw=qw1w⊗qbw1q_{b}^{w}=q_{w1}^{w}\otimes q_{b}^{w1}qbw​=qw1w​⊗qbw1​

如上,分别以旋转矩阵和四元数的形式将 b 系在 w1w1w1 系的姿态与 w1w1w1 系在 w 系的姿态叠加起来。按照之前的习惯,Rw1wR_{w1}^{w}Rw1w​ 对应的旋转向量为:ϕww1w\phi_{ww1}^{w}ϕww1w​。如果 ϕww1w\phi_{ww1}^{w}ϕww1w​ 的模值是小量,那么此时就有:

Rw1w≈I+ϕww1w×R_{w1}^{w}\approx I+\phi_{ww1}^{w}\timesRw1w​≈I+ϕww1w​×

姿态的导数

我们设定一个关于姿态的函数:

g(ϕw1bw1)=Rbw1pb−pwg\left(\phi_{w1b}^{w1}\right)=R_{b}^{w1}p^{b}-p^{w}g(ϕw1bw1​)=Rbw1​pb−pw

该函数表示将坐标 pbp^{b}pb 旋转至 w1w1w1 系,然后与坐标 pwp^{w}pw 相减,pwp^{w}pw 表示点 p 在世界系下的真实坐标。我们选择将 ϕw1bw1\phi_{w1b}^{w1}ϕw1bw1​ 作为函数的自变量,这是因为我们后面要对旋转向量求导。那么世界系 w 为什么要添加符号1 呢?这是因为在估计问题中,我们拿到的状态并不准确,RbwR_{b}^{w}Rbw​ 表示真值,但是我们只能获取到有误差的姿态,这个误差如何体现出来呢?RbwR_{b}^{w}Rbw​ 表示将坐标系 b 中的坐标旋转至坐标系 w 中,但是如果有误差了,那么我们拿到的姿态可能就表示将坐标系b 中的坐标旋转至坐标系 w1w1w1 中,于是就有了 Rbw1R_{b}^{w1}Rbw1​,所以符号1 表达了我们对当前所获得世界系的不信任,也就是误差。关于这个1 为何加在 w 上,不是b 上,我们后面解释。

下面解释为什么要对 g(ϕw1bw1)g(\phi_{w1b}^{w1})g(ϕw1bw1​) 求导,我们注意到 g(ϕw1bw1)g(\phi_{w1b}^{w1})g(ϕw1bw1​) 实质为两个坐标的相减,但因为 Rbw1R_{b}^{w1}Rbw1​ 不是 RbwR_{b}^{w}Rbw​,所以 Rbw1pbR_{b}^{w1}p^{b}Rbw1​pb 与 pwp^{w}pw 相减后得到的很可能是非零向量。如果有一种方法能让我们调整 Rbw1R_{b}^{w1}Rbw1​ 中的 w1w1w1 系,使其不断靠近 w 系,那我们就逐渐估计出了 RbwR_{b}^{w}Rbw​。一种可行的、估计 RbwR_{b}^{w}Rbw​ 的方法就是高斯牛顿法(具体介绍见SLAM 十四讲6.2.2 节)。在我们这个问题中,高斯牛顿法是在做这样一件事:在 ϕw1bw1\phi_{w1b}^{w1}ϕw1bw1​ 的基础上叠加一个微弱转动,叠加微弱转动后的旋转向量所对应的旋转矩阵可以让 g(⋅)g(\cdot)g(⋅) 函数更接近0向量。因为每次添加微弱转动都可以让 g(⋅)g(\cdot)g(⋅) 函数更靠近0向量,所以不断重复上述过程,那么就会估计出较为理想的旋转向量,当然,对应的旋转矩阵也会得到。

下面介绍如何在 ϕw1bw1\phi_{w1b}^{w1}ϕw1bw1​ 上叠加微弱转动以及 g(ϕw1bw1)g(\phi_{w1b}^{w1})g(ϕw1bw1​) 的导数如何计算。

对于函数 f(x)f(x)f(x),其在 x 处的导数为:

f′(x)=lim⁡δx→0f(x⊕δx)−f(x)δxf'(x)=\lim_{\delta x\to 0}\frac{f(x\oplus\delta x)-f(x)}{\delta x}f′(x)=δx→0lim​δxf(x⊕δx)−f(x)​

“⊕”表示广义的加法,因为姿态不满足普通加法,所以我们这里用它泛指一种叠加行为。δx\delta xδx 表示在 x 基础上的一个轻微扰动,那么ϕw1bw1\phi_{w1b}^{w1}ϕw1bw1​ 的轻微扰动是什么?我们知道 ϕw1bw1\phi_{w1b}^{w1}ϕw1bw1​ 的含义是:让 w1w1w1 系绕某个轴转动某个角度,使得 w1w1w1 系三轴与 b 系三轴重合。那么这个小扰动就可以是先让 w2w2w2 系绕某个轴转动某个很小的角度,使得 w2w2w2 系三轴与 w1w1w1 系三轴重合,这个小扰动对应的符号就是 ϕw2w1w2\phi_{w2w1}^{w2}ϕw2w1w2​。而 ϕw2w1w2\phi_{w2w1}^{w2}ϕw2w1w2​ 对应的旋转矩阵为 Rw1w2R_{w1}^{w2}Rw1w2​。于是

∂g(ϕw1bw1)∂ϕw1bw1=lim⁡ϕw2w1w2→0g(ϕw1bw1⊕ϕw2w1w2)−g(ϕw1bw1)ϕw2w1w2\frac{\partial g\left(\phi_{w1b}^{w1}\right)}{\partial\phi_{w1b}^{w1}}=\lim_{\phi_{w2w1}^{w2}\to 0}\frac{g\left(\phi_{w1b}^{w1}\oplus\phi_{w2w1}^{w2}\right)-g\left(\phi_{w1b}^{w1}\right)}{\phi_{w2w1}^{w2}}∂ϕw1bw1​∂g(ϕw1bw1​)​=ϕw2w1w2​→0lim​ϕw2w1w2​g(ϕw1bw1​⊕ϕw2w1w2​)−g(ϕw1bw1​)​

那么 g(ϕw1bw1⊕ϕw2w1w2)g(\phi_{w1b}^{w1}\oplus\phi_{w2w1}^{w2})g(ϕw1bw1​⊕ϕw2w1w2​) 等于什么呢?ϕw1bw1⊕ϕw2w1w2\phi_{w1b}^{w1}\oplus\phi_{w2w1}^{w2}ϕw1bw1​⊕ϕw2w1w2​ 从物理含义上来说是:让 w2w2w2 系绕某个轴转动某个角度,使得 w2w2w2 系三轴与 b 系三轴重合,即旋转向量 ϕw2bw2\phi_{w2b}^{w2}ϕw2bw2​,而 ϕw2bw2\phi_{w2b}^{w2}ϕw2bw2​ 对应的旋转矩阵是 Rbw2R_{b}^{w2}Rbw2​,又因为有 Rbw2=Rw1w2Rbw1R_{b}^{w2}=R_{w1}^{w2}R_{b}^{w1}Rbw2​=Rw1w2​Rbw1​,所以有:

g(ϕw1bw1⊕ϕw2w1w2)=g(ϕw2bw2)=Rbw2pb−pw=Rw1w2Rbw1pb−pw=[I+ϕw2w1w2×]Rbw1pb−pwg\left(\phi_{w1b}^{w1}\oplus\phi_{w2w1}^{w2}\right)=g\left(\phi_{w2b}^{w2}\right)=R_{b}^{w2}p^{b}-p^{w}=R_{w1}^{w2}R_{b}^{w1}p^{b}-p^{w}=\left[I+\phi_{w2w1}^{w2}\times\right]R_{b}^{w1}p^{b}-p^{w}g(ϕw1bw1​⊕ϕw2w1w2​)=g(ϕw2bw2​)=Rbw2​pb−pw=Rw1w2​Rbw1​pb−pw=[I+ϕw2w1w2​×]Rbw1​pb−pw

于是有:

∂g(ϕw1bw1)∂ϕw1bw1=lim⁡ϕw2w1w2→0[I+ϕw2w1w2×]Rbw1pb−Rbw1pbϕw2w1w2\frac{\partial g\left(\phi_{w1b}^{w1}\right)}{\partial\phi_{w1b}^{w1}}=\lim_{\phi_{w2w1}^{w2}\to 0}\frac{\left[I+\phi_{w2w1}^{w2}\times\right]R_{b}^{w1}p^{b}-R_{b}^{w1}p^{b}}{\phi_{w2w1}^{w2}}∂ϕw1bw1​∂g(ϕw1bw1​)​=ϕw2w1w2​→0lim​ϕw2w1w2​[I+ϕw2w1w2​×]Rbw1​pb−Rbw1​pb​

=lim⁡ϕw2w1w2→0[ϕw2w1w2×]Rbw1pbϕw2w1w2=lim⁡ϕw2w1w2→0−[(Rbw1pb)×]ϕw2w1w2ϕw2w1w2=−(Rbw1pb)×=\lim_{\phi_{w2w1}^{w2}\to 0}\frac{\left[\phi_{w2w1}^{w2}\times\right]R_{b}^{w1}p^{b}}{\phi_{w2w1}^{w2}}=\lim_{\phi_{w2w1}^{w2}\to 0}-\frac{\left[\left(R_{b}^{w1}p^{b}\right)\times\right]\phi_{w2w1}^{w2}}{\phi_{w2w1}^{w2}}=-\left(R_{b}^{w1}p^{b}\right)\times=ϕw2w1w2​→0lim​ϕw2w1w2​[ϕw2w1w2​×]Rbw1​pb​=ϕw2w1w2​→0lim​−ϕw2w1w2​[(Rbw1​pb)×]ϕw2w1w2​​=−(Rbw1​pb)×

请注意,上面在 ϕw1bw1\phi_{w1b}^{w1}ϕw1bw1​ 上添加扰动ϕw2w1w2\phi_{w2w1}^{w2}ϕw2w1w2​是为了按照导数的定义计算 ∂g(ϕw1bw1)∂ϕw1bw1\frac{\partial g(\phi_{w1b}^{w1})}{\partial\phi_{w1b}^{w1}}∂ϕw1bw1​∂g(ϕw1bw1​)​,扰动 ϕw2w1w2\phi_{w2w1}^{w2}ϕw2w1w2​ 并不是高斯牛顿法中待求的扰动,且ϕw2w1w2\phi_{w2w1}^{w2}ϕw2w1w2​ 在此处是一个趋于无穷小的量,这些注意事项我们最好都留意一下。上述内容解释了扰动如何加在姿态上,下面我将提到高斯牛顿法中的“扰动”。

我们假设在使用高斯牛顿法时,在 ϕw1bw1\phi_{w1b}^{w1}ϕw1bw1​ 基础上添加的“扰动”(扰动这个词不太好,此处更准确的说法应该是调整量)为 ϕw3w1w3\phi_{w3w1}^{w3}ϕw3w1w3​,ϕw3w1w3\phi_{w3w1}^{w3}ϕw3w1w3​ 是一个有限小的量,这是与 ϕw2w1w2\phi_{w2w1}^{w2}ϕw2w1w2​ 的区别,但是他们表达的都是从其他系向 w1w1w1 系转动的旋转向量。则有:

g(ϕw1bw1⊕ϕw3w1w3)≈g(ϕw1bw1)+∂g(ϕw1bw1)∂ϕw1bw1ϕw3w1w3g\left(\phi_{w1b}^{w1}\oplus\phi_{w3w1}^{w3}\right)\approx g\left(\phi_{w1b}^{w1}\right)+\frac{\partial g\left(\phi_{w1b}^{w1}\right)}{\partial\phi_{w1b}^{w1}}\phi_{w3w1}^{w3}g(ϕw1bw1​⊕ϕw3w1w3​)≈g(ϕw1bw1​)+∂ϕw1bw1​∂g(ϕw1bw1​)​ϕw3w1w3​

参考14 讲,ϕw3w1w3\phi_{w3w1}^{w3}ϕw3w1w3​ 便可求解出来。那么 ϕw3w1w3\phi_{w3w1}^{w3}ϕw3w1w3​ 如何更新在 ϕw1bw1\phi_{w1b}^{w1}ϕw1bw1​ 上呢?直接令 ϕw1bw1=ϕw1bw1⊕ϕw3w1w3\phi_{w1b}^{w1}=\phi_{w1b}^{w1}\oplus\phi_{w3w1}^{w3}ϕw1bw1​=ϕw1bw1​⊕ϕw3w1w3​ 就可以,两个旋转向量可以直接合并(我实际中很少见两个旋转向量直接合并),实际中可能更多是用以下方法更新姿态, ϕw1bw1\phi_{w1b}^{w1}ϕw1bw1​ 对应的四元数为qbw1q_{b}^{w1}qbw1​,ϕw3w1w3\phi_{w3w1}^{w3}ϕw3w1w3​ 对应的四元数为 qw1w3q_{w1}^{w3}qw1w3​,所以利用 qbw3=qw1w3⊗qbw1q_{b}^{w3}=q_{w1}^{w3}\otimes q_{b}^{w1}qbw3​=qw1w3​⊗qbw1​ 更新姿态也是可以的。

备注

(1)为什么使用 ϕw2w1w2\phi_{w2w1}^{w2}ϕw2w1w2​、ϕw3w1w3\phi_{w3w1}^{w3}ϕw3w1w3​?使用 ϕw1w2w1\phi_{w1w2}^{w1}ϕw1w2w1​、ϕw1w3w1\phi_{w1w3}^{w1}ϕw1w3w1​ 可以吗?当然可以,只不过需要注意两件事:
①

Rw1w2≈I−ϕw1w2w1×R_{w1}^{w2}\approx I-\phi_{w1w2}^{w1}\timesRw1w2​≈I−ϕw1w2w1​×

Rw1w3≈I−ϕw1w3w1×R_{w1}^{w3}\approx I-\phi_{w1w3}^{w1}\timesRw1w3​≈I−ϕw1w3w1​×
②

ϕw2w1w2\phi_{w2w1}^{w2}ϕw2w1w2​、ϕw3w1w3\phi_{w3w1}^{w3}ϕw3w1w3​ 是同一组的,ϕw1w2w1\phi_{w1w2}^{w1}ϕw1w2w1​、ϕw1w3w1\phi_{w1w3}^{w1}ϕw1w3w1​ 是同一组的,不要混搭,例如:ϕw2w1w2\phi_{w2w1}^{w2}ϕw2w1w2​,ϕw1w3w1\phi_{w1w3}^{w1}ϕw1w3w1​ 是不建议的。

(2)1 为何加在 w 上,不是 b 上?因为我们是在对当前的世界系调整,使其靠近真正的世界系,如果我们设定拿到的旋转矩阵是 Rb1wR_{b1}^{w}Rb1w​,就代表我们认为 b 系是不准的,需要不断调整 b 系,那么此时的旋转矩阵的调整量就应该表示为 Rb3b1R_{b3}^{b1}Rb3b1​,计算导数和利用高斯牛顿法时,对 Rb1wR_{b1}^{w}Rb1w​ 施加扰动(调整)的方式就变为:Rb2w=Rb1wRb2b1R_{b2}^{w}=R_{b1}^{w}R_{b2}^{b1}Rb2w​=Rb1w​Rb2b1​,Rb3w=Rb1wRb3b1R_{b3}^{w}=R_{b1}^{w}R_{b3}^{b1}Rb3w​=Rb1w​Rb3b1​,对应的旋转向量也将变为:ϕb2b1b2\phi_{b2b1}^{b2}ϕb2b1b2​、ϕb3b1b3\phi_{b3b1}^{b3}ϕb3b1b3​ 或 ϕb1b2b1\phi_{b1b2}^{b1}ϕb1b2b1​、ϕb1b3b1\phi_{b1b3}^{b1}ϕb1b3b1​。

(3)为什么选择 Rbw1R_{b}^{w1}Rbw1​,不选择 Rb1wR_{b1}^{w}Rb1w​,这是我随意假设的。看源码时,往往是作者怎么假设我就怎么看。

(4)g(ϕw1bw1)g(\phi_{w1b}^{w1})g(ϕw1bw1​) 这个残差函数很明显是无法约束住姿态的,即无法有效优化 Rbw1R_{b}^{w1}Rbw1​,但我们的目的是讲解姿态的导数如何计算。

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐