Ceres-solver学习笔记-pose_graph_2d.cc

2023-10-20 19:59

本文主要是介绍Ceres-solver学习笔记-pose_graph_2d.cc,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

[本节官方教程链接🔗](http://ceres-solver.org/nnls_tutorial.html#f9)
pose_graph_2d.cc针对SLAM问题中的位姿图优化问题,
如下,三角点xi表示物体的状态,边zij表示观测,即xi和xj之间的约束,
实线边表示两个状态之间是序列性的(sequential ),虚线则表示非序列性即闭环的两帧之间的约束。

在这里插入图片描述
其中,x由一个表示平移的二维向量p和一维标量φ (弧度制),则观测Zab由Pab及φab表示观测到的a、b两个状态的约束。则应该在ceres实现的cost function中的误差为:
在这里插入图片描述
其中要将角度残差归一化(角度范围为[-π,π)),其中Ra^T为:
这破水印真碍事
最后,考虑到测量的不确定度,需要对残差用信息矩阵进行加权,ceres并没有自动加权,所以要手动给残差左乘一个残差的开方的转置。
程序运行用到了g2o格式的数据文件,g2o数据文件

(详细运行看自己下载的ceres文件夹里examples里相对应的 readme)

程序运行:/path/to/bin/pose_graph_2d --input /path/to/dataset/dataset.g2o
观看输出结果:/path/to/repo/examples/slam/pose_graph_2d/plot_results.py --optimized_poses ./poses_optimized.txt --initial_poses ./poses_original.txt

  • ceres解决优化问题无非两步,建立优化问题然后solve,solve没什么好说的,基本就是选择ceres中定义好的参数往ceres库中的函数传参,建立一个简单的非线性最小二乘优化问题需要:
    1.首先确定好损失函数loss function和定义好基于类对象或结构体对象“函数子”即cost functor的cost function,在cost functor中重载operator()定义残差函数,至于残差对优化变量的导数可用ceres中的自动求导,也可以自行定义。
    2.之后将cost function,lossfunction,各个之间存在约束关系的优化变量加入AddResidualBlock函数中

详细步骤即细节看如下代码注释

// Constructs the nonlinear least squares optimization problem from the pose
// graph constraints.
void BuildOptimizationProblem(const std::vector<Constraint2d>& constraints,std::map<int, Pose2d>* poses,ceres::Problem* problem) {CHECK(poses != NULL);CHECK(problem != NULL);if (constraints.empty()) {LOG(INFO) << "No constraints, no problem to optimize.";return;}//损失函数即鲁棒核函数,鲁棒核函数的主要作用是降低数据中明显错误的数据对优化的影响ceres::LossFunction* loss_function = NULL;//这里LocalParameterization是针对某些优化优化参数过参数化的问题,//例如,对于一个球体上点坐标的优化问题来说,一个点的坐标p=[x,y,z],//但是由球的流形可知其只有两个自由度,因此我们可以仅仅优化两个参数,之后再更新优化后的点ceres::LocalParameterization* angle_local_parameterization =AngleLocalParameterization::Create();for (std::vector<Constraint2d>::const_iterator constraints_iter =constraints.begin();constraints_iter != constraints.end(); ++constraints_iter) {const Constraint2d& constraint = *constraints_iter;std::map<int, Pose2d>::iterator pose_begin_iter =poses->find(constraint.id_begin);CHECK(pose_begin_iter != poses->end())<< "Pose with ID: " << constraint.id_begin << " not found.";std::map<int, Pose2d>::iterator pose_end_iter =poses->find(constraint.id_end);CHECK(pose_end_iter != poses->end())<< "Pose with ID: " << constraint.id_end << " not found.";const Eigen::Matrix3d sqrt_information =constraint.information.llt().matrixL();//求开根号的信息矩阵// Ceres will take ownership of the pointer.//定义残差函数ceres::CostFunction* cost_function = PoseGraph2dErrorTerm::Create(constraint.x, constraint.y, constraint.yaw_radians, sqrt_information);//构建残差块problem->AddResidualBlock(cost_function, loss_function, &pose_begin_iter->second.x,&pose_begin_iter->second.y, &pose_begin_iter->second.yaw_radians,&pose_end_iter->second.x, &pose_end_iter->second.y,&pose_end_iter->second.yaw_radians);//设置LocalParameterization的优化变量problem->SetParameterization(&pose_begin_iter->second.yaw_radians,angle_local_parameterization);problem->SetParameterization(&pose_end_iter->second.yaw_radians,angle_local_parameterization);}//固定第一个优化参数,即第一个参数不优化//因为我们获得的观测都是状态间的相对量,因此最后优化出的轨迹还有一个轨迹位置的不确定性,//即最后得到的轨迹形状是一样的但是其起始位置很可能不同,//举个例子,你在两个不同的房间可以走出相同形状的轨迹,但是轨迹的绝对位置是不一样的,//当固定第一个优化变量后,轨迹位置的不确定性也就消失了std::map<int, Pose2d>::iterator pose_start_iter =poses->begin();CHECK(pose_start_iter != poses->end()) << "There are no poses.";problem->SetParameterBlockConstant(&pose_start_iter->second.x);problem->SetParameterBlockConstant(&pose_start_iter->second.y);problem->SetParameterBlockConstant(&pose_start_iter->second.yaw_radians);
}// Returns true if the solve was successful.
bool SolveOptimizationProblem(ceres::Problem* problem) {CHECK(problem != NULL);ceres::Solver::Options options;options.max_num_iterations = 100;//迭代次数//柯西分解求解具有稀疏性的大规模非线性最小二乘问题options.linear_solver_type = ceres::SPARSE_NORMAL_CHOLESKY;ceres::Solver::Summary summary;ceres::Solve(options, problem, &summary);std::cout << summary.FullReport() << '\n';return summary.IsSolutionUsable();
}

这篇关于Ceres-solver学习笔记-pose_graph_2d.cc的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/249401

相关文章

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧

Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用"判断这段话的情感倾向:积极、消极还是中性"。 快速迭代:善于快速连续调整提示。熟练的提示工程师能够灵活地进行多轮优化。例:从"总结文章"到"用

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

学习hash总结

2014/1/29/   最近刚开始学hash,名字很陌生,但是hash的思想却很熟悉,以前早就做过此类的题,但是不知道这就是hash思想而已,说白了hash就是一个映射,往往灵活利用数组的下标来实现算法,hash的作用:1、判重;2、统计次数;

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]

【机器学习】高斯过程的基本概念和应用领域以及在python中的实例

引言 高斯过程(Gaussian Process,简称GP)是一种概率模型,用于描述一组随机变量的联合概率分布,其中任何一个有限维度的子集都具有高斯分布 文章目录 引言一、高斯过程1.1 基本定义1.1.1 随机过程1.1.2 高斯分布 1.2 高斯过程的特性1.2.1 联合高斯性1.2.2 均值函数1.2.3 协方差函数(或核函数) 1.3 核函数1.4 高斯过程回归(Gauss

【学习笔记】 陈强-机器学习-Python-Ch15 人工神经网络(1)sklearn

系列文章目录 监督学习:参数方法 【学习笔记】 陈强-机器学习-Python-Ch4 线性回归 【学习笔记】 陈强-机器学习-Python-Ch5 逻辑回归 【课后题练习】 陈强-机器学习-Python-Ch5 逻辑回归(SAheart.csv) 【学习笔记】 陈强-机器学习-Python-Ch6 多项逻辑回归 【学习笔记 及 课后题练习】 陈强-机器学习-Python-Ch7 判别分析 【学

系统架构师考试学习笔记第三篇——架构设计高级知识(20)通信系统架构设计理论与实践

本章知识考点:         第20课时主要学习通信系统架构设计的理论和工作中的实践。根据新版考试大纲,本课时知识点会涉及案例分析题(25分),而在历年考试中,案例题对该部分内容的考查并不多,虽在综合知识选择题目中经常考查,但分值也不高。本课时内容侧重于对知识点的记忆和理解,按照以往的出题规律,通信系统架构设计基础知识点多来源于教材内的基础网络设备、网络架构和教材外最新时事热点技术。本课时知识

线性代数|机器学习-P36在图中找聚类

文章目录 1. 常见图结构2. 谱聚类 感觉后面几节课的内容跨越太大,需要补充太多的知识点,教授讲得内容跨越较大,一般一节课的内容是书本上的一章节内容,所以看视频比较吃力,需要先预习课本内容后才能够很好的理解教授讲解的知识点。 1. 常见图结构 假设我们有如下图结构: Adjacency Matrix:行和列表示的是节点的位置,A[i,j]表示的第 i 个节点和第 j 个

Node.js学习记录(二)

目录 一、express 1、初识express 2、安装express 3、创建并启动web服务器 4、监听 GET&POST 请求、响应内容给客户端 5、获取URL中携带的查询参数 6、获取URL中动态参数 7、静态资源托管 二、工具nodemon 三、express路由 1、express中路由 2、路由的匹配 3、路由模块化 4、路由模块添加前缀 四、中间件