李群与李代数初识

在SLAM中, 位姿作为状态变量是未知的,需要解决什么样的相机位姿最符合当前观测数据这样的问题。一种典型的方式是把它构建成一个优化问题,求解最优的R, t,使得误差最小化。旋转矩阵自身是带有约束的(正交且行列式为1)。它们作为优化变量时,会引入额外的约束,使优化变得困难。通过李群——李代数间的转换关系能够把位姿估计变成无约束的优化问题,简化求解方式

一、李群李代数基础定义

  • 三维旋转矩阵构成了特殊正交群SO(3)

在这里插入图片描述

  • 四维变换矩阵构成了特殊欧式群SE(3)

在这里插入图片描述

  • 旋转矩阵、变换矩阵加法是不封闭的:
    在这里插入图片描述
  • SO(3)和SE(3)关于乘法是封闭的:
    在这里插入图片描述

二、群

对于只有一个(良好的)运算的集合,我们称之为群,群是一种集合加上一种运算的代数结构,我们把集合记为A,运算记作.,那么群可以记作G = (A,.)

2.1 群的定义

群满足以下特性
在这里插入图片描述
旋转矩阵集合和矩阵乘法构成群,叫做旋转矩阵群;同样,变换矩阵和矩阵乘法也构成群,叫做变换矩阵群。矩阵中常见的群有:

  • 一般线性群 GL(n): n×n 的可逆矩阵,它们对矩阵乘法成群
  • 特殊正交群 SO(n): 即旋转矩阵群,其中 SO(2) 和 SO(3) 最为常见
  • 特殊欧式群 SE(n): 即 n 维欧氏变换,如 SE(2) 和 SE(3)

我们重点要学习了解的是李群

2.2 李群

  • 指具有连续(光滑)性质的群
  • 直观上看, SO(3) SE(3)在实数空间上都是连续的,所以都可称之为李群,但是,SO(3)和SE(3)只有定义良好的乘法,没有加法,所以难以进行取极限、求导等操作

三、李代数

每一个李群对应一个李代数 ,李代数描述了李群的局部性质,位于向量空间

3.1李代数的引入

任意一个旋转矩阵R(正交阵),它满足:
在这里插入图片描述
R是t的函数,由于它是旋转矩阵,故满足:
在这里插入图片描述
等式两边对t求导:

在这里插入图片描述
移向整理得:
在这里插入图片描述
观察可以看出等式左边为一个反对称矩阵,记作:
在这里插入图片描述
前式两侧右乘R(t),而R(t)为正交矩阵,故有微分方程:
在这里插入图片描述
设t0=0,R(0)=I,将R(t)在0附近进行一阶泰勒展开为:
在这里插入图片描述
可得初始值为:R(t0)=R(0)=I,依据异界线性常系数微分方程的求解公式解得:
在这里插入图片描述

  • 对于任意的t,都可以找到一个R和一个ϕ与之对应
  • 外积引入了^符号,将一个向量变成了反对称矩阵。同理,对于任意反对称矩阵,亦能找到一个与之对应的向量,把这个运算用符号∨表示。(向量加了∧符号变成反对称矩阵,矩阵加了∨符号变成对应的向量)

李代数具有如下性质:

在这里插入图片描述

3.2 李代数so(3)

so(3)是三维向量(三行一列),其矩阵形式为3维反对称矩阵
在这里插入图片描述

  • SO(3)对应的李代数:so(3)

3.3 李代数se(3)

se(3)是一个六维向量(六行一列),前三维是平移,后三位是旋转

在这里插入图片描述

  • SE(3)对应的李代数为:se(3)

3.4 指数映射与对数映射

旋转矩阵 R 与另一个反对称矩阵 ϕ0∧t 通过指数关系发生了联系;给定某时刻的R,就能求得一个ϕ,它描述了R在局部的导数关系。ϕ正是对应到SO(3) 上的李代数so(3);李代数(ϕ)到李群(R)是指数关系,而李群(R)到李代数(ϕ)是对数关系

  • so(3)实际上就是由旋转向量组成的空间,而指数映射即罗德里格斯公式。通过指数映射,把so(3)中任意一个向量对应到了一个位于SO(3)中的旋转矩阵。反之,如果定义对数映射,也能把SO(3)中的元素对应到so(3)中。SO(3)与so(3)的结论和前面的旋转向量与旋转矩阵很相似,而指数映射即是罗德里格斯公式。旋转矩阵的导数可以由旋转向量指定,指导着如何在旋转矩阵中进行微积分运算。SO(3)、SE(3)、so(3)、se(3)之间的对应关系总结如下图

在这里插入图片描述

四、增量扰动模型

使用李代数的一大动机是进行优化,而在优化过程中导数是非常重要信息,首先slam的定位就是在对相机进行位姿估计,李群对加法没有封闭性,但向量对加法具有封闭性

因此,使用李代数解决求导问题的思路分为两种:

  • 用李代数表示姿态,然后根据李代数加法对李代数求导,然后对应到李代数的求导模型
  • 对李群左乘或右乘微小扰动,然后对该扰动求导,称为左扰动和右扰动模型 ,对应到扰动模型(更为简便)

第一种方式对应到李代数的求导模型,第二种方式对应到扰动模型

tips:一般在工程中选择第二种,旋转矩阵的微分是一个反对称矩阵左乘它本身

4.1 SO(3)上的扰动模型(左乘)

在对旋转矩阵R进行求导时,扰动模型指的是对R进行一次扰动R的微小增量,相对于扰动的变化率,左扰动即左乘,右扰动即右乘,两者都行,只是结果会有一些微小差距。以左扰动为例:
在这里插入图片描述
​ 相对于直接对李代数求导,省去了一个雅各比的计算,使得扰动模型更加实用,这种方法在位姿估计中具有重要的意义

4.2 SE(3)上的李代数求导

假设某空间点p经过一次变换T,得到Tp,现在,给T左乘一个扰动:
在这里插入图片描述
在这里插入图片描述

tips:为使乘法成立,p必须使用齐次坐标

五、Sophus库使用

目前,一个较好的李代数库是Strasdat维护的Sophus库,接下来的使用中,我们使用带模板的库

建立useSophus.cpp文件

其主要步骤为:

  • 通过旋转矩阵或者四元数定义李群
  • 通过李群的对数映射得出李代数
  • 在SLAM中,增量扰动模型很关键,对扰动向量进行指数映射,并左乘到原矩阵,就完成了增量扰动的更新
#include <iostream>

#include <cmath>

#include <Eigen/Core>

#include <Eigen/Geometry>

#include "sophus/se3.hpp"
using namespace std;

using namespace Eigen;
/// 本程序演示sophus的基本用法



int main(int argc, char **argv) {



  // 沿Z轴转90度的旋转矩阵

  Matrix3d R = AngleAxisd(M_PI / 2, Vector3d(0, 0, 1)).toRotationMatrix();

  // 或者四元数

  Quaterniond q(R);

  Sophus::SO3d SO3_R(R);              // Sophus::SO3d可以直接从旋转矩阵构造

  Sophus::SO3d SO3_q(q);              // 也可以通过四元数构造

  // 二者是等价的

  cout << "SO(3) from matrix:\n" << SO3_R.matrix() << endl;

  cout << "SO(3) from quaternion:\n" << SO3_q.matrix() << endl;

  cout << "they are equal" << endl;

  // 使用对数映射获得它的李代数

  Vector3d so3 = SO3_R.log();

  cout << "so3 = " << so3.transpose() << endl;

  // hat 为向量到反对称矩阵

  cout << "so3 hat=\n" << Sophus::SO3d::hat(so3) << endl;

  // 相对的,vee为反对称到向量

  cout << "so3 hat vee= " << Sophus::SO3d::vee(Sophus::SO3d::hat(so3)).transpose() << endl;



  // 增量扰动模型的更新

  Vector3d update_so3(1e-4, 0, 0); //假设更新量为这么多

  Sophus::SO3d SO3_updated = Sophus::SO3d::exp(update_so3) * SO3_R;

  cout << "SO3 updated = \n" << SO3_updated.matrix() << endl;



  cout << "*******************************" << endl;

  // 对SE(3)操作大同小异

  Vector3d t(1, 0, 0);           // 沿X轴平移1

  Sophus::SE3d SE3_Rt(R, t);           // 从R,t构造SE(3)

  Sophus::SE3d SE3_qt(q, t);            // 从q,t构造SE(3)

  cout << "SE3 from R,t= \n" << SE3_Rt.matrix() << endl;

  cout << "SE3 from q,t= \n" << SE3_qt.matrix() << 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 = \n" << Sophus::SE3d::hat(se3) << endl;

  cout << "se3 hat vee = " << Sophus::SE3d::vee(Sophus::SE3d::hat(se3)).transpose() << endl;



  // 最后,演示一下更新

  Vector6d update_se3; //更新量

  update_se3.setZero();

  update_se3(0, 0) = 1e-4d;

  Sophus::SE3d SE3_updated = Sophus::SE3d::exp(update_se3) * SE3_Rt;

  cout << "SE3 updated = " << endl << SE3_updated.matrix() << endl;

  return 0;

}

编译运行结果如下:

xyb@xyb:~/slam/ch4/build$ ./useSophus 
SO(3) from matrix:
2.22045e-16          -1           0
          1 2.22045e-16           0
          0           0           1
SO(3) from quaternion:
2.22045e-16          -1           0
          1 2.22045e-16           0
          0           0           1
they are equal
so3 =      0      0 1.5708
so3 hat=
      0 -1.5708       0
 1.5708       0      -0
     -0       0       0
so3 hat vee=      0      0 1.5708
SO3 updated = 
          0          -1           0
          1           0     -0.0001
     0.0001 2.03288e-20           1
*******************************
SE3 from R,t= 
2.22045e-16          -1           0           1
          1 2.22045e-16           0           0
          0           0           1           0
          0           0           0           1
SE3 from q,t= 
2.22045e-16          -1           0           1
          1 2.22045e-16           0           0
          0           0           1           0
          0           0           0           1
se3 =  0.785398 -0.785398         0         0         0    1.5708
se3 hat = 
        0   -1.5708         0  0.785398
   1.5708         0        -0 -0.785398
       -0         0         0         0
        0         0         0         0
se3 hat vee =  0.785398 -0.785398         0         0         0    1.5708
SE3 updated = 
2.22045e-16          -1           0      1.0001
          1 2.22045e-16           0           0
          0           0           1           0
          0           0           0           1
  • 程序中由于对乘法运算发进行了重载,重载功能中完成了相关运算,所以调库编程比实际计算要简单得多
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值