ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

6轴IMU跑通LIO-SAM全指南:配置、改码与避坑实践

6轴IMU跑通LIO-SAM全指南:配置、改码与避坑实践 手里只有一个没有磁力计的6轴IMU想跑LIO-SAM官方demo包跑得很顺一换上自己录的bagrviz里不是没点云就是地图乱飞要么编译就卡在OpenCV版本上要么IMU一直在刷warning。这个问题我见过不少初学者卡了很久网上相关资料又比较分散。这篇教程就是专门为“6轴IMU”这个前提准备的围绕LIO-SAM的参数配置、代码修改、launch调整和问题排查把从环境搭建到跑通自己bag的整条链路展开讲一遍。适合谁看手里只有6轴IMU比如MPU6050、BMI088加一台机械/固态激光雷达想用LIO-SAM做建图或定位的开发者、学生和算法工程师。如果你用的是带磁力计的9轴IMU这篇文章大部分内容也适用但第3、4章里关于姿态协方差的部分可以跳过不看。1. 6轴IMU和LIO-SAM的适配逻辑先搞清楚才能少踩坑1.1 LIO-SAM内部的工作逻辑以及IMU扮演的角色LIO-SAM是一个基于因子图的激光惯性里程计框架输入是3D激光雷达点云和IMU数据输出是经过局部因子图优化后的位姿轨迹和点云地图。名字里的SAM指的是平滑与建图也就是smoothing and mapping。IMU在里面的作用主要有两个。第一个是帧间运动预测。激光雷达扫描一圈需要时间车辆在这个时间内会移动点云会发生运动畸变LIO-SAM用IMU预积分得到这个时间段内的相对位姿然后把每一帧点云校正到起始时刻。第二个是提供帧间位姿先验给激光里程计因子一个初始值和约束让优化不会乱跳。说直白一点激光雷达告诉你“这一段大概走了多远”IMU告诉你“这一段每一瞬间的姿态变化”两者合在一起才能得到平滑的轨迹。所以IMU数据质量直接决定输出的轨迹平滑度和建图效果。1.2 6轴相比9轴少的那三个数到底影响什么LIO-SAM官方demo里用的IMU通常是MicroStrain或者Xsens这类带磁力计的9轴设备本身能输出绝对姿态角。6轴IMU只有加速度计和陀螺仪没有磁力计所以常见的9轴融合算法比如Mahony、Madgwick在6轴上没法得到稳定的航向角只能得到相对姿态。但LIO-SAM对磁力计的依赖其实没有大多数人想象的那么强。它在紧耦合优化里真正用的物理量是线性加速度、角速度以及它们的预积分结果并不是直接消费磁力计输出。换句话说6轴IMU给出的角速度和线加速度如果干净、稳定、频率够高LIO-SAM是可以正常工作的。不少拿到6轴IMU后跑不起来的开发者问题往往出在话题字段语义和参数配置上而不是原理上不允许。1.3 6轴IMU能跑起来的三个基本条件条件一IMU驱动要按ROS标准发布sensor_msgs/Imu消息linear_acceleration和angular_velocity是真实测量值单位分别是m/s²和rad/s而且话题频率要稳定。条件二IMU频率不能太低建议至少100Hz实际工程里我一般要求200Hz以上。雷达按10Hz出帧的话两帧之间需要20个以上IMU样本才够做预积分和畸变补偿。条件三IMU与雷达之间的外参必须正确包括平移和旋转。外参错了预积分算法拿到的“在雷达坐标系下的IMU数据”就是错的畸变补偿越补越歪。这三条里面最后一条是最容易被忽视的。2. 环境准备与源码编译先让官方demo在自己机器上跑通2.1 依赖安装的完整命令与版本避坑环境建议Ubuntu 18.04配ROS Melodic或Ubuntu 20.04配ROS Noetic。这两个组合最稳。官方仓库依赖是gtsam、OpenCV和livox_ros_driver如果用Livox。gtsam的安装推荐直接apt装二进制省时间sudo add-apt-repository ppa:borglab/gtsam-release-4.0 sudo apt update sudo apt install libgtsam-dev libgtsam-unstable-dev如果apt源不顺利可以源码编译但要注意gtsam版本太旧可能会在编译LIO-SAM时报HessianFactor相关的错我这边实测4.1.1之后的版本都比较正常。然后克隆源码、创建catkin工作空间并编译cd ~/catkin_ws/src git clone https://github.com/TixiaoShan/LIO-SAM.git cd ~/catkin_ws catkin_make -j2 -l2 source devel/setup.bash如果你的机器内存不太够编译的时候建议给catkin_make加-j2 -l2限制并行度不然很容易编译到一半被杀掉。这一步看起来简单但很多新手在这里栽跟头最后发现只是内存不足。2.2 编译LIO-SAM与跑官方bag的验证流程编译通过之后先别急着换自己的传感器。先下载官方demo包在launch文件里指定bag路径跑一遍完整流程确认三点都正常终端能持续输出/lio_sam/mapping/odometry没有卡死rviz中能显示增量地图点云没有明显撕裂终端里没有大量IMU丢帧警告。这一步是隔离问题的关键。如果官方demo都跑不起来问题大概率出在环境而不是你的传感器上。不要一上来就拿自己的bag试否则出了问题你根本分不清是环境问题还是数据问题。2.3 自己录包前先确认三个话题相关细节第一步跑通后开始录自己的数据包。建议用rosbag录两个话题雷达原始点云话题和IMU原始话题。雷达点云建议保留原始点类型不要提前做过度的体素滤波IMU话题建议直接从驱动发布端录制不要中间串别的节点。录制时还要注意时间同步。如果只靠rosbag play的--clock而传感器驱动又不带时间戳同步后续会出现点云和IMU时间对不齐的问题表现就是地图在转弯处开裂。这种情况在实车上很常见后面第6章我会给一个排查思路。3. 参数配置逐项拆解决定地图质量的数字都在这里3.1 雷达参数让LIO-SAM认识你的传感器打开config/params.yaml第一组要看的是雷达参数。sensor按对应类型填velodyne、ouster或livoxN_SCAN填雷达线数Velodyne-16就填16Velodyne-32就填32Horizon_SCAN填一帧扫描的水平点数Velodyne-16一般是1800一些固态雷达要按实际输出计算。downsampleRate建议先填1等流程稳了再考虑降采样它表示每多少个点保留一个点。groundScanInterval和groundRemovalAngle是用来做地面分割的主要影响前端匹配的稳定性建议保持默认先跑通再调。lidarMinRange和lidarMaxRange控制参与配准的点云距离范围过近的点会产生噪声过远的点在大场景中容易拖尾一般先设0.5到100左右。3.2 IMU参数6轴最容易写错的三个位置这一段是整个params.yaml里最影响结果的。第一个位置是extrinsicRot填写从IMU坐标系到雷达坐标系旋转变换对应的roll、pitch、yaw单位是弧度。注意LIO-SAM内部构造的是ZYX欧拉角旋转矩阵所以顺序写反会导致结果完全不对。填写的思路是把你的IMU外壳放正观察IMU坐标系和雷达坐标系的偏转关系。第二个位置是extrinsicTransIMU中心相对于雷达坐标系原点的平移单位是米。通常就是几厘米的事但填0和填实际值在近距离建图时能明显看出来。第三个位置是最容易被忽略的imuAccNoise、imuGyrNoise、imuAccBiasNoise、imuGyrBiasNoise四个噪声参数。它们对应加速度计白噪声、陀螺仪白噪声、加速度计零偏随机游走、陀螺仪零偏随机游走。6轴IMU因为缺少磁力计辅助姿态漂移主要靠陀螺仪零偏来补偿这项参数一旦填得离谱地图会在均匀运动时慢慢变弯。没有标定数据时可以从IMU手册里查噪声密度再换算成连续时间噪声密度初始值保守一点没问题。下面是四个噪声参数的常见填写参考表参数名含义6轴IMU常见初始值imuAccNoise加速度计连续时间白噪声1e-2 ~ 1e-3imuGyrNoise陀螺仪连续时间白噪声1e-2 ~ 1e-3imuAccBiasNoise加速度计零偏随机游走1e-4 ~ 1e-5imuGyrBiasNoise陀螺仪零偏随机游走1e-4 ~ 1e-53.3 useImuPatch与imuRate高频IMU的两个关键开关如果你的6轴IMU输出频率超过250Hz比如MPU6050在增强模式下能到400Hz建议把useImuPatch设为true。这个参数官方注释里写得很清楚使用高频IMU时如果积分更新太频繁预积分本身的数值稳定性和CPU占用都会受影响patch机制会把一段窗口内的IMU数据打包处理。实测下来400Hz的IMU不开这个开关CPU占用明显偏高地图偶发跳变打开后流畅很多。imuRate这个参数同样关键它表示IMU的实际输出频率。很多人在params.yaml里不填默认200但手里的6轴IMU实际只有50HzLIO-SAM却按200的期望去缓存和积分结果就是疯狂刷丢帧警告。改的方法很简单先通过rostopic hz确认真实频率再填到imuRate里。3.4 launch调整bag路径与话题映射params.yaml改完后打开launch/run.launch主要改两个位置。一个是rosbag节点里的bag_filename参数改成自己的bagarg namebag_filename default/home/user/data/your.bag/另一个是话题重映射。LIO-SAM默认订阅points_raw和imu_correct如果你的雷达话题是/velodyne_pointsIMU话题是/imu/data就用remap frompoints_raw to/velodyne_points/ remap fromimu_correct to/imu/data/同时注意launch里run_imu_correction节点。如果它开着实际订阅的是/imu_raw经过内部坐标纠正后输出到/imu_correct如果你不想让这层纠正介入直接把useImuCorrection设false并订阅/imu_correct即可。4. 代码修改从驱动到LIO-SAM源码的四处改动4.1 驱动端IMU消息里的姿态协方差陷阱很多6轴IMU的ROS驱动因为本身没有姿态输出为了“像样”会把sensor_msgs/Imu消息里的orientation填成一个固定四元数通常是单位四元数并把orientation_covariance填成全0。这看起来没啥问题但在LIO-SAM的processIMU里它会检查orientation_covariance[0]的值来决定是否走姿态辅助分支。协方差为0表示“姿态绝对准确”这显然和实际不符LIO-SAM会拿着一个错误的姿态去做补偿结果就是轨迹在静止时稳定一动起来就飘。正确的做法是把驱动里orientation_covariance[0]设成-1语义表示“这个量根本没测”。ROS标准规定协方差为负表示该量未提供。如果你的驱动代码不好改最省事的方法是写一个小节点在转发IMU消息时强制把协方差置-1。4.2 源码端LIO-SAM对IMU姿态协方差的处理分支如果你不想改驱动也可以在LIO-SAM源码里处理。打开src/imuPreintegration.cpp定位到processIMU函数中对orientation_covariance的判断。当orientation_covariance[0]等于-1时代码走的是纯惯性预积分分支也就是只用加速度和角速度不等于-1时则尝试用自带的姿态估计。6轴IMU没有姿态源建议强制走-1这个分支。注意这里有一个容易混淆的点改了源码之后要重新编译而且不同分支会影响代码里对IMU数据的使用方式不建议在没搞懂逻辑的情况下随便删代码。我的做法是先在驱动端改字段源码保持官方版本这样方便以后升级代码也方便和其他人讨论问题。4.3 点云字段不匹配时的驱动适配第三个常见代码问题是点云字段格式。少数雷达驱动输出的sensor_msgs/PointCloud2里的point类型不是标准XYZ可能带了额外的通道字段。LIO-SAM内部的imageProjection.cpp是按标准XYZ类型解析的如果接进来的点云字段不匹配会在运行时打印警告甚至崩溃。遇到这种情况可以在驱动端加一个转换节点或者写一个简单节点把点云重发为标准XYZ类型。这个属于“表面上看是代码问题实际上是数据格式问题”的典型。我自己遇到过一台雷达点云里带了一个time字段LIO-SAM解析时就会报警转换掉之后一切正常。4.4 地图颜色与PCD输出路径的实用调整如果你想让建出来的地图带有高度颜色效果而不是一团白点可以去src/cloud_node.cpp里看一下那段根据z轴高度赋颜色索引的代码。默认配置里地图点的颜色来自rgb字段如果不设置rviz里默认是白色或随机色。把颜色按高度生成后建图结果看起来会直观很多判断地面和墙面是否对齐也更方便。另外savePCD开关建议在正式建图时打开它会在地图结束后把拼接点云和轨迹保存到指定目录后面做地图后处理会省很多时间。这个不是必须改的需求但属于那种“改一次一劳永逸”的实用改动。5. 启动与验证跑通只是开始重点看预积分和回环5.1 启动命令与现场检查点跑起来一般就三行命令source ~/catkin_ws/devel/setup.bash roslaunch lio_sam run.launch rosbag play --clock your.bag如果你是用launch里带bag参数的方式直接执行第一条加launch自动播放。启动后终端里出现“IMU data received”或类似提示说明IMU已经接入。这个时候打开rviz检查三个话题是否正常/lio_sam/mapping/odometry里程计是否连续/lio_sam/points_cloud当前帧点云是否正常/lio_sam/imu_preintegrationIMU预积分轨迹是否平滑。5.2 如何判断IMU预积分是否正常光看终端还不够最好打开rviz添加/lio_sam/imu_preintegration相关的轨迹话题观察IMU预积分的表现。简单粗暴的判断方法是雷达静止、IMU静止时预积分轨迹应该是一条长度不增长的点手拿着IMU原地缓慢旋转时轨迹应该平滑跟随不应该突然跳跃。如果出现跳跃先看外参和噪声参数再看时间同步。另一个更直接的验证方式把IMU原始数据和/odometry画在一起对比。如果你发现odometry的延迟明显大于你设置的imuRate对应的周期说明IMU数据没有真正进入预积分或者某个环节被过滤了。5.3 地图质量不佳时的排查顺序跑通之后地图出现拖影或者整体扭曲大概率不是代码问题而是输入数据问题。我的排查顺序是先看外参再看噪声参数再看IMU和雷达的时间戳最后看雷达本身是否有运动畸变。这个顺序不能反尤其是时间戳问题很多新手一上来先改算法参数越改越乱。时间戳问题怎么快速判断把IMU和雷达消息的时间戳差值打出来如果两者差值在几十毫秒以上地图很难建好。这种情况下优先去改驱动的时间戳策略而不是在算法里硬调。6. 三个真实踩坑案例从现象到根因的完整链路6.1 imu message dropped频率与参数的错配现象是终端持续刷[ WARN] ... imu message dropped地图时断时续。排查后发现IMU实际输出频率只有50Hz但params.yaml里imuRate填的200LIO-SAM按200的期望去缓存和积分频率不匹配就不断丢数据。改法是先把IMU驱动确认实际输出频率然后把imuRate改成相同值。进一步说当IMU频率太低比如低于50HzLIO-SAM的预积分质量会显著下降。这种情况下我一般直接换驱动配置把速率调到200Hz以上再继续。频率是基础不要想着靠调噪声参数去弥补频率不足的问题。6.2 转弯处地图撕裂外参旋转方向的符号问题现象是直线行驶时地图很干净一到转弯就错位而且错位方向稳定。最终定位到extrinsicRot的三个角度符号填反了。当时拿着IMU和雷达的外参标定数据却忽略了一个旋转方向正负号的问题。搞懂旋转矩阵方向后把对应角度取负号重新填进去地图瞬间就正了。这个坑在6轴IMU上特别常见。因为很多6轴驱动上电时并不告诉你IMU坐标系的朝向最好的办法是用一个已知的水平面去对齐两个坐标系做验证。具体做法是把雷达放正IMU也放正查看两者在rviz里的坐标系箭头朝向然后反推旋转关系。6.3 编译卡在OpenCV API一个环境兼容问题如果是Ubuntu 20.04配Noetic编译LIO-SAM时经常会遇到imageProjection.cpp里CV_LOAD_IMAGE_GRAYSCALE未声明的错误原因是OpenCV 4把老枚举改名成cv::IMREAD_GRAYSCALE。解决方案很简单把这一处改成新API再编。类似的还有cv::imshow等头文件缺失的问题把#include opencv2/highgui.hpp补上即可。这类问题不是LIO-SAM本身的逻辑问题纯粹是环境版本差异但经常把人卡住很久。写到这里想多分享一个习惯。我每次换传感器组合换雷达或者换IMU之后都会先把小车放在原地静止3到5秒再开始运动这样LIO-SAM在启动阶段能用静止数据把IMU零偏估计得稳一点地图起步不会飘。这个小习惯看起来不起眼但实际排查外参和噪声问题时帮了我不少忙。6轴IMU比9轴少了磁力计这个“指南针”前期的数据质量检查和参数核对就更不能省只要把上面这几个位置都过一遍6轴IMU跑LIO-SAM完全可以达到工程可用的稳定度。
返回列表