第三节课习题
2.群的性质

课上我们讲解了什么是群。请根据群定义,求解以下问题:
1.{Z,+}是否为群?若是,验证其满足群定义;若不是,说明理由。
根据群定义可知{Z,+}是群。证明如下:



3.解释什么是阿贝尔群。并说明矩阵及乘法构成的群是否为阿贝尔群。
阿贝尔群(Abel Group)又称交换群或可交换群,它由自身的集合G和二元运算_构成,它除了满足一般的群公理之外,还满足交换律。因为阿贝尔群的群运算满足交换律和结合律,群元素乘积的值与乘法运算时的次序无关。
矩阵乘法构成的群不是阿贝尔群,因为矩阵乘法不满足交换律。
3.验证向量叉乘的李代数性质
解题思路,将括号部分带入性质定义。
封闭性:集合中任意两元素通过李括号运算得到的结果仍属于集合,a×b得到的结果仍是一个三维向量。



自反性:因为向量和自己叉乘结果为0,集合中元素和自己通过李括号运算结果为0,因此满足自反性。



4.推导SE(3)的指数映射
推导过程如下:



式(2)得证。



根据泰勒展开式:





式(3)得证。


5.伴随



证明SO(3)的伴随性质:
参考资料:
https://math.stackexchange.com/questions/2190603/derivation-of-adjoint-for-so3
[1] Eade E. Lie groups for 2d and 3d transformations[J]. Revised Dec, 2013, 117: 118.



注:这一题的证明我走了一些弯路,在阅读了链接中的提示和文献后还是一头雾水,始终没想到怎么用上图中的公式。网上看到了有人是下图这样证明的,但我感觉这样的证明法在第三行直接引入



这一步我不太理解。希望助教老师如果时间充足的话可以帮忙看下,下图所示的证明方法是否正确?



img source:https://blog.csdn.net/jiahao62/article/details/80655542
_*6.常见函数的求导应用__
1.旋转点对旋转的导数。请分别通过左、右扰动的方式,计算∂Rp / ∂R
存在两种解决方法:

对R对应的李代数加上小量,求相对于小量的变化率(导数模型);
对R左乘或右乘一个小量,求相对于小量的李代数的变化率(扰动模型)。
注:这里并不能按照矩阵微分来定义导数,∂Rp / ∂R只是非正式的定义方式。

左右扰动的原理: 对R进行一次扰动ΔR,看结果相对于扰动的变化率。这个扰动可以乘在左边也可以乘在右边,最后结果会有一点微小的差异。

左扰动计算:

设左扰动ΔR对应的李代数为φ,我们可以计算:∂(Rp) / ∂φ
则,



右扰动计算:

同理,设右扰动ΔR对应的李代数为φ,我们可以计算:∂(Rp) / ∂φ
则,


2.旋转的复合。请分别通过左、右扰动的方式,计算:



会使用链式法则,但是这里不太懂为什么需要将(R1R2)转换成向量形式,也不知道如何处理下尖尖符号。所以下边的求导过程可能错漏百出,还望见谅。经过群里求助大佬,我又重新去看了下BHC公式,BHC公式告诉我们,当处理两个矩阵指数之积时,会产生一些由李括号组成的余项。
左扰动:
BHC线性近似表达:



它的逆:




7.轨迹的描绘



2.完成数据读取部分代码,让程序run起来。

//主要代码 
ifstream fin(trajectory_file);
    while (!fin.eof()) {
        double time, tx, ty, tz, qx, qy, qz, qw;
        fin >> time >> tx >> ty >> tz >> qx >> qy >> qz >> qw;
        Sophus::SE3d p1(Eigen::Quaterniond(qw, qx, qy, qz), Eigen::Vector3d(tx, ty, tz));
        poses.push_back(p1);
    }

CMakeLists部分代码可见代码文件。
注:由于Sophus版本不一样,需要将提供的代码中SE3改成SE3d。另外需要在代码中添加unistd.h头文件,否则在编译时会出现unsleep的错误提示。
代码运行结果:



8.轨迹的误差
本题的代码参考了课本中的示例程序,详细代码和CMakeLists代码可见代码文件。
计算RMSE部分的代码:

 double rmse = 0;
//for循环求所有位姿李代数的均方根误差
  for (size_t i = 0; i < estimated.size(); i++) {
    Sophus::SE3d p1 = estimated[i], p2 = groundtruth[i];
    double error = (p2.inverse() * p1).log().norm();
    rmse += error * error;
  }
  rmse = rmse / double(estimated.size());
  rmse = sqrt(rmse);
  cout << "RMSE = " << rmse << endl; 

轨迹的描绘参考上一题的过程,基本上类似。
得到的误差结果:



最终效果图如下:



github地址: https://github.com/ximing1998/slam-learning.git
国内gitee地址:https://gitee.com/ximing689/slam-learning.git