ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

第三篇 驱动理解与应变

第三篇 驱动理解与应变 相信大家使用到传感器都会用到相应的驱动该驱动主要都是该设备的厂家提供的这里的驱动主要是指软件驱动。为啥这里提前将驱动主要是如果你作为一个算法工程师如果对所使用的传感器的特性不了解包括硬件、软件参数和特性都没有了解那你也无法正确使用它的各种性能不可能充分发挥出该传感器的优良特性。我们主要从传感器的硬件物理特性、通讯文件等入手来充分了解传感器的驱动特性。想主要以livox mid360以及雷神128线激光雷达为例结合物理特性和驱动软件来透彻分析驱动软件为啥那样写。“驱动不就是厂家给个库调个API就完事了吗”如果你这么想那大概率会在某个深夜被一个诡异的点云畸变问题折磨到怀疑人生。作为算法工程师我们习惯把传感器当作一个“黑盒”给电、给网、给数据。但激光雷达不是普通的传感器——它每秒产生数几万到数十万乃至数百万个三维点每帧数据都带着微秒级的时间戳不同型号的扫描方式、数据组织逻辑、同步机制天差地别。如果不理解这些物理特性和通讯协议你连驱动里那些看起来“莫名其妙”的代码为什么要那样写都搞不清楚更别说调优了。话不多说切入正题。首先我们先从激光雷达驱动入手举两个例子说明一下学习的方向。现在的激光雷达可以分为纯固态激光雷达、混合固态激光雷达和机械激光雷达。首先介绍一下当前机器人行业用的最多的混合固态激光雷达livox mid360所有livox激光雷达共用一套官方驱动专门针对这种非重复式花瓣型扫描方式从ros节点入口、SDK接口到数据缓存、多线程分发再到ros消息发布。着重理解一下其多个雷达并行处理怎么实现高并发、低延迟的。在启动多个雷达时是怎么创建与发布线程的可以着重看这三个函数在 Lddc 里OnLidarActivated(uint8_t index)DistributePointCloudData(uint32_t lidar_id)DistributeImuData(uint32_t lidar_id)彻底读懂per-lidar 懒创建原理和好处。从用点云的角度来分析我们先要搞清楚需要什么信息格式的点云一般定位导航采用livox自定义的消息多一些即充分理解CustomPoint.msgLivox costom pointcloud format.uint32 offset_time # offset time relative to the base timefloat32 x # X axis, unit:mfloat32 y # Y axis, unit:mfloat32 z # Z axis, unit:muint8 reflectivity # reflectivity, 0~255uint8 tag # livox taguint8 line # laser number in lidar和CustomMsg.msgLivox publish pointcloud msg format.std_msgs/Header header # ROS standard message headeruint64 timebase # The time of first pointuint32 point_num # Total number of pointcloudsuint8 lidar_id # Lidar device id numberuint8[3] rsvd # Reserved useCustomPoint[] points # Pointcloud data在此只是提示学习方法offset_time、timebase和header的关系tag是干什么用的不要它是否可以num_scans_是什么意思有没有发现很多激光雷达都有这个参数想想不同的激光雷达怎么将这个参数应用在slam的建图定位中 sensor_msgs::PointCloud2和livox_ros_driver2::CustomMsg的转换关系是否两者可以相互转换为什么然后用的时候要着重理解一下次段std::for_each(std::execution::par_unseq, index.begin(), index.end(), [](const uint i) {if ((msg-points[i].line num_scans_) ((msg-points[i].tag 0x30) 0x10 || (msg-points[i].tag 0x30) 0x00)) {if (i % point_filter_num_ 0) {cloud_full_[i].x msg-points[i].x;cloud_full_[i].y msg-points[i].y;cloud_full_[i].z msg-points[i].z;cloud_full_[i].intensity msg-points[i].reflectivity;cloud_full_[i].time msg-points[i].offset_time / float(1000000);if ((abs(cloud_full_[i].x - cloud_full_[i - 1].x) 1e-7) ||(abs(cloud_full_[i].y - cloud_full_[i - 1].y) 1e-7) ||(abs(cloud_full_[i].z - cloud_full_[i - 1].z) 1e-7)) {is_valid_pt[i] true;}}}});在此你就能看出tag的作用了0x30和0x10、0x00分别代表什么这里说一下答案作用目的是只保留第一次回波单回波或双回波的第一回波丢弃后续回波的点避免多回波在点云中造成重叠、拖影或距离歧义。具体分析在 Livox SDK 中LivoxPoint 的 tag 定义bit 0-1: 回波序号0 表示第一次回波1 表示第二次2 表示第三次。bit 2: 扫描方向0 表示正向1 表示反向。bit 3: 点类型0 表示正常点1 表示噪声点。bit 4-5: 保留。bit 6-7: 置信度0 表示低1 表示中2 表示高。Livox SDK 的 livox_def.h 中有typedef enum {kLivoxPointTagSingle 0x00,kLivoxPointTagDual 0x10,kLivoxPointTagTriple 0x20,} LivoxPointTag;再举个例子以雷神的128线固态激光雷达如果要用这个替代livox激光雷达应该怎么样接入建图定位程序中呢比如说fast_lio2、faster_lio或者pointlio首先还是要熟读雷神128线的用户手册如果这种激光雷达接入fast_lio2该怎么进行接入接口信息修改且听下回分解。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进