保姆级教程:在Ubuntu 20.04上从源码编译运行FAST-LIO2(避坑指南)
从零部署FAST-LIO2:Ubuntu 20.04实战指南与深度调优
当激光雷达遇上惯性测量单元,SLAM领域便诞生了无数令人振奋的可能性。FAST-LIO2作为激光惯性里程计中的佼佼者,以其计算效率和鲁棒性在学术界和工业界广受好评。但对于刚接触这一领域的开发者而言,从理论到实践的跨越往往布满荆棘——依赖项冲突、编译错误、参数配置等问题常常让人望而却步。本文将带你穿越这片"无人区",用最接地气的方式完成从源码编译到实际运行的完整旅程。
1. 环境准备:打造FAST-LIO2的温床
在开始编译之前,我们需要为FAST-LIO2准备一个"舒适"的运行环境。Ubuntu 20.04作为长期支持版本,其稳定性和兼容性使其成为理想选择。但仅仅安装操作系统还远远不够——就像烘焙需要精确的原料配比,SLAM系统的构建也需要准确的依赖项组合。
核心依赖清单:
sudo apt-get install -y git cmake libeigen3-dev libboost-all-dev sudo apt-get install -y libpcl-dev ros-noetic-pcl-conversions sudo apt-get install -y ros-noetic-nav-msgs ros-noetic-tf2-geometry-msgs特别提醒:PCL库的版本兼容性往往是第一个"拦路虎"。Ubuntu 20.04默认仓库中的PCL 1.10与FAST-LIO2可能存在兼容性问题。若遇到点云处理相关的编译错误,建议从源码编译PCL 1.12:
git clone https://github.com/PointCloudLibrary/pcl.git cd pcl && git checkout pcl-1.12.1 mkdir build && cd build cmake -DCMAKE_BUILD_TYPE=Release .. make -j$(nproc) sudo make install注意:从源码安装PCL会覆盖系统原有版本,可能影响其他依赖PCL的软件。建议在虚拟环境或容器中操作。
Eigen3的版本同样关键。虽然Ubuntu仓库中的3.3.7版本可以工作,但对于追求极致性能的用户,推荐手动安装Eigen 3.4.0:
wget https://gitlab.com/libeigen/eigen/-/archive/3.4.0/eigen-3.4.0.tar.gz tar xzf eigen-3.4.0.tar.gz cd eigen-3.4.0 mkdir build && cd build cmake .. sudo make install2. 源码获取与编译:避开那些"坑"
有了完善的环境,接下来就是获取FAST-LIO2源码并进行编译。这个过程看似简单,实则暗藏玄机——就像拆解精密仪器,每个步骤都需要恰到好处的力度。
首先克隆官方仓库及其子模块:
git clone --recursive https://github.com/hku-mars/FAST_LIO.git cd FAST_LIO git submodule update --init编译时的第一个常见错误通常与ROS包路径有关。如果遇到"Could not find a package configuration file..."这类错误,尝试以下解决方案:
- 确保已source ROS环境:
source /opt/ros/noetic/setup.bash- 若使用自定义ROS工作空间,需要正确设置
CMAKE_PREFIX_PATH:
catkin_make -DCMAKE_PREFIX_PATH=/opt/ros/noetic常见编译错误速查表:
| 错误类型 | 典型表现 | 解决方案 |
|---|---|---|
| PCL相关 | undefined reference to pcl::... | 检查PCL版本,确保链接正确库文件 |
| Eigen冲突 | Eigen::Matrix ambiguous | 移除旧版本,更新包含路径 |
| ROS消息 | missing roscpp dependencies | 安装完整ROS-Noetic桌面版 |
| C++标准 | requires '-std=c++17' | 在CMakeLists.txt中添加set(CMAKE_CXX_STANDARD 17) |
当编译顺利完成后,你会看到令人欣慰的[100%] Built target fast_lio输出。但别急着庆祝——真正的挑战还在后面。
3. 参数配置:让传感器"说同一种语言"
FAST-LIO2的强大之处在于激光雷达与IMU的紧耦合,但这要求两者必须"心有灵犀"。参数配置不当是导致系统无法正常工作的最常见原因,特别是外参标定和话题配置这两个关键环节。
传感器外参标定: 激光雷达与IMU之间的变换矩阵(外参)需要精确测量或标定。在config/velodyne.yaml中,重点关注以下参数:
# 外参:激光雷达到IMU的变换 extrinsic_T: [0, 0, 0] # 平移向量 (x,y,z) 单位:米 extrinsic_R: [1, 0, 0, 0, 1, 0, 0, 0, 1] # 旋转矩阵 (行优先)实战技巧:对于常见的传感器组合,可以参考以下预设值:
Livox Avia + DJI Manifold2:
extrinsic_T: [0.06, -0.02, 0.03] extrinsic_R: [0, -1, 0, 1, 0, 0, 0, 0, 1]Velodyne VLP-16 + Pixhawk:
extrinsic_T: [0.15, 0, 0.12] extrinsic_R: [0, 0, 1, -1, 0, 0, 0, -1, 0]
话题配置检查: 确保ROS话题名称与实际发布的数据匹配。在config/velodyne.yaml中检查:
# 点云话题 lid_topic: "/velodyne_points" # IMU话题 imu_topic: "/imu/data"重要提示:使用
rostopic list确认实际话题名称。某些设备可能发布类似/imu/data_raw的话题,需要相应调整。
4. 运行与调试:从静态测试到动态建图
当所有准备工作就绪,终于来到最激动人心的时刻——实际运行FAST-LIO2。但即使到了这一步,仍有可能遇到各种"意外情况"。让我们分阶段进行,逐步验证系统性能。
第一阶段:静态测试在静止状态下运行系统,这是验证基础配置的最佳方式:
roslaunch fast_lio mapping_velodyne.launch观察终端输出,重点关注:
- IMU数据是否正常接收(检查频率和数值范围)
- 点云数据是否完整(检查点数量和分布)
- 初始位姿是否稳定(不应有剧烈跳动)
第二阶段:小范围运动测试手持设备缓慢移动,观察建图效果。常见问题及解决方案:
点云漂移:
- 检查IMU数据质量(使用
rostopic echo /imu/data) - 调整
config/velodyne.yaml中的filter_size_corner和filter_size_surf
- 检查IMU数据质量(使用
建图模糊:
- 增加
point_filter_num减少处理点数 - 调整
max_iteration提高优化精度
- 增加
第三阶段:大规模环境测试使用标准数据集(如KITTI)或自采集数据进行完整测试:
rosbag play your_data.bag --clock性能优化参数对照表:
| 参数名 | 默认值 | 作用 | 调整建议 |
|---|---|---|---|
point_filter_num | 1 | 点云降采样率 | 增大可提高速度但降低精度 |
max_iteration | 5 | IEKF迭代次数 | 增加可提高精度但降低速度 |
filter_size_corner | 0.5 | 边缘特征滤波尺寸 | 室外环境可适当增大 |
filter_size_surf | 0.5 | 平面特征滤波尺寸 | 结构化环境可减小 |
cube_side_length | 1000 | 地图分块尺寸 | 根据内存调整 |
5. 高级技巧:让FAST-LIO2发挥极致性能
当基本功能正常运行后,我们可以进一步挖掘FAST-LIO2的潜力。这些技巧来自实际项目经验,能显著提升系统在特定场景下的表现。
多传感器融合增强: 对于有GPS或其他传感器的系统,可以通过修改laserMapping.cpp实现松耦合融合。关键代码段示例:
// 在适当位置添加GPS处理 void LaserMapping::GPSHandler(const sensor_msgs::NavSatFix::ConstPtr& gps_msg) { // 将GPS坐标转换为局部坐标系 Eigen::Vector3d gps_position = convertGPSToLocal(gps_msg); // 创建虚拟观测 Eigen::MatrixXd H_gps = Eigen::MatrixXd::Zero(3, state.rows()); H_gps.block<3,3>(0,0) = Eigen::Matrix3d::Identity(); // 更新状态 ekf.update(H_gps, gps_position - state.head(3), gps_covariance); }自适应参数调整: 针对动态环境,可以实现运行时参数自动调整。例如根据运动速度调整滤波参数:
double current_speed = state.segment<3>(3).norm(); // 获取当前速度 if (current_speed > 2.0) { // 高速运动时 filter_size_corner = 0.8; filter_size_surf = 0.8; } else { // 低速时 filter_size_corner = 0.3; filter_size_surf = 0.3; }点云后处理优化: 在publishCloud函数中添加后处理逻辑,提升可视化效果:
void LaserMapping::publishCloud() { // 原始点云发布代码... // 添加统计离群点去除 pcl::StatisticalOutlierRemoval<pcl::PointXYZI> sor; sor.setInputCloud(cloud_out); sor.setMeanK(50); sor.setStddevMulThresh(1.0); sor.filter(*cloud_filtered); // 发布处理后的点云 sensor_msgs::PointCloud2 output; pcl::toROSMsg(*cloud_filtered, output); pub_cloud.publish(output); }6. 实战案例:从室内到室外的跨越
理论终需实践检验。让我们通过两个典型场景,展示FAST-LIO2的实际应用技巧。
案例一:狭窄室内环境在走廊、楼梯间等场景,系统容易因特征不足而失效。解决方案:
- 降低
point_filter_num至1(处理所有点) - 减小
filter_size_surf至0.2(捕捉细小平面) - 启用
full_cloud_projection(保留完整点云信息)
案例二:开阔室外环境面对大尺度场景,需平衡精度与性能:
- 增大
cube_side_length(避免频繁地图切换) - 提高
point_filter_num(如5-10) - 调整
max_iteration至3-4(防止计算过载)
场景参数优化对照表:
| 场景类型 | 关键参数调整 | 特殊处理 |
|---|---|---|
| 室内狭窄 | filter_size_surf=0.2, full_cloud_projection=true | 增加IMU权重 |
| 室内开阔 | point_filter_num=3, max_iteration=4 | 启用动态降采样 |
| 室外城市 | cube_side_length=2000, point_filter_num=5 | 融合GPS数据 |
| 室外自然 | filter_size_corner=1.0, filter_size_surf=1.0 | 增加特征阈值 |
在完成所有这些步骤后,你应该已经拥有了一个稳定运行的FAST-LIO2系统。但记住,每个应用场景都有其独特性——可能需要反复调整参数才能获得最佳效果。我曾在一次无人机项目中花费整整两周时间才找到理想的外参组合,但当看到系统在高速飞行中依然能输出稳定的建图结果时,所有的努力都变得值得。
