VL53L0X 激光测距传感器(ToF)
| 器材 | 数量 | 参考 |
|---|---|---|
| VL53L0X 模块 | 1 | — |
价格随渠道波动,以购买页实时为准。
做一个隔空感应的小项目:手靠近时灯亮,离开时灯灭。先拿超声波 HC-SR04 试了试,对着手掌还算准,可一对着窗帘、对着倾斜的桌沿,读数就开始乱跳——软东西吸声、斜面把回声偏折走了,超声波天生吃这两样亏。想要一颗"对着什么都准、还能精确到毫米"的测距件,VL53L0X 就是答案。
VL53L0X 是意法半导体(ST)做的一颗激光 ToF 测距芯片,模块只有指甲盖大小,I2C 接口直接吐出毫米级距离。它测的不是回声,而是激光从发出到反射回来飞行的时间,所以物体是黑是白、是软是硬、表面斜不斜,几乎都不影响它判断距离。
工作原理
ToF 是 Time of Flight(飞行时间)的缩写。VL53L0X 内部有一颗 940nm 的不可见激光发射器,工作时它打出一串极短的激光脉冲,脉冲碰到前方物体反射回来,被芯片里的接收阵列收到。芯片精确记录"发出"到"收到"之间的时间差 t,然后:
距离 = 光速 × t ÷ 2
除以 2 是因为光走了"过去 + 回来"两段路。光速约每秒 30 万公里,要测出毫米级的距离,意味着芯片要分辨皮秒(万亿分之一秒)量级的时间差——这件事用普通单片机自己干完全做不到,全靠 VL53L0X 内部专门的高速计时电路完成,结果直接以毫米给你。
关键差别在"测什么":
- 超声波 HC-SR04:测的是声音的回声时间。声音遇到软物(窗帘、海绵、毛绒)会被吸收,遇到斜面会被偏折到别处收不回来,所以怕软、怕斜、近处还有盲区。详见 /sensor/hc-sr04/。
- VL53L0X:测的是激光的飞行时间。激光是一束很集中的光,物体的颜色、反射率、软硬对"光什么时候回来"影响很小(只影响回来的强弱,不影响时间),所以对软窗帘、斜桌面同样能给出稳定读数。
正因为测的是时间而不是回波形状,VL53L0X 在精度、抗干扰、小体积上都明显胜过超声波,代价是量程短一些、单价贵一点。想深入看 I2C 总线的底层机制,参考 /principle/i2c/。
接线
VL53L0X 模块板载稳压,VCC 给 3.3V 或 5V 都行(模块内部会降到芯片需要的电压),I2C 走 SDA/SCL 两根线,默认地址 0x29:
| VL53L0X | ESP32 | 说明 |
|---|---|---|
| VCC | 3.3V | 模块自带稳压,3.3V/5V 均可 |
| GND | GND | 公共地 |
| SDA | GPIO21 | I2C 数据线 |
| SCL | GPIO22 | I2C 时钟线 |
| XSHUT | 不接 / 任意 GPIO | 关断/复位脚,挂单颗可悬空,挂多颗用它逐个改地址 |
| GPIO1 | 不接 | 测量就绪中断输出,一般用不到 |
模块上 SDA/SCL 通常已带上拉电阻,单颗使用多数不用额外加。如果总线上挂了多个设备或读不到数,可在 SDA、SCL 各接一颗 4.7kΩ 上拉到 3.3V,原理见 /principle/pullup/。
完整代码
用 Adafruit 的现成库(Arduino 库管理器里搜 "Adafruit_VL53L0X"),初始化加读数十来行就跑起来了:
#include <Wire.h>
#include "Adafruit_VL53L0X.h"
Adafruit_VL53L0X lox = Adafruit_VL53L0X();
void setup() {
Serial.begin(115200);
Wire.begin(21, 22); // ESP32 指定 SDA=21, SCL=22
// begin() 默认用 0x29 地址初始化
if (!lox.begin()) {
Serial.println("VL53L0X 初始化失败,检查接线和地址(0x29)");
while (1); // 卡住,方便发现问题
}
Serial.println("VL53L0X 已就绪");
}
void loop() {
VL53L0X_RangingMeasurementData_t measure;
lox.rangingTest(&measure, false); // false = 不打印调试信息
// RangeStatus != 4 表示这次测量有效
if (measure.RangeStatus != 4) {
Serial.print("距离: ");
Serial.print(measure.RangeMilliMeter); // 直接给毫米
Serial.println(" mm");
} else {
Serial.println("超出量程"); // 太远或没回波
}
delay(200);
}
rangingTest() 做一次测量,结果存在 measure 结构里:RangeMilliMeter 就是毫米距离,RangeStatus 是状态码——等于 4 表示这次没收到有效回波(太远、玻璃反射、超量程),其它值表示读数可用。把 delay(200) 调小可以更快刷新,VL53L0X 标准模式一次测量约几十毫秒。
你应该看到什么
打开串口监视器(115200 波特率),把手在传感器正前方慢慢前后移动,正常情况下每秒打印几行毫米读数:
VL53L0X 已就绪
距离: 412 mm
距离: 318 mm
距离: 156 mm ← 手慢慢靠近
距离: 47 mm ← 几乎贴上
距离: 893 mm ← 手撤走,照到后面墙
超出量程 ← 前方空旷、无回波
手往前移、读数变小,手往后撤、读数变大,对着白墙、黑布、斜放的本子都能给出稳定数值——这就说明它在正常工作。和超声波对比明显的一点:拿块软毛巾挡在前面,VL53L0X 照样测得准,超声波这时往往就开始乱跳了。
读数解读 / 多颗级联
VL53L0X 的量程约 30 ~ 1200mm(对白色高反射目标最远可到 2m),默认精度约 ±3%,也就是测 1 米误差三厘米左右、测十几厘米能精确到毫米级,刷新也快。常见参数对照:
| 项目 | 典型值 |
|---|---|
| 量程 | 约 30 ~ 1200mm(白目标可达 2m) |
| 精度 | 约 ±3% |
| 激光波长 | 940nm(不可见红外) |
| 默认 I2C 地址 | 0x29 |
| 单次测量耗时 | 标准模式约 30ms |
挂多颗的麻烦:VL53L0X 出厂地址都是 0x29,同一条 I2C 总线上挂两颗以上会地址冲突。解决靠每颗模块的 XSHUT 引脚——它是关断脚,拉低时芯片完全断电、从总线上"消失"。开机流程是:先把所有 XSHUT 拉低让全部芯片休眠,然后逐个把某颗的 XSHUT 拉高唤醒,用 setAddress() 给它改成一个新地址(比如 0x30、0x31……),改完再唤醒下一颗。这样每颗都有独立地址,互不冲突,就能同时读好几个方向的距离。
选型 / 避坑
| 需求 | 选谁 | 理由 |
|---|---|---|
| 毫米精度、小体积、抗干扰、机器人精确避障 | VL53L0X | 激光 ToF,不挑物体颜色软硬 |
| 量程要更远(够用就便宜) | HC-SR04 | 量程到 4m,几块钱,但盲区大、怕软物,见 /sensor/hc-sr04/ |
| 要更远的激光测距(4m) | VL53L1X | 同家升级款,量程到 4m,用法接近 |
隔玻璃 / 强环境光读不准或读 0:激光打在玻璃、亚克力上会被反射回来,芯片以为前方就是玻璃,读出来是玻璃距离而不是后面的物体;正午阳光、强红外灯下,背景噪声会淹没回波,导致 RangeStatus=4(超量程)或读数乱跳。装在外壳里时务必让激光窗口直接对外、不要隔盖板。
超量程读 0 或顶到最大值:前方太远(超过约 1.2m)或太空旷没有回波时,库会返回超量程状态,别把它当成"距离 0"去用,要先判断 RangeStatus。
I2C 扫不到 0x29:先确认接线没接反、上拉到位(见 /principle/pullup/),可先跑一个 I2C 扫描程序看总线上到底出现哪个地址。
进阶 / 变体
多方向避障阵列:用 XSHUT 改地址的办法在小车前方挂 3 颗 VL53L0X(左前、正前、右前),各自独立读距离,就能判断障碍在哪个方向、该往哪边躲。这比单颗超声波只能"正前方一个点"信息丰富得多,做精确避障非常合适。
接入机器人闭环:把三个方向的毫米距离喂给避障逻辑——某方向小于设定阈值就减速或转向,配合电机控制形成"感知 → 决策 → 动作"的闭环。想把这套接到完整的机器人避障项目里,参考 /article/robot-obstacle-avoid/。
升级到 VL53L1X:如果发现 1.2m 量程不够用(比如要测更大的房间或更远的接近),同系列的 VL53L1X 量程到 4m,库和用法非常接近,代码改动很小。
想把"测距读数 → 自动决策"做成完整项目并用 AI 辅助开发,参考 /guide/l4-sensor-ai/。
典型应用
- 机器人 / 小车精确避障(多颗做多方向感知,见 /article/robot-obstacle-avoid/)
- 隔空手势识别(手靠近的距离做翻页、调音量)
- 液位检测(隔空测水面到传感器的距离,换算余量)
- 自动感应(水龙头、皂液器、感应灯的靠近触发)
- 物体在位检测、传送线计数、3D 打印调平辅助
小结 · 相关
VL53L0X 的核心价值是"用激光飞行时间测距,毫米级精度且不挑物体"。它测的是 940nm 激光发出到反射回来的时间,距离 = 光速 × 时间 ÷ 2,所以颜色、软硬、斜面对它影响极小,正好补上超声波怕软怕斜的短板。接线就是 I2C 四线(默认地址 0x29),代码用 Adafruit_VL53L0X 库 begin() 加 rangingTest() 十几行就能读出毫米。要毫米精度、小体积、抗干扰的精确测距,尤其是机器人避障,它是首选;量程不够再上 VL53L1X。
相关阅读:/sensor/hc-sr04/(更便宜更远但怕软物)、/principle/i2c/、/principle/pullup/、/article/robot-obstacle-avoid/、/guide/l4-sensor-ai/,更多器件见 /sensor/ 与 /principle/、/guide/。
参数以 datasheet 为准;本页公开资料整理,接线与代码请结合实物验证。