ROS1机器人SLAM系列(四):Gmapping算法详解与实战

ROS1机器人SLAM系列(四):Gmapping算法详解与实战

本文将深入讲解Gmapping算法的原理,并通过实战演示如何使用Gmapping进行2D激光SLAM建图。

1. Gmapping算法简介

1.1 什么是Gmapping?

Gmapping是一种基于**粒子滤波(Rao-Blackwellized Particle Filter, RBPF)**的2D激光SLAM算法。它由Giorgio Grisetti等人于2007年提出,是ROS中最经典、应用最广泛的SLAM算法之一。

主要特点

  • 基于粒子滤波的概率框架
  • 适用于2D激光雷达
  • 需要里程计信息
  • 实现成熟,稳定可靠
  • 适合中小规模室内环境

1.2 算法流程概述

Gmapping算法流程

里程计数据

运动预测
Motion Model

粒子集合更新

激光雷达数据

扫描匹配
Scan Matching

观测更新
Sensor Model

粒子权重计算

重采样
Resample

地图更新

2. 核心算法原理

2.1 粒子滤波基础

粒子滤波是一种序贯蒙特卡洛方法,通过一组带权重的粒子来近似表示后验概率分布。

基本思想

  • 每个粒子代表机器人可能的位姿
  • 粒子带有权重,表示该位姿的可信度
  • 通过迭代更新粒子来跟踪机器人位姿

数学表示

P(x_t | z_{1:t}, u_{1:t}) ≈ Σ w_t^{[i]} δ(x_t - x_t^{[i]}) 

其中:

  • x_t^{[i]} 是第i个粒子的位姿
  • w_t^{[i]} 是第i个粒子的权重
  • δ 是狄拉克函数

2.2 Rao-Blackwellized粒子滤波

Gmapping采用RBPF,将SLAM问题分解为:

  1. 位姿估计:使用粒子滤波
  2. 地图构建:在已知位姿的条件下,使用分析方法更新地图

这种分解大大降低了计算复杂度:

P(x_{1:t}, m | z_{1:t}, u_{1:t}) = P(m | x_{1:t}, z_{1:t}) × P(x_{1:t} | z_{1:t}, u_{1:t}) 

2.3 运动模型

Gmapping使用概率运动模型预测粒子位置:

// 简化的运动模型 x'= x + Δx + noise_x y'= y + Δy + noise_y θ' = θ + Δθ + noise_θ 

其中噪声与运动量和参数(srr, srt, str, stt)相关。

2.4 扫描匹配(Scan Matching)

扫描匹配是Gmapping的核心技术,用于精确估计机器人位姿。

步骤

  1. 获取当前激光扫描数据
  2. 与粒子携带的局部地图进行匹配
  3. 找到使匹配度最高的位姿修正

匹配得分计算

score = Σ map[endpoint] × beam_weight 

2.5 权重计算与重采样

权重计算

weight[i] ∝ P(z_t | x_t^{[i]}, m^{[i]})

自适应重采样

Gmapping采用自适应重采样策略,只在粒子退化严重时才进行重采样:

N_eff =1/ Σ(w^{[i]})² if N_eff < threshold:resample()

3. Gmapping的ROS实现

3.1 订阅的话题

话题消息类型说明
/scansensor_msgs/LaserScan激光雷达数据
/tftf/tfMessage坐标变换

必需的TF变换

  • odombase_link:里程计变换
  • base_linklaser:激光雷达位置

3.2 发布的话题

话题消息类型说明
/mapnav_msgs/OccupancyGrid栅格地图
/map_metadatanav_msgs/MapMetaData地图元数据
/tftf/tfMessagemap → odom变换

3.3 提供的服务

服务类型说明
dynamic_mapnav_msgs/GetMap获取当前地图

4. Gmapping参数详解

4.1 粒子滤波参数

# 粒子数量(核心参数)particles:30# 默认30,增大可提高精度但增加计算量# 重采样阈值resampleThreshold:0.5# 有效粒子数比例阈值# 最小得分minimumScore:0.0# 扫描匹配最小得分

参数建议

  • 小场景:30-50个粒子
  • 大场景:80-100个粒子
  • 实时性要求高:减少粒子数

4.2 激光雷达参数

# 最大使用距离maxUrange:80.0# 用于地图构建的最大距离maxRange:80.0# 传感器最大量程# 激光束参数lskip:0# 跳过的激光束数量(降采样)

4.3 运动模型参数

# 里程计误差参数srr:0.1# 平移引起的平移误差srt:0.2# 平移引起的旋转误差str:0.1# 旋转引起的平移误差stt:0.2# 旋转引起的旋转误差

参数说明

  • 值越大,表示里程计误差越大
  • 轮式里程计较准:0.05-0.1
  • 里程计不准:0.2-0.5

4.4 更新频率参数

# 线性运动更新阈值linearUpdate:1.0# 移动1米更新一次# 角度运动更新阈值angularUpdate:0.5# 旋转0.5弧度更新一次# 时间更新阈值temporalUpdate:-1.0# -1表示禁用时间更新# 处理周期throttle_scans:1# 每处理1帧扫描

4.5 地图参数

# 地图分辨率delta:0.05# 每个栅格0.05米# 地图大小(初始)xmin:-100.0ymin:-100.0xmax:100.0ymax:100.0# 占据概率参数occ_thresh:0.25# 占据阈值

4.6 扫描匹配参数

# 似然场参数sigma:0.05# 高斯平滑kernelSize:1# 核大小# 优化迭代次数iterations:5# 扫描匹配迭代次数# 搜索步长lstep:0.05# 线性搜索步长astep:0.05# 角度搜索步长# 搜索范围llsamplerange:0.01# 线性采样范围llsamplestep:0.01# 线性采样步长lasamplerange:0.005# 角度采样范围lasamplestep:0.005# 角度采样步长

5. 实战:使用Gmapping建图

5.1 准备工作

确保已安装必要的包:

# 安装Gmappingsudoaptinstall ros-noetic-gmapping # 安装键盘控制sudoaptinstall ros-noetic-teleop-twist-keyboard # 安装地图服务sudoaptinstall ros-noetic-map-server 

5.2 创建Gmapping Launch文件

创建 gmapping.launch

<launch><!-- Gmapping节点 --><nodepkg="gmapping"type="slam_gmapping"name="slam_gmapping"output="screen"><!-- 基本参数 --><paramname="base_frame"value="base_link"/><paramname="odom_frame"value="odom"/><paramname="map_frame"value="map"/><!-- 激光雷达参数 --><paramname="maxUrange"value="10.0"/><paramname="maxRange"value="12.0"/><paramname="lskip"value="0"/><!-- 粒子滤波参数 --><paramname="particles"value="50"/><paramname="minimumScore"value="50"/><!-- 运动模型参数 --><paramname="srr"value="0.1"/><paramname="srt"value="0.2"/><paramname="str"value="0.1"/><paramname="stt"value="0.2"/><!-- 更新频率 --><paramname="linearUpdate"value="0.5"/><paramname="angularUpdate"value="0.436"/><paramname="temporalUpdate"value="-1.0"/><!-- 地图参数 --><paramname="delta"value="0.05"/><paramname="xmin"value="-50.0"/><paramname="ymin"value="-50.0"/><paramname="xmax"value="50.0"/><paramname="ymax"value="50.0"/><!-- 扫描匹配参数 --><paramname="sigma"value="0.05"/><paramname="kernelSize"value="1"/><paramname="iterations"value="5"/><paramname="lstep"value="0.05"/><paramname="astep"value="0.05"/><paramname="llsamplerange"value="0.01"/><paramname="llsamplestep"value="0.01"/><paramname="lasamplerange"value="0.005"/><paramname="lasamplestep"value="0.005"/></node></launch>

5.3 使用TurtleBot3仿真实战

步骤1:启动仿真环境

# 设置机器人型号exportTURTLEBOT3_MODEL=burger # 启动Gazebo仿真 roslaunch turtlebot3_gazebo turtlebot3_world.launch 

步骤2:启动Gmapping

# 使用TurtleBot3的Gmapping配置 roslaunch turtlebot3_slam turtlebot3_slam.launch slam_methods:=gmapping # 或使用自定义配置 roslaunch my_robot_slam gmapping.launch 

步骤3:启动RViz可视化

# 使用TurtleBot3的RViz配置 roslaunch turtlebot3_gazebo turtlebot3_gazebo_rviz.launch # 在RViz中添加以下显示:# - Map: /map# - LaserScan: /scan# - TF# - RobotModel

步骤4:控制机器人建图

# 键盘遥控 rosrun teleop_twist_keyboard teleop_twist_keyboard.py # 控制键:# u i o# j k l# m , .## i: 前进 ,: 后退# j: 左转 l: 右转# k: 停止

步骤5:保存地图

# 建图完成后保存 rosrun map_server map_saver -f ~/maps/my_map # 会生成两个文件:# - my_map.pgm:地图图像# - my_map.yaml:地图配置

5.4 使用rosbag回放建图

如果有录制的数据包,可以离线建图:

# 播放数据包 rosbag play --clock recorded_data.bag # 启动Gmapping(需要使用仿真时间) roslaunch gmapping.launch use_sim_time:=true 

6. 建图效果优化

6.1 常见问题与解决方案

问题1:地图有重影/不清晰

原因:里程计误差大或参数不匹配

解决方案:

# 增加粒子数particles:80# 调整运动模型参数srr:0.2srt:0.3str:0.2stt:0.3# 降低更新阈值linearUpdate:0.3angularUpdate:0.3

问题2:建图速度慢

原因:粒子数过多或更新过于频繁

解决方案:

# 减少粒子数particles:30# 增加更新阈值linearUpdate:1.0angularUpdate:0.5# 降采样激光数据lskip:1

问题3:地图有漂移

原因:里程计累积误差

解决方案:

# 提高扫描匹配精度minimumScore:100iterations:10# 减小搜索步长lstep:0.02astep:0.02

问题4:无法建图/地图为空

检查项:

# 检查TF树 rosrun tf tf_monitor # 检查必需的TF变换是否存在 rosrun tf tf_echo odom base_link rosrun tf tf_echo base_link laser # 检查激光数据 rostopic echo /scan 

6.2 不同场景的参数建议

小型室内环境(< 100㎡)

particles:30maxUrange:10.0delta:0.05linearUpdate:0.5angularUpdate:0.3

中型室内环境(100-500㎡)

particles:50maxUrange:15.0delta:0.05linearUpdate:0.8angularUpdate:0.4

大型环境(> 500㎡)

particles:100maxUrange:20.0delta:0.1linearUpdate:1.0angularUpdate:0.5

7. Gmapping的优缺点

7.1 优点

  • ✅ 算法成熟,经过大量验证
  • ✅ 实现简单,参数调整直观
  • ✅ 对于中小场景效果良好
  • ✅ 计算资源需求适中
  • ✅ ROS社区支持完善

7.2 缺点

  • ❌ 不支持回环检测
  • ❌ 大场景下粒子数需求高
  • ❌ 依赖较准确的里程计
  • ❌ 只支持2D激光SLAM
  • ❌ 无法处理动态环境

7.3 适用场景

适用不适用
中小型室内环境大规模室外环境
静态环境高度动态环境
有可靠里程计无里程计或里程计很差
实时建图需要极高精度

8. 代码示例:程序中调用Gmapping

8.1 获取地图数据

#!/usr/bin/env python3import rospy from nav_msgs.msg import OccupancyGrid from nav_msgs.srv import GetMap defmap_callback(msg):"""处理地图回调""" width = msg.info.width height = msg.info.height resolution = msg.info.resolution rospy.loginfo(f"地图大小: {width}x{height}, 分辨率: {resolution}m")# 统计占据、空闲、未知栅格 occupied =sum(1for cell in msg.data if cell >50) free =sum(1for cell in msg.data if0<= cell <=50) unknown =sum(1for cell in msg.data if cell ==-1) rospy.loginfo(f"占据: {occupied}, 空闲: {free}, 未知: {unknown}")defget_map_service():"""通过服务获取地图""" rospy.wait_for_service('dynamic_map')try: get_map = rospy.ServiceProxy('dynamic_map', GetMap) response = get_map()return response.mapexcept rospy.ServiceException as e: rospy.logerr(f"服务调用失败: {e}")returnNoneif __name__ =='__main__': rospy.init_node('map_listener')# 方法1:订阅话题 rospy.Subscriber('/map', OccupancyGrid, map_callback)# 方法2:调用服务 current_map = get_map_service() rospy.spin()

8.2 判断建图完成度

#!/usr/bin/env python3import rospy from nav_msgs.msg import OccupancyGrid classMappingMonitor:def__init__(self): self.coverage_history =[] rospy.Subscriber('/map', OccupancyGrid, self.map_callback)defmap_callback(self, msg): total_cells =len(msg.data) known_cells =sum(1for cell in msg.data if cell !=-1) coverage = known_cells / total_cells *100 self.coverage_history.append(coverage)# 判断是否稳定(建图基本完成)iflen(self.coverage_history)>10: recent = self.coverage_history[-10:]ifmax(recent)-min(recent)<0.5: rospy.loginfo(f"建图已稳定,覆盖率: {coverage:.1f}%")if __name__ =='__main__': rospy.init_node('mapping_monitor') monitor = MappingMonitor() rospy.spin()

9. 总结

本文详细介绍了Gmapping算法:

  1. 算法原理:基于RBPF的粒子滤波SLAM
  2. 核心技术:运动模型、扫描匹配、权重计算、重采样
  3. 参数配置:详细解释了各类参数的含义和调整方法
  4. 实战演练:完整的建图流程和优化技巧
  5. 适用场景:明确了Gmapping的优缺点和适用范围

Gmapping作为经典的2D SLAM算法,非常适合学习SLAM的入门者。掌握Gmapping后,下一篇文章将介绍更先进的Cartographer算法。


系列导航:

版权声明:本文为原创文章,转载请注明出处

Read more

WebGIS视角下基孔肯雅热流行风险地区分类实战解析

WebGIS视角下基孔肯雅热流行风险地区分类实战解析

目录 前言 一、关于基孔肯雅热 1、病原学特征 2、流行病学特征 3、疫情处置 4、预防措施 二、流行风险地区空间可视化 1、流行风险地区分类标准 2、空间查询基础 3、Leaflet空间可视化 三、流行风险地区WebGIS展示 1、Ⅰ类地区 2、Ⅱ类地区 3、Ⅲ类地区 4、Ⅳ类地区 四、总结 前言         在全球化与城市化进程不断加速的当下,传染病的传播范围与速度呈现出前所未有的态势,给公共卫生安全带来了严峻挑战。基孔肯雅热作为一种由基孔肯雅病毒引起的急性传染病,近年来在多个地区引发疫情,其传播速度快、感染范围广,且易与其他蚊媒传染病叠加流行,严重威胁着人类健康和社会稳定。准确划分基孔肯雅热流行风险地区,对于制定科学合理的防控策略、优化医疗资源配置以及提高公众防范意识具有至关重要的意义。         本研究旨在通过系统梳理 WebGIS 技术在传染病流行风险评估中的应用现状与优势,结合基孔肯雅热的流行特点和防控需求,构建一套基于

CVE-2026-21962漏洞利用工具:Oracle WebLogic代理插件未授权RCE检测与利用

CVE-2026-21962 - Oracle WebLogic Server Proxy Plug-In RCE 项目描述 该项目提供了一个针对Oracle WebLogic Server代理插件(Proxy Plug-In)中一个关键安全漏洞(CVE-2026-21962)的漏洞利用概念验证(PoC)脚本。该漏洞允许未经验证的远程攻击者通过HTTP协议在受影响的服务器上执行任意操作系统命令,风险等级极高(CVSS 10.0)。 影响组件: * Oracle HTTP Server(版本12.2.1.4.0、14.1.1.0.0、14.1.2.0.0) * Oracle WebLogic Server代理插件(用于Apache HTTP Server和Microsoft IIS)

Gemini 无损去水印神器:基于数学算法的纯前端解决方案

Gemini 无损去水印神器:基于数学算法的纯前端解决方案

🎯 Gemini 无损去水印神器:基于数学算法的纯前端解决方案 🔗 项目地址:gemini-watermark-remover 🌐 在线体验:banana.ovo.re ⭐ 如果觉得有用,请给项目点个 Star! 📖 引言 随着 Google Gemini AI 图像生成功能的普及,越来越多的用户开始使用它来创作各种精美的图片。然而,Gemini 生成的图片右下角都会带有一个半透明的水印 Logo,这在某些场景下可能会影响图片的使用效果。 今天给大家推荐一个开源项目 gemini-watermark-remover,它能够完美无损地移除 Gemini 图片上的可见水印,而且完全在浏览器端运行,无需上传图片到服务器,充分保护用户隐私! ✨ 核心特性 🔒 100% 客户端处理,隐私至上 * 无需后端服务器:所有图片处理都在浏览器本地完成 * 零数据上传:图片永远不会离开你的设备 * 即开即用:打开网页即可使用,无需注册登录 🎯 数学精确,非 AI 模型 * 基于反向 Alpha 混合算法(

WebAssembly (WASM) 运行时沙箱逃逸与内存安全实战研究

前言 1. 技术背景 在现代攻防体系中,WebAssembly (WASM) 正迅速成为一个新的攻击与防御焦点。它最初被设计为浏览器内的高性能代码执行引擎,但如今已广泛应用于服务端(如云原生、边缘计算)、物联网(IoT)和区块链等领域。WASM提供了一个接近原生速度、跨平台的沙箱环境,这使得它成为隔离不可信代码的理想选择。然而,任何沙箱技术都面临着“逃逸”的风险。一旦攻击者成功从WASM沙箱中逃逸,他们便可能在宿主环境(Host Environment)中执行任意代码,构成严重的安全威胁。因此,理解WASM的沙箱机制、攻击向量和防御策略,是现代网络安全攻防不可或缺的一环。 2. 学习价值 掌握WASM的沙箱逃逸与内存安全知识,能让您解决以下关键问题: * 对于攻击方:能够审计和利用WASM应用中的漏洞,发现新的攻击面,尤其是在云原生和边缘计算等前沿领域。 * 对于防御方:能够构建更安全的WASM应用,正确配置和加固WASM运行时,理解潜在威胁并设计有效的检测和缓解措施。 * 对于开发者:能够编写出健壮、安全的WASM模块,避免常见的内存安全陷阱,从源头上杜绝漏洞。 3