18 点云格式与点布局
18.1 概述
这里先回顾点及点云的定义,看看有哪些属性,再说明这些属性的确切含义。
18.2 点云格式
18.2.1 点
点的属性如下。这里列出的是 XYZIRT 类型,它包括了 XYZI 类型的所有属性。
struct PointXYZIRT
{
float x;
float y;
float z;
uint8_t intensity;
uint8_t ring;
double timestamp;
uint16_t range;
};
18.2.2 定义点云类型
点云的属性如下。它的成员 points 是一个点的 vector。
template <typename T_Point>
class PointCloudT
{
public:
typedef T_Point PointT;
typedef std::vector<PointT> VectorT;
uint32_t height = 0; // Height of point cloud
uint32_t width = 0; // Width of point cloud
bool is_dense = false; // If is_dense is true, the point cloud does not contain NAN points
double timestamp = 0.0; // Timestamp of point cloud
uint32_t seq = 0; // Sequence number of point cloud
VectorT points;
};
18.3 点的 ring
18.3.1 MEMS 雷达
MEMS 雷达每轮扫描同时扫 5 个区域,每个区域得到上下两个点,总共得到 10 个点,这 10 个点有一样的时间戳。如图中的 t1 时刻。下一时刻同理继续扫描,如 t2 时刻。

18.4 点的布局
18.4.1 MEMS 雷达
MEMS 雷达每轮扫描同时扫 5 个区域,每个区域得到上下两个点,总共得到 10 个点,打包到一个 Block,写入 MSOP Packet。
ag_driver 解析 MSOP Packet 时,按照 Block 的顺序解析,所以在点云的 points 数组中,每个 Block 的 10 个点连续保存为一组。

这里以 A0 为例,说明每个区域的点布局。
A0 的每个区域 (128行 * 256列),上下两个为一组从上往下呈 Z 字型扫描。也因此,128 行只需左右扫描 64 次,即 32 个左右来回。

18.4.2 点云中点的序号
在点云的 points 数组中,点的序号并非按照上述顺序。而是将其按从左到右的顺序,修改点云的序号。如下图。原本一区 1x1 位置的点序号为 1,其下方点为序号 2,而序号 3 在二区的 1x1。

即点的序号如下图箭头顺序

18.5 点的坐标系
ag_driver 输出的点遵循右手坐标系。
如果想改变这一点,可以改变雷达解码器 Decoder 的实现代码,改变坐标 (x,y,z) 的映射关系。如下是 A0 Decoder 的例子。
//.../decoder/decoder_A0.hpp
int elevation = ntohs(channel.elevation) - ANGLE_OFFSET;
int azimuth = ntohs(channel.azimuth) - ANGLE_OFFSET;
float x = distance * COS (elevation) * COS (azimuth);
float y = distance * COS (elevation) * SIN (azimuth);
float z = distance * SIN (elevation);
18.6 点的 timestamp
MEMS 雷达扫描一帧的时间是 100 毫秒。点云中的点散布在这 100 毫秒的范围内。
如何想得到比点云时间戳更高精度的时间戳,请考虑使用 XYZIRT 点格式,它的 T 是点的时间戳。
18.7 点云的 timestamp
点云的时间戳可以来自第一个点,也可以来自最后一点。
18.7.1 雷达的时间,还是主机的时间?
ag_driver 有两种方式得到点云的时间戳。
从 MSOP Packet 解析。这个时间是雷达根据自身的时间设置。一般需要对雷达进行 PTP 时间同步,以保证雷达的时间与 PTP Master 保持一致。
调用操作系统的函数,得到
ag_driver运行的这台主机的时间。这是ag_driver的默认配置。
ag_driver 的选项 use_lidar_clock 可以改变这个配置。
struct AGDecoderParam // LiDAR decoder parameter
{
...
bool use_lidar_clock = false; // true: use LiDAR clock as timestamp;
// false: use system clock as timestamp
...
}
18.7.2 取第一个点的时间,还是最后一个点的?
默认情况下,取最后一个点的时间。
ag_driver 的选项 ts_first_point 可以改变这个配置。
struct AGDecoderParam // LiDAR decoder parameter
{
...
bool ts_first_point = false; // true: time-stamp point cloud with the first point;
// false: with the last point;
...
}
18.7.3 UTC 时间还是本地时间?
雷达写入 MSOP Packet 的时间是 UTC 时间。
ag_driver 工程的 CMakeLists.txt 中的 ENABLE_STAMP_WITH_LOCAL 宏,可以根据本地的时区,将这个时间转换成本地时间。
option(ENABLE_STAMP_WITH_LOCAL "Enable stamp point cloud with local time" OFF)