45.在ROS中实现global planner(1)
前文move_base介绍(4)简单介绍move_base
的全局路径规划配置,接下来我们自己实现一个全局的路径规划
1. move_base规划配置
ROS1
的move_base
可以配置选取不同的global planner
和local planner
, 默认move_base.cpp#L70中可以看到是读取该参数决定的`
private_nh.param("base_global_planner", global_planner, std::string("navfn/NavfnROS"));private_nh.param("base_local_planner", local_planner, std::string("base_local_planner/TrajectoryPlannerROS"));
我们可以通过配置base_global_planner
和base_local_planner
参数修改不同的算法
ros1 navigation中提供了3种base_global_planner
, 分别是
navfn/NavfnROS
global_planner::GlobalPlanner
carrot_planner/CarrotPlanner
下面我们自己实现一个全局的路径规划,并在模拟器测试其执行效果
2. 实现原理
2.1 加载对象
private_nh.param("base_global_planner", global_planner, std::string("navfn/NavfnROS"));
上面我们已经知道 通过参数配置来决定加载哪一个全局规划器,继续跟踪可以看到
查看源码 move_base.cpp#L125 & move_base.h#L210
pluginlib::ClassLoader<nav_core::BaseGlobalPlanner> bgp_loader_;
planner_ = bgp_loader_.createInstance(global_planner);
pluginlib
可以参见这里
pluginlib::ClassLoader<nav_core::BaseGlobalPlanner>::createInstance
根据输入参数名,加载so,并且获取到库的导出类,且创建该类的一个实例planner_
即为该指向该实例的指针, 有了这个对象,就可以通过该成员干活了
2.2 BaseGlobalPlanner接口
planner_
定义在move_base.h#L185
boost::shared_ptr<nav_core::BaseGlobalPlanner> planner_;
前面返回的planner_
类型可以看到是nav_core::BaseGlobalPlanner
类型,我们先来看下该类,在nav_core#L48
class BaseGlobalPlanner{public:virtual bool makePlan(const geometry_msgs::PoseStamped& start, const geometry_msgs::PoseStamped& goal, std::vector<geometry_msgs::PoseStamped>& plan) = 0;virtual bool makePlan(const geometry_msgs::PoseStamped& start, const geometry_msgs::PoseStamped& goal, std::vector<geometry_msgs::PoseStamped>& plan,double& cost){cost = 0;return makePlan(start, goal, plan);}virtual void initialize(std::string name, costmap_2d::Costmap2DROS* costmap_ros) = 0;virtual ~BaseGlobalPlanner(){}protected:BaseGlobalPlanner(){}};
可以看到该类是一个接口类,需要继承该接口做相应的实现,主要接口比较简单,就两个, initialize
和makePlan
, 顾名思义一个初始化,一个规划路径
initialize
传入了name
, 以及地图信息makePlan
传入起点,目标点,返回plan
我们也可以看看在move_base
对应接口的调用
-
move_base.cpp#L126
在创建完成立即调用完成初始化 -
move_base.cpp#L496
进行全局路径规划
if(!planner_->makePlan(start, goal, plan) || plan.empty()){...}
``
在MoveBase::makeplan调用了该函数,返回的plan, 保存后用于local planner的输入
3. 实现global planner
3.1 实现步骤
实现一个自己的全局规划需要下面几个步骤
- 继承
nav_core::BaseGlobalPlanner
实现接口 - 导出该实现类
- 添加
plugin.xml
插件描述文件并导出 - 修改
move_base
配置使用
3.2 实现接口
- 创建包
mkdir -p ~/pibot_ros/ros_ws/src
cd ~/pibot_ros/ros_ws/src
catkin_create_pkg sample_global_planner
创建完成添加一个cpp和h文件,新增一个类继承与nav_core::BaseGlobalPlanner
上面已经看到该接口定义 我们继承并对两个接口initialize
和makePlan
实现即可
initialize
初始化我们暂时先空实现
void GlobalPlanner::initialize(std::string name, costmap_2d::Costmap2DROS *costmap_ros)
{
}
makePlan
规划路径的接口给我们输入起点和终点,我们输出规划出的plan(如可以规划,同时返回true,反之返回false), 我们暂时不考虑具体实现,输出一条从起点到终点的直线路径,这应该是初中几何知识,比较简单如下
bool GlobalPlanner::makePlan(const geometry_msgs::PoseStamped &start,const geometry_msgs::PoseStamped &goal, std::vector<geometry_msgs::PoseStamped> &plan)
{ROS_INFO("make plan start:[%f %f], goal:[%f %f]", start.pose.position.x, start.pose.position.y, goal.pose.position.x, goal.pose.position.y);plan.clear();float yaw = atan2(goal.pose.position.y - start.pose.position.y, goal.pose.position.x - start.pose.position.x);int n = 0;float goal_distance = sqrt(pow((start.pose.position.x - goal.pose.position.x), 2) + pow((start.pose.position.y - goal.pose.position.y), 2));float delta = 0.1; // 间隔delta输出start至end的直线上的点 我们间隔0.1取直线上的所有点,放到输出的参数plan里while (n * delta < goal_distance){geometry_msgs::PoseStamped pose = goal;pose.pose.position.x = (n * delta) * cos(yaw) + start.pose.position.x;pose.pose.position.y = (n * delta) * sin(yaw) + start.pose.position.y;++n;plan.push_back(pose);}plan.push_back(goal); // 这里别忘了终点return !plan.empty();
}
- 添加相应的CMakeList.txt
## Specify additional locations of header files
## Your package locations should be listed before other locations
include_directories(include${catkin_INCLUDE_DIRS}
)## Declare a C++ library
add_library(${PROJECT_NAME}src/planner_node.cpp
)## Add cmake target dependencies of the library
## as an example, code may need to be generated before libraries
## either from message generation or dynamic reconfigure
add_dependencies(${PROJECT_NAME} ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
target_link_libraries(${PROJECT_NAME} ${catkin_LIBRARIES})
3.3 导出类
参考navigation里面, 添加宏导出该类
PLUGINLIB_EXPORT_CLASS(sample_global_planner::GlobalPlanner, nav_core::BaseGlobalPlanner)
3.3 添加plugin.xml
添加一个bgp_plugin.xml
<library path="lib/libsample_global_planner"><class name="sample_global_planner/GlobalPlanner" type="sample_global_planner::GlobalPlanner" base_class_type="nav_core::BaseGlobalPlanner"><description>A sample implementation of a grid based planner </description></class>
</library>
3.4 编译
cd ~/pibot_ros/ros_ws
catkin_make
3.5 修改配置测试
修改~/pibot_ros/src/pibot_simulator/move_base_params.yaml
# base_global_planner: global_planner/GlobalPlanner
base_global_planner: sample_global_planner/GlobalPlanner
global_planner/GlobalPlanner
----> sample_global_planner/GlobalPlanner
- 启动模拟器
pibot_simulator
- 查看当前的
global_planner
❯ rosparam get /move_base/base_global_planner
sample_global_planner/GlobalPlanner # 输出sample_global_planner/GlobalPlanner表示插件已经被正确加载
- 启动rviz发送点位,选点导航测试
pibot_view
3.6 路径显示
上面测试可以看到可以规划已经完成, dwa的局部规划已经启动, 为了方便查看全局全规划路径的输出,我们在makeplan
完成后发出path
的topic
void GlobalPlanner::publishPlan(const std::vector<geometry_msgs::PoseStamped> &path)
{nav_msgs::Path gui_path;gui_path.poses.resize(path.size());gui_path.header.frame_id = frame_id_;gui_path.header.stamp = ros::Time::now();for (unsigned int i = 0; i < path.size(); i++){gui_path.poses[i] = path[i];}plan_pub_.publish(gui_path);
}
把 rviz
Global Map
和Local Map
中的dwa planner
关闭, 只显示Full Plan
修改
move_base_params.yaml
中planner_frequency
值, 0 只规划一次, >0 规划频率
3.7 测试结果
- 选择空旷区域,可以看到可以正常规划,同时控制也可以启动完成,到达目的地
- 跨过障碍物,可以看到规划出路径,显然无法控制过去
4. 总结
本文简单实现了一个global planner
的插件,显然实际没啥用,不过可以作为一个模板,基于该模板实现自己的算法。后面我们将基于该模板实现可用的全局规划。
本文代码见sample_global_planner
相关文章:

45.在ROS中实现global planner(1)
前文move_base介绍(4)简单介绍move_base的全局路径规划配置,接下来我们自己实现一个全局的路径规划 1. move_base规划配置 ROS1的move_base可以配置选取不同的global planner和local planner, 默认move_base.cpp#L70中可以看到是…...

Java中导入、导出Excel——HSSFWorkbook 使用
一、介绍 当前B/S模式已成为应用开发的主流,而在企业办公系统中,常常有客户这样子要求:你要把我们的报表直接用Excel打开(电信系统、银行系统)。或者是:我们已经习惯用Excel打印。这样在我们实际的开发中,很多时候需要…...
c#数据结构-列表
列表 数组可以管理大量数组,但缺点是无法更变容量。 创建小了不够用,创建大了浪费空间。 无法预测需要多少大小的时候,可能范围越大,就会浪费越多的空间。 所以,你可能会想要一种可以扩容的东西,代替数组…...

Sa-Token实现分布式登录鉴权(Redis集成 前后端分离)
文章目录1. Sa-Token 介绍2. 登录认证2.1 登录与注销2.2 会话查询2.3 Token 查询3. 权限认证3.1 获取当前账号权限码集合3.2 权限校验3.3 角色校验4. 前后台分离(无Cookie模式)5. Sa-Token 集成 Redis6. SpringBoot 集成 Sa-Token6.1 创建项目6.2 添加依…...

leaflet显示高程
很多地图软件都能随鼠标移动动态显示高程。这里介绍一种方法,我所得出的。1 下载高程数据一般有12.5m数据下载,可惜精度根本不够,比如mapbox的免费在线的,或者91卫图提供百度网盘打包下载的,没法用,差距太大…...

电子学会2022年12月青少年软件编程(图形化)等级考试试卷(三级)答案解析
目录 一、单选题(共25题,共50分) 二、判断题(共10题,共20分) 三、编程题(共3题,共30分) 青少年软件编程(图形化)等级考试试卷(三级) 一、单选题(共25题,共50分) 1. 默认小猫角色…...

ubuntu 驱动更新后导致无法进入界面
**问题描述: **安装新ubuntu系统后未禁止驱动更新导致无法进入登录界面。 解决办法: 首先在进入BIOS中,修改设置以进行命令行操作,然后卸载已有的系统驱动,最后安装新的驱动即可。 开机按F11进入启动菜单栏…...

解决访问GitHub时出现的“您的连接不是私密连接”的问题!
Content问题描述解决办法问题描述 访问github出现您的连接不是私密连接问题,无法正常访问,如下图所示: 解决办法 修改hosts文件。hosts文件位于:C:\Windows\System32\drivers\etc\hosts 首先在https://www.ipaddress.com/查找两…...

初识数据仓库
一、什么是数据仓库数据库 --> OLTP:(on-line transaction processing)翻译为联机事务处理记录某类业务事件的发生,如购买行为,银行交易行为,当行为产生后,系统会记录是谁在何时何地做了何事…...
FilenameUtils工具类部分源码自研
FilenameUtils工具类部分源码自研getExtension(orgFileName)源码如下逐行分析getExtension(orgFileName)源码如下 public class FilenameUtils {public static int indexOfExtension(String fileName) throws IllegalArgumentException {if (fileName null) {return -1;} els…...

【前端领域】3D旋转超美相册(HTML+CSS)
世界上总有一半人不理解另一半人的快乐。 ——《爱玛》 目录 一、前言 二、本期作品介绍 3D旋转相册 三、效果展示 四、详细介绍 五、编码实现 index.html style.css img 六、获取源码 公众号获取源码 获取源码?私信?关注?点赞&…...

Java——聊聊JUC中的原子变量类
文章目录: 1.什么是原子变量类? 2.AtomicInteger(基本类型原子变量类) 3.AtomicIntegerArray(数组类型原子变量类) 4.AtomicMarkableReference(引用类型原子变量类) 5.AtomicInteger…...

elasticsearch索引与搜索初步
ES支持cURL交互,使用http请求完成索引和搜索操作,最基本的格式如下:创建索引我们可以使用PUT方法创建索引,通过指定“索引”、“类型”、“文档ID”锁定文档,通过参数指定文档的数据。红色部分的路由分别指定了“索引”…...
【Python】多线程与多进程学习笔记
本文是一篇学习笔记,学习内容主要来源于莫凡python的文档:https://mofanpy.com/tutorials/python-basic/threading/thread 多线程 线程基本结构 开启子线程的简单方式如下: import threadingdef thread_job():print(This is a thread of %…...
MySQL基础知识点
1.在Linux上安装好MySQL8.0之后,默认数据目录的具体位置是什么?该目录下都保存哪些数据库组件?在目录/usr/sbin、/usr/bin、/etc、/var/log 分别保存哪些组件? 答:默认数据目录:/var/lib/mysql。保存有mysq…...
代码随想录算法训练营第五十九天| 583. 两个字符串的删除操作、72. 编辑距离
Leetcode - 583dp[i][j]代表以i-1结尾的words1的子串 要变成以j-1结尾的words2的子串所需要的次数。初始化: "" 变成"" 所需0次 dp[0][0] 0, ""变成words2的子串 需要子串的长度的次数,所以dp[0][j] j, 同理,dp[i][0] …...

指针引用字符串问题(详解)
通过指针引用字符串可以更加方便灵活的使用字符串。 字符串的引用方式有两种,下面简单介绍一下这两种方法。 1.用字符数组来存放一个字符串。 1.1 可以通过数组名和下标来引用字符串中的一个字符。 1.2 还可以通过数组名和格式声明符%s输出整个字符串。 具体实…...

数据结构——哈夫曼树编程,输入权值实现流程图代码
一、须知 本代码是在数据结构——哈夫曼树编程上建立的,使用时需将代码剪切到C等软件中。需要输入权值方可实现流程图,但是还需要按照编程换算出的结果自己用笔画出流程图。 下面将代码粘贴到文章中,同时举一个例子:二、代…...

【MySQL】 事务
😊😊作者简介😊😊 : 大家好,我是南瓜籽,一个在校大二学生,我将会持续分享Java相关知识。 🎉🎉个人主页🎉🎉 : 南瓜籽的主页…...

Java测试——selenium常见操作(2)
这篇博客继续讲解一些selenium的常见操作 selenium的下载与准备工作请看之前的博客:Java测试——selenium的安装与使用教程 先创建驱动 ChromeDriver driver new ChromeDriver();等待操作 我们上一篇博客讲到,有些时候代码执行过快,页面…...

国防科技大学计算机基础课程笔记02信息编码
1.机内码和国标码 国标码就是我们非常熟悉的这个GB2312,但是因为都是16进制,因此这个了16进制的数据既可以翻译成为这个机器码,也可以翻译成为这个国标码,所以这个时候很容易会出现这个歧义的情况; 因此,我们的这个国…...

日语AI面试高效通关秘籍:专业解读与青柚面试智能助攻
在如今就业市场竞争日益激烈的背景下,越来越多的求职者将目光投向了日本及中日双语岗位。但是,一场日语面试往往让许多人感到步履维艰。你是否也曾因为面试官抛出的“刁钻问题”而心生畏惧?面对生疏的日语交流环境,即便提前恶补了…...
Java 语言特性(面试系列2)
一、SQL 基础 1. 复杂查询 (1)连接查询(JOIN) 内连接(INNER JOIN):返回两表匹配的记录。 SELECT e.name, d.dept_name FROM employees e INNER JOIN departments d ON e.dept_id d.dept_id; 左…...
uni-app学习笔记二十二---使用vite.config.js全局导入常用依赖
在前面的练习中,每个页面需要使用ref,onShow等生命周期钩子函数时都需要像下面这样导入 import {onMounted, ref} from "vue" 如果不想每个页面都导入,需要使用node.js命令npm安装unplugin-auto-import npm install unplugin-au…...
【位运算】消失的两个数字(hard)
消失的两个数字(hard) 题⽬描述:解法(位运算):Java 算法代码:更简便代码 题⽬链接:⾯试题 17.19. 消失的两个数字 题⽬描述: 给定⼀个数组,包含从 1 到 N 所有…...

蓝桥杯3498 01串的熵
问题描述 对于一个长度为 23333333的 01 串, 如果其信息熵为 11625907.5798, 且 0 出现次数比 1 少, 那么这个 01 串中 0 出现了多少次? #include<iostream> #include<cmath> using namespace std;int n 23333333;int main() {//枚举 0 出现的次数//因…...
从面试角度回答Android中ContentProvider启动原理
Android中ContentProvider原理的面试角度解析,分为已启动和未启动两种场景: 一、ContentProvider已启动的情况 1. 核心流程 触发条件:当其他组件(如Activity、Service)通过ContentR…...

mac:大模型系列测试
0 MAC 前几天经过学生优惠以及国补17K入手了mac studio,然后这两天亲自测试其模型行运用能力如何,是否支持微调、推理速度等能力。下面进入正文。 1 mac 与 unsloth 按照下面的进行安装以及测试,是可以跑通文章里面的代码。训练速度也是很快的。 注意…...

【Post-process】【VBA】ETABS VBA FrameObj.GetNameList and write to EXCEL
ETABS API实战:导出框架元素数据到Excel 在结构工程师的日常工作中,经常需要从ETABS模型中提取框架元素信息进行后续分析。手动复制粘贴不仅耗时,还容易出错。今天我们来用简单的VBA代码实现自动化导出。 🎯 我们要实现什么? 一键点击,就能将ETABS中所有框架元素的基…...

Vue3 PC端 UI组件库我更推荐Naive UI
一、Vue3生态现状与UI库选择的重要性 随着Vue3的稳定发布和Composition API的广泛采用,前端开发者面临着UI组件库的重新选择。一个好的UI库不仅能提升开发效率,还能确保项目的长期可维护性。本文将对比三大主流Vue3 UI库(Naive UI、Element …...