自学SLAM(5)《第三讲:李群和李代数》作业

前言

在这里插入图片描述

小编研究生的研究方向是视觉SLAM,目前在自学,本篇文章为初学高翔老师课的第三次作业。

文章目录

  • 前言
  • 1.群的性质
  • 2.验证向量叉乘的李代数性质
  • 3.推导 SE(3) 的指数映射
  • 4.伴随
  • 5.轨迹的描绘
  • 6.* 轨迹的误差(附加题)


1.群的性质

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

  1. {Z, +} 是否为群?若是,验证其满⾜群定义;若不是,说明理由。
  2. {N, +} 是否为群?若是,验证其满⾜群定义;若不是,说明理由。
    其中 Z 为整数集, N 为⾃然数集。

在这里我再写一下群的定义,满足“凤姐咬你”的就是群,也就是四个性质,如图:
注意:
图中吧集合记作A,运算记作·(·不代表乘法),群可以记作G=(A,·)
对于整数的逆,进行的是乘法它的逆就是它的倒数 进行的是加法,它的逆就是它的相反数
在这里插入图片描述
对于 {Z, +} ,设a1∈Z,a2∈Z,a3∈Z
①封闭性:对于任意的a1∈Z,a2∈Z都有a1+a2∈Z,满足封闭性。
②结合性:对于任意的a1∈Z,a2∈Z,a3∈Z,都有(a1+a2)+a3=a1+(a2+a3),满足结合性。
③幺元:Z中存在0∈Z,对于任意的a∈Z,有a+0=a+0=a,因此满足幺元。
④逆:对于任意的a∈Z,有-a∈Z,a+(-a)=0,任何整数加上它的相反数等于幺元0,所以逆元素是其相反数,因此满足逆。

对于 {N, +}
①封闭性:两个自然数相加依然是自然数,封闭性成立。
②结合性:两个自然数相加可以互换位置,结合性成立。
③幺元:任何自然数与0相加仍然是自然数本身,幺元成立。
④逆: 自然数都是非负数(加法中,自然数的逆已经不属于自然数了),所以两个大于等于0的数相加不可能为0,逆不成立。

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

我们说向量和叉乘运算构成了李代数,现在请你验证它。书中对李代数的定义为:李代数由⼀个集合V,⼀个数域 F 和⼀个⼆元运算 [,]组成。如果它们满⾜以下⼏条性质,称 (V, F, [, ]) 为⼀个李代数,记作g。
注意:自反性是指自己与自己的运算为零。
在这里插入图片描述

解题过程如下:
在这里插入图片描述

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

课上给出了 SO(3) 的指数映射推导,但对于 SE(3),仅介绍了结论,没有给出详细推导。请你完成 SE(3)指数映射部分,有关左雅可⽐的详细推导。
在这里插入图片描述

解题过程如下:
在这里插入图片描述
在这里插入图片描述

4.伴随

在 SO(3) 和 SE(3) 上,有⼀个东西称为伴随(Adjoint)。下⾯请你证明 SO(3)伴随的性质。在这里插入图片描述

解题过程如下:
在这里插入图片描述
完整的 SO(3) 和 SE(3) 性质见下图
在这里插入图片描述
在这里插入图片描述

5.轨迹的描绘

我们通常会记录机器⼈的运动轨迹,来观察它的运动是否符合预期。⼤部分数据集都会提供标准轨迹以供参考,如 kitti、 TUM-RGBD 等。这些⽂件会有各⾃的格式,但⾸先你要理解它的内容。记世界坐标系为 W,机器⼈坐标系为 C,那么机器⼈的运动可以⽤ TWC 或TCW来描述。现在,我们希望画出机器⼈在世界当中的运动轨迹,请回答以下问题:
在这里插入图片描述

解题过程如下:
世界坐标系W(world),机器人坐标系也就是相机坐标系C(camera)

①Twc指的是从世界坐标系原点到相机中心的平移向量,(机器人(相机)坐标系的原点在世界坐标系中的坐标)
世界坐标系是不随相机运动变化的,因此可以认为Twc是机器人相对于原点坐标在移动, 移动可视化在观察者眼中就是机器人的运动轨迹。

如果我们假设机器人坐标系的原点为Oc,此时的Ow就是这个原点在世界坐标系下的坐标:
Ow=TwcOc=twc
这正是Twc的平移部分。因此,可以从Twc中直接看到相机在何处,这也就是我们所说的Twc更为直观。因此在可视化程序里,轨迹文件储存的是Twc而不是Tcw

我想这也是第一问问我们Twc而不是问·Tcw的原因。


首先我们需要安装Sophus

    git clone https://github.com/strasdat/Sophus.gitcd Sophusgit checkout a621ffmkdir buildcd buildcmake ..makesudo make install

但是我们会编译失败,按照如下操作修改后,重新编译即可。
解决方法:打开 Sophus/sophus/so2.cpp文件修改报错内容

//将
SO2::SO2() 
{ unit_complex_.real() = 1.; unit_complex_.imag() = 0.; }
//改为
SO2::SO2() 
{ unit_complex_.real(1.); unit_complex_.imag(0.); }

这时候我们就可以安装成功Sophus了
在这里插入图片描述

draw_trajectory.cpp对应代码如下:

#include "sophus/so3.h"
#include "sophus/se3.h"
#include <string>
#include <iostream>
#include <fstream>
#include <unistd.h>
#include <Eigen/Core>
// need pangolin for plotting trajectory
#include <pangolin/pangolin.h>
using namespace std;
// path to trajectory file
string trajectory_file = "/home/zhe/1/lianxi/3/plotTrajectory/trajectory.txt";
class SE3d;
void DrawTrajectory(vector<Sophus::SE3, Eigen::aligned_allocator<Sophus::SE3>>);
int main(int argc, char **argv) {vector<Sophus::SE3, Eigen::aligned_allocator<Sophus::SE3>> poses;//文件读取器ifstream fin(trajectory_file);if (!fin) {cerr << "trajectory " << trajectory_file << " not found." << endl;}//如果eof()返回0,就没读完while (!fin.eof()) {//按照时间  平移 四元素的顺序定义并读取double time, tx, ty, tz, qx, qy, qz, qw;fin >> time >> tx >> ty >> tz >> qx >> qy >> qz >> qw;Sophus::SE3 p1(Eigen::Quaterniond(qw, qx, qy, qz), Eigen::Vector3d(tx, ty, tz));poses.push_back(p1);}fin.close();// end your code here// draw trajectory in pangolinDrawTrajectory(poses);return 0;
}
/************************************************************************/
void DrawTrajectory(vector<Sophus::SE3, Eigen::aligned_allocator<Sophus::SE3>> poses) {if (poses.empty()) {cerr << "Trajectory is empty!" << endl;return;}// create pangolin window and plot the trajectorypangolin::CreateWindowAndBind("Trajectory Viewer", 1024, 768);glEnable(GL_DEPTH_TEST);glEnable(GL_BLEND);glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);pangolin::OpenGlRenderState s_cam(pangolin::ProjectionMatrix(1024, 768, 500, 500, 512, 389, 0.1, 1000),pangolin::ModelViewLookAt(0, -0.1, -1.8, 0, 0, 0, 0.0, -1.0, 0.0));pangolin::View &d_cam = pangolin::CreateDisplay().SetBounds(0.0, 1.0, pangolin::Attach::Pix(175), 1.0, -1024.0f / 768.0f).SetHandler(new pangolin::Handler3D(s_cam));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 < poses.size() - 1; i++) {glColor3f(1 - (float) i / poses.size(), 0.0f, (float) i / poses.size());glBegin(GL_LINES);auto p1 = poses[i], p2 = 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}
}

CmakeLists.txt对应代码如下:

cmake_minimum_required(VERSION 2.8)
project(draw_trajectory)
set( CMAKE_BUILD_TYPE "Release" )
set( CMAKE_CXX_FLAGS "-std=c++11 -O3" )
set( CMAKE_BUILD_TYPE "Debug" )find_package(Pangolin REQUIRED)
find_package(Sophus REQUIRED)
include_directories("/usr/include/eigen3")
include_directories(${Pangolin_INCLUDE_DIRS}${Sophus_INCLUDE_DIR}
)
add_executable(trajectory draw_trajectory.cpp)
target_link_libraries(trajectory${Pangolin_LIBRARIES}${Sophus_LIBRARIES})

然后

cd  SLAM4track//自己建的文件夹
cat CMakeLists.txt
cd build
cmake ..
make
./trajectory

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

6.* 轨迹的误差(附加题)

本题为附加题。 除了画出真实轨迹以外,我们经常需要把 SLAM 估计的轨迹与真实轨迹相⽐较。下⾯说明⽐较的原理,请你完成⽐较部分的代码实现。
在这里插入图片描述

CMakeLists.txt对应代码

cmake_minimum_required(VERSION 2.8)
project(wucha)set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")#set(CMAKE_CXX_STANDARD 11)
#set(CMAKE_BUILD_TYPE "Release")
#set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/bin)
#set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/lib)
#添加库
#sophus
#  为使用 sophus,需要使用find_package命令找到它并赋给Sophus_INCLUDE_DIRS
find_package(Sophus REQUIRED)
include_directories(${Sophus_INCLUDE_DIRS})
#Pangolin生成一个libPangolin动态链接库
find_package(Pangolin REQUIRED)
include_directories(${Pangolin_INCLUDE_DIRS})include_directories("/usr/include/eigen3")
#编译
add_executable(plotError compare_tra.cpp)
#链接
#target_link_libraries(plotError Sophus::Sophus)
target_link_libraries(plotError ${Sophus_LIBRARIES} )target_link_libraries(plotError ${Pangolin_LIBRARIES})

compare_tra.cpp对应代码:

#include "sophus/so3.h"
#include "sophus/se3.h"
#include <string>
#include <iostream>
#include <fstream>
#include <unistd.h>
#include <Eigen/Core>
#include <Eigen/Geometry>
// need pangolin for plotting trajectory
#include <pangolin/pangolin.h>
using namespace std;
// path to trajectory file
string gt_file = "../groundtruth.txt";
string est_file = "../estimated.txt";
vector<Sophus::SE3, Eigen::aligned_allocator<Sophus::SE3>> gt_poses,est_poses;
// function for plotting trajectory, don't edit this code
// start point is red and end point is blue
void DrawTrajectory(vector<Sophus::SE3, Eigen::aligned_allocator<Sophus::SE3>> gt_poses,vector<Sophus::SE3, Eigen::aligned_allocator<Sophus::SE3>> est_poses);
void readData(string filepath);
void ErrorTrajectory();
int main(int argc, char **argv) {readData(gt_file);readData(est_file);ErrorTrajectory();// draw trajectory in pangolinDrawTrajectory(gt_poses,est_poses);//打印两条轨迹return 0;/// implement pose reading code// start your code here (5~10 lines)
}
/*******************************************************************************************/
void readData(string filepath){vector<Sophus::SE3, Eigen::aligned_allocator<Sophus::SE3>> poses;ifstream infile(filepath);double t1,tx,ty,tz,qx,qy,qz,qw;string line;if(infile){while(getline(infile,line)){stringstream record(line);    //从string读取数据record>>t1>>tx>>ty>>tz>>qx>>qy>>qz>>qw;Eigen::Vector3d t(tx,ty,tz);Eigen::Quaterniond q = Eigen::Quaterniond(qw,qx,qy,qz).normalized();  //四元数的顺序要注意Sophus::SE3 SE3_qt(q,t);poses.push_back(SE3_qt);}}else{cout<<"没找到这个文件"<<endl;}if(filepath==gt_file){gt_poses = poses;}else if( filepath==est_file ){est_poses = poses;}else{ cout<<"读文件出错"<<endl;}infile.close();
}
/*******************************************************************************************/
void ErrorTrajectory()
{double RMSE = 0;Eigen::Matrix<double ,6,1> se3;vector<double> error;for(int i=0;i<gt_poses.size();i++){se3=(gt_poses[i].inverse()*est_poses[i]).log();  //这里的se3为向量形式,求log之后是向量形式//cout<<se3.transpose()<<endl;error.push_back( se3.squaredNorm() );  //二范数// cout<<error[i]<<endl;}for(int i=0; i<gt_poses.size();i++){RMSE += error[i];}RMSE /= double(error.size());RMSE = sqrt(RMSE);cout<<RMSE<<endl;
}
/*******************************************************************************************/
void DrawTrajectory(vector<Sophus::SE3, Eigen::aligned_allocator<Sophus::SE3>> gt_poses,vector<Sophus::SE3, Eigen::aligned_allocator<Sophus::SE3>> est_poses) {if (gt_poses.empty()) {cerr << "groundtruth is empty!" << endl;return;}if (est_poses.empty()) {cerr << "estimated is empty!" << endl;return;}// create pangolin window and plot the trajectorypangolin::CreateWindowAndBind("Trajectory Viewer", 1024, 768);glEnable(GL_DEPTH_TEST);glEnable(GL_BLEND);glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);pangolin::OpenGlRenderState s_cam(pangolin::ProjectionMatrix(1024, 768, 500, 500, 512, 389, 0.1, 1000),pangolin::ModelViewLookAt(0, -0.1, -1.8, 0, 0, 0, 0.0, -1.0, 0.0));pangolin::View &d_cam = pangolin::CreateDisplay().SetBounds(0.0, 1.0, pangolin::Attach::Pix(175), 1.0, -1024.0f / 768.0f).SetHandler(new pangolin::Handler3D(s_cam));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);//窗口,rgbaglLineWidth(2);for (size_t i = 0; i < est_poses.size() - 1; i++) {glColor3f(1 - (float) i / est_poses.size(), 0.0f, (float) i / est_poses.size());glBegin(GL_LINES);auto p1 = est_poses[i], p2 = est_poses[i + 1];glVertex3d(p1.translation()[0], p1.translation()[1], p1.translation()[2]);glVertex3d(p2.translation()[0], p2.translation()[1], p2.translation()[2]);glEnd();}for (size_t i = 0; i < gt_poses.size() - 2; i++) {glColor3f(0.f, 0.8f, 0.f);//绿色glBegin(GL_LINES);auto p3 = gt_poses[i], p4 = gt_poses[i + 1];//只显示tx,ty,tzglVertex3d(p3.translation()[0], p3.translation()[1], p3.translation()[2]);glVertex3d(p4.translation()[0], p4.translation()[1], p4.translation()[2]);glEnd();}pangolin::FinishFrame();usleep(5000);   // sleep 5 ms}
}

然后运行,运行命令如下:

cd track_compare
cd build
cmake ..
make
./plotError

在这里插入图片描述
本人自学SLAM,如果错误,还请见谅留言提醒
希望的我的博客对你有帮助!

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/121850.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

UML中类之间的六种主要关系

UML中类之间的六种主要关系: 继承&#xff08;泛化&#xff09;&#xff08;Inheritance、Generalization&#xff09;, 实现&#xff08;Realization&#xff09;&#xff0c;关联&#xff08;Association)&#xff0c;聚合&#xff08;Aggregation&#xff09;&#xff0c;组…

Linux--进程替换

1.什么是进程替换 在fork函数之后&#xff0c;父子进程各自执行代码的一部分&#xff0c;但是如果子进程想要执行一份全新的程序呢&#xff1f; 通过进程替换来完成&#xff0c;进程替换就是父子进程代码发生写时拷贝&#xff0c;子进程执行自己的功能。 程序替换就是通过特定的…

python 笔记:h5py 读取HDF5文件

1 HDF5文件 HDF5 是 Hierarchical Data Format version 5 的缩写&#xff0c;是一种用于存储和管理大量数据的文件格式一个h5py文件可以看作是 “dataset” 和 “group” 二合一的容器 dataset : 数据集&#xff0c;像 numpy 数组一样工作group : 包含了其它 dataset 和 其它 …

GZ035 5G组网与运维赛题第4套

2023年全国职业院校技能大赛 GZ035 5G组网与运维赛项&#xff08;高职组&#xff09; 赛题第4套 一、竞赛须知 1.竞赛内容分布 竞赛模块1--5G公共网络规划部署与开通&#xff08;35分&#xff09; 子任务1&#xff1a;5G公共网络部署与调试&#xff08;15分&#xff09; 子…

C语言_断言assert详解

一、assert定义 assert() 的用法像是一种"契约式编程"&#xff0c;在我的理解中&#xff0c;其表达的意思就是&#xff0c;程序在我的假设条件下&#xff0c;能够正常良好的运作&#xff0c;其实就相当于一个 if 语句&#xff1a; if(假设成立) {程序正常运行&…

(免费领源码) Asp.Net#SQL Server校园在线投票系统10557-计算机毕业设计项目选题推荐

摘 要 随着互联网大趋势的到来&#xff0c;社会的方方面面&#xff0c;各行各业都在考虑利用互联网作为媒介将自己的信息更及时有效地推广出去&#xff0c;而其中最好的方式就是建立网络管理系统&#xff0c;并对其进行信息管理。由于现在网络的发达&#xff0c;校园投票通过网…

java - IDEA IDE - 设置字符串断点

文章目录 java - IDEA IDE - 设置字符串断点概述笔记END java - IDEA IDE - 设置字符串断点 概述 IDE环境为IDEA2022.3 在看一段序列化的代码, 想找出报错抛异常那个点, 理解一下代码实现. 因为序列化代码实现在第三方jar包中, 改不了(只读的). 根本数不清第几次才会开始报…

OpenCV学习(五)——图像基本操作(访问图像像素值、图像属性、感兴趣区域ROI和图像边框)

图像基本操作 5. 图像基本操作5.1 访问像素值并修改5.2 访问图像属性5.2 图像感兴趣区域ROI5.3 拆分和合并图像通道5.4 为图像设置边框&#xff08;填充&#xff09; 5. 图像基本操作 访问像素值并修改访问图像属性设置感兴趣区域&#xff08;ROI&#xff09;分割和合并图像 …

如何在vscode中添加less插件

Less &#xff08;Leaner Style Sheets 的缩写&#xff09; 是一门向后兼容的 CSS 扩展语言。它对CSS 语言增加了少许方便的扩展&#xff0c;通过less可以编写更少的代码实现更强大的样式。但less不是css&#xff0c;浏览器不能直接识别&#xff0c;即浏览器无法执行less代码&a…

2023年正版win10/win11系统安装教学(纯净版)

第一步&#xff1a;准备一个8G容量以上的U盘。 注意&#xff0c;在制作系统盘时会格式化U盘&#xff0c;所以最好准备个空U盘&#xff0c;防止资料丢失。 第二步&#xff1a;制作系统盘。 安装win10 进入windows官网 官网win10下载地址&#xff1a;https://www.microsoft.c…

安卓开发实例:随机数

点击按钮生成一个1-100之间的随机数 activity_random_number.xml <?xml version"1.0" encoding"utf-8"?> <androidx.constraintlayout.widget.ConstraintLayoutxmlns:android"http://schemas.android.com/apk/res/android"xmlns:a…

记一次vue3实现TRSP大华相机拉流的经历

一、背景 业务场景&#xff0c;大华IP相机安装在A城市某建筑场所&#xff0c;工控机是内网通过4G流量卡上网&#xff0c;工控机通过相机采集数据后做故障识别并上传故障信息到地面服务器&#xff0c;地面服务器在B城市。 现需要在地面服务器提供的WEB界面上实现IP相机实时拉流…

linux套接字选项API

获取套接字的选项值(getsockopt) 【头文件】 #include <sys/types.h> #include <sys/socket.h> 【函数原型】 int getsockopt(int sockfd, int level, int optname,void *optval, socklen_t *optlen); 【函数功能】 用于获取一个套接字的选项 【参数含义】 […

【前端】NodeJS核心知识点整理

1.Node.js入门案例 1.1.什么是Node.js JS是脚本语言&#xff0c;脚本语言都需要一个解析器才能运行。对于写在HTML页面里的JS&#xff0c;浏览器充当了解析器的角色。而对于需要独立运行的JS&#xff0c;NodeJS就是一个解析器。 每一种解析器都是一个运行环境&#xff0c;不但…

数据特征工程 | 主成分分析(Python)

特征抽取(feature extraction)和特征选择(feature selection)不一样,特征抽取是从原特征集中推导出有用的信息构成新的特征集。特征选择是从原特征集中选择一部分子集作为训练特征。 特征抽取将数据集从一个特征空间投影到了一个更低维度的特征空间。 主成分分析(princ…

Kubernetes - Ingress HTTP 负载搭建部署解决方案(新版本v1.21+)

在看这一篇之前&#xff0c;如果不了解 Ingress 在 K8s 当中的职责&#xff0c;建议看之前的一篇针对旧版本 Ingress 的部署搭建&#xff0c;在开头会提到它的一些简介Kubernetes - Ingress HTTP 负载搭建部署解决方案_放羊的牧码的博客-CSDN博客 开始表演 1、kubeasz 一键安装…

十大排序算法(C语言)

参考文献 https://zhuanlan.zhihu.com/p/449501682 https://blog.csdn.net/mwj327720862/article/details/80498455?ops_request_misc%257B%2522request%255Fid%2522%253A%2522169837129516800222848165%2522%252C%2522scm%2522%253A%252220140713.130102334…%2522%257D&…

星闪技术 NearLink 一种专门用于短距离数据传输的新型无线通信技术

本心、输入输出、结果 文章目录 星闪技术 NearLink 一种专门用于短距离数据传输的新型无线通信技术前言星闪技术 NearLink 的诞生背景星闪技术 NearLink 简介星闪技术 NearLink 技术是一种蓝牙技术吗星闪技术 NearLink 优势星闪技术 NearLink 应用前景弘扬爱国精神星闪技术 Nea…

10000字!图解机器学习特征工程

文章目录 引言特征工程1.特征类型1.1 结构化 vs 非结构化数据1.2 定量 vs 定性数据 2.数据清洗2.1 数据对齐2.2 缺失值处理 原文链接&#xff1a;https://www.showmeai.tech/article-detail/208 作者&#xff1a;showmeAI 引言 上图为大家熟悉的机器学习建模流程图&#xff0c;…

技术资料MF74:将图像插入单元格注释

【分享成果&#xff0c;随喜正能量】须知往生净土&#xff0c;全仗信、愿。有信、愿&#xff0c;即未得三昧、未得一心不乱&#xff0c;亦可往生。且莫只以一心不乱&#xff0c;及得念佛三昧为志事&#xff0c;不复以信、愿、净念为事。。 我给VBA的定义&#xff1a;VBA是个人…