ARTICLE DETAIL

资讯详情

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

XTDrone中ALOAM激光SLAM无点云与坐标系报错完整排查指南

XTDrone中ALOAM激光SLAM无点云与坐标系报错完整排查指南 不用怀疑这个组合确实能跑通但前提是你愿意把坐标系那套破事彻底搞明白。我在XTDrone里折腾ALOAM时最崩溃的不是算法本身而是所有传感器都正常启动、点云话题也活着结果rviz里黑屏一片终端疯狂刷“Lookup would require extrapolation into the past”。后来一步步把点云通道、TF树、时间戳机制全部翻了一遍才弄清楚问题基本都集中在两个地方点云有没有真正进入里程计节点以及坐标系变换在时间维度上有没有被满足。这篇文章就把“没有点云”和“坐标系报错”这两类问题的完整排查链路写清楚适合正在XTDrone里做三维激光SLAM、被LOAM系列算法虐到怀疑人生的同学。XTDrone的仿真平台本身已经把PX4、Gazebo和ROS的接口封装得相当友好ALOAM也是开源社区里经典到不能再经典的激光里程计算法理论上在Gazebo里加载一个三维激光雷达模型再跑起来ALOAM应该很顺。但实际动手时你会发现仿真环境给你提供了“理想传感器”同时又把很多在真实硬件上不会暴露的问题提前放大给你看——比如点云帧率对位姿估计的影响、坐标系初始化的时机、TF缓冲区的容差范围。这些细节在官方README里往往一句话带过但恰恰是你能不能出图的关键。1. ALOAM在XTDrone仿真里的完整数据链路1.1 XTDrone为什么适合跑LOAM系算法XTDrone是国内开发者维护的一套基于PX4和Gazebo的无人机仿真平台对ROS的整合程度在开源项目里算相当高的。它最大的优势是你不需要从零去搭Gazebo世界、无人机模型和传感器模型平台已经内置了带3D激光雷达的无人机模型以及配套的启动脚本和键盘控制脚本。ALOAM是港科大开源的单目激光里程计与建图算法把LOAM的前端scanRegistration、laserOdometry和后端laserMapping拆成了三个独立节点还有个transformMaintenance负责发布里程计到地图的坐标变换。整个算法对计算资源的要求不算高在仿真环境里跑起来比在实车上跑更轻松因为点云数据没有真实世界里的噪声、运动畸变和多路径效应。XTDrone加ALOAM的组合适合做这几类事情验证三维SLAM算法在理想传感器模型下的表现、学习LOAM系算法内部的数据流和时间戳同步逻辑、以及在不需要真实硬件的前提下调参和评估建图效果。当然也有不少人是拿它来水论文的这个我不评价但至少你得让它先跑出地图来。1.2 从激光雷达到全局地图的数据流转整个系统说起来其实只有一条数据链路。Gazebo里挂载的激光雷达模型通过ROS驱动节点发布原始点云话题通常是/velodyne_points或者/cloud_registered数据类型是sensor_msgs/PointCloud2。ALOAM的scanRegistration节点订阅这个原始点云提取边缘点和平面点然后发布到/laser_cloud_sharp和/laser_cloud_flat等话题。laserOdometry节点接收这些特征点计算帧间位姿变换发布当前帧在世界坐标系下的位姿同时发送畸变校正后的点云到/laser_cloud_odometry。最后laserMapping节点拿这些去匹配局部地图维护一个更精确的位姿并发布最终地图点云到/laser_cloud_map。这里有个很容易被忽略的点ALOAM里的“世界坐标系”并不是ROS里的map坐标系而是算法自己在收到第一帧点云时初始化的camera_init坐标系。如果你在rviz里把Fixed Frame设成map就看不到地图因为ALOAM发布的所有点云和位姿都在camera_init这个frame下面。这个细节是坐标系报错的前置背景。1.3 环境与Workspace准备XTDrone的安装在这里不展开网上资料很多。只说关键你至少要保证三个workspace能同时共存catkin_ws编译PX4的ROS接口、xtdrone_ws存放XTDrone平台的ROS包、aloam_ws放ALOAM源码。三个workspace的依赖关系要理顺特别是loam_velodyne这个包它依赖velodyne_msgs和aloam_velodyne如果缺了会在编译阶段直接报错。ALOAM源码建议用HKUST-Aerial-Robotics/A-LOAM官方仓库编译前把CMakeLists.txt里的C14标准确认好。我遇到过的问题是在Ubuntu 18.04加ROS Melodic环境下如果同时装了多个版本的Eigen编译会因为头文件路径冲突报一堆莫名其妙的错。解决方法是把/usr/include/eigen3和/usr/local/include/eigen3的软链接指到同一个版本别让两个版本混着用。启动顺序也讲究。先启动XTDrone的仿真环境等Gazebo加载完毕再启动ALOAM的launch文件。很多人习惯一次性roslaunch全部启动结果ALOAM在Gazebo还没发布点云时就启动导致laserMapping收到的第一帧点云是空数据后面整个系统的位姿估计就歪了。我个人的习惯是分终端启动先跑平台再单独跑ALOAM。2. 没有点云从话题、TF到坐标系的全链路排查2.1 第一道检查话题路由有没有通遇到“没有点云”的情况先别急着改参数先确认数据到底有没有流到ALOAM的节点里。用rostopic list看看/velodyne_points是否存在再用rostopic hz /velodyne_points看发布频率。如果话题不存在说明激光雷达模型没挂载成功回Gazebo检查模型文件如果话题存在但频率是0说明雷达模型卡住了大概率是Gazebo的物理引擎抽风重启仿真即可。话题存在且频率正常的情况下用rostopic echo /velodyne_points --noarr看一帧点云的数据结构确认point_step和row_step是不是合理值。我在XTDrone里遇到过一种情况Gazebo发布的点云话题频率正常但每帧点云的坐标全部是NaN。这个问题的根源是雷达模型挂载的link没有设置正确的惯性参数导致雷达在仿真里飘到了无穷远点云坐标全部无效。解决办法是在URDF文件里给雷达link补上inertial标签。如果话题有数据再确认ALOAM节点有没有订阅成功。看终端输出有没有“Segmentation Fault”或者“Failed to load”之类的报错同时用rqt_graph看节点间的连线。ALOAM的scanRegistration节点订阅点云话题的代码是硬编码在launch文件里的如果你用XTDrone默认的话题名且不是/velodyne_points,就必须改launch文件里的remap参数。2.2 LOAM坐标系bugtransformMaintenance这个“定时炸弹”这是ALOAM源码里一个极其经典的bug几乎所有跑ALOAM的人都会遇到。问题出在transformMaintenance.cpp这个文件里。官方原版的逻辑是订阅/integrated_to_init这个里程计话题然后发布camera_init到map的坐标变换。但在某些版本里代码会把camera_init和map的父子关系写反导致TF树上出现循环依赖rviz直接报警并且不显示点云。这个bug的典型特征是终端会刷MessageFilter丢弃消息的警告rviz里Fixed Frame无论设成camera_init还是map都看不到点云。排查方法很简单用tf2_echo camera_init map看TF是否发布成功如果提示“Exception thrown: Lookup would require extrapolation”说明TF树时间戳范围有问题如果提示“Invalid frame ID”说明frame名字对不上。解决方案有两种。第一种简单粗暴把transformMaintenance.cpp里odom_to_map的坐标变换逻辑注释掉因为ALOAM在仿真环境里本身就有漂移这个变换影响不大。第二种是升级到修过bug的ALOAM版本比如HKUST-Aerial-Robotics/A-LOAM的dev分支或者CAPTAIN YUAN佬的ROS2版本。我用的是deepblue社区整理的ALOAM版本已经修掉了这个问题但我在实机测试时又自己改回了注释版因为地图效果更干净。2.3 为什么车不动时点云永远不发布这是很多第一次跑ALOAM的人都会困惑的点我把激光雷达启动了车也在Gazebo里停着为什么rviz里连原始点云都看不到答案其实很简单ALOAM的scanRegistration和laserOdometry里的回调函数会判断当前帧点云和上一帧点云的位姿变化如果变化量小于一个阈值就直接丢弃不处理。这个阈值在代码里写的是0.0001量级的距离和角度变化仿真环境里车完全静止时点云相邻帧几乎没有变化所以不会被发布。这个设计在实车上是为了过滤静止帧避免旋转矩阵奇异。但在仿真里调试时很烦人因为你先要移动无人机才能看到点云。XTDrone平台提供了键盘控制脚本但你得先把飞机解锁并切换到offboard模式否则推油门也没反应。我在调试时吃过这个亏飞机在地上推了半天油门结果Gazebo里Pose没变点云一个都不出。正确做法是先启动XTDrone的无人机控制脚本解锁、切换到offboard、手动起飞到一米高度然后缓慢推前后左右让激光雷达有足够的位移变化量。等rviz里出现稀疏特征点云后再逐渐加大运动幅度让laserMapping开始构建局部地图。2.4 出现点云但rviz一片黑的检查项如果你能看到特征点云话题有数据更新但rviz里还是一团黑那问题基本出在rviz的配置上。首先确认Fixed Frame。ALOAM的所有点云都在camera_init这个frame下如果你的Fixed Frame设置的是map或odom点云会显示不出来。别问我为什么第一条就提这个因为群里至少有十个人是因为这个原因卡了一整天。其次确认你订阅的话题对不对。rviz里显示地图点云的Topic应该选/laser_cloud_map这个点云是laserMapping节点的输出通常要等系统运行一段时间才会有数据因为局部地图匹配需要积累一定帧数。如果你把/laser_cloud_registered和/laser_cloud_map搞混了也会出现显示不对的问题。最后检查点云的颜色设置。ALOAM发布的点云没有RGB信息如果你把Color Transform设置成RGB8所有点都是黑色。正确做法是设成FlatColor或者AxisColor然后手动调一个亮度合适的颜色。这是我见过的最无厘头的报错但也是频率最高的。3. 坐标系报错的根源与三种解法3.1 “Lookup would require extrapolation into the past”到底在说什么这个报错是整个SLAM系统里最容易出现的坐标系问题。它的完整含义是TF树里某个坐标变换的请求时间早于该变换的已知时间范围。换句话说你想知道某个时刻camera_init到map的关系但发布这个关系的节点还没有发布到那个时刻的数据。在ALOAM的架构里laserOdometry节点发布camera_init到base_link的变换laserMapping节点发布camera_init到map的变换。这些变换的频率大约10Hz而点云回调的频率可能到30Hz甚至更高。如果某个节点试图估算一个“比所有已知位姿都早”的坐标变换TF系统就会报这个错。用生活化的方式理解假设你有一张列车时刻表上面只有9点到9点半的到达信息但你非要去查8点45分的到达时间系统当然查不到只能告诉你“抱歉超出查询范围”。在SLAM里这个“超出范围”就是时间戳超出了位姿轨迹的覆盖范围。3.2 根因一局部点云不在位姿时间范围内这是最核心的根因。ALOAM的laserOdometry节点在处理点云时会把当前帧点云转换到camera_init坐标系然后通过和上一帧匹配来估计位姿。如果当前帧点云的时间戳早于已经估计出的位姿轨迹的时间范围坐标变换就会失败。这个问题在仿真环境里特别容易出现因为Gazebo的点云发布频率和实际计算时间存在随机延迟。你可以在rqt_tf_tree里看到TF树的时间戳覆盖范围再用rostopic echo /laser_cloud_odometry看点云的时间戳如果发现点云时间戳比TF树的时间范围更早说明laserOdometry在拿过去的点云和当前的位姿估计做匹配必然报错。解法有两种。第一种是直接过滤在laserOdometry.cpp里加上对时间戳的判断如果点云时间戳小于位姿轨迹尾部时间戳直接跳过。这段逻辑在LIO-SAM里已经写好了ALOAM里需要自己补。第二种是调整ROS的use_sim_time配置确认use_sim_time为true并且Gazebo的仿真时钟是单调递增的。如果仿真时钟跳变也会导致时间戳范围异常。3.3 根因二sensor_msgs/PointCloud2字段与ALOAM不兼容另一个容易导致坐标系报错的原因是点云数据的字段不完整。ALOAM的scanRegistration在读取点云时会遍历点云的fields提取x、y、z、intensity这几个字段。如果雷达驱动发布的点云里没有intensity字段或者字段名称大小写不对代码会跳过该点或者直接崩溃。XTDrone默认的雷达模型发布的点云是包含intensity的这个倒不用担心。但如果你换了其他雷达模型比如把velodyne_vlp16换成ouster的模型可能就会遇到字段不兼容的问题。检查方法是rostopic echo /velodyne_points --noarr看fields数组里的字段名。遇到字段不兼容的报错不要试图改ALOAM的代码因为牵一发动全身。最简单的方式是写一个Python或者C的转换节点订阅原始点云补齐缺失字段再发布到ALOAM订阅的话题上。这个节点大概几十行代码网上有现成的搜“pointcloud2 field adapter”就能找到。3.4 根因三时间戳跳变与TF缓存不足还有一个隐蔽的原因系统时间同步问题。在仿真环境里Gazebo有自己的仿真时钟ROS节点通过/clock话题同步。如果use_sim_time没有设置或者设置晚了ROS节点的系统时间会和Gazebo的仿真时间错位导致TF树的时间戳覆盖范围混乱。我在调试时遇到过一种情况启动所有节点后前两分钟一切正常然后突然开始疯狂报“extrapolation into the past”。后来发现是我设置了use_sim_time为true但Gazebo的时钟在启动过程中有个初始化阶段发布的第一批时钟戳是0导致TF树里有一段异常的时间戳记录。这种情况重启全部节点并且严格按照“先Gazebo后ALOAM”的顺序启动基本就能解决。TF缓存不足的问题比较少见但也遇到过。TF的缓存默认10秒如果你的系统CPU负载过高导致TF发布延迟超过10秒那么查询更早的坐标变换就会失败。解决办法是调大缓窗口期在启动脚本里加一段rosparam set /tf_buffer_duration 30或者在tf2_ros::Buffer的构造函数里把缓存时间改大。3.5 我的最终配置参考这里给出一套在XTDrone里稳定运行ALOAM的配置参考。系统环境是Ubuntu 18.04 ROS Melodic Gazebo 9 PX4 1.11XTDrone版本是master分支ALOAM用的是deepblue社区的修复版。# 终端1启动XTDrone仿真环境 cd ~/PX4_Firmware make px4_sitl gazebo # 终端2启动XTDrone的无人机控制脚本 cd ~/xtdrone_ws source devel/setup.bash cd scripts python3 xtdrone_control.py # 终端3启动ALOAM cd ~/aloam_ws source devel/setup.bash roslaunch aloam_velodyne aloam_velodyne_livox.launch注意aloam_velodyne_livox.launch里的livox字样只是文件名实际可以加载任何雷达模型。你需要根据XTDrone里雷达的话题名修改launch文件中的remap参数。rviz的配置我就不贴文件了因为版本差异太大。核心就一句Fixed Frame设成camera_init添加PointCloud2显示Topic选/laser_cloud_map颜色选FlatColor。我现在每次开新环境都是先手动配一遍rviz嫌麻烦的同学可以把配置文件保存下来下次直接加载。4. 建图效果评估与常见异常地图4.1 重影/错位的判断方法点云出来之后地图不等于就好还要看效果。最常见的异常地图问题是重影和错位。重影的表现是地面上同一堵墙出现两层轮廓错位的表现是某一面墙壁和相邻墙壁之间有明显断差。判断方法很简单在rviz里旋转视角观察地图中直线特征是否连续。如果一条走廊的墙壁在某个位置突然平移了几厘米说明那里的位姿估计有误差。再一个判断标准是看地面——如果地面点云形成了明显的双层结构说明Z轴的漂移比较大。在XTDrone仿真环境里地图重影通常是因为激光雷达的外参标定不准或者运动速度过快导致帧间匹配退化。仿真环境里外参是准的所以问题多半出在运动方式上。不要快速急转弯不要快速升降保持平稳运动重影会少很多。4.2 点云穿透与横向漂移的取舍点云穿透是一个让人很懵的现象。明明地图看起来没问题但某些墙壁的边缘会有一层向外飞的稀疏点云。这通常是激光雷达在低入射角时测距不准导致的Gazebo的雷达模型在仿真时对高反射率表面会有模拟误差也会产生这种效果。横向漂移是另一个绕不开的问题。LOAM系算法在无回环的场景里横向漂移是累计的跑的时间越久漂移越大。在XTDrone仿真里你绕小区跑一圈回来后起点周围的地图大概率会对不齐这就是没有回环检测的后果。对于仿真调试来说不需要太纠结漂移问题毕竟ALOAM本身没有回环检测。我更关心的反而是点云的稀疏程度对匹配质量的影响。XTDrone默认的16线雷达模型在远距离处点云非常稀疏scanRegistration提取的特征点质量不高导致laserOdometry的里程计漂移偏大。如果仿真环境允许换用64线或者128线雷达模型地图效果会好非常多。4.3 仿真环境里手动对齐与闭环缺失的问题如果你需要在仿真里验证某个算法但又被ALOAM的漂移困扰可以考虑手动干预在laserMapping节点里定期重置位姿或者直接把仿真里已知的地面真值pose注入到系统里。XTDrone平台的Ground Truth可以通过/mavros/local_position/pose话题获取但ALOAM不会订阅这个数据。我做过一个比较取巧的事在跑完一圈后用点云配准工具比如CloudCompare的ICP把终点附近的地图和起点对齐然后手动把laserOdometry节点的位姿修正到配准后的值。这样虽然不能实时处理但至少能拿到一张视觉上可用的地图。如果你是做算法研究的建议还是尽快换带回环检测的算法LIO-SAM或者FAST-LIO都行。它们的坐标系管理比ALOAM健壮很多延展性也好。5. 从ALOAM扩展到其他建图算法的经验5.1 数据保存与离线重放的CDR方法在XTDrone里调试SLAM有个很实用的技巧把话题数据保存下来离线重放。这个需求在实际中比你想的多——算法参数调整时如果每次都重新跑仿真浪费时间又折磨显卡。正确做法是先把/velodyne_points和/mavros/local_position/pose录制下来然后离线跑ALOAM调参。ROS1的录制工具是rosbag但XTDrone里的PX4消息走的是MAVROS有时需要额外把MAVROS的Topic也录进去。命令很简单rosbag record /velodyne_points /mavros/local_position/pose /mavros/imu/data -O aloam_test.bag重放时使用rosbag play aloam_test.bag即可。注意use_sim_time要设成true否则重放时的时间戳是系统时间而不是录制时间TF树会乱套。5.2 换LIO-SAM/FAST-LIO要注意的差异如果你决定从ALOAM升级到LIO-SAM会发现架构相似但多了IMU预积分和回环检测坐标系管理的复杂度也上了一个台阶。最重要的一件事是LIO-SAM要求点云话题和IMU话题的时间戳严格同步如果XTDrone的IMU频率和你的雷达频率不匹配会在系统启动时报一大堆警告。FAST-LIO系列则更吃IMU的数据质量。在XTDrone里跑FAST-LIO时你需要把IMU的噪声参数调低否则仿真IMU的噪声会让位姿估计出现高频抖动。这些参数在算法仓库的config文件里都有换算法时务必花时间对着改别偷懒。这三个算法我都跑过。如果你真的很在意算法原理仔细读一遍ALOAM的三个节点代码再换会有完全不同的理解深度。如果只是想出一个图直接把LIO-SAM拉起来调通参数出图比ALOAM漂亮得多。5.3 我自己踩坑后的三个习惯第一个习惯是每个workspace单独开终端并source绝不混用环境变量。XTDrone的bashrc里各种export特别多混用会经常碰到某个包找不到。第二个习惯是启动顺序永远固定Gazebo先跑等雷达话题有数据了再启动ALOAM。每次都不需要想“该先从哪步跑”节省了很多精神内耗。第三个习惯是地图文件随时保存。在XTDrone里跑出来的地图可以用pcl_ros的pcl_ros_pcd节点保存成PCD文件后面用CloudCompare检查效果特别方便。命令是rosrun pcl_ros pcd_to_pointcloud /laser_cloud_map map.pcd这个文件既可以用来做点云配准研究也可以当作后续语义分割、目标检测算法的输入数据用处很多。我在XTDrone里调试ALOAM花的时间远超预期但回头想想这些时间并没有白费。搞清楚点云从哪来、坐标系怎么变换、时间戳为什么会错位之后再切换到任何激光SLAM算法都只是在重复这套基础的排查链路而已。如果你卡在“没有点云”和“坐标系报错”上别急着怀疑代码先按这条链路查一遍大概率很快就能看到一张干净的地图。
返回列表