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

两份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)这个函数循环执行的频率。每次循环都会调用layeredCostmap的updateMap,将各个layer的数据合并算出结果。publishfrequency用来控制向外publishcostmap的频率。所以增大update_frequency频率会加快内部的地图合成速度。增大publish_frequency会加快发送给rviz的速度。

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

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

width: 4.0

height: 4.0

resolution: 0.05 //

transform_tolerance: 0.5//这个是Costmap2DROS::getRobotPose函数获取基于globalframe的robotpose所耗时间的一个阈值,超过这个阈值就会有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中的odom这个globalframe怎么来的,其实就是坐标系。

kobuki的odometry.cpp中advertise了一个topic叫做”odom”,其实产生的topic叫做/mobile_base/odom,然后kobuki_node的launch文件将其从新remap到了odom上:

./navigation-full/kobuki/kobuki_node/src/library/odometry.cpp:76: odom_publisher = nh.advertise<nav_msgs::Odometry>("odom",50); // topic name and queue size

./navigation-full/kobuki/kobuki_node/launch/minimal.launch:11: <remap from="mobile_base/odom" to="odom"/>

这个是topic,不是frame,他是用来发送里程信息的。



我们可以用rostopicinfo看究竟是谁建立的这个topic.

Odometry.cpp中,向tf不断发送transform信息。这个transform信息的构成:parentframe是odom,childframe是base_footprint.这个transform数据就是告诉系统,基于base_footprint的坐标系的位置相对于odomframe坐标系的关系,transform的origin里面的x,y代表childframe base_footprint原点相对于parentframe odom的原点的偏移,也就是childframe原点在parentframe中的坐标。此外transform里还保存一份旋转角度。这就建立的odom和base_footprint的关联。而base_footprint这个frame是定义在kobuki的urdf里面的。在odometry.cpp中当机器人的位置更新时,会调用不断向tf发送这个transform。因为从kobuki的代码研究发现,odometry.cpp拿到的poseupdate的数据并不是一个累积的相对有某个初始坐标点的数据,而是相对于底座的中心的在很短时间的偏移值,但是,Odometry::update函数将poseupdate叠加到pose里面,所以pose是累积数据(经测试kobuki底座,查看其/odom数据发现其x坐标已知递增,所以pose应该是累积数据),pose作为transform里面的偏移,可以推测出odom坐标系可能就是机器人启动时的开始位置,是固定的,而base_footprint坐标系应该是随着机器人移动的。构造这个transfrom使用这样的数据,并且明确表示该transform的frameid是odom而childframe id是base_footprint,那么就是说这个偏移是base_footprint相对于odomframe的偏移了。base_footprint代表了机器人的当前位置。



特别重要:

看一个transform的例子:

child frame名字在最后。

StampedTransform(consttf::Transform& input, const ros::Time& timestamp, conststd::string & frame_id, const std::string & child_frame_id):

这个transform叫做parentframe到childframe的transform.

也就是说一个transform结构体代表的是从parentframe到childframe的转换,其中的数值x,y代表了childframe坐标原点在parentframe中的坐标。

里面包含的偏移值应该是childframe坐标原点在parentframe坐标系中的坐标。





这个transform发送给tf后,就建立了odom和base_footprint的转换关系。

经验:一般来说,在一个transform结构里,origin的x,y值代表childframe坐标系原点在parentframe坐标系中的位置。

void Odometry::publishTransform(const geometry_msgs::Quaternion&odom_quat)

{

if (publish_tf == false)

return;

//这里的odom_trans的parentframe就是odom,child frame就是base_footprint.

odom_trans.header.stamp = ros::Time::now();

odom_trans.transform.translation.x = pose.x();//这里的pose包含了机器人相对于初始位置的移动位移。

odom_trans.transform.translation.y = pose.y();

odom_trans.transform.translation.z = 0.0;

odom_trans.transform.rotation = odom_quat;

odom_broadcaster.sendTransform(odom_trans);

}



另外,我们看到,在globalcostmap的参数里,globalframe是map.可见localmap和globalmap的基本坐标系都是不一样的。localmap相对于odom,而globalmap相对于map.



我们在slam_gmapping里面找到了对mapframe的使用,并且看到他不断发送mapto odom的transform给tf,这样就能建立map和odom坐标系之间的转换。那么他是如何算出mapto odom的转换的?



在SlamGMapping::laserCallback函数中,当接收到一份激光数据后:



GMapping::OrientedPoint odom_pose;



if(addScan(*scan, odom_pose))//odom_pose应该是laser的中心原点相对于odomframe的坐标。,这个函数将激光数据交给了内部的fastslam算法模块,产生了对应的particle等数据。

{



GMapping::OrientedPoint mpose= gsp_->getParticles()[gsp_->getBestParticleIndex()].pose;

gsp就是gridslam processor,是算法的核心。

mpose是粒子中最好的粒子的地图坐标,可能也就是laser中心相对于map的坐标。

ROS_DEBUG("new best pose: %.3f %.3f %.3f", mpose.x,mpose.y, mpose.theta);

ROS_DEBUG("odom pose: %.3f %.3f %.3f", odom_pose.x,odom_pose.y, odom_pose.theta);

ROS_DEBUG("correction: %.3f %.3f %.3f", mpose.x -odom_pose.x, mpose.y - odom_pose.y, mpose.theta - odom_pose.theta);



至此,我们有了laser中心相对于map,和相对于odom的坐标,那么我们就能够算出map和odom之间的转换。

tf::Transform laser_to_map= tf::Transform(tf::createQuaternionFromRPY(0, 0, mpose.theta),tf::Vector3(mpose.x,mpose.y, 0.0)).inverse();

tf::Transform odom_to_laser =tf::Transform(tf::createQuaternionFromRPY(0, 0, odom_pose.theta),tf::Vector3(odom_pose.x, odom_pose.y, 0.0));



map_to_odom_mutex_.lock();

map_to_odom_ = (odom_to_laser * laser_to_map).inverse();

map_to_odom_mutex_.unlock();

}





void SlamGMapping::publishTransform()

{

map_to_odom_mutex_.lock();

ros::Time tf_expiration = ros::Time::now() +ros::Duration(tf_delay_);

tfB_->sendTransform( tf::StampedTransform (map_to_odom_,tf_expiration,map_frame_,odom_frame_));

map_to_odom_mutex_.unlock();

}

下面继续分析这几个transform是如何算出来的。如何使用的。

map_to_odom,从名字上看就知道这个transform的parentframe是map,child frame是odom.并且transform中的坐标值代表odom坐标系原点在map坐标系中的位置。

map_to_odom可以从(odom_to_laser* laser_to_map).inverse()计算而来。

odom_to_laser,从名字上看出parentframe是odom,child frame是laser.这个transform中包含的坐标值是laser坐标系原点在odom坐标系中的位置。

可以把laser_frame中0,0原点转换成基于odomframe,得到的坐标就是laser原点相对于odomframe的偏移:

//基于laserframe的坐标原点就是centerredlaser pose

centered_laser_pose_ =tf::Stamped<tf::Pose>(tf::Transform(tf::createQuaternionFromRPY(0,0,angle_center),

tf::Vector3(0,0,0)),ros::Time::now(), laser_frame_);



//将基于laserframe的坐标原点转换成基于odomframe的坐标值保存在odom_pose里。这个坐标值在数值上其实等于parentframe是odom,child frame是laserframe,从odom frame到laserframe的transform的数值,所以下面第2行可以直接用这个数值构造一个transform结构。

tf_.transformPose(odom_frame_, centered_laser_pose_, odom_pose);



tf::Transform odom_to_laser= tf::Transform(tf::createQuaternionFromRPY(0, 0, odom_pose.theta),tf::Vector3(odom_pose.x,odom_pose.y, 0.0));





laser_to_map从名字上看,parentframe是laser,child frame是map,比较违反常理,于是可通过计算出map_to_laser后inverse也可以得到。

map_to_laser,从名字上看,就是parentframe是map,child frame是laser坐标原点,其中的坐标值应该代表laserframe原点在map坐标系中的位置。

在建图时,particles中的最好的particle的位置就是基于map坐标的laser原点的坐标:

GMapping::OrientedPoint mpose= gsp_->getParticles()[gsp_->getBestParticleIndex()].pose;

那么以mpose的坐标值作为偏移值构建的transform结构就代表了从parentframe map, 到child frame也就是Laserframe的transform,也就是map_to_laser.因为我们最终要的是lase_to_map的transform,所以需要翻转一下:

tf::Transform laser_to_map =tf::Transform(tf::createQuaternionFromRPY(0, 0, mpose.theta),tf::Vector3(mpose.x, mpose.y, 0.0)).inverse();



需要研究gsp,particles什么东西,这就需要研究gridfast slam算法了。

fastslam算法采用粒子滤波器,这里的particle就是粒子。

Gsp 是gridslam processor,包含了具体的fastslam算法,fastslam算法中采用粒子过滤算法,将移动中的机器人和检测到的数据转换成一系列路径中的粒子,我怀疑每个粒子关联一系列的从该粒子位置观察到的景象,把这些数据融合,过滤,合并得到地图。

ROS导航系列(三):costmap2D详解 功能包costmap2D提供一种 阅读详情

相关推荐

slam--代价地图---参数说明

代价地图---参数说明

majingming123的博客 5510

costmap代价地图学习

为什么要有costmap ROS里的地图的概念,地图就是/map这个topic,它也是一张图片,一个像素代表了实际的一块面积,用灰度值来表示障碍物存在的可能性。然而在实际的导航任务中,光有一张地图是不够的,机器人需要能动态的把障碍物加入,或者清楚已经不存在的障碍物,有些时候还要在地图上标出危险区域,为路径规划提供更有用的信息。 因为导航的需要,所以出现了代价地图。你可以将代价地图理解为,在/map...

单线程的Daniel的博客 4598

global_costmap_params.yaml参数解析

global_costmap: # global_frame:代价地图应该运行的坐标系, 将选择/map 坐标系。 global_frame: /map # robot_base_frame:代价地图应该为机器人的基座的坐标系。 应设为 base_footprint。 robot_base_frame: /base_footprint # update_frequency:决定了代价地图更新的频率。 数值越大, CPU 负担会越重。 # 根据传感器数据,全局地图更新的频率,单位为赫兹。这个数值越大,你的..

Studying…… 3054

讯飞线上赛总结(二)

讯飞线上赛总结(二)——全局路径规划

aidimoli123的博客 897

local_costmap_params.yaml参数解释

【代码】local_costmap_params.yaml。

weixin_72050316的博客 458

Arduino-CRSF库详解:嵌入式端CRSF协议解析与ELRS接收机集成

CRSF(Crossfire Serial Protocol)是一种面向FPV无人机的轻量级、高实时性串行通信协议,采用单总线异步传输与8位CRC-8校验机制,广泛应用于遥控链路与遥测交互。其核心在于帧同步(0xC8起始字节)、反相逻辑电平及无重传的广播式设计,对嵌入式平台的UART精度、电平匹配和状态机健壮性提出严苛要求。Arduino-CRSF库正是为资源受限MCU(如ESP32、STM32、ATmega328P)提供零配置、中断安全的协议解析能力,封装了CRC查表计算、超时恢复、多级同步验证等关键机制

weixin_35756690的博客 417

ROS中路径规划、全局代价地图、局部代价地图\Navigation功能包

ROS中路径规划、全局代价地图、局部代价地图

weixin_42301918的博客 4040

Kali使用Metasploit内、外网渗透windows系统

Metasploit是一个免费的、可下载的框架,通过它可以很容易地获取、开发并对计算机软件漏洞实施攻击。它本身附带数百个已知软件漏洞的专业级漏洞攻击工具。当H.D. Moore在2003年发布Metasploit时,计算机安全状况也被永久性地改变了。 一、(内网渗透)内网英文缩写WAN;内网又称局域网 局域网的覆盖范围一般是方圆几千米之内,其具备的安装便捷、成本节约、扩展方便等特点使其在各类办公室内运用广泛。局域网可以实现文件管理、应用软件共享、打印机共享等功能,在使用过程当中,通过维护局域网网...

QQ670663的博客 2万+

costmap配置教程和详细理解

此软件包提供2D成本图的实现,该实现从世界各地接收传感器数据,构建数据的2D或3D占用网格(取决于是否使用基于体素的实现),并基于占用网格和用户指定的膨胀半径在2D成本图中膨胀成本。 此软件包还支持基于map_server的成本图初始化、基于滚动窗口的成本图以及传感器主题的基于参数的订阅和配置。 在上图中,红色单元格表示成本图中的障碍物,蓝色单元格表示机器人内切半径膨胀的障碍物,红色多边形表示机器人的足迹。 为了使机器人避免碰撞,机器人的足迹不能与红细胞相交,机器人的中心点不能越过蓝细胞。 在Hydro版

ahelloyou的博客 5244

安卓风控对抗实战:如何用AOSP定制ROM绕过Momo、AIDA64等检测(从环境搭建到设备画像)

本文详细解析了如何通过定制AOSP ROM绕过Momo、AIDA64等安卓风控检测工具的设备指纹识别。从环境搭建到硬件参数修改,再到内核级特征混淆,提供了一套完整的底层对抗方案,显著提升设备伪装通过率。

weixin_30687051的博客 490

【Coze 扣子案例】第 23 期・商业篇:一键获取精准商机,自动化招标信息查询与分析

通过地区和项目类型等多维度组合查询全国招标信息网数据,实现招标公告的快速定位。自动解析招标公告内容,提取关键信息,并生成结构化摘要。帮助企业高效获取精准商机,提升市场竞争力,降低人工成本,解决 “信息过载” 与 “精准匹配难” 的双重问题。

weixin_72689845的博客 1928

ROS:move_base中yaml文件解析:base_local_planner、global_costmap、local_costmap、base_local_planner

设置了代价地图中障碍物信息的阀值# obstacle_range:确定了最大范围传感器读数,这将导致障碍物被放入代价地图中。# 此处设置为2.5m,意为着机器人只会更新其地图包含距离移动基座2.5m以内的障碍物信息# raytrace_range:确定了用于清楚制定范围外的空间。# 此处设置为3m,意味机器人将尝试清除3m外的空间# robot_radius:设置机器人半径# inflation_radius:设定代价地图的膨胀半径。

weixin_44190648的博客 2548

【MATLAB】STM32电机调速闭环控制工程

本文提出了一种基于MATLAB仿真与STM32实现的直流电机闭环PID调速控制方案。通过MATLAB建立电机数学模型并进行参数整定,仿真验证了增量式PID算法在启停、稳态和抗扰动方面的优越性能。基于STM32F103搭建了硬件系统,实现了编码器测速、定时中断控制、PWM输出等功能。实测表明,该系统转速超调<2%、稳态误差±2r/min,具备快速响应和强抗扰能力。相比开环控制,闭环调速显著提升了动态性能和稳态精度。方案提供了完整的仿真代码和嵌入式工程源码,可直接应用于智能小车、工业传动等场景,具有较高的

unber的博客 50

move base参数解析及经验总结

gmapping建图,然后可以利用建好的图来定位和避障。如果你来做这个任务,会很自然的想到,静态障碍和动态障碍分层处理,这也就是为啥会有,静态层、障碍物层和膨胀层。而让机器人到达目标位置,当前点和目标点之间如何到达,需要一个全局的“天眼”——global_planner,在全局规划的过程中,遇到障碍了,需要局部做调整,因此引入了local planer。......

酸梅果茶的博客 3798

还原 Windows 环境变量的默认值

有时候,我们可能需要还原环境变量的默认值,以修复可能的配置问题或恢复系统的正常运行。如果您只想还原某个特定的环境变量,可以跳过删除其他变量的步骤,仅删除需要还原的变量即可。在“环境变量”对话框中,继续向下滚动到“系统变量”部分。请注意,在执行以下步骤之前,您应该备份当前的环境变量设置,以便在需要时可以还原。在删除所有需要还原的环境变量后,点击“确定”按钮关闭“环境变量”对话框。在“用户变量”部分,选择需要还原的变量,然后点击“删除”按钮。在“高级”选项卡下方的“环境变量”部分,点击“环境变量”按钮。

PvDeveloper的博客 6342

从养虾到退坑:OpenClaw 卸载不留残留,一步到位

文章摘要: 本文提供OpenClaw软件的完整卸载指南,适用于Windows、macOS和Linux系统。内容包含卸载前的数据备份步骤(配置文件、日志、插件列表),以及详细的卸载脚本。Windows版通过批处理文件删除程序文件、注册表项和环境变量;macOS/Linux版则提供shell脚本,涵盖服务停止、软件包卸载、配置清理等步骤。特别强调要删除所有用户数据(包括多用户环境),确保系统无残留。文末建议重启计算机以使更改生效,实现"一步到位"的彻底卸载。

一键难忘的博客 300

【代价地图Costmap&代价地图参数设置】

简单讲解了代价地图的含义与作用,并且通过仿真演示了代价地图在机器人路径导航规划中的使用。

weixin_46187287的博客 4074

【Halcon-2D测量】set_metrology_object_param 函数功能(用于配置计量对象常规参数)

HALCON算子 set_metrology_object_param 是2D计量模块的核心配置工具,用于动态修改计量对象的测量区域、边缘检测和几何拟合参数。该算子需在检测前调用,支持批量或单独修改对象参数,包含三类关键参数:测量区域(如长度、间距)、边缘检测(如平滑Sigma、阈值)和几何拟合(如RANSAC阈值、最小分数)。使用时需注意参数互斥规则(如measure_distance优先于num_measures)和多线程同步要求。算子无输出参数,仅修改计量模型内部状态,需配合apply_metrolo

weixin_45590420的博客 294

costmap解析及笔记 优快云

costmap_2d包提供了一种可配置框架来维护机器人在代价地图上应该如何导航的信息。代价地图使用来自传感器的数据和来自静态地图中的信息,通过costmap_2d::Costmap2DROS 来存储和更新现实世界中的障碍物信息。costmap_2d::Costmap2DROS给用户提供了纯2D的接口,这意味着障碍只能在列上进行。例如,在XY平面上位于同一位置的桌子和鞋,虽然在Z方向上有差异但是他们在costmap_2d::Costmap2DROS对象代价地图中对应的cell上拥有相同的代价值。这种设计对平面

qq_43355922的博客 2028

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

move_base配置参数解析

move_base实际需要设置6部分参数: move_base自身参数 全局代价地图(global_costmap) 局部代价地图(local_costmap) 全局规划器(global_planner) 局部规划器(local_planner) 恢复机制(recovery_behaviors) 以上参数在move_base节点加载时全部加载,用以下参数文件格式: <launch> <node pkg="move_base" type="move_base" respawn="fa

酸梅果茶的博客 7273

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

ros 建图导航参数配置

目录 1.平滑减速功能包 yocs_velocity_smoother Gmapping 建图参数 Navigation 导航避障集合 Move_base 参数 Amcl 蒙特卡罗定位 全局路径规划: global_planner 局部路径规划:base_local_planner 局部路径规划: teb_local_planner 局部路径规划:dwa_global_planner 代价地图 costmap_2d 1.平滑减速功能包 yocs_velocity_smoother .

feidaji的博客 4794

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

ROS下用gmapping 构建实验室地图的实现

ROS下用gmapping 来实现构建实验室地图       由于move_base类已经配置好,可用了,所以就来尝试用gmapping构建地图了,看看效果。下面来说下具体的过程。        Gmapping 构建地图需要里程计的信息的,所以配置了下move_base.xml文件。像hector_slam ,也尝试用了来构建地图,这个不用里程计的信息,手持便可以做到,但是有了会更准确。因为

lanhuadechenmo的博客 4万+

ROS机器人自主探索建图仿真explore_lite及rrt_exploration实践

ubuntu20.04中ros noetic下explore_lite和rrt_exploration自主探索算法的实践

weixin_73831908的博客 4942

ROS 教程之 navigation :在 catkin 环境下创建costmap layer plugin

转自白巧克力亦唯心,保存下来方便自己学习! 在做机器人导航的时候,肯定见到过global_costmap和local_costmap。global_costmap是为了全局路径规划服务的,如从这个房间到那个房间该怎么走。local_costmap是为局部路径规划服务的,如机器人局部有没有遇到行人之类的障碍。costmap就是栅格图,每个栅格里存放着障碍物信息。但是hydro里的costmap不是...

shixiaolu63的博客 1351

ECharts地图Json数据在线下载

项目中使用到了图表插件ECharts,不得不说是真的好用,但是用到地图部分时,竟然没有地图的json数据包,网上、GitHub搜索,找到要么几年前的数据,要么就是需要积分注册账号,里面的行政区域和当下已经有了很多不一致,阿里云里边有地图选择器,里边有各省市区县的的地图json。 阿里云地图选择器地址:http://datav.aliyun.com/tools/atlas 有了这个数据,在结合ECharts,完美解决项目中关于前端各种地图的问题。 ...

qq_44645104的博客 3494
上一篇: movebase导航和地图数据的使用 - 6 local planner如何使用global planner计算出的路径规划和自己的local costmap数据完成避障
下一篇: movebase导航和地图数据的使用 - 8 导航中recovery的逻辑
csshell2002
博客等级 码龄11年 30粉丝 41原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值