近距离传感器
概述
近距离传感器用于检测机器人周围短距离(通常 <5m)的障碍物、悬崖和物理接触。它们是机器人安全系统的最后防线,在扫地机器人、服务机器人和工业机器人中大量使用。
红外接近传感器
工作原理
红外接近传感器发射调制红外光,通过检测反射光的强度或位置来测量距离。
反射式测距:
\[
I_{\text{received}} \propto \frac{\rho}{d^2}
\]
其中 \(\rho\) 为目标表面反射率,\(d\) 为距离。接收信号强度随距离平方衰减。
Sharp GP2Y0A21YK0F
最经典的红外测距传感器,采用三角测距法。
| 参数 | 值 |
|---|---|
| 测距范围 | 10–80 cm |
| 输出 | 模拟电压(与距离非线性关系) |
| 响应时间 | ~39 ms |
| 供电 | 4.5–5.5V |
| 电流 | ~30 mA |
| 尺寸 | 29.5 × 13 × 13.5 mm |
| 价格 | ~$10 |
电压-距离关系(近似):
\[
d = \frac{a}{V - b}
\]
其中 \(V\) 为输出电压,\(a\)、\(b\) 为经验系数(需标定)。
import numpy as np
def sharp_gp2y0a21_distance(voltage):
"""
Sharp GP2Y0A21 电压转距离
voltage: ADC 读取电压 (V)
返回距离 (cm)
"""
if voltage < 0.4 or voltage > 3.1:
return None # 超出有效范围
# 经验公式(需要根据实际标定调整)
distance = 29.988 * pow(voltage, -1.173)
return distance
其他红外传感器
| 型号 | 范围 | 输出 | 特点 | 价格 |
|---|---|---|---|---|
| GP2Y0A21 | 10–80cm | 模拟 | 经典通用 | ~$10 |
| GP2Y0A02 | 20–150cm | 模拟 | 远距离 | ~$12 |
| GP2Y0A41SK | 4–30cm | 模拟 | 近距离 | ~$8 |
| TCRT5000 | 1–25mm | 模拟 | 反射式,适合循线 | ~$0.5 |
超声波传感器
工作原理
发射超声波脉冲(通常 40kHz),测量回波时间来计算距离:
\[
d = \frac{v_s \cdot t}{2}
\]
其中 \(v_s \approx 343 \, \text{m/s}\)(20°C 空气中声速)。
声速与温度
声速随温度变化:\(v_s = 331.3 + 0.606 \cdot T\)(m/s),其中 \(T\) 为摄氏温度。精确测距需要温度补偿。
HC-SR04
最常用的超声波测距模块。
| 参数 | 值 |
|---|---|
| 测距范围 | 2–400 cm |
| 精度 | ±3 mm |
| 测量角度 | ~15°(锥形波束) |
| 工作频率 | 40 kHz |
| 触发方式 | 10μs 高电平脉冲 |
| 供电 | 5V |
| 电流 | ~15 mA |
| 价格 | ~$2 |
使用方式:
- 向 Trigger 引脚发送 >10μs 的高电平脉冲
- 模块自动发送 8 个 40kHz 超声波脉冲
- Echo 引脚输出高电平,持续时间等于回波时间
import RPi.GPIO as GPIO
import time
TRIG = 23
ECHO = 24
def measure_distance():
"""HC-SR04 测距"""
GPIO.output(TRIG, True)
time.sleep(0.00001) # 10μs 触发脉冲
GPIO.output(TRIG, False)
# 等待 Echo 高电平开始
while GPIO.input(ECHO) == 0:
pulse_start = time.time()
# 等待 Echo 高电平结束
while GPIO.input(ECHO) == 1:
pulse_end = time.time()
duration = pulse_end - pulse_start
distance = duration * 34300 / 2 # cm
return distance
超声波的局限性
| 问题 | 原因 | 影响 |
|---|---|---|
| 锥形波束 | 超声波扩散角 ~15° | 角分辨率低,小物体可能漏检 |
| 镜面反射 | 光滑斜面将声波反射偏离 | 测距失败 |
| 吸声材料 | 布料、泡沫吸收声波 | 无回波 |
| 串扰 | 多个超声波模块相互干扰 | 需要时分复用 |
| 最小距离 | 发射和接收需要时间间隔 | 盲区 ~2cm |
ToF 接近传感器
工作原理
使用激光 ToF 测量微型化方案,发射 VCSEL 激光,SPAD 探测器接收。
VL53L0X
STMicroelectronics 出品的微型 ToF 传感器。
| 参数 | 值 |
|---|---|
| 测距范围 | 30–2000 mm |
| 精度 | ±3%(长距离模式) |
| FOV | 25°(锥形) |
| 光源 | 940nm VCSEL |
| 接口 | I2C |
| 测量速率 | 最高 50Hz |
| 供电 | 2.6–3.5V |
| 尺寸 | 4.4 × 2.4 × 1.0 mm |
| 价格 | ~$3 |
VL53L1X(升级版)
| 参数 | 值 |
|---|---|
| 测距范围 | 40–4000 mm |
| FOV | 27°(可编程 ROI) |
| 测量速率 | 最高 50Hz |
| 多区域 | 支持 4×4 区域检测 |
| 价格 | ~$4 |
import board
import adafruit_vl53l0x
# I2C 初始化
i2c = board.I2C()
sensor = adafruit_vl53l0x.VL53L0X(i2c)
# 读取距离
distance_mm = sensor.range
print(f"距离: {distance_mm} mm")
# 设置测量模式
sensor.measurement_timing_budget = 200000 # 200ms,高精度模式
悬崖传感器(Cliff Sensor)
作用
悬崖传感器是扫地机器人、服务机器人等移动平台上的关键安全传感器,用于检测地面的突然下降(楼梯、台阶边缘),防止机器人跌落。
工作原理
使用向下照射的红外反射传感器,检测地面反射信号:
- 正常地面:红外光被反射回来,接收信号强
- 悬崖/台阶:红外光射向远处,反射信号极弱或无
\[
\text{Cliff detected} \iff I_{\text{received}} < I_{\text{threshold}}
\]
典型配置
扫地机器人通常在底部前方安装 3–6 个悬崖传感器:
graph TD
subgraph "扫地机器人底部视图(前方朝上)"
direction TB
A["前方左 ●"] --- B["前方中 ●"] --- C["前方右 ●"]
D["侧方左 ●"] --- E["(底盘)"] --- F["侧方右 ●"]
end
style A fill:#ff6666
style B fill:#ff6666
style C fill:#ff6666
style D fill:#ff9966
style F fill:#ff9966
常用传感器
| 型号 | 类型 | 检测距离 | 说明 | 价格 |
|---|---|---|---|---|
| TCRT5000 | 红外反射 | 1–25mm | 最常用 | ~$0.5 |
| ITR9608 | 红外反射 | 1–15mm | 小型封装 | ~$0.3 |
| QRD1114 | 红外反射 | 1–10mm | 分立式 | ~$1 |
悬崖检测的可靠性
悬崖传感器是安全关键传感器。注意以下失效场景:
- 深色地面:黑色地毯/地面可能被误判为悬崖
- 透明地面:玻璃地面无法反射红外光
- 传感器脏污:灰尘覆盖导致信号衰减
- 强环境光:直射阳光可能干扰红外检测
实际产品中通常采用多传感器冗余 + 保守策略来保证安全。
碰撞传感器(Bumper)
工作原理
碰撞传感器是最简单的近距离检测方式——物理接触触发。通常使用微动开关或触力传感器。
类型
| 类型 | 原理 | 优点 | 缺点 |
|---|---|---|---|
| 微动开关 | 机械触点 | 简单、可靠、成本低 | 需要物理接触 |
| 力敏电阻 | 电阻随压力变化 | 可以感知力度 | 需要 ADC |
| 电容式 | 接近改变电容 | 非接触(~1cm) | 环境敏感 |
| 压电式 | 压电效应 | 灵敏、响应快 | 信号处理复杂 |
扫地机器人碰撞传感器
大多数扫地机器人使用前部的弧形 bumper,内部安装微动开关或光电开关:
# 简单的 bumper 中断处理
import RPi.GPIO as GPIO
BUMPER_LEFT = 17
BUMPER_RIGHT = 27
def bumper_callback(channel):
if channel == BUMPER_LEFT:
print("左侧碰撞!后退并右转")
# motor.backward()
# motor.turn_right()
elif channel == BUMPER_RIGHT:
print("右侧碰撞!后退并左转")
# motor.backward()
# motor.turn_left()
GPIO.setup(BUMPER_LEFT, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(BUMPER_RIGHT, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.add_event_detect(BUMPER_LEFT, GPIO.FALLING,
callback=bumper_callback, bouncetime=200)
GPIO.add_event_detect(BUMPER_RIGHT, GPIO.FALLING,
callback=bumper_callback, bouncetime=200)
扫地机器人传感器布局
graph TD
subgraph "扫地机器人传感器系统"
subgraph "顶部"
L["LiDAR<br/>2D 激光雷达<br/>360° SLAM"]
end
subgraph "前部"
B["Bumper<br/>碰撞传感器<br/>左/右区分"]
IR["红外/ToF<br/>前方避障<br/>3-5cm~2m"]
end
subgraph "底部"
C1["悬崖传感器 ×4-6<br/>IR反射式<br/>防跌落"]
W["轮式编码器 ×2<br/>里程计"]
end
subgraph "侧面"
WALL["沿墙传感器<br/>IR/ToF<br/>保持墙距"]
end
end
传感器协作逻辑
class VacuumRobotSafety:
"""扫地机器人安全传感器管理"""
def __init__(self):
self.cliff_threshold = 100 # ADC 阈值
self.wall_distance = 50 # mm
self.obstacle_distance = 200 # mm
def check_cliff(self, cliff_sensors):
"""检查悬崖传感器,任一触发则紧急停止"""
for i, value in enumerate(cliff_sensors):
if value < self.cliff_threshold:
return True, i # 检测到悬崖
return False, -1
def check_bumper(self, bumper_left, bumper_right):
"""检查碰撞传感器"""
if bumper_left and bumper_right:
return 'front' # 正面碰撞
elif bumper_left:
return 'left' # 左侧碰撞
elif bumper_right:
return 'right' # 右侧碰撞
return None
def safety_loop(self, sensors):
"""安全检查主循环 - 优先级最高"""
# 1. 悬崖检测(最高优先级)
cliff_detected, cliff_id = self.check_cliff(
sensors['cliff'])
if cliff_detected:
return 'EMERGENCY_STOP', f'Cliff at sensor {cliff_id}'
# 2. 碰撞检测
bump = self.check_bumper(
sensors['bumper_left'],
sensors['bumper_right'])
if bump:
return 'BACKUP_AND_TURN', bump
# 3. 接近障碍物
if sensors['front_tof'] < self.obstacle_distance:
return 'SLOW_DOWN', sensors['front_tof']
return 'NORMAL', None
传感器综合对比
| 传感器 | 范围 | 精度 | 速率 | 成本 | 优势 | 劣势 |
|---|---|---|---|---|---|---|
| Sharp IR | 10–80cm | ±1cm | 25Hz | $10 | 简单可靠 | 受光照影响 |
| HC-SR04 | 2–400cm | ±3mm | 20Hz | $2 | 便宜 | 角分辨率低 |
| VL53L0X | 3–200cm | ±3% | 50Hz | $3 | 小巧、数字输出 | 范围有限 |
| Cliff IR | 1–25mm | 检测级 | 快 | $0.5 | 极低成本 | 仅检测有/无 |
| Bumper | 0cm | 接触 | 快 | $0.5 | 最可靠 | 需物理接触 |
ROS2 集成
Range 消息
# sensor_msgs/msg/Range
Header header
uint8 radiation_type # ULTRASOUND=0, INFRARED=1
float32 field_of_view # 检测锥角 (rad)
float32 min_range # 最小距离 (m)
float32 max_range # 最大距离 (m)
float32 range # 当前距离 (m)
发布传感器数据
from sensor_msgs.msg import Range
def publish_ultrasonic(self, distance_m):
msg = Range()
msg.header.stamp = self.get_clock().now().to_msg()
msg.header.frame_id = 'ultrasonic_front'
msg.radiation_type = Range.ULTRASOUND
msg.field_of_view = 0.26 # ~15°
msg.min_range = 0.02
msg.max_range = 4.0
msg.range = distance_m
self.range_pub.publish(msg)
参考资料
- Sharp GP2Y0A21 数据手册
- HC-SR04 技术文档
- STMicroelectronics VL53L0X/VL53L1X 数据手册
- iRobot Roomba 开放接口规范
- ROS2 sensor_msgs 文档