ARTICLE DETAIL

资讯详情

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

Fast-LIVO2传感器时间同步实战:海康相机与Livox雷达硬同步全解析

Fast-LIVO2传感器时间同步实战:海康相机与Livox雷达硬同步全解析 1. Fast-LIVO2跑飞前的信号时间戳不对齐融合全是白搭我先把话说在前面Fast-LIVO2这个系统强是真强但它的稳是建立在“视觉帧、激光帧、IMU数据三者时间严格对齐”这个前提上的。我第一次在园区小路上跑Fast-LIVO2的时候建图建到一半轨迹明显歪出去重启了好几回还是一样。后来一查不是标定参数的问题不是IMU的噪声问题是相机和雷达的时间戳压根没对齐。这个排查过程让我意识到很多人拿到Fast-LIVO2的第一反应是调视觉特征、调激光配准参数但真正让系统直接发散的头号原因往往是时间同步这个看似不起眼的基础工作没做到位。Fast-LIVO2是港大MARS实验室开源的LiDAR-Inertial-Visual融合SLAM框架它把视觉直接法、激光点云、IMU紧耦合在一起做状态估计。这种紧耦合意味着什么呢就是视觉特征点的深度需要用激光点云去关联IMU预积分又要和视觉残差、激光残差在一个优化问题里联合求解。只要某一个传感器数据的时间戳和真实时刻偏了几毫秒甚至几十毫秒优化问题里的每一项都在互相打架系统就会给你颜色看。先看一组直观的数字假设机器人以2m/s的速度移动时间偏差50ms那图像和激光点云对应的空间位置就会差整整10cm。10cm对于SLAM后端来说已经是灾难级别的误差了因为激光点云的分辨率、视觉特征的重投影误差都是以毫米到厘米为单位的。更要命的是Fast-LIVO2的视觉模块用的是稀疏直接法它需要把图像块的灰度值和从激光点云获取的深度关联起来时间戳错位直接导致灰度残差暴涨优化器就算不崩溃估计出来的轨迹也会一天天漂出天际。所以这篇文章我打算把海康工业相机和Livox雷达的硬同步全过程掰开揉碎讲清楚先从原理上说明两边的时间戳到底怎么产生的再给两种可以落地的工程方案然后附上实测数据和一堆我踩过的坑。无论你是第一次搭Fast-LIVO2还是已经在跑但效果不理想这篇都值得花十分钟看完。2. 海康工业相机的时间戳藏着三个你不知道的细节2.1 相机时间戳不是“图像到电脑的时刻”很多人对相机时间戳的理解就是“图像到达主机时的系统时间”这个理解在普通USB摄像头上是没错的但在工业相机上完全不对。以海康MVS系列的工业相机为例它内部有自己的时钟源图像帧信息里的nTimeStamp字段旧版GxSDK里叫nTimestamp记录的是相机内部时钟在触发信号到来时刻的计数值而不是图像数据传输到主机那一刻的CPU时间。这一点极其关键。硬触发模式下外部脉冲信号一个上升沿打到相机Line0输入脚相机立刻开始曝光同时内部时钟被采样这个采样值就作为这帧图像的时间戳。所以这个时间戳天然地和外部世界的时间基准可以挂钩——前提是你得把相机内部时钟也校准到同一个时间基准上。多数人忽略的是海康相机的内部时钟默认是自由运行的上电开始计数精度和稳定性取决于晶振积累一段时间后会有漂移因此它在硬同步方案里扮演的是“相对精确的帧间间隔记录者”而不是“绝对时间源”。2.2 硬触发模式配置别漏了TriggerActivation海康MVS客户端或者SDK里配置硬触发的核心参数就三个TriggerMode、TriggerSource、TriggerActivation。我用SDK举个例子// 海康MVS SDKC接口 MV_CC_SetEnumValue(handle, TriggerMode, MV_TRIGGER_MODE_ON); MV_CC_SetEnumValue(handle, TriggerSource, MV_TRIGGER_SOURCE_LINE0); MV_CC_SetEnumValue(handle, TriggerActivation, MV_TRIGGER_ACTIVATION_RISINGEDGE); MV_CC_SetEnumValue(handle, ExposureMode, MV_EXPOSURE_MODE_TIMED); MV_CC_SetFloatValue(handle, ExposureTime, 2000.0); // 微秒TriggerSource选择Line0还是Line1取决于你硬件上把同步信号接到了哪个引脚。TriggerActivation通常是上升沿触发但如果你用的同步控制器输出的是下降沿有效就需要改成MV_TRIGGER_ACTIVATION_FALLINGEDGE否则相机纹丝不动。这一点在联调时最容易出错——信号接了、SDK也设了就是不出图查半天发现是触发极性反了。另一个容易忽略的地方是曝光模式。硬触发下最好用Timed模式就是固定曝光时长如果你选TriggerWidth模式曝光时间由外部脉冲的宽度决定那同步信号的占空比就直接影响图像亮度排查起来很让人头大。我建议固定曝光时间让触发信号只负责告诉相机“什么时候开始拍”这样时序更干净。2.3 nTimeStamp的单位和基准不同固件存在差异海康工业相机的nTimeStamp字段官方文档里标注的单位是微秒但我在实测中发现部分型号在不同固件版本下返回的可能是100微秒甚至毫秒级分辨率。这不算bug但如果你不校验直接当微秒用时间戳换算成的秒数就可能偏了几个数量级Fast-LIVO2读取到这种时间戳后肯定会把数据当成异常丢弃或者直接发散。最简单的验证方法把相机设置成10fps或者20fps的软件触发连续采集打印相邻两帧的nTimeStamp差值。如果确实是微秒单位差值会在10000010fps左右波动不会差出数量级。如果发现单位不对有两种办法一是查手册确认该型号的时基精度二是通过曝光时间等已知量反推换算系数。我自己的习惯是永远在代码里写死转换函数并加一段单元测试去断言帧间差值的合理性。再来一个坑海康相机内部时钟默认从零点开始累计并不会自动和主机的UTC时间对齐。所以在纯软件方案里哪怕你拿到了相机的nTimeStamp它也只是相对时间戳。要让它变成和Livox雷达可比对的时间要么定期把相机内部时钟同步到主机用PTP或厂商私有时间同步协议要么在硬同步方案里通过外部触发源把相机帧的时间基准锁到GPS上。这就是后面要展开的核心内容。3. Livox雷达的同步机制PPS和GPRMC一个都不能少3.1 雷达时间戳的本质是“相对GPS秒的纳秒偏移”Livox系列雷达Mid-40、Horizon、Avia、Mid-360对时间同步的定义很明确它内部有一个高精度时钟但需要外部提供GPS参考信号雷达才能知道“绝对的UTC时间”和“秒边界”在哪。一旦同步建立每一帧点云里的每个点都会带一个纳秒级时间戳这个时间戳表示该点相对于GPS整秒时刻的偏移量。也就是说雷达时间戳GPS整秒时刻偏移量。这个设计的巧处在于PPS信号每秒一个脉冲用来对齐秒边界GPRMC语句用来给出UTC绝对时间年月日时分秒。两样东西配合起来雷达就能把内部每一个扫描点的时刻映射到全球统一的UTC时间轴上。没有GPRMC只有PPS雷达只知道每一秒在哪但不知道这一秒到底是哪个时刻没有PPS只有GPRMC雷达知道当前UTC时间但没有高精度的秒边界来重置内部时钟时间照样会漂。3.2 同步线怎么接端口定义和电平要求Livox雷达外部有一个8针同步接口其中关键的三根线是PPS IN秒脉冲输入一般要求3.3V或5V TTL电平高电平有效脉宽几十到几百毫秒都可以RMC IN或者叫UART RXGPRMC语句输入常用波特率9600GND共地必须以它作为信号参考地接线时最容易踩的坑是电平匹配。如果你用的GPS模块输出的是RS232电平正负12V那种不能直接怼到Livox的同步口需要加一个RS232转TTL模块。如果GPS模块是开漏输出必须接上拉电阻到3.3V或5V否则PPS信号根本到不了高电平。我用过一个某宝几十块的GPS模块它上面标了“PPS”结果输出的是开漏一开始怎么都同步不上后来加了10k上拉电阻才正常。在livox_ros_driver2里面同步相关的配置集中在launch文件里param nameenable_sync valuetrue/ param namesync_signal value1/ !-- 1PPS GPRMC -- param namesync_freq value1/ !-- PPS频率通常为1Hz --雷达上电后会打印同步状态在ROS里可以监听/livox/lidar/sync_status这个话题正常情况是SYNC_OK如果显示SYNC_NOT_READY或者一直切回SYNC_UNKNOWN基本就是PPS或者GPRMC链路有问题。3.3 雷达时间戳在ROS消息里的实际形态livox_ros_driver2发布点云时header.stamp直接用的是雷达内部解析后的时间。这时候有个有意思的现象如果你的雷达已经和GPS同步好那么点云消息的header.stamp是UTC时间是与主机系统时间无关的。而很多其他传感器的驱动尤其是USB接口的相机发消息时header.stamp用的却是主机接收到数据那一刻的CPU时间。这两种时间戳根本不在同一条时间轴上拿去做融合那才是真正的“鸡同鸭讲”。所以做Fast-LIVO2的同步第一步要做的其实是搞清楚每一条消息的header.stamp到底是谁的时间而不是急着改代码。4. 真正把两路时间戳拉齐两种实战方案对比4.1 方案一主控时间桥接法——软硬结合成本最低这个方案的核心思路是既然海康相机和Livox雷达不能直接共享同一个时间源那就让它们都向主控电脑靠拢。具体分两步第一步把所有传感器消息的header.stamp统一改成主机接收时间。相机的驱动和海康SDK获取图像后取ros::Time::now()作为stampLivox雷达则把livox_ros_driver2配置成使用主机时间或者利用header.stamp重新赋值。这样大家在同一个时间轴上。第二步估计和补偿相机触发到实际曝光之间的固定延迟以及Livox驱动从雷达数据到ROS回调之间的固定延迟。这两个延迟虽然来源不同但通常在短时间内是相对稳定的可以通过离线标定算出。这个方案的优点是改动小、不用加硬件缺点也很明显主机调度抖动、USB/网卡排队延迟都会污染最终的时间精度实测一般只能做到10~30毫秒的等效对齐精度。如果Fast-LIVO2只在低速、近距离场景下跑或许勉强能用但稍微快一点或者环境特征差一点系统就开始飘。4.2 方案二独立同步控制器——全硬同步精度碾压我的最终选择是做一个独立的同步控制器让它统一发出所有传感器的同步信号。这个控制器核心器件是一块STM32F103或者用现成的GPS授时模块也行主要干三件事从GPS模块接收PPS和GPRMC解析出UTC时间把PPS和GPRMC同时转发给Livox雷达的同步接口另外生成一路可编程频率的触发脉冲比如10Hz、20Hz、30Hz送给海康相机的Line0输入触发曝光这里面最大的好处是相机每帧曝光的开始时刻和雷达点云的PPS秒脉冲都来自同一个GPS时间基准。相机的时间戳虽然仍是内部时钟计数值但它的触发源和雷达的秒脉冲是同一个父母生的两者天然在UTC时间轴上对齐。为了让触发脉冲和PPS维持固定的相位关系STM32里要把触发脉冲的上升沿对齐到PPS边沿之后的某个固定局部位移上。这里有一个时间关系式假设雷达PPS的整秒时刻是T同步控制器设定相机触发频率为f则第n个相机触发脉冲的上升沿理论时刻为t_n T n / f其中n是从上一个PPS边沿开始计的周期序号。如果控制器在PPS边沿到来后清零计数器那在整秒边界处相机触发和雷达PPS之间的相位关系就是完全确定的。这意味着你可以在任意时刻把相机的帧和时间轴准确地关联起来再用插值算法让Fast-LIVO2拿到每一个激光点对应的准确时刻。这个方案硬件成本大约在百元级别但要写固件、画板子、接线整套干下来大半天是要的。如果你不想自己画板市面上也有现成的多传感器同步盒功能类似价格几百到几千不等。不少做自动驾驶和机器人研究的实验室最终都走向了这个方案因为它的时间精度可以做到亚毫秒级根本不是软件方案能比的。4.3 方案选型我给一个明确的判断标准到底用方案一还是方案二我个人的判断标准很简单你的机器人的最大移动速度是多少如果速度超过2m/s或者未来打算往室外园区、自动驾驶方向走直接上方案二省得后面返工。如果只是桌面级、室内低速机器人方案一先跑通流程完全可以。另一个判断依据是Fast-LIVO2定位的用途。如果只是录数据包离线跑同步精度差一点可以通过后处理补偿如果要在线跑或者做闭环控制时间精度直接决定了系统能不能收敛必须上硬同步。5. 实测校准软同步和硬同步到底差了多少毫秒5.1 离线标定同一时间轴的两种手段无论用哪种方案做完之后都要做一次时间对齐的校验。最常用的离线标定工具是Kalibr它里面那个kalibr_calibrate_cameras和kalibr_calibrate_imu_camera可以同时标定相机内参、相机-IMU外参以及两者之间的时间延迟。但Kalibr对数据质量要求比较高如果你只是快速判断时间是否对齐有个更直接的方法让机器人做一次快速的来回摆动同时记录相机图像和激光点云然后比较视觉特征和激光点在运动方向上的偏移量。我一般这样做找一个纹理比较丰富但又有明显边缘的场景比如摆放几个带条纹的纸箱让机器人沿直线来回运动几次速度尽量均匀离线把点云投影到图像上叠加显示观察投影的边缘和图像边缘是否重合如果时间没对齐点云投影的边缘和图像边缘之间会出现一个沿运动方向的系统性错位错位量除以运动速度就是时间偏差。比如运动速度2m/s边缘错位2cm时间偏差就是10ms。5.2 实测结果对比我在同一台设备上分别用方案一主控时间桥接和方案二同步控制器做了对比实验结果非常悬殊方案等效时间对齐精度100m建图轨迹漂移视觉-激光投影边缘错位主控时间桥接软硬结合10~30ms0.8~1.2m2~6cm独立同步控制器全硬同步0.1ms0.05~0.1m0.5cm这个结果说明什么当时间误差压到亚毫秒级别后Fast-LIVO2里最敏感的那个视觉-激光深度关联项才真正稳定系统才能在长距离、快速运动下保持不发散。方案一偶尔也能跑但偏差大到一定程度就会触发视觉跟踪失败系统会频繁重置或退出。5.3 Fast-LIVO2对时间偏移是否真的零容忍可能有人会问Fast-LIVO2的论文里好像有在线估计时间偏移的机制确实代码里有对相机-IMU时间偏移的在线估计部分但激光和相机的同步主要还是依赖外部时间基准。你要是把相机时间戳和雷达时间戳两个系统之间的偏差放到几十毫秒量级在线估计大概率收敛不到正确值反而会把其他参数带偏。所以在调Fast-LIVO2时我的顺序永远是先检查时间戳是否在同一个时间轴上再挂可视化看投影重合度最后才去调特征提取和权重参数。时间同步没做好后面的一切调参都是白费功夫。6. 硬件接线和软件配置里的坑我帮你一次踩平6.1 海康相机触发端的信号隔离与驱动能力海康工业相机的Line0输入通常是光耦隔离输入好处是抗干扰但坏处是它对输入电流有要求不是随便一个IO口接上去就行。我用过一个STM32的GPIO直接去触发相机发现相机偶尔触发偶尔不触发后来看手册才知道Line0需要至少5~10mA的灌电流而STM32 GPIO推挽输出也能提供几mA但线一长就衰减。正确做法是在中间加一级三极管或者光耦驱动电路用外部电源去驱动相机的触发输入端。还有一个细节触发线必须用双绞线或者屏蔽线而且尽量远离电机驱动线和雷达的电源线。激光雷达的PPS信号是高阻抗输入容易受到电机PWM干扰相机触发线是低阻抗光耦相对好一些但两者如果捆在一起走线高频干扰照样会影响PPS的上升沿位置导致雷达时间戳抖动。6.2 时间单位不统一us、ns、s三个单位来回换算我见过太多人栽在这个上面。海康相机SDK给的是微秒Livox点云的时间戳是纳秒ROS里header.stamp是秒浮点数Fast-LIVO2内部很多地方又用秒。如果在驱动层不统一单位就往下传后面绝对出幺蛾子。我的做法是在驱动层就统一转成秒并且把所有时间戳明确注释单位。比如相机回调里uint64_t ts_us pFrameInfo-nTimeStamp; double ts_sec (double)ts_us * 1e-6; // 如果使用硬同步GPS理论上可以把GPS整秒加上去 // ts_abs_sec gps_base_sec ts_sec;Livox点云的时间戳需要结合包的时间戳和偏移量换算livox_ros_driver2里已经帮你算过一部分但你要确认它输出的是不是绝对秒。我习惯在代码里加一个断言一旦时间戳算出来和当前系统时间差异超过几分钟立刻报警提示。6.3 ROS header.stamp被覆盖的问题另一个经典坑是Livox驱动默认发布点云时header.stamp用的是雷达时间这个没问题但你如果用类似bag_to_pcd的工具去处理数据它可能用主机录制数据包的时间去覆盖header.stamp。这就导致你回放数据时雷达和相机的时间戳全都变成了同一个时间基准下的接收时刻之前做的硬同步全部作废。我做数据采集时的铁律是录制时要保证所有话题的header.stamp都是传感器时间而不是主机时间。在livox_ros_driver2里有一个参数可以设置是否使用雷达时间作为消息头的时间戳默认是开的别去关相机的驱动则需要自己改一下从SDK的nTimeStamp赋值给header.stamp而不是用ros::Time::now()。6.4 频率设置和曝光时间之间的相互制约同步控制器输出的触发频率决定了相机帧率但帧率不是越高越好。如果相机曝光时间设置为2ms触发频率是30Hz那每帧之间的空闲时间是33ms足够用了。但如果你在暗光环境下把曝光时间拉高到20ms同时触发频率50Hz那触发间隔20ms曝光时间20ms相机的时序就会极其紧张触发脉冲来了但相机还在上一帧曝光里这一帧就直接丢了时间戳会乱跳。这个约束关系很简单曝光时间 触发周期而且要留出至少10%的余量。我一般设置相机帧率和雷达扫描率一致或者成整数倍关系比如雷达10Hz相机10Hz或20Hz曝光时间控制在2ms以内既保证亮度又保证时序干净。6.5 Fast-LIVO2的launch文件里时间相关的参数别乱动Fast-LIVO2的launch文件里有一些时间相关参数比如IMU时间偏移的初始值、视觉特征的时间容差等。默认值在数据干净的前提下没太大问题但如果你改了相机帧率、分辨率或者输入数据的时间抖动偏大就有必要微调。我运行的命令大概长这样roslaunch fast_livo2 mapping.launch \ config:fast_livo2_mid360.yaml \ cloud_topic:/livox/lidar/pointcloud \ img_topic:/camera/image_raw \ imu_topic:/livox/imuconfig文件里的max_iteration、vis_feature这些参数不建议为了追求实时性而调得太激进。时间同步做好之后Fast-LIVO2的默认参数在大多数场景下已经够用了。最后再分享一个小技巧在正式建图之前先拿着设备在场景里快速晃动几秒钟看RViz里输出的点云投影到图像上边缘是否干净、有没有重影。这一招能让你在三分钟内判断出时间同步做没做到位省得跑完整个流程才发现数据是脏的。我后来每次换场景、换传感器配置都先用这个方法过一遍基本没再因为时间同步问题返工过。
返回列表