如何用 GLIM 跑通 LiDAR-IMU 3D 定位建图:从安装到调参的完整教程
【免费下载链接】glimGLIM: versatile and extensible point cloud-based 3D localization and mapping framework项目地址: https://gitcode.com/GitHub_Trending/glim/glim
你刚给机器人装上激光雷达和 IMU,回放一段 10 分钟的采集数据,轨迹却越画越歪——这是很多做点云 SLAM 的人都会遇到的情况。GLIM 是一个点云驱动的 3D 定位建图框架(3D localization and mapping framework),支持 LiDAR-IMU 紧耦合,把配准、因子图优化和闭环处理做成了可插拔模块。这篇文章带你走完一条完整路径:装好环境、跑通官方测试数据、看懂它内部的数据流,最后掌握调几个参数就能让结果变好。
先搞清楚:GLIM 是什么、适合谁
GLIM 的核心思路是"因子图上的直接多扫描配准误差最小化"(direct multi-scan registration error minimization on factor graphs):不依赖传感器特定的处理流程,任何输出点云的测距传感器都能接入——旋转式 LiDAR(Velodyne HDL32e、Ouster OS1-32)、非重复扫描 LiDAR(Livox Avia / MID360)、固态 LiDAR(Intel L515)甚至 RGB-D 相机(Azure Kinect)。
它适合:手上有 LiDAR(最好带 IMU),想要一条实时性好、闭环后全局一致的轨迹和地图,并且希望建图失败时能人工修正的开发者。官方在 Ubuntu 22.04 / 24.04 + CUDA 12.2/12.6/13.1 上验证过,也支持 NVIDIA Jetson Orin(JetPack 6.1)。
安装:三条命令级步骤
完整细节见 官方安装文档,这里给出最短路径。
1. 装依赖:GTSAM 和 gtsam_points
GLIM 的因子图优化基于 GTSAM(一个常用的 SLAM 图优化库),点云配准因子来自 gtsam_points。这两个库需要先于 GLIM 从源码编译安装,版本要求见安装文档(当前基线是 GTSAM 4.3a0 + gtsam_points 1.2.0)。系统依赖一条 apt 命令搞定:
sudo apt install libomp-dev libboost-all-dev libmetis-dev \ libfmt-dev libspdlog-dev \ libglm-dev libglfw3-dev libpng-dev libjpeg-dev装好 GTSAM / gtsam_points / Iridescence(可视化用,强烈建议)后记得执行sudo ldconfig。
2. 克隆并编译
cd ~/ros2_ws/src git clone https://gitcode.com/GitHub_Trending/glim/glim # glim_ros2 是 ROS2 封装包,需一并放入工作空间(地址与编译选项见 docs/installation.md) cd ~/ros2_ws colcon build --cmake-args -DBUILD_WITH_CUDA=ON -DBUILD_WITH_VIEWER=ON source install/setup.bash没有 GPU 就把-DBUILD_WITH_CUDA=ON去掉,之后选 CPU 配置组合即可。
3. 跑官方测试数据,看到轨迹
快速上手文档 提供了 Ouster OS1-128 的测试 bag(os1_128_01,有 426MB 的降采样版和完整版),下载后直接:
# 方式一:从 bag 文件回放建图(自动调速,最快完成) ros2 run glim_ros glim_rosbag os1_128_01 # 方式二:标准 ROS2 节点,接实时传感器 ros2 run glim_ros glim_rosnode ros2 bag play os1_128_01默认配置已指向这套测试数据(config_ros.json中的imu_topic/points_topic,config_sensors.json中的T_lidar_imu),不用改任何文件。想接自己的传感器,按 parameters.md 里的说明改 topic 和外参即可。
跑完后(或按 Ctrl+C 退出后),结果落在/tmp/dump:包含地图图数据和 4 个 TUM 格式轨迹文件(每行t x y z qx qy qz qw)。用离线查看器打开就能可视化、编辑、导出:
ros2 run glim_ros offline_viewer菜单File -> Open Map选中 dump 目录即可。到这里,你就完成了一次完整的定位建图闭环。
数据流:一帧点云如何变成全局地图
GLIM 把整条流水线拆成三层,每层都有多个可互换的实现(上图中星标为 GPU 加速版):
- 里程计层(Odometry):接收点云 + IMU,输出当前帧位姿。
OdometryEstimationGPU:GPU 加速的 LiDAR-IMU 紧耦合估计,基于 fixed-lag 平滑 + 关键帧管理,精度和速度最好;OdometryEstimationCPU:纯 CPU 的 scan-to-model 匹配,中等配置可用;OdometryEstimationCT:无 IMU 时的连续时间 ICP 纯 LiDAR 里程计。
- 子地图层(Sub Mapping):把连续的位姿和点云切分成子地图单元,内部做一次批量优化。
SubMapping支持 CPU/GPU 优化,SubMappingPassthrough则只透传、不做优化,省算力。 - 全局层(Global Mapping):在子地图之间加约束并全局优化。
GlobalMapping做配准误差最小化,子地图重叠度超过阈值(min_implicit_loop_overlap,默认 0.2)时自动建因子——这就是它的隐式闭环:不需要显式检测闭环,走回老路时重叠度一上来约束就生效。GlobalMappingPoseGraph是纯 pose graph 优化的轻量版。
这个分层设计解释了上面那张图为什么要画三条横线:三层之间只靠"位姿 + 子地图"传递,所以你可以自由混搭——GPU 里程计 + CPU 子地图,或 LiDAR-only 里程计 + 位姿图全局优化,而不必动代码。
如果你要往因子图里塞自己的约束(GNSS、视觉、速度抑制等),入口是全局回调槽机制:继承ExtensionModule、注册回调、把 .so 写进config_ros.json的extension_modules列表即可,官方文档 extend.md 里有完整代码示例,开源扩展模块清单见 extensions.md。
关键配置:只需看这几份文件
所有配置在 config/ 目录下,是带中文注释风格的 JSON。入口是config.json,它只决定"用哪份子配置":
| 配置键 | 默认值 | 作用 |
|---|---|---|
config_odometry | config_odometry_gpu.json | 选择里程计实现 |
config_sub_mapping | config_sub_mapping_gpu.json | 选择子地图实现 |
config_global_mapping | config_global_mapping_gpu.json | 选择全局优化实现 |
各子配置的要点(默认值来自仓库内文件):
| 文件 | 关键参数 | 默认 | 什么时候改 |
|---|---|---|---|
config_ros.json | imu_topic/points_topic | 测试数据 topic | 接自己的传感器必改 |
config_ros.json | acc_scale | 0(自动检测) | Livox 系 IMU 输出 g 单位,设为9.80665 |
config_sensors.json | T_lidar_imu | OS1 外参 | 换成你的标定结果;静止时 IMU 加速度应约为[0, 0, +9.81] |
config_preprocess.json | random_downsample_target | 10000 | 机器吃紧时降到 5000,速度明显提升 |
config_preprocess.json | k_correspondences | 10 | Velodyne 等稀疏扫描 LiDAR 调到 15~30,防止协方差退化 |
config_odometry_gpu.json | voxel_resolution | 0.25 | 室内 0.1~0.25,室外 0.5~1.0 |
config_odometry_gpu.json | voxelmap_levels | 2 | 位移大、运动快时加到 3,更鲁棒 |
config_odometry_gpu.json | max_num_keyframes | 15 | 增大可减少里程计漂移 |
config_odometry_gpu.json | keyframe_update_strategy | OVERLAP | 想要直观可调就换DISPLACEMENT |
config_global_mapping_gpu.json | min_implicit_loop_overlap | 0.2 | 调小 → 更多隐式闭环因子 |
config_global_mapping_gpu.json | randomsampling_rate | 1.0 | GPU 下保持 1.0(全点参与全局配准) |
三种常用组合(来自 quickstart.md):
| 组合 | config_odometry | config_sub_mapping | config_global_mapping | 适用硬件 |
|---|---|---|---|---|
| GPU 全功能(默认) | _gpu | _gpu | _gpu | 带 NVIDIA GPU 的工作站 / Orin |
| CPU 轻量 | _cpu | _passthrough | _pose_graph | 无 GPU 的低配 PC |
| 纯 LiDAR(无 IMU) | _ct | _gpu(enable_imu: false) | _gpu(enable_imu: false) | 只有 LiDAR 的平台 |
两个容易踩的坑:ROS2 下改包内配置后要重新colcon build才生效(用colcon build --symlink-install可避免);配置根目录可用启动参数覆盖,例如ros2 run glim_ros glim_rosnode --ros-args -p config_path:=$(realpath ./config)。
效果怎么看:轨迹文件与速度
比轨迹,而不是比"感觉"。dump 目录里成对出现四份轨迹:
odom_imu.txt/odom_lidar.txt:里程计结果,没有闭环修正;traj_imu.txt/traj_lidar.txt:全局优化后结果。
拿任意工具(Python + matplotlib 就够)把odom_imu和traj_imu叠画在同一张图上,两条线在起点和终点附近的差值,就是全局优化(含隐式闭环)实际修掉的累积误差。traj_imu与traj_lidar的差异则反映T_lidar_imu标定是否靠谱——两者应当只差一个常量变换。
看速度,盯两个指标:
- 实时性:
glim_rosbag会自动调速到"不丢数据的最快速度",看日志里最终的回放倍率是否 ≥ 1.0 倍实时; - 瓶颈定位:如果 GPU 利用率很低,多半是预处理或子地图优化占大头,优先降
random_downsample_target。
GLIM 本身不做"精度分"式的基准输出,精度验证建议用已知轨迹的数据集,把traj_*.txt和 GT 对齐后算 ATE——这套流程对任何 SLAM 都通用。
常见问题与调参速查
Q:轨迹整体在漂移,怎么办?先怀疑传感器配置而非算法:确认T_lidar_imu是你的标定值(文件里有 OS1 / Avia / L515 / Kinect 等常见值,但文档明确说"不要盲信");把传感器放静止,检查 IMU 加速度读数是否约为[0, 0, +9.81];Livox 记得acc_scale: 9.80665。GLIM 提供了validate_imu校验日志(config_odometry_gpu.json中默认开启)和 imu_validator 扩展模块辅助排查。
Q:估计太慢,追不上实时?按代价从小到大调:random_downsample_target从 10000 降到 5000;max_num_keyframes从 15 降到 10;子地图/全局层enable_optimization在里程计已经足够稳时可设false省掉一次优化。
Q:点云匹配不收敛、跳变?voxel_resolution和环境尺度不匹配是最常见原因(室内用 0.1~0.25,室外 0.5~1.0);大位移场景把voxelmap_levels加到 3;关键帧策略换成DISPLACEMENT并直接调keyframe_delta_trans/rot阈值,比 OVERLAP 更直观可控。
Q:怎么看协方差估计是否正常?标准查看器把color_mode切到NORMAL:平面上的点颜色均匀,说明协方差正常。
Q:内存告警?默认加载了libmemory_monitor.so扩展模块监控内存,日志里会报使用率;持续高占用就回到上一条"降点云 + 减关键帧"。
Q:地图建错了能救吗?能。offline_viewer里右键子地图球 →Loop begin/Loop end手动加闭环,右键平面点 →Bundle Adjustment (Plane)加平面约束,还可以导出 PLY、合并多次建图会话(见 merge.md、edit.md)。这是 GLIM 相对"跑完即结束"的方案的一个实用差异。
调参优先级速查表:
| 症状 | 首选参数 | 位置 | 方向 |
|---|---|---|---|
| 室内精度不够 | voxel_resolution | odometry | 调小(0.1~0.25) |
| 室外不收敛 | voxel_resolution/voxelmap_levels | odometry | 调大 / 加到 3 |
| 里程计漂移 | max_num_keyframes | odometry | 调大 |
| 速度慢 | random_downsample_target | preprocess | 调小 |
| 稀疏 LiDAR 协方差差 | k_correspondences | preprocess | 15~30 |
| 想多抓闭环 | min_implicit_loop_overlap | global mapping | 调小 |
下一步你可以做什么
一句话总结:GLIM 用"分层 + 因子图 + 隐式闭环"把 LiDAR-IMU 建图做成了一个按硬件档位自由组合的流水线,跑通之后真正的功夫在传感器配置和那几个体素参数上。
接下来按顺序做三件事:
- 接自己的数据:改
config_ros.json的 topic 和config_sensors.json的外参,用validate_imu先验证标定; - 做一次人工闭环:在
offline_viewer里手动加一个闭环因子,直观感受traj轨迹前后的差异; - 试一个扩展模块:从 extensions.md 选一个(如 GNSS 约束或 ScanContext 闭环),走一遍
ExtensionModule开发流程(extend.md)。
没有 CUDA 环境也可以玩——用 CPU 组合 + 官方 Docker 镜像(见 docker.md)先在容器里把流程跑顺,再上真机。
【免费下载链接】glimGLIM: versatile and extensible point cloud-based 3D localization and mapping framework项目地址: https://gitcode.com/GitHub_Trending/glim/glim
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考