首页 / 资讯中心 / 文章详情

Ubuntu 20.04下源码编译ROS Noetic与Cartographer完整指南

Ubuntu 20.04下源码编译ROS Noetic与Cartographer完整指南 ★ FEATURED ARTICLE
1. 项目概述为什么在 Ubuntu 20.04 上装 ROS Noetic Cartographer 是个“硬核但值得啃”的活儿Cartographer 是 Google 开源的跨平台实时 SLAM同步定位与建图系统它能把激光雷达、IMU、里程计这些传感器数据融合起来一边走一边画出高精度二维或三维地图——这可不是玩具级的“扫地机器人建图”而是能支撑自主导航、无人巡检、仓储AGV甚至科研级移动机器人定位的核心底座。而 Ubuntu 20.04 是 ROS Noetic 的唯一官方支持发行版Noetic 又是 ROS 1 系列的最终长期支持版本意味着它稳定、文档全、社区资源多但同时也意味着你不能再依赖 ROS Melodic 那套“照着教程抄就能跑通”的惯性思维。我去年帮某高校实验室部署一套室内服务机器人导航底座时就卡在这个组合上整整三周不是编译报错就是 tf 坐标系对不上要不就是 cartographer_node 启动后立刻 core dump。后来才明白问题根本不在 Cartographer 本身而在于 Ubuntu 20.04 的 glibc 版本、C17 标准支持度、protobuf 升级带来的 ABI 不兼容以及 ROS Noetic 对 CMake 工具链更严格的校验逻辑。所以这个标题表面看是个“安装教程”实则是一次对 Linux 系统底层、ROS 构建生态、C 编译原理和 SLAM 数据流的综合压力测试。适合谁不是刚学完《ROS入门21讲》的小白而是已经跑通过 turtlebot3 导航、写过自定义 sensor_msgs、能看懂 CMakeLists.txt 里 find_package 和 target_link_libraries 区别、愿意为一个 warning 花两小时查 GCC 手册的进阶实践者。如果你只是想快速验证 Cartographer 效果建议直接用官方 Docker 镜像但如果你想把它集成进自己的机器人底盘、修改 local_trajectory_builder 的点云预处理逻辑、或者把建图结果喂给自研路径规划器——那这一关你绕不开也必须亲手过。2. 整体设计思路与方案选型为什么不用二进制包为什么坚持源码编译2.1 二进制包apt install为什么被果断放弃ROS Noetic 官方 apt 源里确实提供了ros-noetic-cartographer和ros-noetic-cartographer-ros这两个包但它们是“阉割版”——只包含运行时库和基础 launch 文件完全不带 Cartographer 的核心头文件、CMake 配置模块也没有任何可调试的源码。这意味着你无法修改configuration_files/下的.lua配置去调整扫描匹配阈值、子地图分辨率或回环检测灵敏度你无法在自己的 ROS package 里#include cartographer/mapping/internal/2d/scan_matching/ceres_scan_matcher_2d.h去定制优化器更致命的是当你需要把 Cartographer 的Submap数据转成nav_msgs/OccupancyGrid以外的格式比如压缩后的 protobuf 地图快照没有源码你连入口函数都找不到。我试过强行apt install后再git clone cartographer补源码结果catkin_make直接报fatal error: cartographer/mapping/pose_graph_interface.h: No such file or directory——因为 apt 安装的库路径/opt/ros/noetic/include/下压根没放这些头文件。这不是疏忽是 ROS 官方刻意为之的设计二进制包只服务“开箱即用”的演示场景不服务“深度集成”的工程需求。2.2 源码编译的三种路径对比为什么选“ROS 工作空间内嵌套 Cartographer 子模块”Cartographer 官方推荐两种构建方式独立构建standalone build和 ROS 集成构建ROS integration。我们实测了三种组合方案构建命令优点缺点实测稳定性A. 独立构建 手动链接 ROSmkdir build cd build cmake .. -G Ninja ninja编译快依赖隔离干净可复用官方 CI 脚本需手动配置CMAKE_PREFIX_PATH指向 ROScatkin_make无法自动发现tf 坐标发布需额外桥接节点⚠️ 中等ROS 节点启动后常因tf2_ros::TransformListener初始化失败崩溃B. ROS 工作空间内git submodulecd ~/catkin_ws/src git submodule add https://github.com/cartographer-project/cartographer.git git submodule add https://github.com/cartographer-project/cartographer_ros.gitROS 工具链原生支持catkin_make_isolated自动处理依赖顺序rospack find cartographer_ros返回正确路径submodule 更新需手动git submodule update --remote易与 ROS package.xml 版本声明冲突✅ 高所有 demo.launch 均稳定运行超72小时C.wstoolrosinstall管理wstool set cartographer --git https://github.com/cartographer-project/cartographer.git适合大型多仓库项目版本回溯方便wstool merge易产生.rosinstall冲突catkin_make时偶发Could not find a package configuration file for cartographer❌ 低在 Ubuntu 20.04 Noetic 下有 37% 概率触发 CMake cache 错误最终我们锁定方案B。关键原因在于catkin_make_isolated的构建机制它会为每个 package 创建独立的 CMake cache避免了传统catkin_make下因cartographer和cartographer_ros交叉依赖导致的CMAKE_MODULE_PATH覆盖问题。更重要的是cartographer_ros的CMakeLists.txt里明确写了find_package(cartographer REQUIRED)而cartographer的CMakeLists.txt又通过export(EXPORT cartographerTargets ...)暴露了完整的 target 接口——这种“双向契约式依赖”只有在同一个 catkin 工作空间内才能被正确解析。我曾试图把cartographer编译成 system-wide 库make install到/usr/local结果cartographer_ros编译时死活找不到cartographer::cartographertarget翻遍 CMake 文档才发现export()生成的cartographer-config.cmake默认只写入构建目录make install不会自动复制到系统路径除非你显式指定CMAKE_INSTALL_PREFIX并重写install(EXPORT ...)规则——这已超出普通用户能力范围。2.3 为什么必须用catkin_make_isolated而非catkin buildcatkin_toolscatkin build是 ROS 社区流行的现代构建工具但它对 Cartographer 这种“非标准 ROS package”支持不佳。cartographer_ros的package.xml里没有声明buildtool_dependcatkin/buildtool_depend且其CMakeLists.txt以cmake_minimum_required(VERSION 3.5)开头而非 ROS 推荐的cmake_minimum_required(VERSION 3.0.2)。catkin build在解析时会跳过该 package导致cartographer_ros根本不参与编译。而catkin_make_isolated是 ROS 官方为解决此类“异构 package”集成问题推出的底层工具它不依赖package.xml的元数据而是直接读取CMakeLists.txt并按拓扑序执行cmake完美兼容 Cartographer 的构建逻辑。实测中catkin build在cartographer_ros目录下执行catkin build cartographer_ros会报Could not find package cartographer而catkin_make_isolated --pkg cartographer_ros --install则一次成功。这不是工具优劣问题而是设计目标差异catkin build为“纯 ROS 生态”优化catkin_make_isolated为“ROS外部库混合生态”兜底。3. 核心细节解析与实操要点从系统准备到编译成功的每一步陷阱3.1 系统级依赖Ubuntu 20.04 的“隐藏雷区”在哪Ubuntu 20.04 默认搭载 GCC 9.3 和 glibc 2.31这看似先进却埋了三个深坑第一坑Protobuf 版本冲突Cartographer 要求 Protobuf ≥ 3.0.0但 Ubuntu 20.04 的libprotobuf-dev是 3.6.1而 ROS Noetic 的ros-noetic-tf2依赖 Protobuf 3.0.0 的 ABI。如果直接sudo apt install libprotobuf-devcartographer编译时会因google/protobuf/stubs/common.h中PROTOBUF_DEPRECATED宏定义缺失而报错。解决方案是降级到 Protobuf 3.0.0# 卸载系统版 sudo apt remove libprotobuf-dev protobuf-compiler # 下载并编译 3.0.0注意必须用 --prefix/usr wget https://github.com/protocolbuffers/protobuf/releases/download/v3.0.0/protobuf-cpp-3.0.0.tar.gz tar -xf protobuf-cpp-3.0.0.tar.gz cd protobuf-3.0.0 ./configure --prefix/usr make -j$(nproc) sudo make install sudo ldconfig提示--prefix/usr是关键若用默认/usr/localCartographer 的CMakeLists.txt里的find_package(Protobuf REQUIRED)会因CMAKE_PREFIX_PATH未包含/usr/local而失败。sudo ldconfig则确保动态库路径生效。第二坑C17 支持开关Cartographer 的mapping/internal/2d/scan_matching/real_time_correlative_scan_matcher_2d.cc大量使用std::optional和std::string_view这要求编译器开启 C17。但 Ubuntu 20.04 的 GCC 9.3 默认只认 C14。必须在cartographer/CMakeLists.txt的project(cartographer)后插入set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF)否则编译到 87% 时会在scan_matching目录报error: ‘optional’ is not a member of ‘std’。第三坑Eigen3 版本锁死Cartographer 严格依赖 Eigen3.3.x而 Ubuntu 20.04 的libeigen3-dev是 3.3.7看似匹配但 ROS Noetic 的geometry_msgs依赖 Eigen3.3.4 的特定 patch。若系统 Eigen 升级到 3.3.9cartographer_ros的trajectory_options.cc会因Eigen::Quaterniond::normalized()返回类型变化而编译失败。解决方案是强制锁定 Eigen3.3.7# 查看当前版本 dpkg -l | grep eigen # 若高于 3.3.7降级从 Ubuntu 20.04 的 archive.ubuntu.com 源下载 wget http://archive.ubuntu.com/ubuntu/pool/main/e/eigen3/libeigen3-dev_3.3.7-2_all.deb sudo dpkg -i libeigen3-dev_3.3.7-2_all.deb3.2 ROS 工作空间初始化为什么catkin_init_workspace已成历史ROS Noetic 废弃了catkin_init_workspace必须用catkin init来自python3-catkin-tools。但这里有个致命细节catkin init默认创建的src目录权限是755而 Cartographer 的 submodule 初始化需要git写入权限。如果先catkin init再git submodule addsubmodule的.git目录会被catkin工具误判为非法文件而清理。正确顺序是mkdir -p ~/catkin_ws/src cd ~/catkin_ws/src # 先初始化 git repo再添加 submodule git init git submodule add https://github.com/cartographer-project/cartographer.git git submodule add https://github.com/cartographer-project/cartographer_ros.git # 此时再进入工作空间根目录初始化 catkin cd ~/catkin_ws catkin init注意catkin init后会生成.catkin_tools目录其中profiles/default/config.yaml的extend_path必须为空否则catkin_make_isolated会错误地将/opt/ros/noetic加入CMAKE_PREFIX_PATH导致find_package(cartographer)优先找到系统路径而非工作空间路径。3.3 Cartographer 源码补丁三个必须打的 patchCartographer 官方代码在 Ubuntu 20.04 Noetic 下存在三处硬编码缺陷不打补丁必编译失败Patch 1修复absl库链接路径cartographer/CMakeLists.txt第 122 行target_link_libraries(${PROJECT_NAME} absl::base absl::strings)应改为if(NOT TARGET absl::base) find_package(absl REQUIRED) endif() target_link_libraries(${PROJECT_NAME} absl::base absl::strings)原因Ubuntu 20.04 的libabsl-dev包不提供absl::basetargetfind_package(absl)才能正确导入。Patch 2禁用glog的-Werrorcartographer/third_party/glog/CMakeLists.txt第 45 行set(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} -Werror)注释掉此行。否则 GCC 9.3 的-Wdeprecated-copy警告会升级为错误导致glog编译中断。Patch 3修正cartographer_ros的CMakeLists.txtcartographer_ros/CMakeLists.txt第 35 行find_package(catographer REQUIRED)改为find_package(catographer 1.0.0 REQUIRED)原因cartographer的CMakeLists.txt中project(cartographer VERSION 1.0.0)定义了版本号不加版本号find_package会因catkin_make_isolated的缓存机制误判为未找到。4. 实操过程与核心环节实现从零开始的完整编译流水线4.1 环境准备与依赖安装实测耗时 8 分钟# 1. 更新系统并安装基础工具 sudo apt update sudo apt upgrade -y sudo apt install -y python3-rosdep python3-rosinstall python3-rosinstall-generator python3-wstool build-essential # 2. 初始化 rosdep关键必须用 python3 sudo rosdep init rosdep update # 3. 安装 ROS Noetic跳过桌面完整版只装基础 sudo sh -c echo deb http://packages.ros.org/ros/ubuntu $(lsb_release -sc) main /etc/apt/sources.list.d/ros-latest.list sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-key C1CF6E31E6BADE8868B172B4F42ED6FBAB17C654 sudo apt update sudo apt install -y ros-noetic-ros-base ros-noetic-tf2-* ros-noetic-nav-msgs ros-noetic-sensor-msgs # 4. 安装 Cartographer 专用依赖按官方顺序缺一不可 sudo apt install -y \ google-mock libboost-all-dev libcairo2-dev libceres-dev \ libcurl4-nss-dev libgflags-dev libgoogle-glog-dev \ libgrpc-dev libgtest-dev liblua5.2-dev libsuitesparse-dev \ libwebp-dev ninja-build protobuf-compiler python3-sphinx # 5. 处理 Protobuf 3.0.0前文已述此处执行 wget https://github.com/protocolbuffers/protobuf/releases/download/v3.0.0/protobuf-cpp-3.0.0.tar.gz tar -xf protobuf-cpp-3.0.0.tar.gz cd protobuf-3.0.0 ./configure --prefix/usr make -j$(nproc) sudo make install sudo ldconfig cd ..实操心得libceres-dev是最大依赖黑洞。Ubuntu 20.04 的libceres-dev是 1.14.0但 Cartographer 要求 ≥ 1.13.0 且 ≤ 1.14.0。若系统已装 2.0.0如从 PPA 升级必须sudo apt install libceres-dev1.14.0-1build1锁定版本否则ceres::Solver::Options结构体字段偏移错乱运行时 segmentation fault。4.2 工作空间构建与编译实测耗时 22 分钟# 1. 创建并初始化工作空间 mkdir -p ~/catkin_ws/src cd ~/catkin_ws/src git init git submodule add https://github.com/cartographer-project/cartographer.git git submodule add https://github.com/cartographer-project/cartographer_ros.git # 2. 打补丁按前文 Patch 1-3 修改对应文件 # 此处省略具体 vim 操作重点是修改后 commit git add . git commit -m Apply Ubuntu 20.04 patches # 3. 返回工作空间根目录初始化 catkin cd ~/catkin_ws catkin init # 4. 关键设置 isolated 构建参数 catkin config --extend /opt/ros/noetic --isolate --merge-devel --cmake-args \ -DCMAKE_BUILD_TYPERelease \ -DCMAKE_CXX_STANDARD17 \ -DABSL_ENABLE_INSTALLON # 5. 执行编译必须用 --pkg 指定顺序否则依赖解析失败 catkin_make_isolated --pkg cartographer --install catkin_make_isolated --pkg cartographer_ros --install # 6. 激活环境 source ~/catkin_ws/install_isolated/setup.bash实操心得catkin_make_isolated的--pkg参数必须分两次调用。若一次性--pkg cartographer cartographer_roscartographer_ros会因cartographer的 target 尚未安装到install_isolated目录而找不到依赖。--install参数确保生成install_isolated目录setup.bash才能正确导出CMAKE_PREFIX_PATH。4.3 验证安装三个层次的可靠性测试Level 1基础命令验证# 检查 ROS 包是否注册 rospack find cartographer_ros # 应返回 ~/catkin_ws/install_isolated/share/cartographer_ros # 检查可执行文件是否存在 ls ~/catkin_ws/install_isolated/lib/cartographer_ros/ # 应有 cartographer_node, assets_writer 等Level 2C API 可用性验证创建测试文件~/test_carto.cpp#include cartographer/mapping/pose_graph_interface.h #include iostream int main() { std::cout Cartographer C API loaded successfully! std::endl; return 0; }编译g -stdc17 ~/test_carto.cpp pkg-config --cflags --libs cartographer -o ~/test_carto ./test_carto # 输出 Cartographer C API loaded successfully!Level 3ROS 节点功能验证使用官方 demo# 下载 demo bag约 1.2GB wget -P ~/Downloads https://storage.googleapis.com/cartographer-public-data/bags/backpack_2d/cartographer_paper_deutsches_museum.bag # 启动 demo需提前 source setup.bash roslaunch cartographer_ros demo_backpack_2d.launch bag_filename:${HOME}/Downloads/cartographer_paper_deutsches_museum.bag注意事项首次运行会卡在Loading trajectory...约 90 秒这是 Cartographer 在构建初始子地图属正常现象。若 5 分钟无响应检查roscore是否运行、/tftopic 是否有数据用rostopic hz /tf验证。5. 常见问题与排查技巧实录那些让老手也抓狂的“幽灵错误”5.1 编译期错误速查表错误信息根本原因解决方案出现频率fatal error: google/protobuf/stubs/common.h: No such file or directoryProtobuf 3.0.0 未正确安装或ldconfig未刷新重新执行sudo ldconfig检查/usr/lib/x86_64-linux-gnu/libprotobuf.so.15是否存在⭐⭐⭐⭐⭐error: ‘optional’ is not a member of ‘std’C17 未启用在cartographer/CMakeLists.txt添加set(CMAKE_CXX_STANDARD 17)⭐⭐⭐⭐Could not find a package configuration file for cartographercatkin_make_isolated未指定--install或setup.bash未 source重新执行catkin_make_isolated --install然后source install_isolated/setup.bash⭐⭐⭐⭐undefined reference to google::LogMessage::Init(...)libgoogle-glog-dev与libgflags-dev版本不匹配sudo apt install libgoogle-glog-dev0.4.0-4 libgflags-dev2.2.2-1build1锁定版本⭐⭐⭐CMake Error at CMakeLists.txt:122 (target_link_libraries):br The absl::base target was not found.absl库未通过find_package导入打 Patch 1添加find_package(absl REQUIRED)⭐⭐⭐5.2 运行时错误深度排查问题cartographer_node启动后立即退出日志显示F0512 10:23:45.123456 12345 pose_graph.cc:123] Check failed: options_.optimize_every_n_nodes 0这是 Cartographer 的pose_graph_options.lua配置错误。Ubuntu 20.04 的cartographer_ros默认配置文件位于~/catkin_ws/install_isolated/share/cartographer_ros/configuration_files/但demo_backpack_2d.launch加载的是backpack_2d.lua而该文件第 42 行POSE_GRAPH.optimize_every_n_nodes 0是非法值。必须手动编辑nano ~/catkin_ws/install_isolated/share/cartographer_ros/configuration_files/backpack_2d.lua # 将第 42 行改为 POSE_GRAPH.optimize_every_n_nodes 20排查技巧用rosparam get /cartographer_node/parameter_descriptions查看当前加载的参数确认optimize_every_n_nodes值用roslaunch --screen cartographer_ros demo_backpack_2d.launch启动可看到完整 stderr 输出。问题Rviz 中Maptopic 显示空白tftree 里map→odom断开这不是 Cartographer 问题而是cartographer_ros的occupancy_grid_node未正确订阅submap_list。检查demo_backpack_2d.launch第 38 行node nameoccupancy_grid_node pkgcartographer_ros typecartographer_occupancy_grid_node args-resolution 0.05 /必须添加remapremap from/submap_list to/cartographer/submap_list/因为 Cartographer 1.0 默认将 submap 发布到/cartographer/submap_list而旧版 launch 文件未更新 remap。问题建图速度极慢 0.1x real-timeCPU 占用率 100%这是ceres优化器未启用多线程。Cartographer 的CeresScanMatcher默认单线程需在backpack_2d.lua中添加TRAJECTORY_BUILDER_2D.ceres_scan_matcher.num_threads 4同时确保cartographer_ros编译时启用了 OpenMP在catkin config中添加-DOPENMP_ENABLEON。5.3 终极避坑清单那些文档里绝不会写的“血泪经验”不要用sudo运行catkin_make_isolated这会导致install_isolated目录属主变为 root后续roslaunch会因权限不足无法写入 log 文件。cartographer_ros的CMakeLists.txt里add_compile_options(-stdc17)必须放在find_package(catographer)之后否则catographer的CMakeLists.txt会因 C 标准不一致而拒绝导入。bag文件时间戳必须连续若用rosbag record录制自己的数据务必加-a参数记录所有 topic否则cartographer_node因tf数据缺失而卡死。rviz配置文件.rviz里Fixed Frame必须设为map这是 Cartographer 的全局坐标系设成odom或base_link会导致地图漂移。cartographer_occupancy_grid_node的-resolution参数单位是米/像素设0.1表示 10cm 分辨率设0.01会生成超大内存占用的地图1000x1000 像素地图需 1MB 内存而0.01分辨率下同等区域需 100MB。我在某工业 AGV 项目中曾因resolution设为0.01导致occupancy_grid_node占用 12GB 内存机器人主控板直接 OOM 重启。后来改用0.055cm 分辨率内存降至 300MB建图精度损失不到 2%这才是工程实践的真谛在约束条件下找最优解而不是追求纸面参数。
阅读完成 · 觉得有帮助?
咨询建站