move base全解

news2024/9/8 12:28:43

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.cpp

4 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: false

controller_frequency: 5.0
controller_patience: 3.0

planner_frequency: 1.0
planner_patience: 5.0

oscillation_timeout: 8.0
oscillation_distance: 0.3

base_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.coloradmin.cn/o/1703107.html

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

相关文章

数组-两个升序数组中位数

一、题目描述 二、解题思路 (一).基本思想&#xff1a; 如果列表总长度allsize( arr1.size()arr2.size() ) 为奇数时&#xff0c;中位数位置应该在两个列表排序后的第 allsize/2 位置处&#xff0c;如果allsize为偶数&#xff0c;中位数应该取 (allsize/2)-1 和 allsize/2 的…

python数据类型之列表

目录 1.创建列表 2.列表基础操作 常用操作 对列表元素顺序随机打乱 列表下标和切片 字符串分割为列表 列表位移 列表切片替换 3.列表内置方法 4.列表排序 简单排序 使用key参数按指定规则排序 二维列表排序 自定义排序规则函数 5.列表排序算法 选择排序 柱状图…

4-主窗口

4-主窗口 1、简介2 菜单栏、工具栏、状态栏2.1 菜单栏2.2 QAction2.3 工具栏2.4 状态栏 3 混合方式UI设计 1、简介 QMainWindow是一个为用户提供主窗口程序的类&#xff0c;包含一个菜单栏、多个工具栏、多个停靠控件、一个状态栏以及一个中心控件&#xff0c;是许多应用程序&…

宝塔部署前后端分离项目手册

文章目录 安装宝塔安装环境开始部署1. 前端Vue项目1.先本地启动前端项目&#xff08;记住端口号&#xff09;2.打包前端项目3.上传前端项目4.创建PHP站点5.安全里开放端口号6.测试前端 2. 后端boot项目1. 先在本地跑起来2.修改数据库的配置信息3. 项目打包4. nohup启动项目4.1 …

2024年必看!会声会影神器升级,让你的视频制作技能直线上升

在数字媒体内容呈现爆炸式增长的今天&#xff0c;无论是个人还是企业&#xff0c;都开始重视视频制作与编辑的质量。一款优秀的视频编辑软件&#xff0c;不仅需要具备强大的功能&#xff0c;更需要提供直观、高效的用户体验。在这样的背景下&#xff0c;会声会影2024应运而生&a…

《开发问题解决》Window下7z解压:cannot create symbolic link : 客户端没有所需的特权

问题描述&#xff1a; 今天使用7z来解压东西的是突然出现这个问题。 问题解决&#xff1a; download直接下载到c盘中&#xff0c;由于所在文件夹有权限限制。无法进行正常解压。 7.zip解压时使用管理员权限进行解压&#xff0c;解压时使用管理员权限。即如图 使用管理员权限重…

基于飞书机器人跨账号消息提醒

事情的起因是飞书中不同的账号不能同时登录&#xff0c;虽然可以在飞书的账号切换页面看到其他账号下是否有消息提醒&#xff08;小红点&#xff09;&#xff0c;但是无法实现提醒功能&#xff0c;很不优雅&#xff0c;因此本文尝试提出一种新的方式实现不同账号之间的提醒功能…

基于Go实现的分布式主键系统

基于Go实现的分布式主键系统 摘要 随着互联网的发展&#xff0c;微服务得到了快速的发展&#xff0c;在微服务架构下&#xff0c;分布式主键开始变得越来越重要。目前分布式主键的实现方式颇多&#xff0c;有基于数据库自增的、基于UUID的、基于Redis自增的、基于数据库号段的…

时空AI软件:地理信息与遥感领域的智慧引擎

在地理信息与遥感技术的广阔疆域&#xff0c;时空AI软件如同一颗璀璨新星&#xff0c;将时空信息与智能深度融合&#xff0c;驱动着地理信息分析、决策支持、环境监测、城市规划等领域的深刻变革。本文将深入剖析其技术核心、应用实例、未来趋势&#xff0c;探索时空AI软件如何…

OrangePi Kunpeng Pro 开发板测评及Python开发实测

一、背景 首先感谢 创新乐知通过CSDN 邀请本人&#xff0c;参与这次 评测活动。这块开发板是香橙派联合华为精心打造&#xff0c;具有超强算力的鲲鹏开发板。本人使用最多的还是树莓派系列的板子&#xff0c;国产板子特别是华为为核心的板子还是头一次使用&#xff0c;特别感兴…

使用 Spring Cloud Alibaba AI 构建 RAG 应用

作者&#xff1a;姬世文 背景介绍 RAG&#xff08;Retrieval Augmented Generation&#xff09; 检索增强生成&#xff08;RAG&#xff09;是一种用于将数据与人工智能模型集成的技术。在 RAG 工作流程中&#xff0c;第一步将文档数据加载到矢量数据库&#xff08;例如 Redi…

【Day8:JAVA字符串的学习】

目录 1、常用API2、String类2.1 String类的特点2.2 String类的常见构造方法2.3 String类的常见面试题&#xff1a;2.3.1 面试题一&#xff1a;2.3.2 面试题二&#xff1a;2.3.3 面试题三&#xff1a;2.3.4 面试题四&#xff1a; 2.4 String类字符串用于比较的方法2.5 String类字…

万博智云×华为云 | HyperBDR云容灾上架,开启联营联运新篇章

日前&#xff0c;万博智云HyperBDR云容灾正式入驻华为云云商店&#xff0c;成为华为云基础软件领域联营联运合作伙伴。通过联营联运&#xff0c;双方将进一步加深在产品、解决方案、渠道拓展等多方面的强强联合&#xff0c;为企业提供更加安全、高效的数据保护解决方案&#xf…

halcon 传统缺陷检测

一、电路检测 算子解释 dyn_threshold *dyn_threshold 利用局部阈值分割图像*OrigImage (input_object)&#xff1a;原始图像*ThresholdImage (input_object)&#xff1a;处理后图像&#xff08;一般采用滤波处理&#xff09;*RegionDynThresh (output_object)&#xff1…

GpuMall智算云:QwenLM/Qwen1.5/Qwen1.5-7B-Chat

Qwen 是阿里巴巴集团 Qwen 团队的大型语言模型和大型多模态模型系列&#xff0c;现在大型语言模型已经升级到 Qwen1.5 版本。 GpuMall智算云 | 省钱、好用、弹性。租GPU就上GpuMall,面向AI开发者的GPU云平台 无论是语言模型还是多模态模型&#xff0c;都在大规模的多语言和多模…

新楚文化知网收录文学艺术类期刊投稿

《新楚文化》是由国家新闻出版总署批准&#xff0c;湖北省文学艺术界联合会主管&#xff0c;湖北今古传奇传媒集团有限公司主办的正规期刊。主要刊登文化、文学、艺术类稿件&#xff1b;包括传统文化、非遗、历史文化、地方文化、中外友好文化交流、文学作品研究、艺术研究等方…

20240527每日前端-------聊聊前端input file 文件框“取消”按钮事件

文件选择窗口 正常我们使用input type"file"属性上传文件&#xff0c;会唤起系统的文件选择器如下&#xff1a; 打开按钮 可以通过change事件监听&#xff1a; // 增加的部分&#xff1a;创建 loading 实例变量 let loadingInstance;let box document.createEl…

流量分析入门

什么是流量分析 通过捕捉网络中流动的数据包&#xff0c;查看里面的数据和协议&#xff0c;流量分析和各种数据的统计来发现网络运行中的问题&#xff0c;在ctf中一般是一个包含流量数据的 PCAP 文件。 [陇剑杯 2021]签到 1.题目问我们正在进行的事什么协议的攻击 2.打开wire…

Spring Boot开发中常用注解总结【建议收藏】

Spring Boot 是一款非常流行的 Java 框架&#xff0c;其注解用法复杂而丰富。 在介绍 Spring Boot 的注解之前&#xff0c;我们需要先了解 Spring框架中的 AOP&#xff08;面向切面编程&#xff09;概念。 Spring 的 AOP 可以帮助开发者实现一些非业务功能的代码&#xff0c;如…

Vue3:封装Table 表格组件

组件官网 elementPlus : 点击跳转 封装组件 创建新的组件文件: Table.vue <!-- PropTableS &#xff1a; 父组件传递过来的数据 (对象)PropTableS.tables : 父组件传递的对象中 存放表格每行显示的数据PropTableS.keyS &#xff1a; 父组件传递过来的对象&#xff0c;里…