slam入门——十四讲笔记(三)

第4讲 李群与李代数

本节目标

  1. 理解李群与李代数的概念,掌握 S O ( 3 ) SO(3) SO(3), S E ( 3 ) SE(3) SE(3)与对应李代数的表示方式。
  2. 理解BCH近似的意义
  3. 学会在李代数上的扰动模型
  4. 使用Sophus对李代数进行运算

上一讲重点介绍了旋转的表示,但是在SLAM中,除了表示之外,我们还要对它们进行估计和优化。因为在SLAM中位姿是未知的,而我们需要解决什么样的相机位姿最符合当前观测数据这样的问题。一种典型的方式是把它构建成一个优化问题,求解最优的 R , t R,\mathbf{t} R,t,使得误差最小化。

如前所言,旋转矩阵自身是带有约束的(正交且行列式为 1 1 1)。它们作为优化变量时,会引入额外的约束,使优化变得困难。通过李群-李代数间的转换关系,我们希望把位姿估计变成无约束的优化问题,简化求解方式。由于我没有李群李代数的基本知识,从最基础的开始看起。

4.1 李群与李代数基础

上一讲,我们介绍了旋转矩阵和变换矩阵的定义。当时,我们说三维旋转矩阵构成了特殊正交群 S O ( 3 ) SO(3) SO(3),而变换矩阵构成了特殊欧氏群 S E ( 3 ) SE(3) SE(3)
S O ( n ) = { R ∈ R n × n ∣ R R T = I , d e t ( R ) = 1 } (4.1) SO(n)=\{R\in\mathbb{R}^{n\times n}|RR^T=I,det(R)=1\} \quad \text{(4.1)} SO(n)={RRn×nRRT=I,det(R)=1}(4.1)
S E ( 3 ) = { T = [ R t 0 T 1 ] ∈ R 4 × 4 ∣ R ∈ S O ( 3 ) , t ∈ R 3 } . (4.2) SE(3) = \{T=\begin{bmatrix}R&t\\ \mathbf{0}^T & 1 \end{bmatrix} \in \mathbb{R}^{4\times 4} | R \in SO(3), \mathbf{t} \in \mathbb{R}^3 \}. \quad \text{(4.2)} SE(3)={T=[R0Tt1]R4×4RSO(3),tR3}.(4.2)

不过,当时我们并没有详细解释的含义。我们会发现他们只有一种较好的运算:乘法。 S O ( 3 ) SO(3) SO(3) S E ( 3 ) SE(3) SE(3)关于乘法是封闭的。对于这种只有一个运算的集合。我们把它叫做

4.1.1 群

群(Group)是一种集合加上一种运算的代数结构。我们把集合记作 A A A,运算记作 ⋅ \cdot ,那么群可以记作 G = ( A , ⋅ ) G=(A,\cdot) G=(A,)。群要求这个运算满足一下几个条件:

  1. 封闭性: ∀ a 1 , a 2 ∈ A , a 1 ⋅ a 2 ∈ A \forall a_1,a_2\in A, a_1 \cdot a_2 \in A a1,a2A,a1a2A
  2. 结合律: ∀ a 1 , a 2 , a 3 ∈ A , ( a 1 ⋅ a 2 ) ⋅ a 3 = a 1 ⋅ ( a 2 ⋅ a 3 ) . \forall a_1, a_2, a_3 \in A, (a_1 \cdot a_2) \cdot a_3 = a_1 \cdot (a_2 \cdot a_3). a1,a2,a3A,(a1a2)a3=a1(a2a3).
  3. 幺元: ∃ a 0 ∈ A , s . t . ∀ a ∈ A , a 0 ⋅ a = a ⋅ a 0 = a \exists a_0 \in A, s.t. \forall a \in A, a_0 \cdot a = a \cdot a_0 = a a0A,s.t.aA,a0a=aa0=a
  4. 逆: ∀ a ∈ A , ∃ a − 1 ∈ A , s . t . a ⋅ a − 1 = a 0 \forall a \in A, \exists a^{-1} \in A, s.t. a \cdot a^{-1} = a_0 aA,a1A,s.t.aa1=a0

李群是指具有连续(光滑)性质的群。像整数群 Z \mathbb{Z} Z那样离散的群没有连续性质,所以不是李群。而 S O ( n ) SO(n) SO(n) S E ( n ) SE(n) SE(n),它们在实数空间上是连续的。我们能够直观地想象一个刚体能够连续地在空间中运动,所以它们都是李群。由于 S O ( 3 ) SO(3) SO(3) S E ( 3 ) SE(3) SE(3)对于相机姿态估计尤为重要,我们主要讨论这两个李群。

下面,我们先从较简单的 S O ( 3 ) SO(3) SO(3)开始讨论,我们将会发现每个李群都有对应的李代数。我们首先引出 S O ( 3 ) SO(3) SO(3)上面的李代数 s o ( 3 ) \mathfrak{so}(3) so(3)

4.1.2 李代数的引出

考虑任意旋转矩阵 R R R,我们知道它满足:
R R T = I ( 4.5 ) RR^T = I \quad (4.5) RRT=I(4.5)

现在,我们说, R R R是某个相机的旋转,它会随时间连续地变化,即为时间的函数: R ( t ) R(t) R(t)。由于它仍是旋转矩阵,有
R ( t ) R ( t ) T = I R(t)R(t)^T = I R(t)R(t)T=I

在等式两边对时间求导,得到:
R ˙ ( t ) R ( t ) T + R ( t ) R ˙ ( t ) T = 0 \dot R(t)R(t)^T + R(t)\dot R(t)^T = 0 R˙(t)R(t)T+R(t)R˙(t)T=0
整理得:
R ˙ ( T ) R ( t ) T = − ( R ˙ ( t ) R ( t ) T ) T . ( 4.6 ) \dot R(T)R(t)^T = -\big(\dot R(t)R(t)^T\big) ^T. \qquad (4.6) R˙(T)R(t)T=(R˙(t)R(t)T)T.(4.6)

在这里插入图片描述
在这里插入图片描述

(额……由于不会打那个向上和向下尖的符号,直接把书上的搬过来了。。)

我们看到,旋转矩阵 R R R与另一个反对称矩阵 ϕ 0 \phi_0 ϕ0通过指数关系发生了联系。也就是说,当我们知道某个时刻的 R R R时,存在一个向量 ϕ \phi ϕ,我们满足这个矩阵指数关系。但是矩阵的指数是什么呢?这里有两个问题需要澄清:

  1. 如果上式成立,那么给定某时刻的 R R R,我们就能求得一个 ϕ \phi ϕ,它描述了 R R R在局部的导数关系。与 R R R对应的 ϕ \phi ϕ有什么含义呢?后面会看到, ϕ \phi ϕ正是对应到 S O ( 3 ) SO(3) SO(3)上的李代数 s o ( 3 ) \mathfrak{so}(3) so(3)
  2. 其次,矩阵指数 e x p ( ϕ ^ ) exp(\hat \phi) exp(ϕ^)如何计算?——事实上,这正是李群与李代数间的指数/对数映射。

下面我们一一加以介绍。

4.1.3 李代数的定义

每个李群都有与之对应的李代数。李代数描述了李群的局部性质。通用的李代数定义如下:
李代数由一个集合 V \mathbb{V} V,一个数域 F \mathbb{F} F和一个二元运算 [ , ] [,] [,]组成。如果它们满足以下几条性质,称 ( V , F , [ , ] ) (\mathbb{V}, \mathbb{F}, [,]) (V,F,[,])为一个李代数,记作 g \mathfrak{g} g
在这里插入图片描述
其中二元运算被称为李括号。从表面上来看,李代数所需要的性质还是挺多的。相比于群中的较为简单的二元运算,李括号表达了两个元素的差异。它不要求结合律,而要求元素和自己做李括号之后为零的性质。

作为例子,三维向量 R 3 \mathbb{R}^3 R3上定义的叉积 × \times ×是一种李括号,因此 g = ( R 3 , R , × ) \mathfrak{g} = (\mathbb{R}^3, \mathbb{R}, \times) g=(R3,R,×)构成了一个李代数。我们可以尝试将叉积的性质代数到上面四条性质中。

a = ( a x , a y , a z ) b = ( b x , b y , b z ) \mathbf{a} = (a_x, a_y, a_z) \quad \quad \mathbf{b} = (b_x, b_y, b_z) a=(ax,ay,az)b=(bx,by,bz)
a ∈ R 3 , b ∈ R 3 \mathbf{a} \in \mathbb{R}^3, \mathbf{b} \in \mathbb{R}^3 aR3,bR3
a × b = ∣ i j k a x a y a z b x b y b z ∣ = ( a y b z − a z b y , a z b x − a x b z , a x b y − a y b x ) \mathbf{a} \times \mathbf{b} = \begin{vmatrix}i & j & k \\a_x & a_y & a_z \\ b_x & b_y & b_z \end{vmatrix} =(a_yb_z-a_zb_y, a_zb_x-a_xb_z, a_xb_y-a_yb_x) a×b=iaxbxjaybykazbz=(aybzazby,azbxaxbz,axbyaybx)
显然, a × b ∈ R 3 \mathbf{a} \times \mathbf{b} \in \mathbb{R}^3 a×bR3 ,满足性质1:封闭性


额… 这些符号打起来 emmm… 其他的 就不验证了,我信。。在纸上自行验证

4.1.4 李代数 s o ( 3 ) \mathfrak{so}(3) so(3)

下面我们说,之前提到的 ϕ \phi ϕ,事实上是一种李代数。 S O ( 3 ) SO(3) SO(3)对应的李代数是定义在 R 3 \mathbb{R}^3 R3上的向量,我们记作 ϕ \phi ϕ。根据前面的推导,每个 ϕ \phi ϕ都可以生成一个反对称矩阵:
在这里插入图片描述
在此定义下,两个向量 ϕ 1 , ϕ 2 \phi_1, \phi_2 ϕ1,ϕ2的李括号为:
在这里插入图片描述
可以验证,该定义下的李括号满足上面的几条性质。由于 ϕ \phi ϕ与反对称矩阵关系很紧密,在不引起歧义的情况下,就说 s o ( 3 ) \mathfrak{so}(3) so(3)的元素是3维向量或者3维反对称矩阵,不加区别:
在这里插入图片描述
至此,我们清楚了 s o ( 3 ) \mathfrak{so}(3) so(3)的内容。它们是一个三维向量组成的集合,每个向量对应到一个反对称矩阵,可以表达旋转矩阵的导数。它与 S O ( 3 ) SO(3) SO(3)的关系由指数映射给定:
在这里插入图片描述
指数映射会在稍微介绍。由于已经介绍了 s o ( 3 ) \mathfrak{so}(3) so(3),我们顺带先来看看 S E ( 3 ) SE(3) SE(3)上对应的李代数。

4.1.5 李代数 s e ( 3 ) \mathfrak{se}(3) se(3)

s o ( 3 ) \mathfrak{so}(3) so(3)相似, s e ( 3 ) \mathfrak{se}(3) se(3)位于 R 6 \mathbb{R}^6 R6空间中:
在这里插入图片描述
我们把每个 s e ( 3 ) \mathfrak{se}(3) se(3)元素记作 ξ \xi ξ,它是一个六维向量。前三维为平移,记作 ρ \rho ρ;后三维为旋转,记作 ϕ \phi ϕ,实质上是 s o ( 3 ) \mathfrak{so}(3) so(3)元素。同时,我们扩展了 ∧ ^{\wedge} 符号的含义。在 s e ( 3 ) \mathfrak{se}(3) se(3)中,同样使用^符号,将一个六维向量转换成四维矩阵,但这里不再表示反对称:
在这里插入图片描述


立个flag:下一次刷这本书的时候,一定要手动推导一下,把图贴上来。 --2020.12.14

4.2 指数与对数映射

4.2.1 s o ( 3 ) \mathfrak{so}(3) so(3)上的指数映射

现在来考虑第二个问题: e x p ( ϕ exp(\phi exp(ϕ^ ) ) )是如何计算的?它是一个矩阵的指数,在李群和李代数中,称为指数映射。

任意矩阵的指数映射可以写成一个泰勒展开,但是只有在收敛的情况下才会有结果,其结果仍是一个矩阵。
e x p ( A ) = ∑ n = 0 ∞ 1 n ! A n (4.18) exp(A)=\sum_{n=0}^{\infty}{\frac{1}{n!}A^n} \qquad \text{(4.18)} exp(A)=n=0n!1An(4.18)
同样地,对 s o ( 3 ) \mathfrak{so}(3) so(3)中任一元素 ϕ \phi ϕ,我们亦可按此方式定义它的指数映射:
e x p ( ϕ ^ ) = ∑ n = 0 ∞ 1 n ! ϕ ^ n (4.19) exp(\hat\phi)=\sum_{n=0}^{\infty}{\frac{1}{n!}\hat\phi^n} \qquad \text{(4.19)} exp(ϕ^)=n=0n!1ϕ^n(4.19)

在这里插入图片描述

在这里插入图片描述
回忆前一讲内容,它和罗德里格斯公式,即式 ( 3.14 ) (3.14) (3.14)如出一辙。这表明, s o ( 3 ) \mathfrak{so}(3) so(3)实际上就是所谓的旋转向量组成的空间,而指数映射即罗德里格斯公式。通过它们,我们把 s o ( 3 ) \mathfrak{so}(3) so(3)中任意一个向量对应到了一个位于 S O ( 3 ) SO(3) SO(3)中的旋转矩阵。反之,如果定义对数映射,我们也能把 S O ( 3 ) SO(3) SO(3)中的元素对应到 s o ( 3 ) \mathfrak{so}(3) so(3)中:
在这里插入图片描述
不过我们通常不按照泰勒展开式去计算对数映射。在第3讲中,我们已经介绍过如何根据旋转矩阵计算对应的李代数,即使用 ( 3.16 ) (3.16) (3.16),利用迹的性质分别求解转角和转轴,采用那种方式更加省事一些。

现在,我们介绍了指数映射的计算方法。读者可能会问,指数映射性质如何呢?是否对于任意的 R R R都能找到一个唯一的 ϕ \phi ϕ?很遗憾,指数映射只是一个满射。这意味着每个 S O ( 3 ) SO(3) SO(3)中的元素,都可以找到一个 s o ( 3 ) \mathfrak{so}(3) so(3)元素与之对应;但是可能存在多个 s o ( 3 ) \mathfrak{so}(3) so(3)中的元素,对应到同一个 S O ( 3 ) SO(3) SO(3)。至少对于旋转角 θ \theta θ,我们知道多转360度和没有转是一样的——它具有周期性。但是,如果我们把旋转角固定在 ± π \pm\pi ±π之间,那么李群和李代数元素是一一对应的。
S O ( 3 ) SO(3) SO(3) s o ( 3 ) \mathfrak{so}(3) so(3)的结论似乎在我们意料之中。它和我们前面讲的旋转向量与旋转矩阵很相似,而指数映射即是罗德里格斯公式。旋转矩阵的导数可以由旋转向量指定,指导着如何在旋转矩阵中进行微积分运算。

4.2.2 s e ( 3 ) \mathfrak{se}(3) se(3)上的指数映射

下面我们来介绍 s e ( 3 ) \mathfrak{se}(3) se(3)上的指数映射。为了节省篇幅,我们不再像 s o ( 3 ) \mathfrak{so}(3) so(3)那样详细推导指数映射。 s e ( 3 ) \mathfrak{se}(3) se(3)上的指数映射形式如下:
在这里插入图片描述
该式与罗德里格斯有些相似,但不完全一样。我们看到,平移部分经过指数映射之后,发生了一次以 J J J为系数矩阵的线性变换。请读者重视这里的 J J J,因为我们后面还要用到它。

同样的,虽然我们也可以类比推得对数映射,不过根据变换矩阵 T T T s o ( 3 ) \mathfrak{so}(3) so(3)上的对应向量也有更省事的方式:从左上的 R R R计算旋转向量,而右上的 t \mathbf{t} t满足:
t = J ρ ( 4.27 ) \mathbf{t} = J\rho \qquad (4.27) t=Jρ(4.27)
由于 J J J可以由 ϕ \phi ϕ得到,所以这里的 ρ \rho ρ亦可由此线性方程解得。现在,我们已经弄清了李群、李代数的定义与相互的转换关系,总结如下图所示。
在这里插入图片描述

4.3 李代数求导与扰动模型

4.3.1 BCH公式与近似公式

使用李代数的一大动机是为了进行优化,而在优化过程中导数是非常必要的信息(会在第六讲详细介绍)。下面我们来考虑一个问题。虽然我们已经清楚了 S O ( 3 ) 和 S E ( 3 ) SO(3) \text{和} SE(3) SO(3)SE(3)上的李群与李代数关系,但是,当我们在 S O ( 3 ) SO(3) SO(3)中完成两个矩阵乘法时,李代数中 s o ( 3 ) \mathfrak{so}(3) so(3)上发生了什么改变呢?反过来说,当 s o ( 3 ) \mathfrak{so}(3) so(3)上做两个李代数的加法时, S O ( 3 ) SO(3) SO(3)上是否对应着两个矩阵的乘积?如果成立的话,相当于:
在这里插入图片描述
如果 ϕ 1 , ϕ 2 \phi_1, \phi_2 ϕ1,ϕ2是标量,那么显然该式成立;但此处我们计算的是矩阵的指数函数,而非标量的指数。换言之,我们在研究下式是否成立:
l n ( e x p ( A ) e x p ( B ) ) = A + B ? ln(exp(A)exp(B)) = A+B? ln(exp(A)exp(B))=A+B?
很遗憾,该式在矩阵时并不成立。

两个李代数指数映射乘积的完整形式,由Baker-Campbell-Hausdorff公式(BCH公式)给出。由于它完整的形式比较复杂,我们给出它展开式的前几项:
在这里插入图片描述
以第一个近似为例。该式告诉我们,当对一个旋转矩阵 R 2 R_2 R2左乘一个微小旋转矩阵 R 1 R_1 R1时,可以近似看作,在原有李代数 ϕ 2 \phi_2 ϕ2上,加上了一项 J l ( ϕ 2 ) − 1 ϕ 1 J_l(\phi_2)^{-1}\phi_1 Jl(ϕ2)1ϕ1。同理,第二个近似描述了右乘一个微小位移的情况。于是,李代数在BCH近似下,分成了左乘近似和右乘近似两种,在使用时我们须加注意,使用的是左乘模型还是右乘模型。

本书以左乘为例。左乘BCH近似雅可比 J l J_l Jl事实上就是式(4.26)的内容:
在这里插入图片描述
这样,我们就可以谈论李群乘法与李代数加法的关系了。为了方便读者理解,我们重新叙述一下BCH近似的意义。
在这里插入图片描述

4.3.2 S O ( 3 ) SO(3) SO(3)上的李代数求导

下面我们来讨论一个带有李代数的函数,如何关于该李代数求导的问题。该问题有很强的实际背景。在SLAM中,我们要估计一个相机的位置和姿态,该位姿是由 S O ( 3 ) SO(3) SO(3)上的旋转矩阵或 S E ( 3 ) SE(3) SE(3)上的变换矩阵描述的。不妨设某个时刻小萝卜的位姿为 T T T。它观察到了一个世界坐标系位于 p p p的点,产生了一个观测数据 z z z。那么,由坐标变换关系知:
z = T p + w ( 4.37 ) z = Tp+w \qquad (4.37) z=Tp+w(4.37)
然而,由于观测噪声 w w w的存在, z z z往往不可能精确地满足 z = T p z=Tp z=Tp的关系。所以,我们通常会计算理想的观测与实际数据的误差:
e = z − T p ( 4.38 ) e = z - Tp \qquad (4.38) e=zTp(4.38)
假设一共有N个这样的路标点和观测,于是就有N个上式。那么,对小萝卜的位姿估计,相当于是寻找一个最优的 T T T,使得整体误差最小化:
min ⁡ T J ( T ) = ∑ i = 1 N ∣ ∣ z i − T p i ∣ ∣ 2 2 . ( 4.39 ) \min_T{J(T)} = \sum_{i=1}^{N}{||z_i-Tp_i||_2^2}. \qquad(4.39) TminJ(T)=i=1NziTpi22.(4.39)
求解此问题,需要计算目标函数 J J J关于变换矩阵 T T T的导数。我们把具体的算法留到后面再讲。这里重点要说的是,我们经常会构建与位姿有关的函数,然后讨论该函数关于位姿的导数,以调整当前的估计值。然而, S O ( 3 ) , S E ( 3 ) SO(3),SE(3) SO(3),SE(3)上并没有良好定义的加法,他们只是群。如果我们把 T T T当成一个普通矩阵来处理优化,那就必须对它加以约束。而从李代数角度来说,由于李代数由向量组成,具有良好的加法运算。因此,使用李代数解决求导问题的思路分为两种:

  1. 用李代数表示姿态,然后根据李代数加法来对李代数求导。
  2. 对李群左乘右乘微小扰动,然后对该扰动求导,称为左扰动和右扰动模型。

第一种方式对应到李代数的求导模型,而第二种则对应到扰动模型。下面我们来讨论这两种思路的异同。

4.3.3 李代数求导

在这里插入图片描述
在这里插入图片描述
第二行的近似为BCH线性近似,第三行为泰勒展开舍去高阶项后近似,第四行至第五行将反对称符号看作叉积,交换之后变号。于是,我们推导了旋转后的点相对于李代数的导数:
在这里插入图片描述
不过,由于这里仍然含有形式比较复杂的 J l J_l Jl,我们不太希望计算它。而下面要讲的扰动模型则提供了更简单的导数计算方式。

4.3.4 扰动模型(左乘)

另一种求导方式,是对 R R R进行一次扰动 Δ R \Delta R ΔR。这个扰动可以乘在左边也可以乘在右边,最后结果会有一点儿微小的差异,我们以左扰动为例。设左扰动 Δ R \Delta R ΔR对应的李代数为 φ \varphi φ。然后,对 φ \varphi φ求导,即:
在这里插入图片描述
该式的求导比上面更为简单:
在这里插入图片描述
可见,扰动模型相比于直接对李代数求导,省去了一个雅可比 J l J_l Jl的计算。这使得扰动模型更为实用。请读者务必理解这里的求导运算,这在位姿估计当中具有重要的意义。

4.3.5 S E ( 3 ) SE(3) SE(3)上的李代数求导

最后,我们给出 S E ( 3 ) SE(3) SE(3)上的扰动模型,而直接李代数上的求导就不再介绍了。假设某空间点 p p p经过一次变换 T T T(对应李代数为 ξ \xi ξ),得到 T p Tp Tp。现在,给 T T T左乘一个扰动 Δ T = e x p ( δ ξ ^ ) \Delta T = exp(\delta \hat\xi) ΔT=exp(δξ^),我们设扰动项的李代数为 δ ξ = [ δ ρ , δ ϕ ] T \delta \xi = [\delta \rho, \delta \phi]^T δξ=[δρ,δϕ]T,那么:
在这里插入图片描述
我们把最后的结果定义成一个算符 ⊙ \odot ,它把一个齐次坐标的空间点变换成一个 4 × 6 4\times6 4×6的矩阵。

至此,我们已经介绍了李群李代数上的微分运算。之后的章节中,我们将应用这些知识去解决实际问题。关于李群李代数的某些重要数学性质,我们作为习题,有缘再学。

4.4 实践:Sophus

我们已经介绍了李代数的入门知识,现在是通过实践演练巩固一下所学知识的机会了。我们来讨论如何在程序中操作李代数。在第三讲中,我们看到Eigen提供了几何模块,但没有提供李代数的支持。一个较好的李代数库是Strasdat维护的Sophus库。Sophus库支持本章主要讨论的 S O ( 3 ) 和 S E ( 3 ) SO(3)和SE(3) SO(3)SE(3),此外还含有二维运动 S O ( 2 ) , S E ( 2 ) SO(2), SE(2) SO(2),SE(2)以及相似变换 S i m ( 3 ) Sim(3) Sim(3)的内容。它是直接在Eigen基础上开发的,我们不需要安装额外的依赖库。读者可以直接从github上获取Sophus,或者,在本书(《视觉slam十四讲》)的代码目录slambook/3rdparty下也提供了Sophus源代码。由于历史原因,Sophus早期版本只提供了双精度的李群/李代数类。后续版本改写成了模板类。模板类的Sophus中可以使用不同精度的李群/李代数,但同时增加了使用难度。本书使用非模板的Sophus库。如果读者准备使用github上的Sophus,请确保使用的是非模板的版本。你可以输入一下命令获得非模板类的Sophus:

git clone https://github.com/strasdat/Sophus.git
cd Sophus
git checkout a621ff

Sophus库只需编译即可,无须安装。
下面我们来演示一下Sophus库中的 S O ( 3 ) 和 S E ( 3 ) SO(3)和SE(3) SO(3)SE(3)运算:

#include <iostream>
#include <cmath>
using namespace std;

#include <Eigen/Core>
#include <Eigen/Geometry>

#include <sophus/so3.h>
#include <sophus/se3.h>

int main() {

    // 沿Z轴转90度的旋转矩阵
    Eigen::Matrix3d R = Eigen::AngleAxisd(M_PI/2, Eigen::Vector3d(0,0,1)).toRotationMatrix();

    Sophus::SO3 SO3_R(R); // Sophus::SO(3)可以直接从旋转矩阵构造
    Sophus::SO3 SO3_v(0, 0, M_PI/2); // 亦可从旋转向量构造
    Eigen::Quaterniond q(R);  // 或者四元数
    Sophus::SO3 SO3_q(q);

    // 上述表达方式都是等价的
    // 输出SO(3)时,以so(3)形式输出
    cout << "SO(3) from matrix: " << SO3_R << endl;
    cout << "SO(3) from vector: " << SO3_v << endl;
    cout << "SO(3) from quaternion: " << SO3_q << endl;

    // 使用对数映射获得它的李代数
    Eigen::Vector3d so3 = SO3_R.log();
    cout << "so3 = " << so3.transpose() << endl;
    // hat 为向量到反对称矩阵
    cout<<"so3 hat=\n"<<Sophus::SO3::hat(so3)<<endl;
    // 相对的,vee为反对称到向量
    cout << "so3 hat vee = " << Sophus::SO3::vee(Sophus::SO3::hat(so3)).transpose() << endl; // transpose纯粹是为了输出美观一些

    // 增量扰动模型的更新
    Eigen::Vector3d update_so3(1e-4, 0, 0); // 假设更新量为这么多
    Sophus::SO3 SO3_updated = Sophus::SO3::exp(update_so3)*SO3_R;
    cout << "SO3 updated = " << SO3_updated << endl;

    /********************萌萌的分割线*****************************/
    cout<<"************我是分割线*************"<<endl;
    // 对SE(3)操作大同小异
    Eigen::Vector3d t(1,0,0);           // 沿X轴平移1
    Sophus::SE3 SE3_Rt(R, t);           // 从R,t构造SE(3)
    Sophus::SE3 SE3_qt(q,t);            // 从q,t构造SE(3)
    cout<<"SE3 from R,t= "<<endl<<SE3_Rt<<endl;
    cout<<"SE3 from q,t= "<<endl<<SE3_qt<<endl;
    // 李代数se(3) 是一个六维向量,方便起见先typedef一下
    typedef Eigen::Matrix<double,6,1> Vector6d;
    Vector6d se3 = SE3_Rt.log();
    cout<<"se3 = "<<se3.transpose()<<endl;
    // 观察输出,会发现在Sophus中,se(3)的平移在前,旋转在后.
    // 同样的,有hat和vee两个算符
    cout<<"se3 hat = "<<endl<<Sophus::SE3::hat(se3)<<endl;
    cout<<"se3 hat vee = "<<Sophus::SE3::vee( Sophus::SE3::hat(se3) ).transpose()<<endl;

    // 最后,演示一下更新
    Vector6d update_se3; //更新量
    update_se3.setZero();
    update_se3(0,0) = 1e-4d;
    Sophus::SE3 SE3_updated = Sophus::SE3::exp(update_se3)*SE3_Rt;
    cout<<"SE3 updated = "<<endl<<SE3_updated.matrix()<<endl;

    return 0;
}

cmake_minimum_required(VERSION 3.17)
project(useSophus)

set(CMAKE_CXX_STANDARD 14)

find_package(Sophus REQUIRED)
include_directories(${Sophus_INCLUDE_DIRS})

add_executable(useSophus useSophus.cpp)
target_link_libraries(useSophus ${Sophus_LIBRARIES})

4.5 *相似变换群与李代数

最后,我们要提一下在单目视觉中使用的相似变换群 S i m ( 3 ) Sim(3) Sim(3),以及对应的李代数 s i m ( 3 ) \mathfrak{sim}(3) sim(3)。如果你只对双目SLAM或RGBD SLAM感兴趣,可以跳过本节。
我们已经介绍过单目的尺度不确定性。如果在单目 SLAM 中使用 S E ( 3 ) SE(3) SE(3) 表示位姿,那么由于尺度不确定性与尺度漂移,整个 SLAM 过程中的尺度会发生变化,这在 S E ( 3 ) SE(3) SE(3)中 未能体现出来。因此,在单目情况下我们一般会显式地把尺度因子表达出来。用数学语言 来说,对于位于空间的点 p p p,在相机坐标系下要经过一个相似变换,而非欧氏变换:
p ′ = [ s R t 0 T 1 ] p = s R p + t . ( 4.42 ) p\prime = \begin{bmatrix} sR & t \\ 0^T & 1 \end{bmatrix}p = sRp + t. \qquad (4.42) p=[sR0Tt1]p=sRp+t.(4.42)
在相似变换中,我们把尺度 s s s表达了出来。它同时作用在 p p p的三个坐标之上,对 p p p进行了一次缩放。与 S O ( 3 ) 、 S E ( 3 ) SO(3)、SE(3) SO(3)SE(3)相似,相似变换亦对矩阵乘法构成群,称为相似变换群 S i m ( 3 ) Sim(3) Sim(3)
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4.6 小结

本讲引入了李群SO(3)和SE(3),以及它们对应的李代数 s o ( 3 ) 和 s e ( 3 ) \mathfrak{so}(3)和\mathfrak{se}(3) so(3)se(3)。我们介绍了位姿在它们上面的表达和转换,然后通过BCH的线性近似,我们可以对位姿进行求导和扰动了。这给之后讲解位姿的优化打下了理论基础,因为我们需要经常的对某一个位姿的估计值进行调整,使它对应的误差减小。只有在弄清楚如何对位姿进行调整和更新之后,我们才能继续下一步的内容。

之所以这一章写的比较粗糙,是因为 一方面,时间有限;另一方面,我认为学习slam需要反复多次,整体把握,逐步深入。而不适合在一个点上琢磨太久。所以后面的东西更精彩,继续往后吧,改天再回来!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值