3. 传感器与感知:激光雷达、深度相机、超声波传感器的工作原理、数据预处理与障碍物检测

各位同学,欢迎来到传感器与感知这一章。

做机器人控制,说白了就是让机器人知道「我在哪」和「周围有什么」。这两件事,全靠传感器撑着。我这些年调试过的机器人,从几万块的工业AGV到几百块的DIY小车,传感器选型永远是第一个坑。今天咱们就把三种最常用的传感器——激光雷达、深度相机、超声波——掰开揉碎了讲清楚。

3.1 激光雷达:机器人的「眼睛」

激光雷达,英文叫LiDAR。它的原理其实很简单:发射一束激光,打到物体上反射回来,测量飞行时间(ToF)或者相位差,就能算出距离。我最早接触激光雷达是在2016年,那时候一个单线雷达要上万块,现在几百块就能买到不错的国产货了。

核心原理:激光雷达每秒发射数万到数十万个激光点,每个点包含距离和角度信息。把这些点拼起来,就形成了「点云」。

实际项目中,激光雷达最怕什么?怕玻璃、怕黑漆漆的物体、怕雨雾。我记得有一次在工厂调试,机器人死活检测不到一块透明亚克力板,直接撞上去了。后来才意识到,激光穿过透明材料,反射信号太弱了。

3.1.1 数据预处理

拿到原始点云数据,不能直接用。为什么?因为噪声太多了。我习惯做三步预处理:

  1. 离群点滤除:用统计滤波器,去掉那些明显偏离的点。比如一个点周围5厘米内没有其他点,大概率是噪声。
  2. 地面滤除:对于移动机器人,地面上的点会干扰障碍物检测。用RANSAC算法拟合地面平面,然后去掉。
  3. 体素滤波:点云太密了,计算量太大。把空间划分成小立方体(体素),每个体素内只保留一个代表点。
// 伪代码:体素滤波
VoxelGrid filter;
filter.setLeafSize(0.05f, 0.05f, 0.05f); // 5cm体素
filter.setInputCloud(original_cloud);
filter.filter(filtered_cloud);

我的经验:体素大小别设太小,否则降采样效果不明显。我一般设5-10cm,既能保留结构,又能把点云量降到原来的十分之一。

3.1.2 障碍物检测

预处理完,怎么判断有没有障碍物?最经典的方法是「栅格地图」。把机器人周围划分成一个个小格子,每个格子统计有多少个激光点落进去。如果某个格子的点密度超过阈值,就标记为障碍物。

嗯,这里要注意:激光雷达只能检测一个平面上的障碍物。比如一张桌子,激光只能扫到桌腿,扫不到桌面。所以单线雷达做避障,一定要把安装高度和角度算好。

3.2 深度相机:看得更「立体」

深度相机,比如Intel RealSense、微软Kinect、奥比中光,它们能输出RGB图像+深度图。说白了,就是每个像素不光有颜色,还有距离信息。

深度相机有三种主流技术:

  • 结构光:投射红外光斑图案,通过变形计算深度。室内效果好,室外见光死。
  • 双目视觉:两个摄像头模拟人眼,通过视差算深度。计算量大,但室外也能用。
  • ToF:和激光雷达类似,发射红外光测飞行时间。速度快,但分辨率低。

避坑指南:我曾经在室外用结构光相机做避障,结果大太阳底下深度图全是黑的。后来换成双目方案才解决。如果你要做户外机器人,别选结构光。

3.2.1 数据预处理

深度相机的原始数据,问题比激光雷达还多。我总结了几大痛点:

  • 空洞:某些区域没有深度值,比如反光表面、黑色物体。需要用插值算法填补。
  • 噪声:深度值抖动厉害,尤其是边缘区域。用双边滤波可以保边去噪。
  • 对齐:RGB图和深度图的分辨率、视角不一样,需要做对齐(registration)。
# Python示例:深度图空洞填充
import cv2
import numpy as np

def fill_depth_holes(depth_img):
    # 用形态学操作填补小空洞
    kernel = np.ones((5,5), np.uint8)
    dilated = cv2.dilate(depth_img, kernel, iterations=1)
    mask = (depth_img == 0).astype(np.uint8)
    filled = depth_img * (1 - mask) + dilated * mask
    return filled

3.2.2 障碍物检测

深度相机的好处是能检测三维障碍物。比如悬空的柜子、地上的坑,激光雷达可能漏掉,但深度相机能看见。

我常用的方法是:把深度图转成点云,然后做欧几里得聚类。说白了,就是把靠得近的点归为一类,每个类就是一个障碍物。

关键参数:聚类距离阈值。设太小,一个障碍物被拆成好几块;设太大,多个障碍物被合并。我一般设0.2-0.5米,具体看场景。

3.3 超声波传感器:便宜但「粗糙」

超声波传感器,比如HC-SR04,几块钱一个。原理是发射超声波脉冲,等回声回来,算时间差。速度慢、精度低,但胜在便宜、不怕透明物体。

说实话,超声波在机器人避障里越来越边缘化了。但我还是会在一些场景用它:比如近距离防撞(<30cm),或者作为激光雷达的补充——激光扫不到玻璃,超声波可以。

3.3.1 数据预处理

超声波的数据预处理,其实就两件事:

  1. 去噪:超声波容易受环境干扰,比如电机噪声、其他超声波的串扰。我习惯做中值滤波,取最近3-5次测量的中位数。
  2. 角度补偿:超声波波束角很宽(通常30-60度),测到的距离不一定是正前方的。如果机器人有姿态变化,需要做补偿。
// 伪代码:超声波中值滤波
float ultrasonic_filter(float new_reading) {
    static float buffer[5] = {0};
    static int index = 0;
    buffer[index] = new_reading;
    index = (index + 1) % 5;
    // 排序取中值
    std::sort(buffer, buffer + 5);
    return buffer[2];
}

我的习惯:超声波采样频率别太高,20-30Hz就够了。太快了数据抖动大,而且多个超声波同时工作会互相干扰。

3.3.2 障碍物检测

超声波检测障碍物,说白了就是设一个阈值。比如距离小于30cm,就认为有障碍物。但要注意:超声波测距有最小盲区,一般是2-5cm。太近了反而测不准。

我曾经犯过一个错:把超声波装在机器人正前方,结果机器人原地转弯时,超声波打到自己的轮子上,误报障碍物。后来加了角度过滤才解决。

3.4 传感器融合:取长补短

单个传感器总有短板。激光雷达怕玻璃,深度相机怕强光,超声波精度低。所以实际项目中,我几乎都是多传感器融合。

下面这张图是我常用的融合策略:

多传感器融合策略 激光雷达 距离精确,平面扫描 深度相机 三维感知,纹理丰富 超声波 近距离,不怕透明 数据预处理(滤波、去噪、对齐) 传感器融合(卡尔曼滤波 / 贝叶斯) 障碍物地图 / 避障决策

你看,每个传感器先自己做预处理,然后统一送到融合模块。我常用的融合方法是扩展卡尔曼滤波(EKF),把不同传感器的观测值按置信度加权合并。说白了,就是谁准就多信谁一点。

一句话总结:激光雷达管远距离和平面,深度相机管三维空间,超声波管近距离和特殊材质。三者配合,才能让机器人「眼观六路」。

好了,这一章的内容就到这里。传感器感知是避障控制的基础,数据预处理做不好,后面算法再牛也白搭。各位在实际项目中,一定要多花时间调传感器参数,这个功夫省不得。


公众号:蓝海资料掘金营,微信deep3321