ARTICLE DETAIL

资讯详情

深耕商务建站与企业官网运营的一线实战洞察。

Cartographer 2D/3D建图与定位:ROS环境配置到源码编译实战

Cartographer 2D/3D建图与定位:ROS环境配置到源码编译实战 先说个现象不少技术群里隔三差五就会有人贴同一句报错——无法定位软件包 ros-noetic-desktop-full底下回复基本是一串“换源、sudo apt update、再试试”。这句报错背后其实是安装Cartographer的第一道门槛ROS环境没理清楚。如果你也被困在环境上或者已经装好了ROS但不知道接下来怎么编译Cartographer这篇就是给你写的。这篇文章会从Ubuntu和ROS版本的选择讲起把Cartographer的源码编译、官方2D/3D建图demo、再到纯定位模式pure localization的配置一条线走通。我假设你至少有基本的Linux命令行能力也用过rosbag、rviz这类工具。整个过程中我会把容易踩的坑单独指出来尤其是那些“网上教程不会写但几乎人人都会遇到”的细节。1. 先别急着编译ROS版本和安装源决定了一半的成败1.1 版本匹配为什么我推荐Ubuntu 20.04 Noetic Cartographer 1.0Cartographer是Google维护的激光SLAM库核心是纯C的cartographer库加一层ROS适配层cartographer_ros。它支持2D和3D建图也支持基于已有地图的纯定位这也是标题里“2D/3D建图与定位”分不开的原因。先说版本。目前网上能找到的Cartographer教程主要针对ROS1其中Ubuntu 20.04配ROS Noetic是最稳的组合。用Ubuntu 22.04配ROS2 Humble也可以从源码编Cartographer但ROS2分支的文档、launch组织方式、依赖处理都更绕对新手不友好。你要是为了快速跑通、理解原理直接选20.04 Noetic别纠结。很多人挂在“无法定位软件包 ros-noetic-desktop-full”这一步大概率是系统版本不是20.04或者apt源里没有ROS仓库。这里有个隐藏前提Cartographer目前没有打包好的二进制必须源码编译但它的依赖又大量来自ROS所以ROS环境是绕不开的前置条件。与其纠结要不要装desktop-full不如先把ROS源的配置搞明白。1.2 报“无法定位软件包 ros-noetic-desktop-full”时先查这三处无法定位软件包的直译就是apt源里找不到这个候选包。按下面顺序排查比盲目换源有效得多确认系统版本。运行lsb_release -a看Ubuntu版本是不是20.04。Noetic只支持20.04你在18.04上装当然找不到。确认ROS源是否正确配置。查看/etc/apt/sources.list以及/etc/apt/sources.list.d/下的文件看有没有ROS官方源或国内镜像源。官方源格式大致是deb http://packages.ros.org/ros/ubuntu focal main其中focal对应20.04。执行sudo apt update。很多时候是索引没刷新包列表还是旧的。更新完再试一次apt policy ros-noetic-desktop-full如果能看到候选版本说明源没问题。如果你是国内网络建议直接配置清华或阿里云的ROS镜像速度差距非常明显。apt-key过期也是一个高频问题如果在apt update时报NO_PUBKEY需要提前把ROS公钥重新导入具体命令ROS官方文档里有按当前版本的指引操作即可。另外很多一键安装脚本会把ROS源、python工具、rosdep一把梭装好比如“鱼香ROS”那套脚本确实省事。我的建议是可以用但你最好知道它改了什么。它通常做的事情无非是写入ROS apt源、安装python3-rosdep等基础工具。如果你自己排查问题心里要有数别出事了连自己改过什么都不知道。1.3 不装desktop-full也能跑按需裁剪依赖很多人卡在“无法定位软件包 ros-noetic-desktop-full”其实即使定位到了desktop-full的体积也很大因为里面带了Gazebo、navigation、move_base这些和Cartographer无关的包。如果你只想跑Cartographer装ros-noetic-ros-base就够然后额外补ros-noetic-rviz和ros-noetic-rosbag。Cartographer的demo launch会依赖rviz所以这个包必须装。最小化安装的参考命令sudo apt update sudo apt install -y ros-noetic-ros-base ros-noetic-rviz ros-noetic-rosbag echo source /opt/ros/noetic/setup.bash ~/.bashrc source ~/.bashrc这样装完再补python3-wstool、python3-rosdep、ninja-build等编译工具就够了。别小看这个选择编译Cartographer时如果系统里的ROS包越多遇到依赖版本冲突的可能性也越大精简环境反而好排查问题。2. 源码编译没有捷径先把cartographer和cartographer_ros的关系理清2.1 你编译的不是一个包而是两层Cartographer从宏观上看分两层cartographer核心SLAM算法库纯C不依赖ROS。它负责激光扫描匹配、子图构建、位姿图优化、回环检测这些真正的“大脑”工作。cartographer_rosROS适配层把激光话题、IMU话题、TF变换、launch文件、参数配置接进去并调用cartographer完成建图和定位。这个区分非常重要。你去看“cartographer代码解析”时如果直接一头扎进cartographer_ros包里的源码会发现大量代码都是ROS消息和内部数据结构互转真正的算法都在cartographer核心库里。编译时也建议从核心库开始然后再编译ROS层。2.2 完整编译命令与顺序官方推荐用catkin_make_isolated来编译原因是cartographer本身不是catkin包catkin_make_isolated会按依赖顺序逐个编译不会因为非catkin包的存在而中断。完整流程如下mkdir -p ~/cartographer_ws/src cd ~/cartographer_ws wstool init src wstool merge -t src https://raw.githubusercontent.com/cartographer-project/cartographer_ros/master/cartographer_ros.rosinstall wstool update -t src sudo src/cartographer/scripts/install_proto3.sh sudo rosdep init rosdep update rosdep install --from-paths src --ignore-src --rosdistronoetic -y catkin_make_isolated --install --use-ninja注意几个关键点wstool update之后src目录下会多出cartographer、cartographer_ros、abseil-cpp几个仓库这是好事。很多人编译时报缺失abseil就是因为这步没执行成功导致仓库根本没有拉全。install_proto3.sh脚本会从源码编译安装一个特定版本的protobuf到/usr/local。这个脚本比较耗时但必须执行因为Cartographer对protobuf版本有硬性要求。rosdep install这步会读取包依赖并自动安装系统依赖。如果它报找不到某个包多半是ROS源没配好或者版本不对。编译时用--use-ninja会快不少尤其是改代码后重新编译体验差距明显。2.3 abseil和protobuf组合新手最容易栽的坑编译过程中最经典的错误是一堆和absl相关的编译失败类似fatal error: absl/strings/str_split.h: No such file or directory原因在于Cartographer依赖的abseil版本是特定的它并不是随便用系统里apt install libabsl-dev装出来的版本就能替代。官方cartographer_ros.rosinstall文件里已经锁定了abseil的commit这个版本和Cartographer当时使用的protobuf接口是配套的。如果你系统环境里同时存在其他abseil版本链接阶段可能直接冲突。我的建议是严格按官方rosinstall的版本走不要自己升级abseil或protobuf。如果之前在系统里装过libabsl-dev最好先卸掉再用wstool拉下来的版本编译。另外也不要图省事手动apt install python3-protobuf或升级系统protobuf一旦/usr/local的protobuf和ROS自带的protobuf混合就会冒出一堆“google::protobuf版本冲突”的诡异报错。2.4 编译完成后的自检清单编译完成不代表万事大吉建议按顺序验证一次执行source install_isolated/setup.bash确认环境变量生效。这个setup.bash替代了普通工作空间的devel/setup.bash路径别搞混。运行rosversion cartographer_ros如果能输出版本号一般是1.0.0说明ROS层安装成功。试着启动一个不会跑数据的launch例如roslaunch cartographer_ros demo_revo_lds.launch。这一步即使没有任何bag只要launch能正常加载参数、rviz能打开、终端不报FATAL就说明基本环境已经OK。如果这三步都过了你已经跨过了最痛苦的环境阶段接下来就是真正打开建图世界的大门。3. 2D建图实战用官方bag跑通第一个完整流程3.1 数据包准备先检查bag再跑省得白折腾我第一次跑Cartographer时犯过一个低级错误直接拿自己录的2D激光bag去跑结果rviz里什么点云都没有。后来才发现是话题名对不上官方launch配置里订阅的是/scan我的bag里话题叫/laser_scan。所以无论官方数据集还是自己录的bag先执行一遍rosbag info your_bag.bag重点看两个方面话题名和消息类型。如果是2D建图需要的是sensor_msgs/LaserScan或sensor_msgs/PointCloud2如果话题名不是/scan要么改launch的remap参数要么改bag里的topic名用rosbag reindex这类操作比较麻烦推荐直接remap。官方2D数据集可以从Cartographer项目的GitHub页面找到常见的是基于Revo LDS传感器采集的bag。这个bag体积不大适合第一次用来理解整个流程。3.2 一条launch命令背后发生了什么运行2D建图demo最常用的命令是roslaunch cartographer_ros demo_revo_lds.launch bag_filename:/path/to/your.bag这条launch展开后做了这么几件事启动cartographer_node它负责接收传感器数据、调用核心SLAM算法并发布子图、轨迹、位姿估计等话题。加载revo_lds.lua参数文件。这个lua文件在/opt/ros/noetic/share/cartographer_ros/configuration_files目录下里面定义了map_builder、trajectory_builder、pose_graph等一大串参数。启动rviz并加载预制的显示配置你不需要手动添加PointCloud2、Map、Trajectory等显示项。看到这里你应该理解了lua文件就是Cartographer的“大脑配置文件”想要调参改的就是这个文件。launch本身只是把它读进来再传给节点。3.3 运行与观察回环闭合那一刻发生了什么用官方bag跑起来之后rviz里会看到这样的过程一开始激光点云拼出一片模糊的小块轨迹线歪歪扭扭地延伸子图也是零散的随着数据继续播放当机器人走回曾经经过的位置时会发生一次明显的“拉回”——原本错开的走廊、墙角突然对齐了整幅地图一下子变得干净了很多。这个“拉回”瞬间就是回环闭合触发了全局位姿图优化。Cartographer之所以比很多传统2D SLAM表现好关键在于它把建图看成“在不断增长的子图集合里做全局优化”回环检测一旦命中优化器会把之前所有累积的漂移重新分配让地图收敛。如果你跑的时候发现全程没有明显的回环优化或者地图永远不会闭合可能是数据集本身不包含回环也可能是参数里的回环检测阈值不合适。后面会专门讲参数。3.4 影响2D建图质量的参数按优先级排序很多人拿到lua文件不知道从哪下手几个关键参数我整理成了表格参数作用经验参考use_online_correlative_scan_matching是否使用实时CSM做前端匹配2D建议truefalse时纯Ceres匹配容易陷入局部极值num_subdivisions_per_laser_scan每帧激光被细分成几段参与匹配数值越大计算越密一般保持默认rotation_weight/translation_weightCeres匹配器对旋转和平移的权重平移权重稍大更有利于走廊环境纯旋转场景适当调大rotation_weightmin_score回环检测的最低分数阈值太高会漏检太低会误检默认值附近微调max_range超过该距离的激光点会被忽略空旷场景可以调大但要注意噪点调参千万不要一次动五六个参数。先改一个跑一段bag看效果再改下一个。我自己常用的做法是先保证use_online_correlative_scan_matching true然后调max_range把异常远点过滤掉最后再看回环情况。一个参数一个参数改才知道哪个改动起了作用。4. 3D建图实战传感器不同逻辑同根4.1 硬件前提与数据条件没有IMU3D基本是空中楼阁3D建图比2D复杂一大截最核心的区别在于2D激光通常只输出一个平面范围内的扫描而3D建图面对的是多线激光雷达输出的大量三维点且机器人自身有俯仰、横滚、偏航六个自由度。没有IMU提供的姿态先验6自由度位姿估计很容易发散。所以官方3D demo的数据包中一定有IMU话题通常叫/imu消息类型是sensor_msgs/Imu。如果你要跑自己录的数据务必检查三点点云话题类型是sensor_msgs/PointCloud2并且话题名和launch里配置一致。IMU话题存在且有数据rostopic hz /imu能看到正常频率。TF树里有imu_link到base_link、base_link到雷达的变换通常通过URDF描述。没有IMU的情况下3D建图几乎不可用。网上也有人尝试只用3D激光做纯匹配但那种方案对环境要求极高也容易漂实际项目里不要这么干。4.2 3D demo跑起来和2D的直观差异3D官方demo命令和2D很像roslaunch cartographer_ros demo_backpack_3d.launch bag_filename:/path/to/your.bag但启动之后你会很快感受到差异rviz里显示的是三维子图submap不再是二维栅格平面视野里是一片立体点云。加载的是backpack_3d.lua不是revo_lds.lua。这个lua里trajectory_builder的配置整体换成3D版本比如num_accumulated_range_data、motion_filter这些参数。同样的bag时长3D的处理速度和效率明显低于2DCPU占用率会高一大截。我第一次跑3D时明显感觉体感不同激光一帧的数据量比2D大一个数量级整个前端匹配和子图构建的计算量都上来了。如果你的电脑性能一般跑起来会卡顿甚至出现实时性跟不上导致漂移。4.3 3D调参的观察与心得3D建图的调参相比2D更谨慎。以下是我实际测试后的几个结论optimize_every_n_nodes这个参数在3D下对性能影响很大。它表示每积累多少个节点触发一次全局优化。数值越小优化越频繁地图越容易收敛但CPU压力也越大。实测中如果CPU顶不住可以把默认的10改成20甚至更高牺牲一些收敛速度换实时性。use_online_correlative_scan_matching在3D下是否需要开启要分场景。开起来对精度有帮助但计算压力大在一些点云特征丰富的室内环境不开也够用。3D建图数据里机器人的运动速度对结果影响很大。转场太快时点云会拖影站定不动时IMU零偏会累积。理想的数据是匀速慢速移动让雷达和IMU都能持续观测到足够多的特征。3D调参比2D更容易陷入“盲目调参”的泥潭。我的建议是先把CPU占用和实时性控制住再谈精度。如果节点本身都跑不到实时任何参数优化都白搭。5. 建完图之后才是重头戏把pbstream变成可用定位服务5.1 定位和建图的本质区别地图固定轨迹单开建图的过程中Cartographer会不断添加新的子图到全局地图并不断做回环优化来修正地图本身。而纯定位模式做的事情完全不同它把已经保存好的地图当作固定世界不再往地图里添加新子图只开一条新的轨迹用实时激光数据和IMU去估计这辆机器人在地图中的位姿。这个区分对理解“定位”非常关键。很多人以为定位就是“跑一个建图节点但不用保存地图”这是错误的。定位必须有一个预先建好的地图文件Cartographer官方后缀名是.pbstream它是序列化后的整个子图集合和位姿图状态然后你在启动时加载它并让算法以“纯定位”方式运行。5.2 导出地图从pbstream到定位地图建图完成后先结束轨迹再保存状态rosservice call /finish_trajectory 0 rosservice call /write_state {filename: /home/user/maps/my_map.pbstream, include_unfinished_submaps: false}注意/finish_trajectory 0里的0是轨迹ID第一次建图通常是0如果你开过多条轨迹这个ID不一定是0。include_unfinished_submaps建议设false这样保存的是已经完成优化的子图定位时更稳定。保存出.pbstream后如果你只是要在Cartographer内部使用这个文件就够了。如果你还想把它转成ROS的.pgm.yaml地图给map_server或Navigation栈用那还需要额外转换工具步骤比较繁琐。这里我只讲Cartographer自身定位因为它最能发挥这套系统闭环优化的优势。5.3 定位模式的配置pure_localization与初始位姿定位模式的launch通常是从建图launch改过来的。关键步骤复制一份建图用的lua比如my_2d.lua在里面找到-- pure_localization相关的字段不同版本写法略有差异但核心是pure_localization true同时确保把建图相关的“新建子图”逻辑关掉。在launch文件里给cartographer_node增加一个参数用load_state_filename指定pbstream路径例如node namecartographer_node pkgcartographer_ros typecartographer_node outputscreen param nameconfiguration_directory value$(find cartographer_ros)/configuration_files/ param nameconfiguration_basename valuemy_2d.lua/ param nameload_state_filename value/home/user/maps/my_map.pbstream/ /node启动后在rviz里用2D Pose Estimate给一个大约的初始位姿。这一步是必须的系统无法自己猜出你在地图的哪个位置。初始位姿给得越准匹配收敛越快。有一个非常常见的现象初始位姿给错后定位直接跳到一个奇怪的地方随后完全丢失。这不是算法坏了而是激光扫描匹配落在了错误的局部极值上。遇到这种情况重新给一次准确的初始位姿即可。定位模式下系统依然会发布/map、/scan_matched_points2、/submap_list等话题但地图不会变了。你可以把定位节点当作一个“只输出位姿的无地图更新SLAM”这是理解它输出结果的最快路径。5.4 实测定位的漂移问题和排查顺序纯定位模式跑起来后漂移是最常见的抱怨。我的排查顺序是先看TF树。map - odom - base_link这条链路必须完整。如果odom来自轮式里程计它的漂移会影响整个系统的稳定性如果odom完全没有输出定位很难跑好。确认IMU方向。IMU的坐标系和朝向必须和建图时一致否则算法对姿态的信念会错位。这点在建图时不明显因为建图容忍度大定位时初始状态高度依赖姿态一错就崩。验证初始位姿。不要相信模糊的“大概在那个方向”。先对比rviz里激光点云和地图的墙体重合情况再确认位姿发布的方向角对不对。看参数是否和建图时一致。定位时使用的地图是之前建图参数下产生的如果传感器内外参、max_range这些和建图时相差太大算法会“读不懂”激光数据。定位模式跑稳之后会明显感受到它和建图的区别地图不再增长但轨迹和位姿依然实时更新小范围绕圈几乎不漂长距离匀速跑会有累积误差但一般比纯轮式里程计要准得多。6. 编译和运行过程中的高频报错附排查思路6.1 编译期报错版本冲突类编译期报错大多集中在依赖版本上没有太多“灵丹妙药”但常见问题可以快速定位fatal error: absl/strings/...abseil缺失或版本不对。检查src目录下有没有abseil-cpp仓库重新执行wstool update -t src后再编译。如果系统里装了libabsl-dev先卸掉再编。Could not find a package configuration file provided by cartographer核心库没编译成功或者install_isolated路径没有正确加载。确认source install_isolated/setup.bash执行过再重新编译cartographer_ros。protobuf相关错误比如*.pb.h文件过旧或缺失重新执行sudo src/cartographer/scripts/install_proto3.sh确认/usr/local/bin/protoc版本和Cartographer要求一致。不要随手apt install protobuf-compiler去覆盖它。6.2 运行期报错话题、TF树、数据不匹配跑demo时报错先分清是数据问题还是配置问题Message dropped: No match for time stamp时间戳不匹配常见原因是bag里的话题时间戳跳变或者没有设置use_sim_time: true。官方launch已经设置了use_sim_time如果你自己手写launch很容易漏掉。No transform from [map] to [base_link]TF树断链。先跑rosrun tf tf_echo map base_link看输出是否正常。如果output报错说明某个TF没有发布。2D建图、3D建图、定位都依赖URDF和TF树这一步是排查的重中之重。rviz里没有任何点云检查话题名。/scan、/points2、/imu的话题名有任何一处和launch配置不一致都可能导致数据没有被订阅。用rostopic list对比一下就知道。6.3 建图/定位效果差的排查顺序效果类问题比报错难查因为系统不会直接告诉你哪里不对。我的顺序一般是先确认数据质量。rosbag play --pause暂停后在rviz里检查当前时刻的激光点云有没有抖动、跳变、测距噪声。再确认传感器外参。雷达安装位置和IMU的坐标变换如果差了几厘米室内环境可能看不出来走廊或门框边上就会暴露问题。然后调整前端匹配和后端优化的参数。但记住参数是“锦上添花”不是“无中生有”。数据质量太差时参数怎么调都没用。最后才是看回环检测阈值、优化频率这类细节参数。很多初学者一上来就先改min_score结果越改越乱就是因为跳过了前面的步骤。定位效果差时优先怀疑初始位姿和坐标系其次再怀疑参数。定位对环境和地图的匹配要求比建图更苛刻地图旧了、环境变了定位质量下降是正常现象不是算法出了问题。Cartographer这套东西我第一次从零到跑通2D花了一整天3D又花了一整天。回过头看最大的感受是先跑通官方bag再碰自己的传感器。拿自己小车的数据直接上很容易把参数问题、数据问题、硬件问题混在一起最后卡到怀疑人生。建议你第一次就老老实实用官方数据包把建图、回环、定位机制都看明白再一步步替换成自己的数据。遇到报错时先把launch、lua、TF这三样理一遍八成问题都出在这里。Cartographer的版本更新不算快但它的2D/3D建图和定位能力依然是移动机器人项目里的可靠选择值得花时间吃透。
返回列表
PREV
查看更多资讯
NEXT
返回资讯列表