SLAM框架Cartographer使用教程
开源SLAM框架Cartographer使用教程1. 环境部署1. Dockerfile# 基于 ROS2 Humble 完整桌面版镜像包含 Gazebo 和 Rviz FROM osrf/ros:humble-desktop-full WORKDIR /workspace # 设置环境变量避免交互式安装时区等提示 ENV DEBIAN_FRONTENDnoninteractive ENV TZAsia/Shanghai # 1. 安装系统依赖编译工具、Cartographer所需的第三方库 RUN apt-get update apt-get install -y \ # 编译工具链 build-essential \ clang \ cmake \ git \ python3-colcon-common-extensions \ python3-rosdep \ python3-vcstool \ wget \ # Cartographer 核心依赖库 libceres-dev \ liblua5.3-dev \ libboost-all-dev \ libprotobuf-dev \ protobuf-compiler \ libeigen3-dev \ libgflags-dev \ libgoogle-glog-dev \ libcairo2-dev \ libpcl-dev \ libsuitesparse-dev \ python3-sphinx \ ninja-build \ stow \ google-mock \ # Gazebo 与 Turtlebot3 仿真包 ros-humble-turtlebot3 \ ros-humble-turtlebot3-gazebo \ ros-humble-turtlebot3-cartographer \ ros-humble-cartographer \ ros-humble-cartographer-ros \ # 其他实用工具 nano \ vim \ tree \ bash-completion \ rm -rf /var/lib/apt/lists/* # 2. 初始化并更新 rosdep使用国内版 rosdepc 解决网络问题 RUN apt-get update apt-get install -y python3-pip \ pip3 install rosdepc \ rosdepc init || echo rosdep already initialized \ rosdepc update # 3. 设置环境变量自动加载 RUN echo source /opt/ros/humble/setup.bash /root/.bashrc RUN echo export TURTLEBOT3_MODELburger /root/.bashrc # 4. 设置启动命令默认进入交互式终端 CMD [/bin/bash]2. 下载 Cartographer 源码下载 Cartographer 的 算法核心库 和 ROS2 接口封装# 下载与 ROS2 Humble 兼容的稳定版本gitclone-b2.0.9001 https://github.com/ros2/cartographer.gitgitclone-b2.0.9001 https://github.com/ros2/cartographer_ros.git创建容器启动脚本#!/bin/bash# ~/cartographer_ws/docker/docker_run.sh# 配置区 CONTAINER_NAMEcartographer_devIMAGE_NAMEmy_cartographer_env:latestWORKSPACE_HOST/home/wangye/cartographer_wsWORKSPACE_CONTAINER/workspaceMEMORY16gMEMORY_SWAP20gCPUS8# # Linux: 允许容器访问 GUIif[[$OSTYPElinux-gnu*]];thenxhost local:root/dev/null21fi# 检查容器是否存在if!dockerps-aq-fname^/${CONTAINER_NAME}$2/dev/null|grep-q.;thenecho 正在创建新容器$CONTAINER_NAME...dockerrun-d\--name$CONTAINER_NAME\--memory$MEMORY\--memory-swap$MEMORY_SWAP\--cpus$CPUS\--networkhost\-v/dev/shm:/dev/shm\-v/tmp/.X11-unix:/tmp/.X11-unix\-v$WORKSPACE_HOST:$WORKSPACE_CONTAINER\-w$WORKSPACE_CONTAINER\-eDISPLAY$DISPLAY\-eQT_X11_NO_MITSHM1\-eLIBGL_ALWAYS_SOFTWARE1\--device/dev/dri:/dev/dri\--group-add video\$IMAGE_NAME\tail-f/dev/nullif[$?-eq0];thenecho 容器创建成功sleep2# 一次性写入所有必需的环境变量到 bashrcdockerexec$CONTAINER_NAMEbash-ccat ~/.bashrc EOF # ROS2 环境 source /opt/ros/humble/setup.bash export TURTLEBOT3_MODELburger # 图形渲染解决 Gazebo/Rviz2 卡死 export LIBGL_ALWAYS_SOFTWARE1 # Gazebo 模型路径解决找不到模型 export GAZEBO_MODEL_PATH/opt/ros/humble/share/turtlebot3_gazebo/models:/usr/share/gazebo-11/models:\$GAZEBO_MODEL_PATH# Gazebo 插件路径解决 /spawn_entity 服务不存在 export GAZEBO_PLUGIN_PATH/opt/ros/humble/lib:/usr/lib/x86_64-linux-gnu/gazebo-11/plugins:\$GAZEBO_PLUGIN_PATHexport LD_LIBRARY_PATH/opt/ros/humble/lib:/usr/lib/x86_64-linux-gnu/gazebo-11/plugins:\$LD_LIBRARY_PATH# Cartographer 工作空间 if [ -f /workspace/install/setup.bash ]; then source /workspace/install/setup.bash fi EOFecho 所有环境变量已写入 ~/.bashrcelseecho容器创建失败exit1fifi# 启动容器if!dockerps-q-fname^/${CONTAINER_NAME}$2/dev/null|grep-q.;thenecho 容器已停止正在启动...dockerstart$CONTAINER_NAME/dev/nullsleep2fi# 进入容器echo 进入容器$CONTAINER_NAME...dockerexec-it$CONTAINER_NAMEbash增加执行权限chmodx docker_run.sh3. 编译colcon build --packages-up-to cartographer_ros --symlink-install --cmake-args-DCMAKE_BUILD_TYPERelease4. 加载环境sourceinstall/setup.bash2. 仿真建图1. 启动Gazebo仿真器终端1ros2 launch turtlebot3_gazebo turtlebot3_world.launch.py2. 键盘控制终端2ros2 run turtlebot3_teleop teleop_keyboard3. 构建地图终端3# 启动Cartographer 建图ros2 launch turtlebot3_cartographer cartographer.launch.py4. 保存建图终端4# 保存建好的地图到map中ros2 run nav2_map_server map_saver_cli-f/workspace/map/my_map保存后会生成两个文件my_map.pgm- 地图图片文件my_map.yaml- 地图配置文件3. 使用地图进行自主导航关闭之前的Cartographer启动导航系统加载您保存的地图ros2 launch turtlebot3_navigation2 navigation2.launch.py map:/workspace/map/my_map.yaml在 rviz2 中点击 “2D Pose Estimate” 设置机器人初始位置点击 “Nav2 Goal” 设置目标点机器人会自动规划路径并移动4. 参数调优官方默认参数无法适配所有场景。例如默认参数可能在机器人快速转弯时导致地图“拉飞”或产生重影参数调优可以根据你的机器人和使用场景去微调Cartographer算法的行为习惯让它建图更准、跑得更稳。1. Cartographer两个核心部分调参通常会先分开处理避免相互干扰局部SLAM (前端)负责实时构建局部一致的子图Submap。它非常依赖传感器数据激光、里程计、IMU来预测机器人的位置。如果发现地图在短时间内就飘了问题通常出在这里。全局SLAM (后端)在后台运行负责检测“回环”Loop Closure即识别出机器人是否回到了之前到过的地方然后对整个地图的轨迹进行全局优化和修正。2. Cartographer支持调参2D/3D SLAM具体要调哪个参数取决于你需要什么地图一般来说大部分机器人都使用2D SLAM。真实场景的选择参考应用场景模式理由室内配送/巡检机器人平层地面平整2D SLAM二维栅格地图对导航规划最友好ROS2 Navigation2 原生支持计算量小嵌入式设备也能跑室外低速无人车园区、校园有斜坡但不陡2D SLAM很多产品级方案就是把多线雷达压平成 2D 用——足够导航又稳定省算力煤矿/矿井机器人地形复杂需要感知高度信息3D SLAM必须保留 Z 轴信息否则无法判断坑道、顶板、障碍物高度自动驾驶/RoboTaxi高速需要完整环境感知3D SLAM必须知道前方物体的三维尺寸和距离2D 不够无人机空中飞行3D SLAM6 自由度全都要优化3. ROS2 中的切换方法在启动 Cartographer ROS2 时通过configuration_files参数指定不同的.lua文件# 2D 建图通常用于室内小车ros2 launch cartographer_ros cartographer.launch.py\configuration_basename:my_robot_2d.lua# 3D 建图通常用于室外或大型机器人ros2 launch cartographer_ros cartographer.launch.py\configuration_basename:my_robot_3d.lua4. 2D SLAM调优方法阶段对应文件主要功能调整时机前端trajectory_builder_2d.lua实时匹配激光帧生成子图地图局部变形、转弯漂移、雷达丢帧后端pose_graph.lua检测回环全局优化整张地图大圈闭合不上、全局轨迹扭曲、CPU 过高1. 2D 前端参数调优trajectory_builder_2d.lua1. 运动滤波器 —— 控制雷达处理频率motion_filter{max_time_seconds5.,-- 最长多少秒必须处理一帧一般不调max_distance_meters0.2,-- 移动超过此距离才处理新帧max_angle_radiansmath.rad(1.),-- 转动超过此角度才处理新帧},症状调整方向原因快速转弯时地图断层、断开max_angle_radians改小至0.005(约 0.3°)确保转弯时每一度都采样防止漏帧直线行走时地图有阶梯状重影max_distance_meters改小至0.1增加采样密度减少跳变CPU 占用过高、雷达帧积压两者都改大如0.3/0.03减少处理帧数释放算力2. Ceres 扫描匹配器 —— 核心防漂移参数ceres_scan_matcher{occupied_space_weight1.,-- 点云贴合地图的权重translation_weight10.,-- 平移变化惩罚rotation_weight40.,-- 旋转变化惩罚ceres_solver_options{use_nonmonotonic_stepsfalse,-- false稳定收敛true可跳出局部最优max_num_iterations20,-- 迭代次数调小省CPU调大精度高num_threads1,-- 线程数},},症状参数调整方向原理长廊建图越走越歪直线变弧线translation_weight改大至30~100强制约束平移量抵抗长廊无特征时的漂移转弯后地图错位/倾斜rotation_weight改大至100~400强制约束旋转量抵抗纯旋转时的角度误差地图边缘模糊、不锐利occupied_space_weight改大至2~5增加障碍物贴合的权重建图卡顿、实时性差max_num_iterations改小至10~15减少优化迭代次数牺牲一点精度换速度3. 自适应体素滤波器 —— 控制点云密度adaptive_voxel_filter{max_length0.5,-- 下采样的“粗糙程度”格子越大点越少min_num_points200,-- 下采样的“底线”一帧最少保留多少个点max_range50.,-- 最大考虑距离一般不调},症状参数调整方向原理远距离物体10m建不出来max_length改小至0.2~0.3保留更多远处的稀疏点CPU 占用过高max_length改大至0.8~1.0更激进的下采样减少点数近距离也出现断线、空洞min_num_points改小至100确保近距离场景也有足够点用于匹配2. 2D 后端参数调优pose_graph.lua注意后端参数属于全局调优仅在前端无法解决大尺度漂移时调整。POSE_GRAPH{optimize_every_n_nodes90,-- 每多少个节点做一次全局优化constraint_builder{sampling_ratio0.3,-- 回环检测采样比例max_constraint_distance15.,-- 回环搜索的最大距离min_score0.55,-- 回环匹配的最低置信度fast_correlative_scan_matcher{linear_search_window7.,-- 回环搜索的平移窗口angular_search_windowmath.rad(30.),-- 回环搜索的角度窗口branch_and_bound_depth7,-- 分枝定界深度越大越准但越慢},},optimization_problem{-- 以下权重控制全局优化时各约束的重要性local_slam_pose_translation_weight1e5,-- 相信前端子图位姿的程度local_slam_pose_rotation_weight1e5,odometry_translation_weight1e5,-- 相信轮式里程计的程度odometry_rotation_weight1e5,},}症状参数调整方向原理转了一圈终点和起点对不上max_constraint_distance改大至20~30扩大回环搜索半径min_score改小至0.45~0.5降低回环确认门槛但可能引入误匹配回环检测太慢、CPU 满载sampling_ratio改小至0.1~0.15减少参与回环检测的子图数量branch_and_bound_depth改小至5~6减少搜索树的深度回环把正确的地图拉歪了min_score改大至0.7~0.8提高回环置信度门槛拒绝误匹配local_slam_pose_*_weight改大至1e6更相信前端的结果不让后端过度拉扯地图出现波浪线里程计打滑/噪音大odometry_translation_weight改小至1e3降低对轮子里程计的信任度更多依赖激光匹配5. 3D SLAM 的调整方法3D 的前端与后端划分阶段对应文件主要功能调整时机前端trajectory_builder_3d.lua实时匹配 3D 点云生成3D 子图Z 轴漂移、点云匹配失败、强度数据利用后端pose_graph.lua检测 3D 回环全局优化6-DoF 位姿图高度方向累积误差、全局轨迹闭合3D 前端参数调优trajectory_builder_3d.lua1. 双分辨率体素滤波器3D 特有3D 雷达点云数据量巨大Cartographer 3D 采用双分辨率策略近处用高分辨率保证精度远处用低分辨率节省算力。-- 高分辨率滤波器用于近距离精细匹配high_resolution_adaptive_voxel_filter{max_length2.,-- 高分辨率体素边长min_num_points150,-- 最少保留点数max_range15.,-- 在此距离内使用高分辨率},-- 低分辨率滤波器用于远距离粗匹配low_resolution_adaptive_voxel_filter{max_length4.,-- 低分辨率体素边长比高分辨率大min_num_points200,max_rangeMAX_3D_RANGE,-- 全量程使用},症状参数调整方向原理近处物体15m建图粗糙high_resolution.max_length改小至1.0~1.5保留更多近处细节CPU/内存占用过高low_resolution.max_length改大至6~8更激进地稀释远处点云high_resolution.max_range改小至10缩小高分辨率的作用范围2. 3D Ceres 扫描匹配器含强度信息3D 版本有两个占据空间权重_0和_1分别对应低分辨率和高分辨率的匹配。还可以利用激光反射强度提升匹配精度。ceres_scan_matcher{occupied_space_weight_01.,-- 低分辨率匹配的占据权重occupied_space_weight_16.,-- 高分辨率匹配的占据权重translation_weight5.,-- 平移约束3D 中比 2D 小因为点云更丰富rotation_weight4e2,-- 旋转约束only_optimize_yawfalse,-- 是否只优化偏航角false 优化全部 6-DoF-- 强度信息利用如果 use_intensities trueintensity_cost_function_options_0{weight0.5,huber_scale0.3,intensity_thresholdINTENSITY_THRESHOLD,},}症状参数调整方向原理Z 轴高度漂移严重only_optimize_yaw确保为false允许优化 Roll/Pitch/Z抑制垂直漂移平移时点云匹配不上translation_weight改小至1~3放松平移约束允许更大范围搜索匹配旋转时点云匹配不上rotation_weight改小至1e2放松旋转约束环境特征稀疏如空地时漂移occupied_space_weight_0/1改大至10~20强制点云贴合已有地图想利用反射强度提升精度use_intensities设为true启用强度代价函数3. 3D 子图配置submaps{high_resolution0.10,-- 高分辨率子图的栅格大小米high_resolution_max_range20.,-- 高分辨率子图的作用半径low_resolution0.45,-- 低分辨率子图的栅格大小num_range_data160,-- 多少帧激光组成一个子图}症状参数调整方向原理子图内点云对不齐num_range_data改小至80~120减少子图内的累积误差远距离建图粗糙low_resolution改小至0.3提高低分辨率子图的精度内存占用过高high_resolution_max_range改小至15减少高分辨率子图的覆盖范围3D 后端参数调优pose_graph.lua3D 后端与 2D 共用同一个pose_graph.lua但使用3D 专用的扫描匹配器参数。constraint_builder{-- 3D 回环检测专用参数fast_correlative_scan_matcher_3d{branch_and_bound_depth8,-- 分枝定界深度full_resolution_depth3,-- 全分辨率搜索的深度min_rotational_score0.77,-- 旋转匹配的最低分数min_low_resolution_score0.55,-- 低分辨率匹配的最低分数linear_xy_search_window5.,-- XY 方向搜索窗口米linear_z_search_window1.,-- Z 方向搜索窗口米angular_search_windowmath.rad(15.),-- 角度搜索窗口},ceres_scan_matcher_3d{occupied_space_weight_05.,-- 回环验证时的占据权重occupied_space_weight_130.,translation_weight10.,rotation_weight1.,only_optimize_yawfalse,-- 3D 回环必须优化全部 6-DoF},}症状参数调整方向原理回环检测不到轨迹明明重合了linear_xy_search_window改大至8~10扩大 XY 平面的搜索范围linear_z_search_window改大至2~3扩大 Z 轴搜索范围如上下坡场景min_low_resolution_score改小至0.45~0.5降低粗匹配的通过门槛回环误匹配把不同楼层连起来了min_rotational_score改大至0.85~0.9提高旋转匹配的严格程度min_low_resolution_score改大至0.65~0.7提高粗匹配的通过门槛回环优化后 Z 轴跳变optimization_problem.fix_z_in_3d设为true固定 Z 轴只优化 X/Y/Yaw适用于平面运动