☰
Cartographer安装与建图实战:从环境搭建到跑通第一个SLAM Demo
2026/10/15 1:27:19 网站建设 项目流程

1. 从零搭建SLAM环境:cartographer安装前必须想清楚的几件事

很多人第一次接触cartographer,都是被它在建图效果上的口碑吸引过来的。激光SLAM领域里,cartographer的建图精度和回环处理能力确实属于第一梯队,尤其是室内大场景下的表现,比不少同类方案要稳。但真正动手装的时候,十个人里有八个会卡在依赖、编译或者运行报错上,最后折腾两三天都没跑起来一个demo。

这篇内容就是冲着这个问题来的。我会把cartographer从环境准备到跑通第一个建图demo的完整链路拆开讲,重点放在那些官方文档里一笔带过、但实际操作中一定会踩的坑上。不管你是刚接触ROS的新手,还是已经用过其他SLAM方案想转过来的老手,都能从里面找到能直接用的东西。

先说清楚cartographer是什么。它是某实验室开源的一套实时SLAM系统,支持2D和3D建图,核心优势在于用图优化后端配合扫描匹配前端,能在回环检测上做到比较高的精度。它依赖的组件不少,包括ceres-solver、protobuf、abseil-cpp、Eigen3这些,任何一个版本对不上,编译就会失败。这也是为什么很多人觉得它"难装"——不是步骤复杂,而是依赖链太长,容错空间小。

适合读这篇内容的人,我大致分三类:第一类是有ROS基础、想快速跑通cartographer建图的;第二类是在编译阶段反复报错、需要排查思路的;第三类是准备把cartographer集成到自己项目里、需要理解依赖关系的。如果你属于这三类中的任何一类,下面的内容应该都能帮上忙。

提示:cartographer的安装方式主要有两种,一种是二进制包直接安装,一种是源码编译。前者快但版本受限,后者灵活但依赖多。本文以源码编译为主线,因为实际项目里几乎都会涉及改配置、调参数,二进制包满足不了。

2. 环境准备:版本匹配比什么都重要

2.1 系统与ROS版本的选择逻辑

cartographer对系统版本和ROS版本是有明确对应关系的。这不是随便选的,因为底层依赖的库版本在不同系统上差异很大。目前主流的选择是Ubuntu 20.04配ROS Noetic,或者Ubuntu 18.04配ROS Melodic。这两个组合的社区资料最全,遇到问题也最容易搜到答案。

为什么不建议用更新的系统?因为cartographer的源码更新频率不高,新系统上的库版本往往太新,编译时会出现API不兼容的问题。比如某些系统自带的protobuf版本过高,而cartographer依赖的版本较低,直接编译就会报符号找不到的错误。所以选一个"成熟稳定"的组合,比追新要省事得多。

我个人的建议是:如果你没有特殊需求,直接用Ubuntu 20.04加ROS Noetic。这个组合的依赖包在apt源里都能找到,安装过程最顺。如果你已经在用18.04,也不用换,Melodic同样能跑通,只是部分依赖需要手动编译。

2.2 依赖安装的完整清单与顺序

依赖安装是cartographer安装过程中最容易出问题的环节。顺序很重要,因为有些库之间存在依赖关系,装反了会导致后续步骤失败。下面是我整理的一份完整清单,按推荐顺序排列:

依赖项作用安装方式注意事项
Eigen3线性代数运算apt安装版本要求3.3以上
ceres-solver非线性优化后端源码编译版本1.14.0最稳
protobuf数据序列化源码编译版本3.6.1到3.21之间
abseil-cpp基础库源码编译需要匹配protobuf版本
Lua配置文件解析apt安装5.2或5.3
Boost通用库apt安装1.65以上

这里重点说三个最容易出问题的:ceres-solver、protobuf和abseil-cpp。

ceres-solver是cartographer的核心优化库,版本选1.14.0是最稳妥的。更高的版本(比如2.x)在API上有变动,cartographer的代码没有跟进适配,编译时会报一堆模板错误。安装ceres之前,先确认Eigen3已经装好,否则ceres编译会直接失败。

protobuf的版本选择是个大坑。cartographer要求protobuf版本在3.6.1以上,但太新的版本(比如3.22以上)又会有问题。实测下来,3.6.1到3.21这个区间最安全。安装protobuf的时候,一定要记得装完执行sudo ldconfig刷新动态库缓存,否则编译时会出现"找不到libprotobuf"的错误。

abseil-cpp是protobuf的依赖,从protobuf 3.21开始,abseil变成了必需项。如果你选的protobuf版本较新,就必须先装abseil-cpp。这里有个细节:abseil-cpp的版本要和protobuf匹配,装错了同样会报错。最省事的办法是看protobuf的CMakeLists里要求的abseil版本,照着装。

注意:所有源码编译的库,安装路径建议统一用/usr/local,这样后续编译cartographer时不需要额外指定路径。如果装到了其他位置,记得在CMake命令里加上对应的前缀。

2.3 工作空间的创建与初始化

依赖装完之后,接下来是创建ROS工作空间。这一步本身不复杂,但有几个细节容易忽略。

mkdir -p ~/cartographer_ws/src cd ~/cartographer_ws/src catkin_init_workspace

创建完工作空间后,先别急着克隆代码。建议先执行一次catkin_make,确认基础环境没问题。这一步会生成devel和build目录,后续编译cartographer时会用到。

克隆代码的时候,cartographer需要三个仓库:cartographer本身、cartographer_ros和ceres-solver(如果之前没单独装的话)。这里有个版本对应的问题:cartographer_ros的版本要和cartographer的版本匹配,否则接口对不上。最稳妥的方式是看cartographer_ros的README里指定的cartographer版本,用git checkout切到对应分支。

cd ~/cartographer_ws/src git clone https://github.com/cartographer-project/cartographer.git git clone https://github.com/cartographer-project/cartographer_ros.git

克隆完之后,cartographer_ros的目录下有一个scripts/install_abseil.sh脚本,如果之前没装abseil,可以直接跑这个脚本。但要注意,这个脚本装的abseil版本可能和你系统里已有的版本冲突,跑之前最好确认一下。

3. 编译过程:报错不可怕,怕的是不知道错在哪

3.1 编译命令的正确用法

cartographer的编译用的是catkin_make,但直接跑catkin_make大概率会失败。原因是cartographer的编译需要指定一些CMake参数,尤其是ceres和protobuf的路径。

正确的编译命令是这样的:

cd ~/cartographer_ws catkin_make_isolated --install --use-ninja

这里用catkin_make_isolated而不是catkin_make,是因为cartographer_ros和cartographer是两个独立的包,用isolated模式可以避免包之间的依赖干扰。--install参数会把编译产物安装到install目录,方便后续使用。--use-ninja是可选但推荐的,ninja比make快不少,尤其是多核机器上。

如果编译过程中报错说找不到ceres,需要在命令里加上ceres的路径:

catkin_make_isolated --install --use-ninja -DCMAKE_PREFIX_PATH=/usr/local

这个-DCMAKE_PREFIX_PATH参数很关键,它告诉CMake去哪里找ceres和protobuf。如果装依赖的时候用了非默认路径,这里就要对应修改。

3.2 常见编译错误与排查思路

编译报错是cartographer安装的常态,但大部分错误就那么几类。下面我按出现频率从高到低列一下,并给出排查思路。

第一类:找不到protobuf相关符号

报错信息通常是undefined reference to google::protobuf::...。这个问题的根因是protobuf版本不匹配,或者动态库路径没刷新。排查步骤:先确认protoc --version输出的版本在3.6.1到3.21之间;然后检查/usr/local/lib下有没有libprotobuf.so;最后执行sudo ldconfig刷新缓存。

第二类:ceres模板报错

报错信息里会出现大量模板相关的错误,比如no matching function for call to ...。这基本可以确定是ceres版本过高。解决办法是卸载当前ceres,重新编译1.14.0版本。卸载的时候注意把/usr/local/lib下的libceres相关文件删干净,否则新版本编译时可能链接到旧库。

第三类:abseil符号冲突

报错信息里会出现absl::相关的符号找不到或者重复定义。这个问题通常是因为系统里装了多个版本的abseil。排查方法是find / -name "libabsl*",看看有几个版本,把多余的删掉,只保留一个。

第四类:内存不足导致编译中断

cartographer的编译对内存要求比较高,尤其是编译cartographer核心库的时候,单个编译单元可能占用几个G的内存。如果机器内存小于8G,很容易在编译到一半的时候被系统杀掉进程。解决办法是减少并行编译的任务数:

catkin_make_isolated --install --use-ninja -j2

-j2表示只用两个线程编译,虽然慢一点,但不容易爆内存。如果还是不行,可以临时增加swap空间。

3.3 编译成功的验证方法

编译完成后,怎么确认装好了?最直接的方法是跑一个demo。cartographer_ros包里自带了一个2D建图的demo,用bag数据回放就能跑。

source ~/cartographer_ws/install_isolated/setup.bash roslaunch cartographer_ros demo_backpack_2d.launch bag_filename:=${HOME}/Downloads/cartographer_paper_deutsches_museum.bag

如果rviz能正常打开,并且能看到地图逐渐构建出来,说明安装成功了。如果rviz报错说找不到某个配置,检查一下install_isolated/share/cartographer_ros/configuration_files目录下的lua文件是否存在。

提示:跑demo之前,确保bag文件已经下载到本地。cartographer官方提供了一些测试用的bag,可以在其文档页面找到下载链接。如果网络条件不好,也可以自己用激光雷达录一段bag来测试。

4. 跑通第一个建图demo:从bag回放到实时建图

4.1 demo launch文件的结构解析

cartographer_ros的demo launch文件是理解整个系统配置的入口。以demo_backpack_2d.launch为例,它主要做了三件事:加载lua配置文件、启动cartographer_node、启动rviz。

lua配置文件是cartographer的核心配置,里面定义了传感器参数、建图参数、回环参数等。2D建图的配置文件在configuration_files目录下,叫backpack_2d.lua。这个文件里几个关键参数值得关注:

  • tracking_frame:跟踪坐标系,通常是激光雷达的frame_id
  • published_frame:发布出去的坐标系
  • num_laser_scans:激光扫描的数量,单线雷达是1
  • submap_size:子图大小,影响建图精度和内存占用

理解这些参数的作用,后续调参的时候才知道改哪个。比如建图漂移严重,可能需要调submap_size或者回环相关的参数。

4.2 用自己的数据跑建图

跑通官方demo之后,下一步是用自己的数据。这里的前提是你有一台激光雷达,并且已经能通过ROS发布scan话题。

首先需要确认雷达的frame_id和话题名。用rostopic echo /scan看一下数据是否正常,用rosrun tf view_frames确认tf树是否完整。cartographer对tf的要求比较严格,雷达的frame必须能通过tf树追溯到base_link。

然后修改lua配置文件,把tracking_frame改成雷达的frame_id,num_laser_scans改成实际数量。如果用的是单线雷达,num_laser_scans设为1;如果是多线雷达做2D建图,需要把点云转成scan,或者用pointcloud相关的配置。

启动建图的命令和demo类似,只是把bag回放换成实时数据:

roslaunch cartographer_ros cartographer_2d.launch

如果一切正常,rviz里应该能看到地图实时构建。如果地图不动或者报tf错误,检查一下雷达数据的时间戳和tf的时间戳是否对齐。

4.3 建图效果不理想时的调参方向

第一次用自己的数据跑,建图效果大概率不会太完美。常见的问题和调参方向如下:

问题现象可能原因调参方向
地图重影扫描匹配精度不够调小submap_size,增大linear_search_window
回环错误回环检测过于激进增大constraint_builder.min_score
地图漂移里程计不准检查odom数据,或调大pose_graph.optimize_every_n_nodes
建图断断续续雷达数据丢帧检查雷达驱动,确认scan话题频率稳定

调参是个经验活,没有一套参数能适配所有场景。我的建议是先用默认参数跑一遍,记录下问题现象,然后针对性地调一两个参数,每次只改一个,观察效果变化。这样更容易定位到哪个参数在起作用。

5. 那些官方文档不会告诉你的实操经验

5.1 依赖版本冲突的预防比修复更重要

cartographer安装过程中,大部分时间都花在处理依赖冲突上。与其出了问题再修,不如一开始就做好隔离。我的做法是用Docker或者虚拟机,把cartographer的环境和主机环境隔开。这样即使装崩了,删掉容器重来就行,不会影响主机上的其他项目。

如果不用Docker,至少要做到一点:装依赖之前,先记录下系统里已有的版本。比如protoc --version、dpkg -l | grep ceres,把这些信息存下来。出问题的时候,对比一下版本变化,能快速定位到是哪个依赖被改动了。

5.2 编译日志的阅读技巧

cartographer编译报错的时候,终端会刷出大量信息,很多人看到就懵了。其实关键信息就那么几行。我的习惯是把编译输出重定向到文件,然后用grep搜"error":

catkin_make_isolated --install --use-ninja 2>&1 | tee build.log grep -n "error" build.log

这样能快速定位到第一个报错的位置。注意是第一个,因为后面的报错往往是第一个错误引发的连锁反应。解决掉第一个,后面的可能就自动消失了。

5.3 长期使用的环境维护建议

cartographer装好之后,如果长期不用,再次使用的时候可能会遇到环境变量失效的问题。这是因为source命令只在当前终端有效,新开终端就没了。解决办法是把source命令写到~/.bashrc里:

echo "source ~/cartographer_ws/install_isolated/setup.bash" >> ~/.bashrc

但要注意,如果同时有多个ROS工作空间,source的顺序会影响环境变量的优先级。后source的会覆盖先source的。所以如果有多个工作空间,建议写一个脚本,按需source,而不是全塞进bashrc。

另外,cartographer的bag文件占空间比较大,长期录制的话建议定期清理。建图用的bag和建好的地图文件分开存放,避免混淆。

5.4 从安装到实际项目集成的过渡

跑通demo只是第一步,真正把cartographer用到项目里,还需要考虑几个问题。一是建图模式的选择,cartographer支持纯定位模式和建图模式,纯定位模式下不会更新地图,适合已知环境下的导航。二是地图的保存和加载,cartographer建好的地图可以保存成pbstream格式,下次启动时直接加载,不用重新建图。

保存地图的命令是:

rosservice call /write_state "{filename: '${HOME}/map.pbstream'}"

加载地图则是在lua配置里指定load_state_filename参数。这些操作在官方文档里有提及,但实际用的时候需要注意路径权限和文件格式,否则会加载失败。

还有一个容易被忽略的点:cartographer的实时性对CPU要求比较高,如果建图过程中出现卡顿,可能是CPU占用过高。可以在lua配置里调小num_submaps或者降低optimize_every_n_nodes的频率,牺牲一点精度换流畅度。

我在实际项目里用cartographer做过几个室内建图的任务,最大的体会是:安装只是门槛,真正决定建图效果的是参数调优和传感器数据的质量。雷达的安装角度、标定精度、里程计的准确性,这些因素对最终地图的影响,比cartographer本身的参数要大得多。所以如果你发现怎么调参地图都不理想,不妨回头检查一下硬件层面的问题。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询