1. 雷达点云基础:激光雷达工作原理、点云数据格式、点云坐标系与变换
大家好,欢迎来到我们雷达点云处理的第一课。我是你们的老朋友,一个在雷达感知领域摸爬滚打了十来年的工程师。今天咱们聊聊最基础的东西——激光雷达是怎么工作的,点云数据长什么样,以及那个让人头疼的坐标系变换。
说实话,我刚入行那会儿,觉得点云就是一坨带坐标的点,没什么了不起。直到第一次调试多传感器融合,发现雷达和摄像头对同一个物体的位置描述差了十万八千里……嗯,从那以后我再也不敢小看坐标系变换了。
1.1 激光雷达工作原理
激光雷达,英文叫LiDAR(Light Detection And Ranging)。说白了,就是通过发射激光束,测量目标距离的传感器。你想想看,它就像一只蝙蝠,只不过蝙蝠用超声波,我们用激光。
工作原理其实不复杂:
- 发射激光脉冲:激光器发出一束极短的红外激光脉冲
- 反射接收:激光打到物体表面后反射回来,被接收器捕获
- 计算距离:根据发射和接收的时间差,用光速算出距离
- 确定角度:通过旋转机构或固态扫描,知道激光束的发射角度
- 生成点云:每个激光束返回一个点,包含距离、角度、反射强度等信息
核心公式:距离 = 光速 × 飞行时间 / 2
为什么除以2?因为激光走了个来回,发射到接收是双程距离。
我在项目中遇到过一种情况:雨天激光雷达的探测距离会大幅下降。因为雨滴会散射激光,导致回波信号变弱。所以做自动驾驶的朋友,千万别指望激光雷达在暴雨天还能看得清200米外的行人。
1.2 点云数据格式
点云数据,本质上就是一个三维空间中的点集合。每个点通常包含以下信息:
| 字段 | 含义 | 典型数据类型 |
|---|---|---|
| x, y, z | 三维坐标(米) | float32 |
| intensity | 反射强度(0-255) | uint8 或 float32 |
| ring | 激光线束编号 | uint16 |
| timestamp | 时间戳(微秒) | float64 |
最常见的点云数据格式是PCD(Point Cloud Data)和PLY。我个人习惯用PCD格式,因为它结构简单,解析起来不费劲。下面是一个PCD文件的片段:
# .PCD v0.7 - Point Cloud Data file format
VERSION 0.7
FIELDS x y z intensity ring
SIZE 4 4 4 4 2
TYPE F F F F U
COUNT 1 1 1 1 1
WIDTH 1000
HEIGHT 1
VIEWPOINT 0 0 0 1 0 0 0
POINTS 1000
DATA ascii
1.234 2.345 3.456 128 0
1.235 2.346 3.457 200 1
...
注意看那个HEIGHT 1,这表示是无序点云。如果HEIGHT大于1,那就是有序点云,像图像一样有行列结构。我建议初学者先处理无序点云,逻辑更简单。
小技巧:用Python的open3d库读取点云,一行代码搞定:
import open3d as o3d
pcd = o3d.io.read_point_cloud("scan.pcd")
points = np.asarray(pcd.points)
1.3 点云坐标系与变换
坐标系这块,是新手最容易翻车的地方。我曾经在项目里因为坐标系搞反了,导致融合后的目标位置偏了整整两米……排查了三天才发现问题。
常见的坐标系有:
- 激光雷达坐标系:以激光雷达自身为原点,x轴朝前,y轴朝左,z轴朝上(右手系)
- 车体坐标系:以车辆后轴中心为原点,x轴朝前,y轴朝左,z轴朝上
- 世界坐标系:通常是UTM坐标系或经纬度,用于全局定位
为什么要做坐标系变换?因为激光雷达装在车上,它看到的是「雷达坐标系」下的点。但我们要知道这些点相对于车的位置,甚至相对于地图的位置。这就涉及到刚体变换:
# 点云从雷达坐标系变换到车体坐标系
import numpy as np
def transform_point_cloud(points, rotation_matrix, translation_vector):
"""
points: Nx3 的点云数组
rotation_matrix: 3x3 旋转矩阵
translation_vector: 3x1 平移向量
"""
# 齐次坐标变换
transformed = (rotation_matrix @ points.T).T + translation_vector
return transformed
# 举个例子:雷达装在车顶,向前偏移0.5米,向上偏移1.2米
R = np.eye(3) # 假设雷达和车体朝向一致
t = np.array([0.5, 0.0, 1.2])
points_car = transform_point_cloud(points_lidar, R, t)
避坑指南:我曾经在项目中遇到一个问题——激光雷达的安装角度不是正对着车头,而是偏了5度。结果所有点云都歪了。所以一定要做外参标定,获取准确的旋转矩阵和平移向量。
关于坐标系变换,有几点要记住:
- 旋转矩阵是正交矩阵:它的逆等于它的转置,可以用来反向变换
- 变换顺序很重要:先旋转,再平移。顺序反了结果完全不对
- 欧拉角有万向锁问题:我建议用四元数或旋转矩阵,别用欧拉角
最后,给大家一个实用建议:在代码里统一用齐次坐标(4x4矩阵)来表示变换。这样旋转和平移可以一次搞定,代码更简洁,也不容易出错。
# 齐次变换矩阵
T = np.eye(4)
T[:3, :3] = R # 旋转部分
T[:3, 3] = t # 平移部分
# 点云齐次化
points_hom = np.hstack([points, np.ones((points.shape[0], 1))])
points_transformed = (T @ points_hom.T).T[:, :3]
好了,这一章的内容就到这里。下一章我们会讲点云滤波和地面分割,到时候会用到今天学的坐标系变换知识。有什么问题欢迎在评论区交流,咱们下期见!
本章小结:
- 激光雷达通过激光飞行时间测距,生成三维点云
- 点云数据包含xyz坐标、强度、线束号等信息
- 坐标系变换是点云处理的基础,务必掌握齐次变换矩阵
公众号:蓝海资料掘金营,微信deep3321