跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像AI 生图工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
C++AI算法

ROS1 机器人 SLAM:Gmapping 算法详解与实战

Gmapping 是基于粒子滤波的 2D 激光 SLAM 算法,适用于中小规模室内环境。解析其 RBPF 原理、运动模型及扫描匹配机制,提供 ROS 参数配置指南与 TurtleBot3 建图实战步骤。涵盖常见地图漂移、重影问题的解决方案,并给出 Python 调用地图服务的代码示例,适合 SLAM 入门者掌握核心流程与优化技巧。

人间过客发布于 2026/4/7更新于 2026/7/2534 浏览

ROS1 机器人 SLAM:Gmapping 算法详解与实战

1. Gmapping 算法简介

1.1 什么是 Gmapping?

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

主要特点:

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

Gmapping 的核心流程可以概括为:

  1. 运动预测:利用里程计数据更新粒子集合。
  2. 扫描匹配:将激光雷达数据与粒子携带的局部地图进行匹配。
  3. 观测更新:计算粒子权重并执行重采样。
  4. 地图更新:根据最优位姿更新全局栅格地图。

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 变换:

  • odom → base_link:里程计变换
  • base_link → laser:激光雷达位置
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.0
ymin: -100.0
xmax: 100.0
ymax: 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 准备工作

确保已安装必要的包:

# 安装 Gmapping
sudo apt install ros-noetic-gmapping
# 安装键盘控制
sudo apt install ros-noetic-teleop-twist-keyboard
# 安装地图服务
sudo apt install ros-noetic-map-server
5.2 创建 Gmapping Launch 文件

创建 gmapping.launch:

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

启动仿真环境

首先设置机器人型号并启动 Gazebo 仿真:

export TURTLEBOT3_MODEL=burger
roslaunch turtlebot3_gazebo turtlebot3_world.launch

启动 Gmapping

可以使用 TurtleBot3 的内置配置,或者加载自定义 launch 文件:

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

启动 RViz 可视化

打开 RViz 并添加以下显示项以便观察:

roslaunch turtlebot3_gazebo turtlebot3_gazebo_rviz.launch

在 RViz 中添加:

  • Map: /map
  • LaserScan: /scan
  • TF
  • RobotModel

控制机器人建图

使用键盘遥控机器人移动:

rosrun teleop_twist_keyboard teleop_twist_keyboard.py

控制键说明:

  • u: 前进,,: 后退
  • j: 左转,l: 右转
  • k: 停止

保存地图

建图完成后,使用 map_server 工具保存:

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.2
srt: 0.3
str: 0.2
stt: 0.3
linearUpdate: 0.3
angularUpdate: 0.3

问题 2:建图速度慢

如果粒子数过多或更新过于频繁,会降低性能:

particles: 30
linearUpdate: 1.0
angularUpdate: 0.5
lskip: 1

问题 3:地图有漂移

这通常源于里程计累积误差,提高扫描匹配精度有助于缓解:

minimumScore: 100
iterations: 10
lstep: 0.02
astep: 0.02

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

检查项包括 TF 树和激光数据:

# 检查 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: 30
maxUrange: 10.0
delta: 0.05
linearUpdate: 0.5
angularUpdate: 0.3

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

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

大型环境(> 500㎡):

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

7. Gmapping 的优缺点

7.1 优点
  • ✅ 算法成熟,经过大量验证
  • ✅ 实现简单,参数调整直观
  • ✅ 对于中小场景效果良好
  • ✅ 计算资源需求适中
  • ✅ ROS 社区支持完善
7.2 缺点
  • ❌ 不支持回环检测
  • ❌ 大场景下粒子数需求高
  • ❌ 依赖较准确的里程计
  • ❌ 只支持 2D 激光 SLAM
  • ❌ 无法处理动态环境
7.3 适用场景
适用不适用
中小型室内环境大规模室外环境
静态环境高度动态环境
有可靠里程计无里程计或里程计很差
实时建图需要极高精度

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

8.1 获取地图数据

下面是一个 Python 脚本示例,演示如何订阅地图话题并通过服务获取地图:

#!/usr/bin/env python3
import rospy
from nav_msgs.msg import OccupancyGrid
from nav_msgs.srv import GetMap

def map_callback(msg):
    """处理地图回调"""
    width = msg.info.width
    height = msg.info.height
    resolution = msg.info.resolution
    rospy.loginfo(f"地图大小:{width}x{height}, 分辨率:{resolution}m")
    # 统计占据、空闲、未知栅格
    occupied = sum(1 for cell in msg.data if cell > 50)
    free = sum(1 for cell in msg.data if 0 <= cell <= 50)
    unknown = sum(1 for cell in msg.data if cell == -1)
    rospy.loginfo(f"占据:{occupied}, 空闲:{free}, 未知:{unknown}")

def get_map_service():
    """通过服务获取地图"""
    rospy.wait_for_service('dynamic_map')
    try:
        get_map = rospy.ServiceProxy('dynamic_map', GetMap)
        response = get_map()
        return response.map
    except rospy.ServiceException as e:
        rospy.logerr(f"服务调用失败:{e}")
        return None

if __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 python3
import rospy
from nav_msgs.msg import OccupancyGrid

class MappingMonitor:
    def __init__(self):
        self.coverage_history = []
        rospy.Subscriber('/map', OccupancyGrid, self.map_callback)

    def map_callback(self, msg):
        total_cells = len(msg.data)
        known_cells = sum(1 for cell in msg.data if cell != -1)
        coverage = known_cells / total_cells * 100
        self.coverage_history.append(coverage)
        # 判断是否稳定(建图基本完成)
        if len(self.coverage_history) > 10:
            recent = self.coverage_history[-10:]
            if max(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 等算法。

目录

  1. ROS1 机器人 SLAM:Gmapping 算法详解与实战
  2. 1. Gmapping 算法简介
  3. 1.1 什么是 Gmapping?
  4. 1.2 算法流程概述
  5. 2. 核心算法原理
  6. 2.1 粒子滤波基础
  7. 2.2 Rao-Blackwellized 粒子滤波
  8. 2.3 运动模型
  9. 2.4 扫描匹配(Scan Matching)
  10. 2.5 权重计算与重采样
  11. 3. Gmapping 的 ROS 实现
  12. 3.1 订阅的话题
  13. 3.2 发布的话题
  14. 3.3 提供的服务
  15. 4. Gmapping 参数详解
  16. 4.1 粒子滤波参数
  17. 粒子数量(核心参数)
  18. 4.2 激光雷达参数
  19. 最大使用距离
  20. 4.3 运动模型参数
  21. 里程计误差参数
  22. 4.4 更新频率参数
  23. 线性运动更新阈值
  24. 4.5 地图参数
  25. 地图分辨率
  26. 4.6 扫描匹配参数
  27. 似然场参数
  28. 5. 实战:使用 Gmapping 建图
  29. 5.1 准备工作
  30. 安装 Gmapping
  31. 安装键盘控制
  32. 安装地图服务
  33. 5.2 创建 Gmapping Launch 文件
  34. 5.3 使用 TurtleBot3 仿真实战
  35. 使用 TurtleBot3 的 Gmapping 配置
  36. 或使用自定义配置
  37. 5.4 使用 rosbag 回放建图
  38. 播放数据包
  39. 启动 Gmapping(需要使用仿真时间)
  40. 6. 建图效果优化
  41. 6.1 常见问题与解决方案
  42. 检查 TF 树
  43. 检查必需的 TF 变换是否存在
  44. 检查激光数据
  45. 6.2 不同场景的参数建议
  46. 7. Gmapping 的优缺点
  47. 7.1 优点
  48. 7.2 缺点
  49. 7.3 适用场景
  50. 8. 代码示例:程序中调用 Gmapping
  51. 8.1 获取地图数据
  52. 8.2 判断建图完成度
  53. 9. 总结
  • 免费图片AI生成工具免费生成了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 免费图片视频在线生成30秒,将你的创意变成现实开始设计
  • X/Twitter免费视频下载器免登陆无限额度免费视频解析下载了解详情
  • 100+免费在线小游戏爽一把
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • 机器人阻抗控制器与导纳控制器原理对比
  • 使用 Figma MCP 配合 Claude Code 实现 UI 设计稿 1:1 还原
  • AI 绘画技术原理与商业化应用指南
  • CentOS Stream Docker 安装与配置全流程指南
  • Flutter 三方库 discord_interactions 的鸿蒙化适配指南
  • IntelliJ IDEA 打包 Web 项目 WAR 包及 Tomcat 部署指南
  • Web 自动化测试入门:从概念到百度搜索实战
  • 本地跑DeepSeek:用Ollama和Chatbox搭建私密AI助手
  • OpenClaw 移动端部署实战:iOS/Android 语音唤醒与离线 AI
  • SSRFmap Docker 部署指南:容器化渗透测试环境搭建
  • ROS 实战:5 分钟掌握 rqt 工具箱核心插件配置与调试技巧
  • NXOpen Python API 二次开发环境配置
  • Python 数据分析与可视化全面指南
  • AI 辅助 Python 编程实战:5 个提升效率的真实案例
  • pywebview:用 Python+Web 技术打造轻量级桌面应用
  • C++ 精灵库相对运动动画演示:葫芦娃飞向太空
  • 免费 AI 编辑器 Trae 实测:i18n 任务排队千位与死循环问题
  • 手写 STL Set/Map:基于红黑树的泛型容器封装
  • UniApp 前端项目源码搭建与二次开发指南
  • MATLAB 找不到编译器?MinGW-w64 C/C++环境配置与验证

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • RSA密钥对生成器

    生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online

  • Mermaid 预览与可视化编辑

    基于 Mermaid.js 实时预览流程图、时序图等图表,支持源码编辑与即时渲染。 在线工具,Mermaid 预览与可视化编辑在线工具,online

  • 随机西班牙地址生成器

    随机生成西班牙地址(支持马德里、加泰罗尼亚、安达卢西亚、瓦伦西亚筛选),支持数量快捷选择、显示全部与下载。 在线工具,随机西班牙地址生成器在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online