base_lcoal_planner的LocalPlannerUtil类中getLocalPlan函数详解
本文主要介绍base_lcoal_planner功能包中LocalPlannerUtil类的getLocalPlan函数,以及其调用的transformGlobalPlan函数、prunePlan函数的相关内容
一、getLocalPlan函数
getLocalPlan函数的源码如下:
bool LocalPlannerUtil::getLocalPlan(const geometry_msgs::PoseStamped& global_pose, std::vector<geometry_msgs::PoseStamped>& transformed_plan) {//get the global plan in our frameif(!base_local_planner::transformGlobalPlan(*tf_,global_plan_,global_pose,*costmap_,global_frame_,transformed_plan)) {ROS_WARN("Could not transform the global plan to the frame of the controller");return false;}//now we'll prune the plan based on the position of the robotif(limits_.prune_plan) {base_local_planner::prunePlan(global_pose, transformed_plan, global_plan_);}return true;
}
下面对函数的主要功能和步骤进行介绍
1. 函数签名:
bool LocalPlannerUtil::getLocalPlan(const geometry_msgs::PoseStamped& global_pose, std::vector<geometry_msgs::PoseStamped>& transformed_plan)
2. 函数参数:
- global_pose:机器人在全局坐标系中的当前位置,通常表示为位姿信息(包括位置和方向)。
- transformed_plan:函数将转换后的局部路径规划存储在此参数中。
3. 函数功能:
这个函数的主要功能是获取机器人的局部路径规划的初始参考路径,并存储在 transformed_plan 中。函数执行以下步骤:
- 首先,它调用名为 transformGlobalPlan 的函数来将全局路径规划 global_plan_ 转换为机器人的局部路径规划,结果存储在 transformed_plan 中。注意:transformed_plan中的坐标依然为全局坐标系
- 如果转换失败(transformGlobalPlan 返回 false),函数打印警告消息并返回 false
- 接下来,如果 limits_.prune_plan 为真,函数会调用名为 prunePlan 的函数,以根据机器人的当前位置修剪局部路径规划。这将确保局部路径规划与机器人的当前位置对齐。
- 最后,函数返回 true,表示成功获取局部路径规划。
4. 返回值:
- 如果获取局部路径规划成功,函数返回 true。
- 如果获取失败,函数返回 false,并在需要时输出警告消息。
5. 函数效果示意
为了方便大家理解,我从实际运行过程中导出了转换前后的数据,绘制了以下图像,下图中的绿色虚线是一些列全局路径规划器规划的路径,蓝色实线是其对应的经过getLocalPlan函数后,得到的局部初始路径transformed_plan,从图中可以发现getLocalPlan函数对全局路径进行了裁剪,仅取与当前点距离小于局部地图一半尺寸的部分,在下图示例中,局部地图的设定尺寸为5x5m,下图中红色虚线圆圈的半径为5/2=2.5m。
需要注意的是,尽管transformed_plan中存储着局部初始路径,但其坐标的坐标系依然为全局坐标系
二、transformGlobalPlan 函数
transformGlobalPlan 函数的源码如下:
bool transformGlobalPlan(const tf2_ros::Buffer& tf,const std::vector<geometry_msgs::PoseStamped>& global_plan,const geometry_msgs::PoseStamped& global_pose,const costmap_2d::Costmap2D& costmap,const std::string& global_frame,std::vector<geometry_msgs::PoseStamped>& transformed_plan){transformed_plan.clear();if (global_plan.empty()) {ROS_ERROR("Received plan with zero length");return false;}const geometry_msgs::PoseStamped& plan_pose = global_plan[0];try {// get plan_to_global_transform from plan frame to global_framegeometry_msgs::TransformStamped plan_to_global_transform = tf.lookupTransform(global_frame, ros::Time(),plan_pose.header.frame_id, plan_pose.header.stamp, plan_pose.header.frame_id, ros::Duration(0.5));//let's get the pose of the robot in the frame of the plangeometry_msgs::PoseStamped robot_pose;tf.transform(global_pose, robot_pose, plan_pose.header.frame_id);//we'll discard points on the plan that are outside the local costmapdouble dist_threshold = std::max(costmap.getSizeInCellsX() * costmap.getResolution() / 2.0,costmap.getSizeInCellsY() * costmap.getResolution() / 2.0);unsigned int i = 0;double sq_dist_threshold = dist_threshold * dist_threshold;double sq_dist = 0;//we need to loop to a point on the plan that is within a certain distance of the robotwhile(i < (unsigned int)global_plan.size()) {double x_diff = robot_pose.pose.position.x - global_plan[i].pose.position.x;double y_diff = robot_pose.pose.position.y - global_plan[i].pose.position.y;sq_dist = x_diff * x_diff + y_diff * y_diff;if (sq_dist <= sq_dist_threshold) {break;}++i;}geometry_msgs::PoseStamped newer_pose;//now we'll transform until points are outside of our distance thresholdwhile(i < (unsigned int)global_plan.size() && sq_dist <= sq_dist_threshold) {const geometry_msgs::PoseStamped& pose = global_plan[i];tf2::doTransform(pose, newer_pose, plan_to_global_transform);transformed_plan.push_back(newer_pose);double x_diff = robot_pose.pose.position.x - global_plan[i].pose.position.x;double y_diff = robot_pose.pose.position.y - global_plan[i].pose.position.y;sq_dist = x_diff * x_diff + y_diff * y_diff;++i;}}catch(tf2::LookupException& ex) {ROS_ERROR("No Transform available Error: %s\n", ex.what());return false;}catch(tf2::ConnectivityException& ex) {ROS_ERROR("Connectivity Error: %s\n", ex.what());return false;}catch(tf2::ExtrapolationException& ex) {ROS_ERROR("Extrapolation Error: %s\n", ex.what());if (!global_plan.empty())ROS_ERROR("Global Frame: %s Plan Frame size %d: %s\n", global_frame.c_str(), (unsigned int)global_plan.size(), global_plan[0].header.frame_id.c_str());return false;}return true;}bool getGoalPose(const tf2_ros::Buffer& tf,const std::vector<geometry_msgs::PoseStamped>& global_plan,const std::string& global_frame, geometry_msgs::PoseStamped &goal_pose) {if (global_plan.empty()){ROS_ERROR("Received plan with zero length");return false;}const geometry_msgs::PoseStamped& plan_goal_pose = global_plan.back();try{geometry_msgs::TransformStamped transform = tf.lookupTransform(global_frame, ros::Time(),plan_goal_pose.header.frame_id, plan_goal_pose.header.stamp,plan_goal_pose.header.frame_id, ros::Duration(0.5));tf2::doTransform(plan_goal_pose, goal_pose, transform);}catch(tf2::LookupException& ex) {ROS_ERROR("No Transform available Error: %s\n", ex.what());return false;}catch(tf2::ConnectivityException& ex) {ROS_ERROR("Connectivity Error: %s\n", ex.what());return false;}catch(tf2::ExtrapolationException& ex) {ROS_ERROR("Extrapolation Error: %s\n", ex.what());if (global_plan.size() > 0)ROS_ERROR("Global Frame: %s Plan Frame size %d: %s\n", global_frame.c_str(), (unsigned int)global_plan.size(), global_plan[0].header.frame_id.c_str());return false;}return true;}
下面对函数的主要功能和步骤进行介绍
1. 函数签名:
bool transformGlobalPlan(const tf2_ros::Buffer& tf,const std::vector<geometry_msgs::PoseStamped>& global_plan,const geometry_msgs::PoseStamped& global_pose,const costmap_2d::Costmap2D& costmap,const std::string& global_frame,std::vector<geometry_msgs::PoseStamped>& transformed_plan
)
2. 参数:
- tf:tf2_ros::Buffer 对象,用于进行坐标变换(Transform)的查询。
- global_plan:全局路径规划的一系列位姿(姿态信息),通常包含从机器人当前位置到目标点的路径。
- global_pose:机器人在全局坐标系中的当前位置,通常表示为位姿信息(包括位置和方向)。
- costmap:局部代价地图,用于检查路径规划中的点是否在局部地图中。
- global_frame:全局坐标系的名称,通常是机器人的地图坐标系。
- transformed_plan:函数将转换后的全局路径规划存储在此参数中。
3. 函数功能:
这个函数的主要功能是将全局路径规划 global_plan 转换为局部路径规划,并存储在 transformed_plan 中。函数执行以下步骤:
- 首先,它清空 transformed_plan,以确保在填充之前不包含任何数据。
- 如果 global_plan 为空,它将打印错误消息并返回 false,表示接收到零长度的路径规划。
- 获取全局路径规划的第一个位姿 plan_pose,通常表示目标点。
- 使用 tf 对象查询全局坐标系 global_frame 到 plan_pose 所在坐标系的坐标变换。这里暂时没有看明白,貌似转换后还是全局坐标系,不清楚此操作的作用
- 计算机器人当前位置 robot_pose 在路径规划坐标系中的姿态,以便确定机器人在哪个位置附近需要开始路径转换。
- 计算一个距离阈值 dist_threshold,它通常是局部代价地图的一半尺寸,用于确定哪些点需要保留在局部路径规划中。
- 使用一个循环,找到全局路径规划中距离机器人位置不超过 dist_threshold 的点,并将它们添加到 transformed_plan 中,同时计算距离并更新 i。
- 最后,函数处理可能的异常,如坐标变换失败,并返回 false,以指示转换失败。
4. 返回值:
- 如果路径转换成功,函数返回 true,并将转换后的路径存储在 transformed_plan 中。
- 如果出现异常或全局路径规划为空,函数返回 false。
三、prunePlan函数
prunePlan函数的源码如下:
void prunePlan(const geometry_msgs::PoseStamped& global_pose, std::vector<geometry_msgs::PoseStamped>& plan, std::vector<geometry_msgs::PoseStamped>& global_plan){ROS_ASSERT(global_plan.size() >= plan.size());std::vector<geometry_msgs::PoseStamped>::iterator it = plan.begin();std::vector<geometry_msgs::PoseStamped>::iterator global_it = global_plan.begin();while(it != plan.end()){const geometry_msgs::PoseStamped& w = *it;// Fixed error bound of 2 meters for now. Can reduce to a portion of the map size or based on the resolutiondouble x_diff = global_pose.pose.position.x - w.pose.position.x;double y_diff = global_pose.pose.position.y - w.pose.position.y;double distance_sq = x_diff * x_diff + y_diff * y_diff;if(distance_sq < 1){ROS_DEBUG("Nearest waypoint to <%f, %f> is <%f, %f>\n", global_pose.pose.position.x, global_pose.pose.position.y, w.pose.position.x, w.pose.position.y);break;}it = plan.erase(it);global_it = global_plan.erase(global_it);}}
下面对函数的主要功能和步骤进行介绍
1. 函数签名:
void prunePlan(const geometry_msgs::PoseStamped& global_pose, std::vector<geometry_msgs::PoseStamped>& plan, std::vector<geometry_msgs::PoseStamped>& global_plan)
2. 参数:
- global_pose:机器人在全局坐标系中的当前位置,通常表示为位姿信息(包括位置和方向)。
- plan:一个存储局部路径规划的一系列位姿(姿态信息),这是局部路径规划器生成的候选路径。
- global_plan:全局路径规划的一系列位姿,通常包含从起点到终点的路径。
3. 函数功能:
这个函数的主要目的是将plan和global_plan修剪,以便将全局路径规划和局部路径规划的起点对齐。它的实现逻辑如下:
- 首先,函数使用断言 ROS_ASSERT 来确保global_plan的大小大于等于plan的大小,因为全局规划必须包括局部规划。
- 接下来,函数使用迭代器遍历plan和global_plan中的位姿信息。
- 对于每个位姿,它计算全局位置 global_pose 与该位姿的距离的平方,这是通过计算差值并计算欧几里德距离的平方来完成的。
- 如果距离的平方小于1(可以根据需要更改阈值),则认为机器人已经接近路径的一部分,函数会停止修剪,这通常意味着机器人已经到达或非常接近路径上的某个点。
- 如果距离的平方大于等于1,函数会将plan和global_plan中的当前位姿从列表中删除,以便继续修剪下一个位姿。
4. 总结:
该函数的目的是将局部路径规划器生成的位姿列表plan修剪到机器人当前位置附近的部分,并且同时将全局路径规划器生成的路径global_plan做相应的修剪,以确保局部路径规划与全局路径规划对齐。这是导航中的一个常见操作,以确保机器人沿着规划路径前进。如果机器人远离路径,函数将删除不再需要的位姿,以节省计算资源。
相关文章:
base_lcoal_planner的LocalPlannerUtil类中getLocalPlan函数详解
本文主要介绍base_lcoal_planner功能包中LocalPlannerUtil类的getLocalPlan函数,以及其调用的transformGlobalPlan函数、prunePlan函数的相关内容 一、getLocalPlan函数 getLocalPlan函数的源码如下: bool LocalPlannerUtil::getLocalPlan(const geomet…...
elasticSearch put全局更新和单个字段更新语法
1、如下:更新改类型未doc(文档)的全局字段数据 注意:如果你使用的是上面的语句,但是只写了id和title并赋值,图片上其他字段没有填写,执行命令后,则会把原文档中的其他字段都给删除了,你会发现查…...
记录一次时序数据库的实战测试
0x1.前言 本文章仅用于信息安全防御技术分享,因用于其他用途而产生不良后果,作者不承担任何法律责任,请严格遵循中华人民共和国相关法律法规,禁止做一切违法犯罪行为。文中涉及漏洞均以提交至教育漏洞平台。 0x2.背景 在某…...
HTML中文本框\单选框\按钮\多选框
<!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Title</title> </head> <body> <h1>登录注册</h1> <form action"第一个网页.html" method"post&quo…...
解释器模式——化繁为简的翻译机
● 解释器模式介绍 解释器模式(Interpreter Pattern)是一种用的比较少的行为型模式,其提供了一种解释语言的语法或表达的方式,该模式定义了一个表达式接口,通过该接口解释一个特定的上下文。在这么多的设计模式中&…...
【凡人修仙传】定档,四女神出场,韩立遭极阴岛陷阱,蛮胡子亮相
【侵权联系删除】【文/郑尔巴金】 距离凡人修仙传动画星海飞驰序章完结,已经过去了两个月的时间,相信大家等待的心情相当难熬,而且也愈发期待韩立结丹后在乱星海发生的故事。按照官方当初立下的FLAG,新年番动画即将在金秋十一月上…...
【解决】设置pip安装依赖包路径默认路径在conda路径下,而不是C盘路径下
【解决】设置pip安装依赖包路径默认路径在conda路径下,而不是C盘路径下 问题描述 在win11下安装miniconda,在conda环境里使用pip安装,依赖包总是安装到C盘路径,如 C:\Users\Jimmy\AppData\Local\Programs\Python\Python311\Lib\…...
JoySSL-新兴国产品牌数字证书
随着我国对数据安全重视程度的不断提升,国产SSL证书越来越受到广大政府机关和企业的青睐,成为提升网站数据安全能力的重要技术手段。那么什么是国产SSL证书?国产SSL证书和普通SSL证书又有什么区别呢? 什么是国产SSL证书ÿ…...
kafka3.X基本概念和使用
kafka基本概念和使用 文章目录 kafka基本概念和使用 kafka的概念基本概念Kafka的使用 首先kafka的安装kafka的简单实用和理解搭建集群(3个节点)windows版本环境搭建 本文"kafka的概念"部分是在[初谈Kafka][ https://juejin.im/post/5a8e7f…...
用低代码平台代替Excel搭建进销存管理系统
目录 一、用低代码平台搭建系统 1.需求调研 2.基于痛点梳理业务流程 3.低代码实现 (1)基础资料模块 (2)采购管理模块 (3)销售管理模块 (4)库存管理模块 (5&…...
Redis和Memcached网络模型详解
1. Redis单线程单Reactor网络模型 1.1 redis单线程里不能执行十分耗时的流程,不然会客户端响应不及时 解决方法一: beforesleep里删除过期键操作若存在大量过期键时,会耗费大量时间,redis采用的策略之一就是采用timelimit方案超过…...
二叉搜索树的实现(递归方式)
目录 实现思路 插入操作 删除操作 完整代码 测试案例 总结 二叉搜索树(Binary Search Tree,BST)是一种常用的数据结构,它具有以下特点: 左子树上所有节点的值均小于它的根节点的值右子树上所有节点的值均大于它的…...
NetCore IIS Redis JMeter 登录压力测试
近期,由于某项目验收需要,需要登录接口同时满足至少400个账号同时并发登录,于是开始编写测试代码,以满足项目业务需要。首先,安装jdk,由于本机已安装jdk8: 如果你机器上没有安装jdk,…...
进一步了解视频美颜SDK:美颜SDK的技术原理
美颜技术在当今的数字世界中变得越来越流行,尤其是在视频直播、社交媒体和视频通话应用中。用户寻求通过美颜效果增强自己的外观,这种需求催生了众多美颜SDK(软件开发工具包)的出现。这些SDK使开发者能够轻松地将美颜功能集成到他…...
【Qt之QSetting】介绍及使用
概述 QSettings类提供了一种持久的、与平台无关的应用程序设置存储功能。 用户通常期望一个应用能在不同会话中记住其设置(窗口大小和位置,选项等)。在Windows上,这些信息通常存储在系统注册表中;在macOS和iOS上&…...
基于WebRTC构建的程序因虚拟内存不足导致闪退问题的排查以及解决办法的探究
目录 1、WebRTC简介 2、问题现象描述 3、将Windbg附加到目标进程上分析 3.1、Windbg没有附加到主程序进程上,没有感知到异常或中断 3.2、Windbg感知到了中断,中断在DebugBreak函数调用上 3.3、32位进程用户态虚拟地址和内核态虚拟地址的划分 …...
通过jdk自制https证书并配置到nginx并配置http2
生成证书 这里使用自己生成的免费证书。在${JAVA_HOME}/bin 下可以看到keytool.exe,在改目录打开cmd然后输入: keytool -genkey -v -alias lgq.com -keyalg RSA -keystore d:/zj/ssl/fastfly.com.keystore -validity 3650生成证书过程中:【你的名字】对…...
祝贺中国煤科重庆研究院和达索、百世慧PLM项目顺利结项
引言 2023年10月17日,中国煤科重庆研究院与达索系统、百世慧在重庆研究院会议室召开了产品全生命周期管理(PLM)系统结项会。中国煤科重庆研究院科技发展部副主任孙海涛、测控技术研究分院副院长于庆、重庆大学教授鄢萍、达索公司工业装备部南…...
基于springboot实现数码论坛系统设计与实现系统【项目源码+论文说明】
基于springboot实现数码论坛系统设计与实现系统演示 摘要 网络的广泛应用给生活带来了十分的便利。所以把数码论坛与现在网络相结合,利用java技术建设数码论坛系统,实现数码论坛的信息化。则对于进一步提高数码论坛发展,丰富数码论坛经验能起…...
魔域开服需要什么样的配置
魔域是一个非常受玩家喜欢的游戏,是一款大型魔幻题材的网络游戏,关于魔族入侵亚特大陆的故事,玩家在游戏里扮演不同的角色捍卫大陆安全,很多玩家想要更多的体验就会选择开新服,今天就让小编来讲一讲魔域开服要什么配置…...
RestClient
什么是RestClient RestClient 是 Elasticsearch 官方提供的 Java 低级 REST 客户端,它允许HTTP与Elasticsearch 集群通信,而无需处理 JSON 序列化/反序列化等底层细节。它是 Elasticsearch Java API 客户端的基础。 RestClient 主要特点 轻量级ÿ…...
简易版抽奖活动的设计技术方案
1.前言 本技术方案旨在设计一套完整且可靠的抽奖活动逻辑,确保抽奖活动能够公平、公正、公开地进行,同时满足高并发访问、数据安全存储与高效处理等需求,为用户提供流畅的抽奖体验,助力业务顺利开展。本方案将涵盖抽奖活动的整体架构设计、核心流程逻辑、关键功能实现以及…...
阿里云ACP云计算备考笔记 (5)——弹性伸缩
目录 第一章 概述 第二章 弹性伸缩简介 1、弹性伸缩 2、垂直伸缩 3、优势 4、应用场景 ① 无规律的业务量波动 ② 有规律的业务量波动 ③ 无明显业务量波动 ④ 混合型业务 ⑤ 消息通知 ⑥ 生命周期挂钩 ⑦ 自定义方式 ⑧ 滚的升级 5、使用限制 第三章 主要定义 …...
通过Wrangler CLI在worker中创建数据库和表
官方使用文档:Getting started Cloudflare D1 docs 创建数据库 在命令行中执行完成之后,会在本地和远程创建数据库: npx wranglerlatest d1 create prod-d1-tutorial 在cf中就可以看到数据库: 现在,您的Cloudfla…...
最新SpringBoot+SpringCloud+Nacos微服务框架分享
文章目录 前言一、服务规划二、架构核心1.cloud的pom2.gateway的异常handler3.gateway的filter4、admin的pom5、admin的登录核心 三、code-helper分享总结 前言 最近有个活蛮赶的,根据Excel列的需求预估的工时直接打骨折,不要问我为什么,主要…...
土地利用/土地覆盖遥感解译与基于CLUE模型未来变化情景预测;从基础到高级,涵盖ArcGIS数据处理、ENVI遥感解译与CLUE模型情景模拟等
🔍 土地利用/土地覆盖数据是生态、环境和气象等诸多领域模型的关键输入参数。通过遥感影像解译技术,可以精准获取历史或当前任何一个区域的土地利用/土地覆盖情况。这些数据不仅能够用于评估区域生态环境的变化趋势,还能有效评价重大生态工程…...
UR 协作机器人「三剑客」:精密轻量担当(UR7e)、全能协作主力(UR12e)、重型任务专家(UR15)
UR协作机器人正以其卓越性能在现代制造业自动化中扮演重要角色。UR7e、UR12e和UR15通过创新技术和精准设计满足了不同行业的多样化需求。其中,UR15以其速度、精度及人工智能准备能力成为自动化领域的重要突破。UR7e和UR12e则在负载规格和市场定位上不断优化…...
Rapidio门铃消息FIFO溢出机制
关于RapidIO门铃消息FIFO的溢出机制及其与中断抖动的关系,以下是深入解析: 门铃FIFO溢出的本质 在RapidIO系统中,门铃消息FIFO是硬件控制器内部的缓冲区,用于临时存储接收到的门铃消息(Doorbell Message)。…...
10-Oracle 23 ai Vector Search 概述和参数
一、Oracle AI Vector Search 概述 企业和个人都在尝试各种AI,使用客户端或是内部自己搭建集成大模型的终端,加速与大型语言模型(LLM)的结合,同时使用检索增强生成(Retrieval Augmented Generation &#…...
华硕a豆14 Air香氛版,美学与科技的馨香融合
在快节奏的现代生活中,我们渴望一个能激发创想、愉悦感官的工作与生活伙伴,它不仅是冰冷的科技工具,更能触动我们内心深处的细腻情感。正是在这样的期许下,华硕a豆14 Air香氛版翩然而至,它以一种前所未有的方式&#x…...
