move base全解

0. 简介

之前我们专门有一节讲到了《move_base源码学习》。主要介绍了MoveBase基类中函数的大概意思以及调用的方式。move_base是ROS下关于机器人路径规划的中心枢纽。它通过订阅激光雷达、map地图、amcl的定位等数据,然后规划出全局和局部路径,再将路径转化为机器人的速度信息,最终实现机器人导航。下面是move_base的整个框架。

1. 代码详解

1.1 代码结构

$ tree .
.
├── cfg
│   └── MoveBase.cfg
├── CHANGELOG.rst
├── CMakeLists.txt
├── include
│   └── move_base
│       └── move_base.h
├── package.xml
├── planner_test.xml
└── src├── move_base.cpp└── move_base_node.cpp4 directories, 8 files

如右侧代码所示,我们通过Git工具把navigation从github上拉下来,并查看包move_base的目录结构。涉及到的文件和目录并没有多少。

其中子目录cfg中只有一个MoveBase.cfg的文件,实际上它是一个python的脚本,用于动态的修改运行节点的参数。与导航控制的实现无关,这里不再赘述。

子目录include中的move_base.h和src目录下的move_base.cpp一起定义和实现了我们要研究的导航框架类MoveBase。而源文件move_base_node.cpp是ROS系统的节点实现, 它实例化了MoveBase,并开启了ROS的消息循环。

CHANGELOG.rst是更新日志,记录了move_base的历次版本的修改内容。package.xml是ROS系统用于描述包的基本信息的文件,其中记录了包的名称、作者信息、以及依赖关系。

文件planner_test.xml实际上是一个launch文件,是一个以PR2机器人为平台测试规划器的demo,对于我们而言没有什么用处。

CMakeLists.txt是CMake的编译指导文件,描述了如何把源文件编译成实际运行的节点move_base。下面是从中截取的一段代码片段,我们可以看到move_base.cpp被编译成为一个库, 而实际的可执行文件move_base则是由move_base_node.cpp生成的。

        add_library(move_base src/move_base.cpp)target_link_libraries(move_base ${Boost_LIBRARIES} ${catkin_LIBRARIES})add_dependencies(move_base ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})add_executable(move_base_node src/move_base_node.cpp)add_dependencies(move_base_node ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})target_link_libraries(move_base_node move_base)set_target_properties(move_base_node PROPERTIES OUTPUT_NAME move_base)

1.2 代码解析

以下是MoveBase的构造函数,为了方便本文的写作,我将它的语句顺序做了适当的调整,不影响整个系统的运行。如下面的代码片段所示,在一开始对一系列的成员变量赋予了初值:

  • tf_是坐标变换TF2的接口对象;
  • as_则是Action服务器;
  • planner_costmap_ros_是用于全局规划器的代价地图对象;
  • controller_costmap_ros_则是局部规划器所用的代价地图对象;
  • bgp_loader_是装载全局规划器插件的工具;
  • blp_loader_是装载局部规划器插件的工具;
  • planner_plan_, latest_plan_ 和controller_plan_是三个记录规划结果的缓存;
  • runPlanner_, setup_, p_freq_change_, c_freq_change_, new_global_plan_则是一些控制和反映MoveBase系统状态的布尔变量。
        MoveBase::MoveBase(tf2_ros::Buffer& tf) :tf_(tf), as_(NULL), planner_costmap_ros_(NULL), controller_costmap_ros_(NULL),bgp_loader_("nav_core", "nav_core::BaseGlobalPlanner"),blp_loader_("nav_core", "nav_core::BaseLocalPlanner"), recovery_loader_("nav_core", "nav_core::RecoveryBehavior"),planner_plan_(NULL), latest_plan_(NULL), controller_plan_(NULL),runPlanner_(false), setup_(false), p_freq_change_(false), c_freq_change_(false), new_global_plan_(false){

在构造函数的一开始,定义了两个ROS的句柄,用于获取节点参数,订阅和发布主题。以下面的第13和14行为例,MoveBase从参数服务器中获取了全局规划器和局部规划器的名称, 如果系统中没有定义这些参数,将以默认值"navfn/NavfnROS"和"base_local_planner/TrajectoryPlannerROS"完成初始化工作。还有很多其它参数需要配置,这里不再一一介绍。

            ros::NodeHandle private_nh("~");ros::NodeHandle nh;std::string global_planner, local_planner;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"));// 省略其它加载参数的语句

通过在一开始获取的全局规划器名称global_planner构造全局规划器,并用刚刚构建的全局代价地图完成对其的初始化操作。整个过程在一个try-catch语句块中完成,如果出现异常将退出整个系统。

            // 全局规划器try {planner_ = bgp_loader_.createInstance(global_planner);planner_->initialize(bgp_loader_.getName(global_planner), planner_costmap_ros_);} catch (const pluginlib::PluginlibException& ex) {ROS_FATAL("Failed to create the %s planner, are you sure it is properly registered and that the containing library is built? Exception: %s", global_planner.c_str(), ex.what());exit(1);}

以类似的套路,MoveBase还构建了局部代价地图和局部规划器的对象。

            // 局部代价地图和局部规划器controller_costmap_ros_ = new costmap_2d::Costmap2DROS("local_costmap", tf_);controller_costmap_ros_->pause();try {tc_ = blp_loader_.createInstance(local_planner);tc_->initialize(blp_loader_.getName(local_planner), &tf_, controller_costmap_ros_);} catch (const pluginlib::PluginlibException& ex) {ROS_FATAL("Failed to create the %s planner, are you sure it is properly registered and that the containing library is built? Exception: %s", local_planner.c_str(), ex.what());exit(1);}

该规划方法具体实现在 navigation/navfn中,标志在文件 navigation/navfn/bgp_plugin.xml中。这也是每一个插件必须要有的

  <class name="navfn/NavfnROS" type="navfn::NavfnROS" base_class_type="nav_core::BaseGlobalPlanner">

该方法的核心调用在move_base.cpp下

// 函数 MoveBase::makePlan()下
planner_->makePlan(start, goal, plan)


详细的内容和结构可以参考:《move_base源码学习》以及《ROS DWA局部路径规划原理详解+源码分析》

2. 参数配置

启动move_base的launch,包括解析map,move_base和amcl定位三个部分,这构成了一个完整的框架,下面我们主要来看move_base.launch里的配置。

<launch><param name="use_sim_time" value="false" /><!-- EDIT THIS LINE TO REFLECT THE NAME OF YOUR OWN MAP FILE Can also be overridden on the command line --><arg name="map" default="test_map.yaml" /><!-- Run the map server with the desired map --><node name="map_server" pkg="map_server" type="map_server" args="$(find dart_nav)/maps/dart.yaml"/> <!-- Start move_base  --><include file="$(find dart_nav)/launch/tb_move_base_test.launch" /><!-- Fire up AMCL --><include file="$(find dart_nav)/launch/tb_amcl.launch" /> </launch>

下面是move_base.launch内的配置:

在这里插入图片描述

<launch><node pkg="move_base" type="move_base" respawn="false" name="move_base" output="screen" clear_params="true"><rosparam file="$(find dart_nav)/config1/move_base_params.yaml" command="load" ns="global_costmap" /><rosparam file="$(find dart_nav)/config1/move_base_params.yaml" command="load" ns="local_costmap" /><rosparam file="$(find dart_nav)/config1/local_costmap_params.yaml" command="load" /><rosparam file="$(find dart_nav)/config1/global_costmap_params.yaml" command="load" /><rosparam file="$(find dart_nav)/config1/teb_local_planner_params.yaml" command="load" /><param name="base_global_planner" value="global_planner/GlobalPlanner"/> <param name="planner_frequency" value="1.0" /><param name="planner_patience" value="5.0" /><param name="base_local_planner" value="teb_local_planner/TebLocalPlannerROS" /><param name="controller_frequency" value="15.0" /><param name="controller_patience" value="15.0" /><rosparam file="$(find dart_nav)/config1/costmap_conversion_params.yaml" command="load" /></node></launch>

如上所示,我使用的是global_planner这个包,它默认使用的是dijkstra,当然也可以使用A*全局路径规划,局部路径规划我使用的是teb,同样需要配置上面第3行到第7行的一些yaml,这些yaml是costmap和planner的一些配置文件。上图已经展示了对应部分的配置代表的含义,下面我们来主要看一下local_costmap_params.yaml和global_costmap_params.yaml。这里配置了上面提到的各个层(layers)的使用。

2.1 move_base_params.yaml

配置文件内容如下:

#FileName: move_base_params.yaml 
#Copyright: 2016-2018 ROS小课堂www.corvin.cn
#Author: corvin
#Description:
# move_base软件包的通用配置参数,现在依次解释每个参数意义:
#   shutdown_costmaps:当move_base在不活动状态时,是否关掉costmap.
#   controller_frequency:向底盘控制移动话题cmd_vel发送命令的频率.
#   controller_patience:在空间清理操作执行前,控制器花多长时间等有效控制下发.
#   planner_frequency:全局规划操作的执行频率.如果设置为0.0,则全局规划器仅
#       在接收到新的目标点或者局部规划器报告路径堵塞时才会重新执行规划操作.
#   planner_patience:在空间清理操作执行前,留给规划器多长时间来找出一条有效规划.
#   oscillation_timeout:执行修复机制前,允许振荡的时长.
#   oscillation_distance:来回运动在多大距离以上不会被认为是振荡.
#   base_local_planner:指定用于move_base的局部规划器插件名称.
#   base_global_planner:指定用于move_base的全局规划器插件名称.
#History:
# 20180726: initial this comment.
#shutdown_costmaps: falsecontroller_frequency: 5.0
controller_patience: 3.0planner_frequency: 1.0
planner_patience: 5.0oscillation_timeout: 8.0
oscillation_distance: 0.3base_local_planner: "dwa_local_planner/DWAPlannerROS"
base_global_planner: "global_planner/GlobalPlanner"

下面来依次解释下各参数的意义,其中base_local_planner和base_global_planner我们可以替换自己的算法:

  • shutdown_costmaps:当move_base在不活动状态时,是否关掉costmap.
  • controller_frequency:向底盘控制移动话题cmd_vel发送命令的频率.
  • controller_patience:在空间清理操作执行前,控制器花多长时间等有效控制下发.
  • planner_frequency:全局规划操作的执行频率.如果设置为0.0,则全局规划器仅在接收到新的目标点或者局部规划器报告路径堵塞时才会重新执行规划操作.
  • planner_patience:在空间清理操作执行前,留给规划器多长时间来找出一条有效规划.
  • oscillation_timeout:执行修复机制前,允许振荡的时长.
  • oscillation_distance:来回运动在多大距离以上不会被认为是振荡.
  • base_local_planner:指定用于move_base的局部规划器名称.
  • base_global_planner:指定用于move_base的全局规划器插件名称.

…详情请参照古月居

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

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

相关文章

2024年03月 Python(三级)真题解析#中国电子学会#全国青少年软件编程等级考试

Python等级考试(1~6级)全部真题・点这里 一、单选题(共25题,共50分) 第1题 在Python中,hex(2023)的功能是?( ) A:将十进制数2023转化成十六进制数 B:将十进制数2023转化成八进制数 C:将十六进制数2023转化成十进制数 D:将八进制数2023转化成十进制数 答案:A …

东莞MES管理系统在电子工厂的益处

东莞MES管理系统对东莞电子企业带来了许多好处&#xff0c;包括但不限于以下几点&#xff1a; 提高生产效率&#xff1a;MES系统可以优化生产计划、监控生产过程&#xff0c;提高生产效率&#xff0c;减少生产中的浪费和停机时间&#xff0c;提高产能利用率。 优化库存管理&a…

洛谷 CF1209D Cow and Snacks

题目来源于&#xff1a;洛谷 题目本质&#xff1a;并查集 解题思路&#xff1a; 我们以每种化为一个点&#xff0c;以每个客人喜欢的两朵花给两朵花连一条无向边。则会出现一定数目的连通块&#xff0c;连通块总个数为 ans。 对每个连通块进行分析&#xff1a;第一个客人买走…

指纹识别经典图书、开源算法库、开源数据库

目录 1. 指纹识别书籍 1.1《精通Visual C指纹模式识别系统算法及实现》 1.2《Handbook of Fingerprint Recognition》 2. 指纹识别开源算法库 2.1 Hands on Fingerprint Recognition with OpenCV and Python 2.2 NIST Biometric Image Software (NBIS) 3. 指纹识别开源数…

马斯克:AI时代人人高收入,不需要工作,商品服务不再短缺,可能性80%

当前人工智能现状和未来如何&#xff1f;AI时代下&#xff0c;人类未来会发生哪些变化&#xff1f; 埃隆马斯克&#xff08;Elon Musk&#xff09;在2024 VivaTech大会上分享了关于地球未来的诸多愿景。 投资作业本课代表摘录了其中的要点&#xff0c;分享给大家&#xff1a…

ROS | 自动导航

保存&加载地图&#xff1a; image:地图文件 resolution:地图分辨率&#xff08;珊格地图&#xff09; origin&#xff1a;地图左下标 第三个参数是偏转角度 加载创建好的yaml文件&#xff1a; 年轻人第一次导航&#xff1a; 全局规划器&#xff1a; 代价地图设置参数&#…

QQ名片满级会员展示生成HTML源码

源码介绍 QQ名片满级会员展示生成HTML源码&#xff0c;源码由HTMLCSSJS组成&#xff0c;双击html文件可以本地运行效果&#xff0c;也可以上传到服务器里面&#xff0c;保存素材去选择QQ个性名片-选择大图模板-把图上传照片墙即可 源码效果 源码下载 蓝奏云&#xff1a;http…

Habicht定理中有关子结式命题3.4.6的证明

个人认为红色区域有问题&#xff0c;因为 deg ⁡ ( ϕ ( S j ) ) r \deg{\left( \phi\left( S_{j} \right) \right) r} deg(ϕ(Sj​))r&#xff0c;当 i ≥ r i \geq r i≥r时&#xff0c; s u b r e s i ( ϕ ( S j 1 ) , ϕ ( S j ) ) subres_{i}\left( \phi(S_{j 1}),\p…

C++进阶 | [4] map and set

摘要&#xff1a;set&#xff0c;multiset&#xff0c;map&#xff0c;multimap 前言 1. 容器 序列式容器&#xff1a;只存储数据&#xff0c;数据之间无关联关系。例如&#xff0c;vector、list、deque、……关联式容器&#xff1a;不仅存储数据&#xff0c;且数据之间有关联…

AI智能体|扣子Coze文生图功能接入微信公众号

大家好&#xff0c;我是无界生长。 AI智能体&#xff5c;扣子Coze文生图功能接入微信公众号本文分享了如何将Coze平台的文生图功能接入微信公众号的详细操作流程&#xff0c;包括创建图像流、创建并配置Bot、设置提示词和开场白、调试、发布等步骤。如果看完还没学会的话&…

stream-并行流

定义 常规的流都是串行的流并行流就是并发的处理数据&#xff0c;一般要求被处理的数据互相不影响优点&#xff1a;数据多的时候速度更快&#xff0c;缺点&#xff1a;浪费系统资源&#xff0c;数据少的时候开启线程更耗费时间 模版 Stream<Integer> stream1 Stream.of…

ELK 日志监控平台(一)- 快速搭建

文章目录 ELK 日志监控平台&#xff08;一&#xff09;- 快速搭建1.ELK 简介2.Elasticsearch安装部署3.Logstash安装部署4.Kibana安装部署5.日志收集DEMO5.1.创建SpringBoot应用依赖导入日志配置文件 logback.xml启动类目录结构启动项目 5.2.创建Logstash配置文件5.3.重新启动L…

wordpress教程视频 wordpress教程网盘 wordpress教程推荐wordpress教程网

WordPress&#xff0c;作为一款强大且灵活的开源内容管理系统&#xff0c;已成为许多网站开发者与运营者的首选。其强大的功能、丰富的插件以及易于上手的特点&#xff0c;使得无论是初学者还是专业开发者都能轻松构建出个性化的网站。然而&#xff0c;对于初学者来说&#xff…

亚马逊高效广告打法及数据优化,亚马逊高阶广告打法课

课程下载&#xff1a;https://download.csdn.net/download/m0_66047725/89342733 更多资源下载&#xff1a;关注我。 课程内容&#xff1a; 001.1-亚马逊的广告漏斗和A9算法的升级变化.mp4 002.2-流量入口解析和广告的曝光机制.mp4 003.3-标签理论 .mp4 004.4-不同广告类…

在未来你将何去何从?

在数字化的浪潮中&#xff0c;信息技术行业无疑是推动全球经济和社会发展的重要动力。随着科技的不断迭代与进步&#xff0c;云计算、大数据、人工智能&#xff08;AI&#xff09;、物联网&#xff08;IoT&#xff09;、5G通信和区块链等技术已经深入到我们生活的每一个角落&am…

计算机专业必考之计算机指令设计格式

计算机指令设计格式 例题&#xff1a; 1.设相对寻址的转移指令占3个字节&#xff0c;第一字节为操作码&#xff0c;第二&#xff0c;第三字节为相对偏移量&#xff0c; 数据在存储器以低地址为字地址的存放方式。 每当CPU从存储器取出一个字节时候&#xff0c;自动完成&…

Java实现图书系统

首先实现一个图书管理系统,我们要知道有哪些元素? 1.用户分成为管理员和普通用户 2.书:书架 书 3.操作的是: 书架 目录 第一步:建包 第二步:搭建框架 首先:完成book中的方法 其次:完成BookList 然后:完成管理员界面和普通用户界面 最后:Main 第三步:细分方法 1.退…

【数学建模】碎纸片的拼接复原

2013高教社杯全国大学生数学建模竞赛B题 问题一模型一模型二条件设立思路 问题求解 问题一 已知 d i d_i di​为第 i i i张图片图片的像素矩阵 已知 d i d_i di​都是 n ∗ m n*m n∗m二维矩阵 假设有 N N N张图片 模型一 我们认为对应位置像素匹配为 d i [ j ] [ 1 ] d k…

访问构造方法(反射)

文章目录 前言一、反射是什么&#xff1f;二、访问构造方法 1.Constructor对象的获取方法2.Constructor方法的使用总结 前言 Java的反射机制可以实现访问、检测和修改Java对象本身信息的功能&#xff0c;在java.lang.reflect包下提供此功能。可以使程序员更加深入地控制程序的运…

openflow协议抓包分析

1、准备实验拓扑&#xff1a; 在Mininet环境中创建一个简单的SDN拓扑&#xff0c;包括控制器、交换机、主机等。 确保拓扑能够正常运行&#xff0c;SDN交换机与控制器建立连接。 采用主机Ubuntu22.04主机&#xff0c;IP地址是192.168.87.130&#xff0c;安装opendaylight控制…