0. 简介

李群李代数作为SLAM当中非常重要的一部分,作者最近才对该部分有了清晰地认知,感觉有必要放出来说一说。因为李群本身存在加法不闭合性,所以李群与李代数之间的转换需要每一个slamer人有着充分清晰地认识。

1. 李群扰动

Baker-Campbell-Hausdorff公式,这个公式作为李群相乘转到李代数的式子,我们可以看到李群的相乘会带来李代数产生高次项输出。。
近似为
在这里插入图片描述
在SO(3)上,我们可以求它关于某一个变量的一阶近似:
在这里插入图片描述
对我们用处最大的就是这个近似式。在 $ϕ_1$ 较小时,使用第一个式;在在$ϕ_2$ 较小时,使用第二个式。这里的 $J_l$ 和 $J_r$ 也称为左/右雅可比——从而李代数就分成了左右两种模型

而这个所谓的左乘和右乘代表了不同的意义。对于矩阵乘法的本质意义有了初步的认识后,对于许多应用场景就非常清晰了,一般都是“方法x对象”,或者具体地讲几何意义,即“坐标系x坐标”。

矩阵P(对象),对于P进行左乘,可视化后,比较容易理解:P 左乘A,表示P 进行了A 变换,A 是在绝对坐标系I中表示的。
在这里插入图片描述

P 右乘B,表示P 进行了B 变换,B 是在相对坐标系P中表示的。这里的B,并不是我们实际看到的B,而是在相对坐标系P中表示为B
在这里插入图片描述
我们可以默认普通的李群和李群相乘没有含义,只有在极小范围内可以默认为近似于李代数。

2. 流形以及切线

SLAM当中我们常见到的群一般都是欧式变换群,当然在回环检测中还会存在相似变换群【sim(3)】。当然符合封闭性,结合性,幺元和逆的群,都是李群,只是作者还没了解的这么深入。作为欧式变换群,除了上述的相乘以外,还会存在李群逆函数*李群的做法【形如: $Pc_1 = Tcw_1 _ Pw$ ,$Pc_1 = Tcw_2 _ Pc_2$,$Pc_2 = Tcw_2^{-1} _ Tcw_1 _ Pw$】。这样的做法仅仅是坐标系与坐标系之间的转换而已
流形(Manifold)是局部具有欧式空间性质的空间,包括各种纬度的曲线曲面,例如球体、弯曲的平面等。流形的局部和欧式空间是同构的。流形就包括各种维数的曲线曲面等。和一般的降维分析一样,流形学习把一组在高维空间中的数据在低维空间中重新表示。和以往方法不同的是,在流形学习中有一个假设,就是所处理的数据采样于一个潜在的流形上,或是说对于这组数据存在一个潜在的流形。
在这里插入图片描述
流形是线性子空间的一种非线性推广。

  • 拓扑学角度:局部区域线性,与低维欧式空间拓扑同胚(连续的变换最后都能变成一样的两个物体,称为同胚,Homeomorphism)。

  • 微分几何角度:有重叠chart的光滑过渡(把流体的任何一个微小的局部看作是欧几里德空间,称为一个chart)。

流形的局部几何表达先用切坐标,也就是PCA的主子空间中的坐标。那末对于流形一点处的切空间,它是线性子空间,所以可以和欧式空间中的一个开子集建立同构关系,最简单的就是线性变换。在微分流形中,就叫做切映射 (tangential map),是个很自然很基础的概念。把切坐标求出来,建立出切映射,剩下的就是数值计算了。最终这个算法划归为一个很简单的叠加和形式。当然这样的处理反映到Ceres中就是约束的问题,通过对雅克比矩阵的限制,来实现让某些变量在切空间中不参与优化

#include "pose_local_parameterization.h"

bool PoseLocalParameterization::Plus(const double *x, const double *delta, double *x_plus_delta) const
{
    Eigen::Map<const Eigen::Vector3d> _p(x);
    Eigen::Map<const Eigen::Quaterniond> _q(x + 3);

    Eigen::Map<const Eigen::Vector3d> dp(delta);

    Eigen::Quaterniond dq = Utility::deltaQ(Eigen::Map<const Eigen::Vector3d>(delta + 3));

    Eigen::Map<Eigen::Vector3d> p(x_plus_delta);
    Eigen::Map<Eigen::Quaterniond> q(x_plus_delta + 3);

    p = _p + dp;
    q = (_q * dq).normalized();

    return true;
}
bool PoseLocalParameterization::ComputeJacobian(const double *x, double *jacobian) const
{
    Eigen::Map<Eigen::Matrix<double, 7, 6, Eigen::RowMajor>> j(jacobian);
    j.topRows<6>().setIdentity();
    j.bottomRows<1>().setZero();

    return true;
}

3. 参考链接

https://blog.csdn.net/weixin_45632220/article/details/117735223
http://www.360doc.com/content/19/0217/09/39935401_815482761.shtml
https://blog.csdn.net/weixin_45632220/article/details/117735223