# 点云数据格式
## 概述
激光雷达(LiDAR)完成激光发射、扫描以及接收的同步,信号处理以及点云生成,并向以太网输出处理后的点云数据(Point Cloud)。
### 点云数据
点云是激光雷达探射过程点信息的一个集合,描述了部分空间角度或360度全方位环境的深度、反射信息。可通过点云直观观测前方障碍物,来帮助实现避障功能。简单的扫描画面呈现如下:

点云数据包括以下内容:
- 点云数据生成的时间戳
- 测量到的点的方位、距离以及灰度信息
- 系统检测信息(如各部件的温度和其他工作参数)
- 系统诊断信息(如温度过高,器件故障后生成的诊断信息)
### 点云扫描方式
点云扫描方式大致可分为以下三种:
1. 机械扫描/一维 MEMS 扫描,光束只在水平方向扫描,所有线束扫过的完整视场角即为一帧画面;
2. 二维MEMS扫描,将整个视场角在水平方向上分成几个区域,每个线束负责一个区域的点,扫描方式为逐行扫描,最后所有区域合成一帧完整的画面。
3. 线扫描(LeddarTech),将整个视场角在水平与竖直方向分为数个区域,每个线束负责一个区域,与二维MEMS不同的是,激光不再是点而是线,扫描方式与一维MEMS扫描一致,只不过可能是水平方向扫描,也可能是竖直方向扫描。最后所有区域合成一帧完整的画面。
另外还可能是一维转镜,转镜+振镜,OPA 等扫描方式。

## 点云数据基本信息
点云作为激光雷达的重要信息,包含必要的空间参数、激光反射信息等。其中,空间信息可用直角坐标系下的 x、y、z 来表示,也可用极坐标下的 azimuth、elevation、radius 来表示。另外,点云还包含参数如 intensity/reflectivity、RGB、timestamp、return 等等。相关参数详解如下:
| 参数 | 说明 |
| ---------------------- | ------------------------------- |
| X | X 轴方向距离,单位 mm |
| Y | Y 轴方向距离,单位 mm |
| Z | Z 轴方向距离,单位 mm |
| Azimuth | 水平方位角,分辨率 0.01° |
| Elevation | 垂直俯仰角,分辨率 0.01° |
| Roll | 侧倾角,分辨率 0.01° |
| Radius | 极坐标下的点的径向距离,单位 mm |
| Intensity/Reflectivity | 点的反射强度或反射率 |
| RGB | 点的颜色信息 |
| Return | 回波次数 |
| Timestamp | 时间戳 |
一般的,点信息封装在 pointT 结构体中,在定空间信息的时候选用极坐标系方式而不是直角坐标系,考虑到角度是雷达设备产出的原始数据,因而直接输出角度数据更高效,避免激光雷达算力消耗,如果需要转换为直角坐标系 xyz,可交给上位机或主控设备去做,或者通过参数管理来实现相关配置输出。
关于二者转换原理和方法如下:

> 极坐标与直角坐标之间的转化


### RSView 点云数据点
| 数据 | 数据类型 | 说明 |
| ---------- | -------- | ---------------------------------- |
| Point ID | int | 点的序号,从 0 递增 |
| Point_X | double | |
| Point_Y | double | |
| Point_Z | double | |
| distance_m | double | |
| intensity | char | 用 8 bit 表示,有效范围为 1 到 255 |
| laser_id | char | Sensor 的编号 |
| pitch | double | |
| yaw | double | |
我们自定义的结构体:
```c
typedef struct
{
uint16_t distance; // 距离,极坐标的径向距离?单位 mm
uint16_t azimuth; // 水平方位角
uint16_t elevation; // 垂直俯仰角
uint8_t reflectivity; // 回波强度
uint16_t rsv; // 预留?
}PointT;
```
## 点云数据包(MSOP)格式
众多的点按照一定的规则组成数据包,规则可能包括存储最小空间原则、解析效率优先原则、便于传输原则、排列格式清晰原则等,此外定义的时候还可能参考设备输出的整体特征。所以在设计数据包格式的时候,尽可能:
1. 将公共信息存放到公共位置,减少 pointT、block 结构内部所使用的空间;
2. 数据包结构尽可能简单整齐划一,避免多级包头嵌套,每层数据实现字节对齐;
3. 数据包长度适中,不能太短,也不能太长,公共头太短浪费带宽,太长不利于报文传输;
4. 贴合物理硬件,数据块按扫描线束分组,一帧图像包含整数个数据包原则;
4. 实时高效原则,采集到的点及时组包传输;
完整的数据包包括三部分,数据头(Head)、数据块(Block)、数据尾(Tail),其中数据头包含必要的包识别序列如 0xFF/0xEE、包序列号 sn,数据块个数 block num,协议版本 protocol version,回波模式、扫描时间 Timestamp、激光雷达类型、时间同步模式、温度信息以及必要的预留字段等。数据块长度可根据 lidar 个数和 block 个数确定。
以二维MEMS振镜扫描为例,5个通道水平排列,既可以在水平扫描也可以竖直方向扫描, 完整的数据包定义如下:

> 激光雷达点云数据包格式
### 数据头
**40 byte frame head 包括**
| 字段 | 序号 | 属性 | 信息 | 长度 |
| ----------------- | ---- | ------------ | ------------------------------------------------------------ | ------- |
| header | 1 | 帧头 | 消息识别头,如 0xFF 0xEE | 4 byte |
| Pkg len | 2 | 包长 | 净荷长度 | 2 byte |
| Pkt sn | 3 | Sn号 | 包序列号,对每帧图像,每帧数据起点包计数为1,最后一个点的包计数为最大值 | 2 byte |
| Lidar type | 4 | 雷达类型 | 区分产品型号 | 2 byte |
| Protocol version | 5 | 协议版本 | 区分通信协议版本 | 2 byte |
| timestamps | 6 | 时间戳 | 记录系统时间,高6byte为秒,低4byte为微秒(需要年月日) | 10 byte |
| Measurement model | 7 | 测量模式 | 分城市道路、高速等模式等 | 1 byte |
| Laser num | 8 | 激光通道数 | 激光线束 Channel,线束具有相同的时间系统 | 1 byte |
| Block num | 9 | block数 | 数据包中的 block 数 | 1 byte |
| Wave mode | 10 | 回波模式 | 第一回波,最后回波,最强回波,双回波,暂时可只实现单回波 | 1 byte |
| Time sync mode | 11 | 时间同步模式 | 1、自己内部时间;
2、1pps进行亚秒在整秒复位模式;
3、PTP时间同步模式 | 1 byte |
| Time sync state | 12 | 时间同步状态 | 时间同步状态 | 1 byte |
| Slot num | 13 | 槽位号 | 区分不同槽位 | 1 byte |
| reserved | 14 | 预留位 | | 11 byte |
数据块区间是MSOP包中雷达测量值部分,由多个block组成,关于数据包、block数、一个block数中channel数之间关系,该部分设计支持变长模式,确定方法如下:
1. 一个block中channel数即为激光线束数;
2. 保证一个数据包有尽可能多的block数;
3. 保证整个包组成以太网帧后长度不超过1500字节;
双回波模式下,数据包格式可能有以下三种策略:
1. 奇偶block,分别存放第一回拨、第二回拨,三回波以此类推;
2. 奇偶MSOP包,在包头中设置字段表明当前包所属回波;
3. 扩展block,在原来的block后追加block,
当前考虑第三种解决方案。解析过程中可通过return sn判断属于第几回波(如果有更多回波可以此类推,支持动态配置,block数相应衰减,相比策略1可节省一个time offset字段)。而策略1可用在增采样模式下。

### 数据体
48 byte block数据包括:
| 段落规划 | 序号 | 属性 | 信息 | 长度 |
| -------------------- | ---- | ---------- | ------------------------------------------------------------ | ---- |
| Channel num | 0 | Channel 数 | 检测到的channel数 | 1 |
| Time offset | 1 | 偏移 | 该组block所有点相对包头的timestamp的时间偏移,综合时间=timestamp + timeoffset | 1 |
| Return seq | 2 | 回波序号 | 单回波模式下,该值恒为0,双回拨模式下,第一回波为0x01,第二回拨为0x02 | 1 |
| Channel distance | 3 | 径向距离 | 极坐标系下,该channel的径向距离,距离分辨率5mm | 2 |
| Channel azimuth | 4 | 水平方位角 | 极坐标系下,该channel的水平方位角,分辨率0.01° | 2 |
| Channel elevation | 5 | 垂直俯仰角 | 极坐标系下,该channel的垂直俯仰角角,分辨率0.01° | 2 |
| Channel reflectivity | 6 | 反射强度 | 反射强度,范围0-255 | 1 |
| Channel reserved | 7 | 预留位 | 预留位 | 2 |
### 数据尾
30 byte tail包括:运行状态、回波模式、电机转速、UTC时间、IMU相关信息以及相应的预留位等(功能可追加开发),详情如下;
| 段落规划 | 序号 | 属性 | 信息 | 长度 |
| ---------------------------- | ---- | -------------------- | ---- | ---- |
| Motor speed | | 电机转速 | | 1 |
| IMU temperature | | IMU温度 | | 2 |
| IMU acceleration Unit | | 加速度的单位换算系数 | | 2 |
| IMU angular velocity Unit | | 角速度的单位换算系数 | | 2 |
| IMU timestamp | | IMU 数据的时间戳 | | 4 |
| IMU x axis acceleration | | X轴加速度 | | 2 |
| IMU y axis acceleration | | Y轴加速度 | | 2 |
| IMU z axis acceleration | | Z轴加速度 | | 2 |
| IMU x axis angular velocity | | X轴角速度 | | 2 |
| IMU y axis angular velocity | | Y轴角速度 | | 2 |
| IMU z axis angular velocity | | Z轴角速度 | | 2 |
| CRC | | CRC校验码 | | 4 |
| Reserve | | | | 3 |
## 设备辅助信息(DIFOP)
## 以太网传输效率
以FoV 120*25,Resolution 0.05*0.05,帧率10HZ为例,传输带宽要求如下:
- 水平方向探测点数:120/0.05 = 2400;
- 垂直方向探测点数:25/0.05 = 500;
假设激光束为5,一个block长度为47byte,一个数据包包含25个block,总共125个点,则payload部分长度为47*25 = 1175byte;(激光束个数对带宽要求影响不大,不考虑)
**一个完整的MSOP包长为:**
```
1175(payload) + 40(head)+ 17(function safty)+ 32(network safty)+30(tail) = 1294 bytes
```
加上以太网包头后为1294 + 50 = 1344byte;
一帧图像包含2400*500/125=9600个MSOP包 ,大小为9600 * 1344 = 12902400byte;
帧率10HZ,则一秒钟数据量大小为12902400 * 10 = 129024000byte;(约103Gbps)
Resolution 0.1*0.2设置下为16128000byte;约129Mbps;(10HZ,单回波)
Resolution 0.05*0.1设置下为64512000byte;约516Mbps;(10HZ,单回波)
另外,帧率提升一倍,数据size提升一倍;回拨次数+1,size增长一倍;
(如果把安全信息放在DIFOP包中,发送频率1HZ,传输速率可能稍微有所降低,但不超过10%)
## 点云数据包体量优化
### 无效点过滤策略
考虑到点云数据体量较大,对以太网速率提出了很高的要求,可以考虑无效点的过滤机制;无效点可能包括:
1. 没有发光的点;
2. 收到回波,但脉冲在近距盲区(小于能正确测量的最小值如0.3m),判定点云无效;
3. 收到回波,但脉冲在通道盲区(小于该通道能测的最小值,如0.3-2m),判定无效;
4. 收到回波,但不符合要求,判定无效,可能原因包括:
- 回波来自其他雷达;
- 测量距离超过测距上限;
- 脉冲强度低于阈值;
- 脉冲被鬼像等滤波模块滤除;
由于滤波打乱了block的整齐性,原本一个block包含固定的5个点,现在过滤某个/某些点后需要有额外的字段标记当前block中一共有多少个点;这里可用channel num定义;
**一个数据包保持固定的25个block(可配置),即使只有一个block有有效数据;**
数据包中block或者channel X“缺失-替补”方法(channel替补或block替补)可能会让传输效率提高一点,但对数据包长度维护、解析、配置会变得非常复杂,暂不考虑。数据包中有效点个数范围1-125,当没有有效点时,退出组包过程,并开始下一MSOP包的组包。
所以一个过滤策略下的数据包格式可能如下:

当然,加入过滤条件后,我们依然需要去考虑极端数据量的情况,传输速率是否能满足要求。
### 缩减channel X结构体策略
为了节省点云的结构大小,也可以考虑如下格式,这种格式在机械式激光雷达中非常适用,因为机械式扫描一列激光束俯仰角固定,通过查表可知;方位角可通过固定的起始角+转速*时间计算得到,起始角查表可知,转速和时间在头信息中可知;因此每个block中channel的azimath可以计算得到,俯仰角可缺省;
在二维MEMS中,也可考虑该策略,需要提前设置每个激光束的起始方位角和俯仰角,结合转速和时间,可计算得到该点的实时俯仰/方位角;
LeddarTech线扫描也支持该策略,原理和机械扫描一致;

如果是如下这种格式,关于无效点的过滤,可考虑在block中使用bitmap来标记存在的channel;因为channel不能打乱顺序,因此设计一个16byte的bitmap,可以用来标记当前哪些channel是存在/缺失的;
### 序号代替浮点类型角度策略
扫描角度通常情况下是固定的(即点云数据帧中的每个点俯仰水平发射角不变),那么我们可以建立一个扫描周期内的扫描时间与角度之间的函数关系,或维护一张map表,来通过计算或查找对应角度,这样可以将浮点类型转化为整形,缩减点的大小。
最小分辨率场景下,水平方向需要120/0.05 = 2400个点, 垂直方向需要25/0.05 = 500,用序号表示,俯仰角、水平角各需要两个2字节变量表示。而正常表示俯仰角、水平角我们可以乘以一定倍率,比如100(分辨率为0.01),表示范围为120*100 = 12000,仍然只需要2字节表示,因此我们可以认为在用序号表示策略下没有增益,且需要维护一张额外的序号-角度查找表,因此暂不考虑该策略。
## ROI分辨率动态配置下的点云格式
二维MEMS扫描下,如果存在ROI视场角区域,点云格式与上述一致,增采样的点放在独立的一个block中即可(该block只有增采样那些tile的点);
线扫秒场景下,格式完全一样,只是部分Tile区的block密度变为以前的2倍或更多。
## 以太网帧格式与 pcap 数据包