zoukankan      html  css  js  c++  java
  • 视觉SLAM(三)李群与李代数 后续作业

    第三章作业

    作业:曾是少年

    二 群的性质

    课上我们讲解了什么是群。请根据群定义,求解以下问题:

    1. ({Z, +}) 是否为群?若是,验证其满足群定义;若不是,说明理由。

    答:{Z,+}是群

    对于({Z,+}),设 (a_1in Z) , (a_2 in Z) , (a_e in Z)

    1. 对于(forall a_1in Z) , (a_2 in Z), 有(a_1+a_2in Z), 因此满足封闭性
    2. 对于(forall a_1in Z,a_2in Z,a_3in Z), ((a_1+a_2)+a_3 = a_1+(a_2+a_3)),因此满足结合律
    3. Z中存在(0in Z),对于(forall a in Z),有(a+0=a),因此慢足幺元
    4. 对于(forall a in Z), 存在 (-ain Z),使得 (a+(-a) = 0),因此满足

    ({Z,+})满足以上四条性质,因此是群

    2. ({N, +}) 是否为群?若是,验证其满足群定义;若不是,说明理由。

    其中(Z)为整数集,(N)为自然数集

    答: ({N,+}) 不是群;

    对于(forall ain N),且(a eq0),(-a otin N),不满足逆的性质要求。因此不是群。

    三 验证向量叉乘的李代数性质

    我们说向量和叉乘运算构成了李代数,现在请你验证它。书中对李代数的定义为:李代数由⼀个集合,V,⼀个数域 F 和⼀个⼆元运算 [, ] 组成。如果它们满足以下集几条性质,称$ (V, F, [, ])$ 为⼀个李代数,记作(g)

    1. 封闭性 (∀X, Y ∈ V, [X, Y ] ∈ V).

    2. 双线性 (∀X, Y , Z ∈ V, a, b ∈ F), 有:

      [[aX + bY , Z] = a[X, Z] + b[Y , Z], [Z, aX + bY ] = a[Z, X] + b[Z, Y ]. ]

    3. 自反性 (∀X ∈ V, [X, X] = 0).

    4. 雅可比等价 (∀X, Y , Z ∈ V, [X, [Y , Z]] + [Y , [Z, X]] + [Z, [X, Y ]] = 0).

    其中二元运算被称为李括号。

    现取集合(V=R^3),数域(F=R),李括号为:

    [[a,b]=a imes b ]

    请验证(g=(R^3,R, imes))构成李代数。

    验证

    1. 封闭性

    对于(forall X,Y in R^3)(X imes Y)依然是一个向量,即(X imes Y in R^3),因此满足封闭性条件。

    1. 双线性

    对于(forall X,Y,Z in R^3)(a,bin R),向量叉乘运算满足分配律和线性性,因此有:

    ((aX+bY) imes Z = aX imes Z+bY imes Z = a(X imes Z)+b(Y imes Z))

    (Z imes(aX+bY) = aZ imes X+bZ imes Y=a(Z imes X)+b(Z imes Y))

    因此满足双线性

    1. 自反性

    对于 (forall X in R^3),(|X imes X| = |X||X|sin0=0),因此(X imes X = 0),满足自反性。

    1. 雅可比等价

    把三适量叉乘展开成点乘,向量的叉乘运算满足一下性质:

    对于(forall X,Y,Z in R^3)

    • ((X×Y)×Z=(XZ)Y-(YZ)X)
    • (X imes(Y imes Z) = (XZ)Y-(XY)Z)

    因此

    [X imes(Y imes Z)+Y imes(Z imes X)+Z imes(X imes Y) \ = X(YZ)-Z(XY) + (YX)Z-(YZ)X+(ZY)X-(ZX)Y \ = 0 ]

    因此向量的叉乘运算满足雅可比恒等式。

    综上所述,(g=(R^3,R, imes))构成李代数

    四 推导 SE(3) 的指数映射

    课上给出了 SO(3) 的指数映射推导,但对于 SE(3),仅介绍了结论,没有给出详细推导。请你完成SE(3) 指数映射部分,有关左雅可比的详细推导。

    (xi = [ ho,phi]^Tin se(3)),它的指数映射为:

    (phi = heta a),那么:

    这也正是课件里提到的左雅可比。

    答:(phi = heta a)

    [egin{aligned} sum^{infty}_{n=0}frac{1}{(n+1)!}(phi^{wedge})^n & = sum^{infty}_{n=0}frac{1}{(n+1)!}( heta a^{wedge})^n\ &= I+frac{1}{2!}( heta a^{wedge})+frac{1}{3!}( heta a^{wedge})^2+frac{1}{4!}( heta a^{wedge})^3+frac{1}{5!}( heta a^{wedge})^4+... \ & = I+frac{1}{2!} heta {a^{wedge}}+frac{1}{3!} heta^2 {a^{wedge}}^2+frac{1}{4!}{ heta}^3 {a^{wedge}}^3+frac{1}{5!} heta^4 {a^{wedge}}^4+...\ end{aligned} ]

    其中:

    [egin{equation} (a^{wedge})^{n} = egin{cases} pm(a^wedge) & ext{n为奇数}\ pm(aa^T-I) & ext{n为偶数} \ end{cases} end{equation} ]

    所以:

    [egin{aligned} sum^{infty}_{n=0}frac{1}{(n+1)!}(phi^{wedge})^n & = I+frac{1}{2!} heta {a^{wedge}}+frac{1}{3!} heta^2 {a^{wedge}}^2+frac{1}{4!}{ heta}^3 {a^{wedge}}^3+frac{1}{5!} heta^4 {a^{wedge}}^4+...\ & = I + (frac{1}{2!} heta-frac{1}{4!} heta^3+...)a^{wedge}+(frac{1}{3!} heta^2-frac{1}{5!} heta^4+...)(aa^T-I)\ & = I + frac{1}{ heta}(frac{1}{2!} heta^2-frac{1}{4!} heta^4+...)a^{wedge}+frac{1}{ heta}(frac{1}{3!} heta^3-frac{1}{5!} heta^5+...)(aa^T-I)\ & = I + frac{1}{ heta}(frac{1}{2!} heta^2-frac{1}{4!} heta^4+...)a^{wedge}+frac{1}{ heta}(frac{1}{3!} heta^3-frac{1}{5!} heta^5+...)(aa^T-I)\ & = frac{1}{ heta}(frac{1}{2!} heta^2-frac{1}{4!} heta^4+...)a^{wedge}+frac{1}{ heta}(frac{1}{3!} heta^3-frac{1}{5!} heta^5+...)aa^T +frac{1}{ heta}( heta-frac{1}{3!} heta^3+frac{1}{5!} heta^5+...)I\ & = frac{1-cos heta}{ heta}a^{wedge}+frac{1}{ heta}( heta-sin heta)aa^T+frac{sin heta}{ heta}I end{aligned} ]

    即:

    [sum^{infty}_{n=0}frac{1}{(n+1)!}(phi^{wedge})^n = frac{1-cos heta}{ heta}a^{wedge}+frac{1}{ heta}( heta-sin heta)aa^T+frac{sin heta}{ heta}I ]

    五 伴随

    SO(3)SE(3) 上,有⼀个东西称为伴随(Adjoint)。下面请你证明SO(3) 伴随的性质。
    对于SO(3),有:

    [Rexp (p^{wedge})R^T = exp((Rp)^{wedge}) ]

    此时称Ad(R) = R
    提示:首先你需要证明(forall ain R^3,Ra^{wedge}{R^T} = (Ra)^{wedge}),[页面](https://math.stackexchange.com/questions/
    2190603/derivation-of-adjoint-for-so3) 提示了⼀种简洁的途径。
    对于SE(3),有:

    [T exp(xi^{wedge})T^{-1}= exp((Ad(T)xi^{wedge}) ]

    其中Ad(T)定义为:

    [Ad(T) = left[egin{array}{ccc} R & t^{wedge}R \ 0&R end{array} ight] ]

    这个性质将在后文的Pose Graph 优化中用到。但是SE(3) 的证明较为复杂,不作要求。
    完整的SO(3) 和SE(3) 性质见1和2。

    证明

    我们先来证明(Ra^{wedge}R^T=(Ra)^{wedge}),过程如下:·

    [a^{wedge}v = a imes v ]

    我们可以通过使等式的RHS作用于任意向量v来证明该等式:

    [egin{aligned} (Ra)^{wedge}v &= (Ra) imes v \&=(Ra) imes (RR^{-1}v) &(RR^{-1}=I) \&=R[a imes(R^{-1}v)] &(分配律) \&=Ra^{wedge}R^{-1}v &(结合律) end{aligned} ]

    因此得到:

    [(Ra)^{wedge}=Ra^{wedge}R^{-1} ]

    而R是正交矩阵,因此

    [(Ra)^{wedge}=Ra^{wedge}R^{T} ]

    ( ho= heta a)

    [egin{aligned} Rexp( heta a^{wedge})R^T & = R(cos heta I+(1-cos heta)aa^T+sin heta a^{wedge})R^T\ & = cos heta I+(1-cos heta)Ra(Ra)^T+sin heta Ra^{wedge}R^T\ &=cos heta I+(1-cos heta)Ra(Ra)^T+sin heta (Ra)^{wedge}\ &= exp( heta (Ra)^{wedge})\ &= exp((R ho)^{wedge}) end{aligned} ]

    证毕。


    拓展:伴随表示

    数学中,一个李群 G伴随表示(adjoint representation)或伴随作用(adjoint action)是 G 在它自身的李代数上的自然表示。这个表示是群 G 在自身上的共轭作用的线性化形式。

    六 轨迹的描绘

    我们通常会记录机器人的运动轨迹,来观察它的运动是否符合预期。大部分数据集都会提供标准轨迹以供参考,如 kittiTUM-RGBD 等。这些文件会有各自的格式,但首先你要理解它的内容。记世界坐标系为 W,机器⼈坐标系为 C,那么机器人的运动可以用 (T_{WC})(T_{CW}) 来描述。现在,我们希望画出机器⼈在世界当中的运动轨迹,请回答以下问题:

    1. 事实上,(T_{WC}) 的平移部分即构成了机器人的轨迹。它的物理意义是什么?为何画出 (T_{WC}) 的平移部分就得到了机器⼈的轨迹?

      :物理意义: (T_{WC})指的是从世界坐标系原点到相机中心的平移向量;

      世界坐标系不随相机运动变化,因此可以认为(T_{wc})是机器人相对于原点坐标在移动, 移动可视化在观察者眼中就是是机器人的运动轨迹

    2. 我为你准备了⼀个轨迹文件(code/trajectory.txt)。该文件的每⼀行由若干个数据组成,格式为

      [[t, t_x, t_y, t_z, q_x, q_y, q_z, q_w] ]

      其中 t 为时间,(tx, ty, tz)(T_{WC}) 的平移部分,(q_x, q_y, q_z, q_w) 是四元数表示的 (T_{WC}) 的旋转部分,(q_w)为四元数实部。同时,我为你提供了画图程序 draw_trajectory.cpp 文件。该⽂件提供了画图部分的代码,请你完成数据读取部分的代码,然后书写 CMakeLists.txt 以让此程序运行起来。注意我们需要用到 Pangolin 库来画图,所以你需要事先安装 Pangolin(如果你做了第⼀次作业,那么现在已经安装了)。CMakeLists.txt 可以参照 ORB-SLAM2 部分。

      :实现过程:使用fstream读取文件中的数据,在编译的时候遇到一点小bug,不过都解决了.

      读取数据的代码块如下:

          double t,t_x,t_y,t_z,q_x,q_y,q_z,q_w;
          while(!inFILE.eof())
          {
              inFILE>>t;
              inFILE>>t_x;
              inFILE>>t_y;
              inFILE>>t_z;
              inFILE>>q_x;
              inFILE>>q_y;
              inFILE>>q_z;
              inFILE>>q_w;
              poses.push_back(Sophus::SE3(Eigen::Quaterniond(q_w,q_x,q_y,q_z),Eigen::Vector3d(t_x,t_y,t_z)));
          }
      

      运行结果如下所示;

    该图中:轨迹首尾颜色不一样,通过观察,发现是着色函数设置的颜色随位置变化.

    附加题 七 轨迹的误差

    除了画出真实轨迹以外,我们经常需要把 SLAM 估计的轨迹与真实轨迹相比较。下面说明比较的原理,请你完成比较部分的代码实现。

    设真实轨迹(ground-truth)为 (T_g),估计轨迹 (T_e)。它们都以 (T_{WC}) 的形式存储,格式同上题。现在,你需要计算估计轨迹的误差。我们假设每⼀个 (T_g) 都与给定的 (T_e) 对应。那么,对于任意第 i 个位姿,它的误差可定义为:

    [e_i=||log(T^{-1}_{gi}T_{ei})^{vee}||_2. ]

    即两个位姿之差的李代数二范数。于是,可以定义两条轨迹的均方根(Root-Mean-Square-Error, RMSE)误差为:

    [RMSE(g,e)=sqrt{frac{1}{n}sum^{n}_{i=1}e_i^2} ]

    我为你准备了 code/ground-truth.txtcode/estimate.txt 两条轨迹。请你根据上⾯公式,实现 RMSE的计算代码,给出最后的 RMSE 结果。作为验算,参考答案为:2.207。

    注:

    1. 实际当中的轨迹比较还要更复杂⼀些。通常 ground-truth 由其他传感器记录(如 vicon),它的采样频率通常高于相机的频率,所以在处理之前还需要按照时间戳对齐。另外,由于传感器坐标系不一致致,还需要计算两个坐标系之间的差异。这件事也可以⽤ ICP 解得,我们将在后面的课程中讲到。

    2. 你可以用上题的画图程序将两条轨迹画在同⼀个图里,看看它们相差多少。

    :添加的代码主要包括三部分:

    1. 读取两个文件ground-truth.txtestimate.txt,该部分与上一题中的相同。

    2. 计算rmse,对于已经得到的两个pose集合,可以通过以下代码计算。

      double calculateRMSE(vector<Sophus::SE3, Eigen::aligned_allocator<Sophus::SE3>> truth_poses,vector<Sophus::SE3, Eigen::aligned_allocator<Sophus::SE3>> estimated_poses)
      {
          double rmse=0.0;
          for(int i = 0;i<truth_poses.size();i++)
          {
              Eigen::Matrix<double ,6,1> se3;
              se3 = (truth_poses[i].inverse()*estimated_poses[i]).log(); //这里是通过一个把其中一个变换乘以一个逆变换得到一个差矩阵,再通过.log()可以转换为向量形式
              rmse+=se3.squaredNorm();
          }
          rmse = sqrt(rmse/(double)truth_poses.size());
          return rmse;
      }
      
    3. 画图,修改轨迹绘制代码,函数部分代码如下所示:

      while (pangolin::ShouldQuit() == false) {
          glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
      
          d_cam.Activate(s_cam);
          glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
      
          glLineWidth(2);
          for (size_t i = 0; i < truth_poses.size() - 1; i++) {
              glColor3f(1.0f, 0.0f, 0.0f);
              glBegin(GL_LINES);
              auto p1 = truth_poses[i], p2 = truth_poses[i + 1];
              glVertex3d(p1.translation()[0], p1.translation()[1], p1.translation()[2]);
              glVertex3d(p2.translation()[0], p2.translation()[1], p2.translation()[2]);
              glEnd();
      
              glColor3f(0.0f, 0.0f, 1.0f);
              glBegin(GL_LINES);
              p1 = estimated_poses[i], p2 = estimated_poses[i + 1];
              glVertex3d(p1.translation()[0], p1.translation()[1], p1.translation()[2]);
              glVertex3d(p2.translation()[0], p2.translation()[1], p2.translation()[2]);
              glEnd();
      
          }
          pangolin::FinishFrame();
          usleep(5000);   // sleep 5 ms
      }
      

      最后运行结果如下:

      /home/guoben/Project/SLAM-homework/ch3/draw_trajectory/bin/drawtraj
      rmse:2.20727
      

    其中,红色轨迹表示真值,蓝色轨迹表示估计值

  • 相关阅读:
    JS 数组及函数的应用
    JavaScript 基础知识点
    利用css布局效果图
    css 区块与盒子模型
    JS数组及函数的应用
    JavaScript基础
    近期总结12.30
    层叠样式与盒子模型
    PHP课后小结 2017.12.22
    PHP课后小结 12.20
  • 原文地址:https://www.cnblogs.com/guoben/p/13122426.html
Copyright © 2011-2022 走看看