movebase导航和地图数据的使用 - 7 global costmap和local costmap的区别和用途

本文介绍了ROS中movebase的global_costmap和local_costmap的差异,包括它们的参数设置如`update_frequency`、`publish_frequency`、`rolling_window`等。local_costmap用于机器人局部避障,具有`rolling_window`属性,而global_costmap则用于全局路径规划。同时,解析了odom和map坐标系转换的过程,以及如何通过tf广播建立这两个坐标系之间的关系。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

两份costmap如下:

planner_costmap_ros_ = newcostmap_2d::Costmap2DROS("global_costmap", tf_);

controller_costmap_ros_ = newcostmap_2d::Costmap2DROS("local_costmap", tf_);

看看区别:

他们的参数分别如下;

local_costmap_params.yaml:

local_costmap:

global_frame: odom

robot_base_frame: /base_footprint

update_frequency: 5.0

publish_frequency: 2.0

//注意,其实ros里提供了一种cfg机制,可以建立dynamic_reconfigure::Server并设置callback,当配置变化时,会调用callback。那么那些config会被通知到?需要定义一些cfg文件,config文件制定了关心的config参数。在make时,python处理这些cfg文件生成一些cpp的类,这些类就是具体的config类,他们会从rosparam server获取和设置参数,而rosparam中的参数的源头其实都是这里的yaml文件中的参数。所以我们看到的cfg文件中的和这里同名的参数,那只是说明那些自动生成的类会用到我们在yaml中设置的参数。并且设置了默认,最小,最大值等等。这样以来,我们可以有两条获取config的方法,一是直接访问paramserver,一是访问config。数据源头其实都是yaml文件。

//update frequency控制voidCostmap2DROS::mapUpdateLoop(doublefrequency)这个函数循环执行的频率。每次循环都会调用layeredCostmapupdateMap,将各个layer的数据合并算出结果。publishfrequency用来控制向外publishcostmap的频率。所以增大update_frequency频率会加快内部的地图合成速度。增大publish_frequency会加快发送给rviz的速度。

static_map: false //这个参数貌似是老板本的代码遗留物,目前有了plugins项目后,就不再使用这个了

rolling_window: true //这个costmap是否随着robotroll.默认是false.这里因为是local costmap要随着机器人滚动。而globalcostmap就不需要。当滚动时,layeredcostmaporigin要在每次updatemap时都被更新。

width: 4.0

height: 4.0

resolution: 0.05 //

transform_tolerance: 0.5//这个是Costmap2DROS::getRobotPose函数获取基于globalframerobotpose所耗时间的一个阈值,超过这个阈值就会有warning.

plugins:

- {name: obstacle_layer, type: "costmap_2d::VoxelLayer"}

- {name: inflation_layer, type: "costmap_2d::InflationLayer"}







global_costmap_params.yaml:

global_costmap:

global_frame: /map

robot_base_frame: /base_footprint

update_frequency: 1.0

publish_frequency: 0.5

static_map: true

transform_tolerance: 0.5

plugins:

- {name: static_layer, type:"costmap_2d::StaticLayer"}

- {name: obstacle_layer, type:"costmap_2d::VoxelLayer"}

- {name: inflation_layer, type:"costmap_2d::InflationLayer"}





看看缺别,看看如何使用这些参数的。

先来看看localcostmap

<think>我们正在讨论用户订阅`/move_base/global_costmap/costmap`话题时只收到一次数据的问题。根据引用[1][2],我们知道`move_base`是ROS导航的核心节点,负责全局局部路径规划,并发布全局局部代价地图。全局代价地图通常用于全局路径规划,而局部代价地图用于局部避障。 问题分析:为什么只接收到一次数据? 根据ROS的发布-订阅机制,话题的发布频率由发布者决定。在`move_base`节点中,全局代价地图的发布行为受到其配置参数的影响。常见原因如下: 1. **发布频率设置过低或设置为单次发布**:在`global_costmap_params.yaml`配置文件中,`publish_frequency`参数控制发布频率。如果该值设为0,则会周期性发布,而只在特定事件(如地图更新)时发布。此外,还有一个关键参数`always_send_full_costmap`(默认为false)[^2]。当该参数为false时,`move_base`可能只在地图发生变化时才发布更新,而如果地图长时间变,则会发布新数据。 2. **地图更新条件**:全局代价地图通常基于静态地图(如通过`map_server`加载的地图)构建,并叠加一些动态障碍(如通过传感器检测到的静态障碍)。如果环境是静态的,并且机器人没有添加新的障碍信息(例如,全局代价地图的更新层只包括静态层),那么全局代价地图可能会更新,因此会发布新数据。 3. **节点初始化问题**:在`move_base`启动时,它会发布一次全局代价地图。如果后续没有触发更新,则订阅者只会收到这一次数据。 4. **话题的latch(锁定)属性**:在ROS中,发布者可以设置`latch`选项,这样当新的订阅者连接时,会立即收到最后一次发布的消息。但`move_base`在发布全局代价地图时,默认会锁定(除非配置为锁定)。然而,即使锁定,也只是在订阅时收到一次,后续如果没有新数据,也会再收到。 解决方案: 1. **检查参数配置**:确保在`global_costmap_params.yaml`中设置了周期性的发布频率。例如: ```yaml publish_frequency: 1.0 # 每秒发布一次 always_send_full_costmap: true # 每次发布完整地图,而仅仅是变化部分 ``` 注意:`always_send_full_costmap`参数在早期ROS版本中可能默认是false,这可能导致只在地图变化时才发布更新。 2. **确保地图更新**:如果环境是静态的,可以尝试添加一个虚拟的层(如通过`obstacle_layer`)来模拟动态变化,或者确保有传感器数据输入到全局代价地图(虽然通常全局代价地图使用静态层,但也可以配置为包含全局障碍层)。 3. **验证发布者状态**:使用`rostopic hz /move_base/global_costmap/costmap`命令来查看实际的发布频率。如果确实只发布一次,则问题在发布端。 4. **在代码中检查订阅**:确保订阅代码正确,没有在回调函数中意外退出。例如,以下是一个正确的订阅示例: ```python import rospy from nav_msgs.msg import OccupancyGrid def callback(msg): rospy.loginfo("Received a global costmap!") rospy.init_node('listener') rospy.Subscriber("/move_base/global_costmap/costmap", OccupancyGrid, callback) rospy.spin() # 保持节点运行,持续接收 ``` 5. **查看`move_base`日志**:检查`move_base`节点的输出日志,看是否有关于代价地图发布的提示信息。 如果以上方法都能解决问题,可能需要深入`move_base`节点的源代码,特别是`costmap_2d`包中的`Costmap2DPublisher`类,它负责发布代价地图。默认情况下,它会在每次更新后发布,但更新又由`map_update_frequency`参数控制(在`global_costmap_params.yaml`中)。因此,确保更新频率发布频率都设置正确。 注意:全局代价地图的更新通常由静态地图传感器数据(如果配置了全局障碍物层)触发。在静态环境中,如果没有传感器数据输入到全局层,则地图会更新,因此也会发布新数据。 总结:订阅者只收到一次数据的主要原因是全局代价地图没有更新,因此没有新数据发布。通过调整参数强制周期性发布或确保地图有更新可以解决此问题。 引用说明: [^1]: 引用自用户提供的引用[1],说明`move_base`的作用。 [^2]: 引用自用户提供的引用[2],关于`move_base`的配置。</think>### 订阅`/move_base/global_costmap/costmap`只接收一次数据的原因分析 根据您描述的订阅问题,结合ROS导航堆栈的工作原理引用内容[1][2][3],根本原因在于**全局代价地图的发布机制**。以下是具体分析解决方案: --- #### 核心原因:全局代价地图的更新机制 1. **静态地图特性** 全局代价地图(`global_costmap`)主要基于静态地图构建(如`map_server`加载的地图)[^1][^2]。在静态环境中: - 地图数据会频繁更新 - `move_base`仅在**地图初始化完成时发布一次完整地图** - 后续只在检测到**重大变化时更新**(如添加/删除障碍物层) 2. **参数配置影响** 在`global_costmap_params.yaml`中,以下参数控制发布行为: ```yaml publish_frequency: 0.0 # 默认0表示主动发布 always_send_full_costmap: false # 仅在地图变化时发送 ``` 3. **与局部代价地图的差异** | 特性 | 全局代价地图(`global_costmap`) | 局部代价地图(`local_costmap`) | |------|-------------------------------|------------------------------| | 更新频率 | 低频(环境变化时) | 高频(通常10Hz)[^2] | | 数据源 | 静态地图+长期障碍 | 实时传感器数据 | | 发布机制 | 事件触发 | 周期发布 | --- #### 解决方案:强制持续接收数据 ##### 方法1:修改发布参数 在`global_costmap_params.yaml`中添加: ```yaml publish_frequency: 1.0 # 设置1Hz发布频率 always_send_full_costmap: true # 强制发送完整地图 ``` 重启`move_base`节点后,地图将周期性发布。 ##### 方法2:主动触发更新 通过代码模拟环境变化: ```python # 动态添加虚拟障碍物(示例) from geometry_msgs.msg import PointStamped def trigger_update(): pub = rospy.Publisher('/move_base/global_costmap/footprint', PointStamped, queue_size=1) point = PointStamped() point.header.stamp = rospy.Time.now() point.point.x = 1.0 # 虚拟障碍物坐标 point.point.y = 2.0 pub.publish(point) # 在需要时调用 trigger_update() ``` ##### 方法3:RViz可视化验证 在RViz中添加`Map`显示组件: 1. Topic设置为`/move_base/global_costmap/costmap` 2. 勾选**Always Update**选项 3. 移动机器人或添加障碍物观察地图更新 --- #### 根本原因验证 使用诊断命令检查发布状态: ```bash # 查看发布者实际发布频率 rostopic hz /move_base/global_costmap/costmap # 检查参数配置 rosparam get /move_base/global_costmap/publish_frequency ``` 若输出为`0.0`,则确认是参数配置导致单次发布。 --- #### 设计原理说明 全局代价地图设计为低频更新,因为: 1. **计算开销大**:全局路径规划需要处理完整地图 2. **稳定性需求**:频繁更新全局路径会导致机器人抖动[^1] 3. **效率优化**:静态环境无需重复发送相同数据 > **提示**:若需实时获取环境变化,应订阅`/move_base/local_costmap/costmap`(局部代价地图),该话题默认高频更新[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值