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 时刻。

../../_images/18_02_mems_lasers.png

18.4 点的布局

18.4.1 MEMS 雷达

MEMS 雷达每轮扫描同时扫 5 个区域,每个区域得到上下两个点,总共得到 10 个点,打包到一个 Block,写入 MSOP Packet。

ag_driver 解析 MSOP Packet 时,按照 Block 的顺序解析,所以在点云的 points 数组中,每个 Block 的 10 个点连续保存为一组。

../../_images/18_05_mems_lasers_and_points.png

这里以 A0 为例,说明每个区域的点布局。

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

../../_images/18_06_mems_points.png

18.4.2 点云中点的序号

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

../../_images/18_07_points_sn.png

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

../../_images/18_08_points_sn_direction.png

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)