
最近群里好几个朋友卡在LIO-SAM编译这一步而且卡得最多的就是Ubuntu 20.04 ROS Noetic这个组合。原因不复杂LIO-SAM官方README写的是Ubuntu 18.04 Melodic环境到了Noetic这里OpenCV从3.x跳到4.xPCL和Eigen的版本也变了再加上gtsam这个关键依赖库本身编译就有讲究直接照着官方步骤走大概率会在某个环节翻车。这篇文章把我从零开始在Ubuntu 20.04 ROS Noetic下编译LIO-SAM的完整过程、踩过的坑、以及排查思路整理出来。不管你是刚接触激光雷达SLAM的新人还是已经被编译报错折磨了一下午的老手照着这份记录操作基本可以顺利跑通。文章会覆盖环境准备、依赖库编译、主程序构建、launch文件调试、数据集回放以及高频报错的解决方案。有些细节是官方文档里不会写的属于实操踩坑后的经验总结。1. 环境准备与版本避坑1.1 先搞清楚你的系统状态动手之前先确认三件事操作系统版本、ROS版本、以及系统里是否装过其他版本的ROS或CUDA相关组件。LIO-SAM这套框架本身不挑显卡纯CPU就能跑但不少人是在装了NVIDIA驱动和CUDA的环境中编译的。如果你之前折腾过显卡驱动、装过TensorRT或者别的深度学习环境编译时偶尔会出现libopencv版本冲突或者Eigen头文件被错误链接的情况。我的建议是如果机器只是用来跑SLAM尽量不要在同一个系统里混装过多版本的OpenCV。Noetic默认自带OpenCV 4.2LIO-SAM某些节点用到了旧版API稍后会讲怎么改。确认完这些打开终端执行lsb_release -a rosversion -d如果rosversion -d输出的是noetic很好如果什么都没输出说明你的/opt/ros/noetic/setup.bash没source进bashrc这个先解决echo source /opt/ros/noetic/setup.bash ~/.bashrc source ~/.bashrc1.2 依赖库版本先对齐再谈其他按官方README装ros-noetic-pcl-ros、ros-noetic-velodyne-msgs、ros-noetic-cv-bridge这些包基本没错。但以我实际操作的经验有几个包就算官方没写你也会用得上建议一次性装齐sudo apt install ros-noetic-pcl-ros ros-noetic-velodyne-msgs ros-noetic-cv-bridge ros-noetic-image-transport ros-noetic-tf2-geometry-msgs ros-noetic-robot-state-publisher顺便装一些基础工具sudo apt install git cmake libeigen3-dev libopencv-dev python3-catkin-tools这里要特别提醒一个很多人忽略的点Eigen版本。Ubuntu 20.04的软件源里Eigen是3.3.7LIO-SAM对Eigen的需求不算苛刻3.3.x都能用。怕的是你之前从源码装过更高版本的Eigen导致头文件路径混乱。如果真的遇到过类似问题可以先用dpkg -l | grep eigen看看系统里到底装了什么版本再决定要不要清掉手动安装的版本。2. 核心依赖逐一手动编译2.1 gtsam的编译是整个流程的胜负手LIO-SAM的位姿图优化、因子图构建全建立在GTSAM这个库上。官方推荐的是4.0.0-alpha2这个版本不是最新的4.1.1或者4.2.0。有人用新版本也编过了但我的建议是别折腾老老实实按推荐版本来。编译gtsam之前先把它的依赖装好sudo apt install libtbb-dev libboost-all-dev然后clone源码并编译git clone https://github.com/borglab/gtsam.git cd gtsam git checkout 4.0.0-alpha2 mkdir build cd build cmake -DGTSAM_BUILD_EXAMPLESOFF -DGTSAM_BUILD_TESTSOFF -DGTSAM_TANGENT_PREINTEGRATIONOFF .. make -j$(nproc) sudo make install编译参数里有两个坑需要解释一下为什么-DGTSAM_TANGENT_PREINTEGRATIONOFFLIO-SAM作者在代码里明确建议关闭这个选项。开启状态下gtsam会使用新的切空间预积分接口而LIO-SAM的IMU预积分代码还是老接口链接时会报一堆“未定义符号”的错。为什么关掉examples和tests这两个选项会生成大量测试程序和示例代码编译时间极长内存占用也高。关掉之后能节省至少一半的编译时间。make -j$(nproc)这里也注意一下如果电脑内存只有8G-j$(nproc)可能直接把内存吃满导致编译被杀。建议内存小的机器改用make -j4或者make -j2。编译过程大概需要10到20分钟取决于机器性能。装完之后确认一下gtsam是否被正确安装ls /usr/local/lib | grep gtsam ls /usr/local/include/gtsam | head能看到libgtsam.so和头文件目录说明gtsam这块稳了。2.2 OpenCV版本差异处理Noetic自带的OpenCV是4.2LIO-SAM里imageProj节点读取图像时用了老写法CV_LOAD_IMAGE_GRAYSCALE在OpenCV 4环境会直接报错。这个错误不用怕改一行代码就行后面第三章具体说。如果你特别介意这些API差异有个取巧方案把LIO-SAM的CMakeLists.txt里OpenCV相关的引用改成find_package(OpenCV REQUIRED COMPONENTS core imgproc imgcodecs)然后代码里的旧API全部替换。但说实话不值得为了追求“零警告”去折腾能用就行。2.3 关于Ceres和LIO-SAM的关系有些教程会让你额外编译Ceres Solver那是针对LIO-SAM作者另一个项目LIO-SAM的变体或者LOAM系列项目的。原版LIO-SAM根本不依赖Ceres它的后端优化由gtsam完成。看到网上教程让你装Ceres时可以跳过别浪费时间。3. LIO-SAM主程序编译全流程3.1 建立工作空间并获取源码这一步是所有ROS项目的常规操作mkdir -p ~/lio_sam_ws/src cd ~/lio_sam_ws catkin_make这里catkin_make第一次运行是为了生成devel目录和build目录很多教程跳过了这一步直接clone源码再catkin_make也问题不大但先执行一次能避免某些情况下CMake缓存没初始化导致的怪问题。然后clone LIO-SAM源码cd ~/lio_sam_ws/src git clone https://github.com/TixiaoShan/LIO-SAM.git cd ~/lio_sam_ws catkin_make如果你需要修改源码后重新编译推荐用catkin_make --pkg lio-sam单独编译这个包编译速度快很多cd ~/lio_sam_ws catkin_make --pkg lio-sam3.2 修改CMakeLists.txt里的编译标准LIO-SAM源码默认的CMakeLists.txt里有这么一行add_compile_options(-stdc11)在Noetic环境下某些头文件尤其是PCL 1.10和OpenCV 4.2的用了C14的特性继续用C11标准编译会报一堆莫名其妙的错误比如shared_ptr相关的问题。把这一行改成add_compile_options(-stdc14)或者直接用更稳妥的方式在文件开头加上set(CMAKE_CXX_STANDARD 14) set(CMAKE_CXX_STANDARD_REQUIRED ON)具体操作gedit ~/lio_sam_ws/src/LIO-SAM/CMakeLists.txt找到add_compile_options那一行改完保存。3.3 imageProj节点的OpenCV API替换如果你用的是比较新的LIO-SAM源码分支imageProjection.cpp里可能已经修复了OpenCV 4兼容性。如果编译时报错定位到报错的文件找到类似这样的代码cv::Mat image cv::imread(bag_path, CV_LOAD_IMAGE_GRAYSCALE);改成cv::Mat image cv::imread(bag_path, cv::IMREAD_GRAYSCALE);改完后重新编译cd ~/lio_sam_ws catkin_make --pkg lio-sam3.4 最容易忘的一步launch文件加执行权限这是个特别容易踩的坑。LIO-SAM的launch文件在源码里默认没有x执行权限直接用roslaunch启动时偶尔会出现“Permission denied”或者直接没有任何反应。虽然有些系统下roslaunch能自动处理这个问题但保险起见建议先手动加一下权限chmod x ~/lio_sam_ws/src/LIO-SAM/launch/*.launch chmod x ~/lio_sam_ws/src/LIO-SAM/rviz/*.rviz网上很多教程压根不提这一步导致很多人卡在“明明编译成功了但roslaunch就是报错”的环节。3.5 编译成功之后的验证编译完成后确认可执行文件已经生成ls ~/lio_sam_ws/devel/lib/lio_sam/正常会看到lio_sam_imuPreintegration、lio_sam_imageProjection、lio_sam_featureExtraction、lio_sam_mapOptimization四个可执行文件。看到这四个文件说明编译阶段全部通过。4. 常见问题排查与避坑经验4.1 编译阶段的高频报错报错Could not find a package configuration file provided by gtsam百分之百是gtsam没装或者安装路径不在CMake默认搜索范围里。先确认/usr/local/lib/cmake/GTSAM目录是否存在。如果存在在CMakeLists.txt里加一句list(APPEND CMAKE_PREFIX_PATH /usr/local/lib/cmake/GTSAM)如果连这个目录都不存在回第二章重新编译gtsam。报错fatal error: gtsam/nonlinear/ISAM2.h: No such file or directory头文件路径没找到。确认/usr/local/include/gtsam存在如果之前把gtsam安装在自定义前缀比如~/gtsam_install需要显式指定set(GTSAM_INCLUDE_DIR ~/gtsam_install/include) set(GTSAM_LIBRARY_DIR ~/gtsam_install/lib)报错candidate expects 2 arguments, 2 provided这种一般是gtsam版本不对用了最新版gtsam的接口差异导致。回退到4.0.0-alpha2版本重新编译。报错undefined reference tocv::imread(...)OpenCV 4改了图像读取接口按照3.3节的替换方法处理。报错PCL 1.10的警告warning特别多这个不影响编译结果不用管它。PCL 1.10在C14下编译时会有大量“deprecated”警告属于正常现象。4.2 运行阶段的常见问题问题roslaunch一键启动后RViz弹出来了但没有任何点云先检查rosbag play有没有真的在播数据。LIO-SAM没有数据源输入时所有话题都是空的RViz自然什么都没有。确认一下bag文件路径和launch文件里读取的路径是否一致。问题提示No transform from [imu] to [base_link]这是TF树不完整导致的。LIO-SAM的launch文件里已经包含了静态TF发布节点正常情况下会发布base_link到imu、base_link到lidar_link的坐标变换。如果报错试着在另一个终端手动发布一次静态变换rosrun tf2_ros static_transform_publisher 0 0 0 0 0 0 base_link imu但根本性的解决办法还是检查launch文件里robotStatePublisher节点有没有被正确加载。问题启动后立刻段错误Segmentation fault多半是gtsam库版本不匹配。有人用gtsam 4.1.1编译通过但运行时内存访问出错退回4.0.0-alpha2之后问题消失。这种就是典型的“能编译不代表能运行”遇到段错误优先排查依赖库版本。问题位姿飘了点云发散这已经不是编译问题是传感器标定问题。检查三点IMU的噪声密度和随机游走参数是否配置正确lidar到IMU的外参是否按你的传感器实际安装位置写了bag里的IMU话题频率是否正常一般200Hz。参数文件在config/params.yaml改完需要重新编译才能生效。4.3 launch文件修改了需要重新编译吗这是很多新手会问的问题也确实是ROS里最容易混淆的一个点。答案是不需要编译。launch文件本质上是XML格式的启动描述文件roslaunch在运行时会直接读取并解析它不会编译成二进制。修改launch文件、改参数文件.yaml之后只要重新roslaunch一次改动就会生效。但要注意区分如果你改的是.cpp或.h源码文件、CMakeLists.txt、package.xml那就必须重新编译。这里有个速查标准改动的文件类型是否需要编译说明.launch否roslaunch直接解析XML.yamlparams否节点启动时读取参数服务器.cpp / .h是需要重新catkin_makeCMakeLists.txt是需要重新catkin_makepackage.xml是需要重新catkin_make实际操作中频繁改launch文件和yaml参数时我习惯先catkin_make一次再把所有终端重启一遍。这样能避免老节点的参数服务器缓存没清干净导致的“改了没生效”假象。4.4 数据集回放时的Topic名称匹配问题用rosbag回放数据时要先看bag里的topic名称是否和LIO-SAM期望的一致。LIO-SAM节点订阅的话题主要有/points_raw原始点云类型sensor_msgs/PointCloud2/imu_correctIMU数据类型sensor_msgs/Imu/imu_preintegration预积分的IMU增量类型sensor_msgs/Imu/odometry/imuIMU里程计输出/odometry/lidar激光里程计输出先用rosbag info yourbag.bag看一下topic名称。有些公开数据集把IMU话题命名为/imu/data这时候要么改launch文件里的remap要么改params.yaml里的订阅话题名称。我记得有个公开数据集叫Parking Garage它的bag里IMU话题是/imu_correct正好和LIO-SAM默认的匹配适合第一次跑通流程时使用。跑通之后再换成自己的数据逐步调整参数。5. 参数配置与运行效果观察5.1 先跑官方demo数据验证全链路编译完成且ROS环境正常之后建议先跑官方提供的demo数据验证整个系统是否正常工作。官方README里给了两个bag下载链接Walking degParking Garage下载后直接在终端里播放rosbag play your_downloaded.bag同时另开一个终端启动LIO-SAMroslaunch lio_sam run.launch如果一切正常你会看到RViz里出现当前扫描的点云地图点云逐渐累积形成完整的3D地图轨迹线里程计路径随数据输入不断延伸终端里定时输出位姿变换信息第一次跑通的时候建议盯着RViz的左上角看消息频率如果/odometry/lidar以接近10Hz的频率更新说明整个链路是通的。5.2 用自己的传感器数据时需要注意什么换到自己的传感器数据后外参标定是绕不开的坑。LIO-SAM对IMU和LiDAR之间的外参非常敏感外参差个几厘米、几度建图质量就可能从“清晰”变成“糊成一片”。params.yaml里的外参需要填的是LiDAR坐标系到IMU坐标系的变换矩阵extrinsicRot: [1, 0, 0, 0, 1, 0, 0, 0, 1] extrinsicRPY: [1, 0, 0, 0, 1, 0, 0, 0, 1]这里建议动笔前先确认自己的传感器坐标定义别照抄demo数据里的默认值。不少人卡在“跑demo数据很好换自己数据就飘”的问题上八成就是外参没标对。另外注意IMU话题的静止状态。LIO-SAM启动后IMU预积分节点需要一小段时间让IMU达到静止偏置收敛状态如果数据一开始就是运动状态初值偏差大会影响后续优化效果。实际操作时录制bag前最好让设备静止1到2分钟再开始运动。6. 编译过程中的几条实践心得这套LIO-SAM在Ubuntu 20.04 Noetic环境下的编译流程我前前后后操作过不下十次帮别人排查问题的次数更多。最后说几条自己的心得。第一尽量别用最新的gtsam版本。很多人觉得库越新越好但在SLAM这种对接口稳定性要求极高的场景里新版本反而可能带来不兼容问题。LIO-SAM作者明确指定了4.0.0-alpha2一定有他的道理。这个版本的问题不是最新版但它是和LIO-SAM代码配合最稳定的版本。第二编译时别贪多线程。make -j$(nproc)在16核桌面上编译gtsam能瞬间把内存吃到20G以上。如果编译中途被系统OOM杀死别急着加内存先用make -j4试试编译慢一点总比反复被杀舒服。第三多留一个备用终端。LIO-SAM运行时涉及多个节点建议至少开三个终端一个跑roslaunch、一个跑rosbag play、一个用来rostopic echo或者rqt_graph检查话题概要。遇到问题的时候第三终端能很快定位是哪个节点没起来、哪个话题没有数据。第四学会看日志而不是乱猜。编译报错或者运行报错后一行行看输出。大多数情况下报错信息已经把原因写得明明白白只是太长了没人愿意读完。先把最后的10行输出读完再看报错的文件和行号80%的问题能自己定位。剩下的20%再把报错信息复制去搜比只搜“LIO-SAM编译失败”这种模糊关键词有效太多。最后说一个关于Noetic环境的小技巧如果你在Ubuntu 20.04上同时装了ROS1和ROS2有人会这么搞一定要检查一下bashrc里source的顺序。Noetic的setup.bash必须在任何ROS2环境之前source否则ROS1的命令会被覆盖roslaunch直接找不到。这个坑很冷门但只要碰到过一次就会记得一辈子。