RTAB-Map 3D SLAM
一句话读懂:前 6 个实验,小车眼里世界是"一张平面图"(俯视图,像户型图)。这节课让小车"长出一双立体眼睛"——用 RGB-D 深度相机 + RTAB-Map,构建三维点云/八叉树地图,让机器人理解高度、层次、悬空障碍,为"分楼层导航、抓取定位"打基础。
01问题引入:平面图看不见"头顶的横梁"
02原理通俗讲解:从"照片"到"立体"的两步跳
RTAB-Map 用图像特征(ORB)聚类成"词汇",一帧图 = 一组词汇集合;检索"和当前帧最像的历史帧",相似度过阈值即回环 → g2o 图优化消漂移。就像凭"照片里出现吧台+红椅+吊灯"判断"我回到了这家咖啡馆",而不是逐像素比照片。
有内参 (fx, fy, cx, cy) 就能把 (u,v,d) 换算成空间点:X=(u−cx)·d/fx,Y=(v−cy)·d/fy,Z=d。像素放图像中心 (cx,cy) 时应得 X≈0、Y≈0——这是自检口诀。
slam_toolbox:激光雷达 + 扫描匹配回环 + 二维栅格;RTAB-Map:RGB-D 相机 + 图像词袋回环 + 三维点云/OctoMap。两者都是图优化 SLAM,只是"用什么看世界"不同。
三维地图替代二维栅格作 costmap 输入,悬空障碍可被正确区分(低矮可跨、横梁必躲)。但 ROS2 里需要投影/转换环节,地面小车通常二维就够——三维更多服务感知/抓取/展示。
选型口诀:二维 = 平面图(便宜够用),三维 = 3D 模型(信息全但贵)。核心判据就一条——任务需不需要"高度"这一维:出现悬空障碍 / 高度分层 / 抓取定位需求时,才该上三维。
03关联知识点
Real-Time Appearance-Based Mapping:前端图像特征里程计 → 局部地图 → 词袋回环 → g2o/GTSAM 位姿图优化。
HP60C 同时输出彩色图(640×480)与深度图(每像素距离 d,单位毫米,25 fps);反光、超距、强光处深度返回 0(图上全黑)。
海量 3D 点直观但冗余不可编辑;体素八叉树可压缩、增量更新、支持占据查询——导航/避障更常用后者。
回环触发时地图会整体抖一下——那是图优化一次性校正所有历史帧的瞬间,属正常现象,不是 bug。
/camera_info 里带 fx/fy/cx/cy;ros2 topic echo /ascamera_hp60c/camera_publisher/depth0/camera_info 可查。反投影公式必须配内参才成立。
RK3576 跑实时三维 SLAM 压力大;三维比二维更怕运动畸变——遥控角速度 ≤0.5 rad/s,转角处多停留。
04实验目标
- 理解视觉 SLAM 与 RTAB-Map 基本原理(ORB 特征、词袋回环、图优化) —— 原理理解
- 理解 RGB-D 相机工作原理与反投影公式、点云/八叉树两种地图表示 —— 原理理解
- 掌握三维建图与三维导航的通用流程(相机 → RTAB-Map → 操控 → 保存) —— 流程掌握
- 能够完成 RGB-D 数据链路验证(话题频率 / 深度图查看 / 手算反投影) —— 流程掌握
- 能对比二维与三维 SLAM 的六维差异并做场景选型分析 —— 迁移应用
05实验环境与准备
| 类别 | 配置 |
|---|---|
| 硬件 | 小车 C1 + HP60C RGB-D 深度相机(驱动在 examples/camera/HP60C/src/ascamera/) |
| 系统 | Ubuntu 22.04 + ROS 2 Humble |
| 核心库 | rtabmap_ros(ROS2 版)、depth_image_proc、octomap_server、rviz2 |
| 依赖 | HP60C 驱动(ascamera)能发布 RGB + Depth 话题;Nav2 可用(EXP-03) |
| 主入口 | 通用流程 ros2 run rtabmap_slam rtabmap + 相机驱动 ros2 launch ascamera hp60c.launch.py;本项目为原理演示型 |
/ascamera_hp60c/camera_publisher/rgb0/image、.../depth0/image_raw、.../depth0/camera_info、.../depth0/points——不是教科书里常见的 /camera/rgb/image_raw。第 08 节的命令都按真实名写。06动画讲解:RGB-D 反投影生成三维点云
图 7-1:深度图每个像素 (u,v,d) 携带"方向+距离",乘相机内参反投影成空间点 (X,Y,Z);逐帧累积并用相机自身运动拼接,就长出了带颜色的三维点云——再体素化(乐高化)即得 OctoMap。动画中彩色点与左侧深度图像素块一一对应。注意:上式是"相机光学坐标系"约定,Z 朝前、X 朝右、Y 朝下,所以 v 小于 cy(图像偏上)时 Y 为负——这也是深度图坐标系与 RViz 世界系不一致的根源。
07互动讲解:2D 栅格 vs 3D 点云选型台
| 维度 | 二维 SLAM(slam_toolbox) | 三维 SLAM(RTAB-Map) |
|---|---|---|
| 传感器 | 激光雷达 | RGB-D 深度相机 |
| 地图 | 栅格(俯视) | 点云 / OctoMap(立体) |
| 算力 | 低(RK3576 轻松) | 高(实时需更强算力) |
| 精度 | 水平精度高 | 含高度信息,垂直精度依赖深度质量 |
| 导航 | Nav2 直接消费 /map | 需投影/转换后才能消费 |
| 适用 | 地面巡检 / 送货 | 分层避障 / 抓取定位 / 展示 |
08实操步骤:RGB-D 数据链路验证与通用流程
# ① 启动相机(命名空间 ascamera_hp60c),核对四话题 ros2 launch ascamera hp60c.launch.py ros2 topic list | grep ascamera_hp60c # /ascamera_hp60c/camera_publisher/rgb0/image # /ascamera_hp60c/camera_publisher/depth0/image_raw # /ascamera_hp60c/camera_publisher/depth0/camera_info ros2 topic hz /ascamera_hp60c/camera_publisher/depth0/image_raw ros2 topic echo /ascamera_hp60c/camera_publisher/depth0/camera_info # 抄 fx fy cx cy # ② 查看深度图(近红远蓝,反光/超距处发黑) ros2 run rqt_image_view rqt_image_view /ascamera_hp60c/camera_publisher/depth0/image_raw # ③ 启动 RTAB-Map(通用命令:话题名不匹配就显式指定) ros2 run rtabmap_slam rtabmap --ros-args -p subscribe_rgbd:=true \ -p rgb_topic:=/ascamera_hp60c/camera_publisher/rgb0/image \ -p depth_topic:=/ascamera_hp60c/camera_publisher/depth0/image_raw \ -p approx_sync:=true # ④ 遥控低速走闭环(角速度 ≤ 0.5 rad/s,转角停留 1-2s)观察 RViz 点云 ros2 run teleop_twist_keyboard teleop_twist_keyboard # ⑤ 保存数据库 / 导出八叉树 ros2 service call /rtabmap/save std_srvs/srv/Empty ros2 launch octomap_server octomap_mapping.launch.xml # 通用
# 反投影手验算(numpy):中心像素应得到 X≈0, Y≈0, Z=d import numpy as np fx, fy, cx, cy = 380.0, 380.0, 320.0, 240.0 # ← 以实测 camera_info 为准 u, v, d = 320.0, 240.0, 1.500 # 深度换算成「米」再算 X = (u - cx) * d / fx Y = (v - cy) * d / fy Z = d print(X, Y, Z) # 期望 ≈ 0, 0, 1.5
09重点与易错点
| 坑 | 现象 | 解决 |
|---|---|---|
| 深度图全黑 | 无深度数据 | 超出有效距离或反光/强光直射;调整距离与环境 |
| 话题名照抄教科书 | RTAB-Map 收不到数据 | 真实名是 /ascamera_hp60c/camera_publisher/rgb0/image 与 depth0/image_raw;用 -p rgb_topic:=… / -p depth_topic:=… 显式指定 |
| 给相机做 remap | 话题改名后相机不再出流 | 驱动靠话题名里的 "rgb0/depth0" 子串判断推哪路流,remap 会丢掉这个线索——不要 remap |
| 深度单位当米用 | 点云/点算出来大 1000 倍 | depth 图是 16UC1 毫米编码,计算前先 /1000 |
| 反投影公式记反 | 点云左右/上下镜像 | 中心像素自检:(cx,cy) → X≈0、Y≈0、Z=d |
| 三维地图"花" | 点云散乱重影 | 走太快导致运动畸变;更慢速(≤0.5 rad/s),转角停留 1-2 s |
| 回环时地图乱一下 | 点云整体抖动 | 正常!图优化一次性校正所有帧,记录即可 |
| 算力不足卡顿 | RViz 卡、掉帧 | 降分辨率/关闭额外显示;实时性优先场景改用二维 |
| 以为三维导航直接替换 | Nav2 吃不到 OctoMap | 需投影/转换成 Nav2 costmap 可消费的格式,工程有额外环节 |
| 以为词袋 = 深度学习 | 概念混淆 | 词袋是经典特征聚类(ORB + KMeans),不是神经网络 |
| 跟风上三维 | 成本失控 | 三维算力与工程成本翻倍;地面任务优先二维,确有高度需求再上 |
- 本实验为原理+演示型,不强行要求跑通三维导航,重点在理解与选型分析
- RGB-D 强光/远距/反光处失效——户外或大场景优先激光雷达
- 三维地图文件大,保存后检查磁盘空间
- 记住"话题名 + 毫米单位"这两个本机特有的坑,比背公式更容易拿分