披露:我是这类模块的厂商(ERDILRF,成都)一方的工程人员。文中的帧格式、波特率、单位都转录自厂商手册,驱动是 MIT 协议开源的。我没有在这里贴任何实测精度或性能数据,文末会说清楚哪些没验证过。
第一次接激光测距模块,最常见的两种翻车:串口一片安静,或者读出来的数差了 10 倍。两种我们都见过,原因几乎都在协议细节上,不在接线。下面按"先认协议家族,再接线,再写代码"的顺序走一遍。
1. 先认家族:我们这条 905nm 产品线有两套串口协议
A 族:8 字节55 AA命令/应答。LR1000E2/E4、LR1200E2/E4、LR1500E2/E4、LR2000E2/E4、LRF1200A1、LRF3000A1、SPD1200N0/N2/N4、SPD1200D03。默认 115200 bps。
B 族:5C开头的连续输出。LRF50H/100H/200H/300H/600H/1500H、LRF22VB、LRF50VB。默认 460800 bps(可调),8 位数据、1 位停止、无校验,小端。
选型号之前先别写代码,先看你手上是哪一族,因为两族的"单位"根本不是一回事。
2. 帧格式
A 族
byte 0 1 2 3 4 5 6 7 55 AA 功能码 D1 D2 D3 D4 校验单次测距发送:55 AA 88 FF FF FF FF 84
应答:55 AA 88 STA FF DIS_H DIS_L SUM
STA = 1表示测量成功,其他值表示失败。- 距离是
DIS_H<<8 | DIS_L,大端,手册写明"输出为实际值 × 10",所以原始计数 1 个数 = 0.1 m。 - 连续测距
0x89、停止0x8E。
这里最容易踩的坑:发送和应答的校验范围不一样。
- 发送:功能码 + D1~D4 求和取低 8 位
- 应答:0x55 + 0xAA + 功能码 + D1~D4 求和取低 8 位
两者正好差0x55+0xAA = 0xFF。如果拿发送公式去验应答,几乎每帧都差 1,看起来像"偶尔能对上"。手册自己也提醒了收发校验内容可能不同。
举个手算例子(构造帧,不是从硬件抓的):55 AA 88 01 FF 04 D2 5D。求和 0x55+0xAA+0x88+0x01+0xFF+0x04+0xD2 = 0x35D,低 8 位 0x5D;距离 0x04D2 = 1234,除以 10 得 123.4 m。
B 族
byte 0 1 2 3 5C dist_lo dist_hi 校验例:5C 02 11 EC。校验是"从第 2 字节到倒数第 2 字节求和再按位取反":~(0x02+0x11) = ~0x13 = 0xEC。
单位按型号,不按家族:
| 型号 | 原始计数单位 | 同一帧5C 02 11 EC的含义 |
|---|---|---|
| LRF50H/100H/200H/300H/600H/1500H | 厘米 | 43.54 m |
| LRF22VB、LRF50VB | 毫米 | 4.354 m |
同样 4 个字节,差 10 倍。所以别让程序"自动判断家族然后选单位",老老实实按型号查表。LRF1500H 是目录里唯一的 5 字节帧(距离占 3 字节),手册里它的示例帧校验和自己的公式对不上,我们在驱动里把这个差异保留并标注了,没有悄悄改掉。
3. 接线
先说一句最重要的:供电电压和串口信号电平是两个独立的指标。手册给出供电范围,不等于给出了 TX/RX 的逻辑电平,别自己从供电推断。
以 LRF3000A1 为例,手册 6 针接口(A1002WV-S-6P):
| 针 | 定义 | 说明 |
|---|---|---|
| 1 | GND | 地 |
| 2 | 电源 | 3.3V–5V DC |
| 3 | NC | 预留 |
| 4 | TTL_TXD | 模块发送,TTL 3.3V 电平 |
| 5 | TTL_RXD | 模块接收,TTL 3.3V 电平 |
| 6 | Enable | 低电平开机 |
对板子:模块 TX → 主控 RX,模块 RX → 主控 TX,GND 共地。Enable 脚按手册是低电平使能,别悬空乱接,具体到你收到的那一台,以随货资料为准。
另外两点别混:LRF50H 的供电是 9–36 V,LRF22VB 是 3.0–3.6 V;有些型号手册里没单独写信号电平,这种情况先向厂商要书面确认再接。所有型号一律不要拿别的型号的电气参数顶替。
4. Arduino
官方库名ErdiLRF(已进 Arduino Library Manager,也可用 PlatformIO:erdi-tech/ErdiLRF)。
#include<ErdiLRF.h>ErdiLRFlrf(Serial1,ERDI_LRF3000A1);voidsetup(){Serial.begin(115200);Serial1.begin(erdiDefaultBaud(ERDI_LRF3000A1));// A 族 115200,B 族 460800}voidloop(){ErdiMeasurement m;if(lrf.measure(&m)==ERDI_OK)Serial.println(m.metres,3);delay(500);}波特率和换算由型号表决定。注意:Uno 的 SoftwareSerial 跑不到 460800,B 族要用硬件串口(Mega、ESP32 等),或者先用命令把模块波特率改到手册支持的低速率。
5. 树莓派(Python)
pipinstallhttps://github.com/yu911517778-a11y/erdi-lrf-drivers/releases/download/v0.1.0/erdi_lrf-0.1.0-py3-none-any.whl erdi-lrf--port/dev/ttyUSB0--modelLRF3000A1 measurefromerdi_lrfimportErdiLRFwithErdiLRF("/dev/ttyUSB0",model="LRF3000A1")aslrf:print(f"{lrf.measure().metres:.1f}m")withErdiLRF("/dev/ttyUSB0",model="LRF100H")aslrf:forminlrf.stream():# B 族自己连续输出print(m.metres,"(超量程)"ifm.out_of_rangeelse"")用 USB-TTL 适配器最省事;直接接树莓派 GPIO 串口也行,3.3V 电平,同样 TX/RX 交叉。编解码函数是不依赖串口的纯函数,可以直接拿去做单元测试。
6. ROS2
cp-rros2/erdi_lrf_ros2 ~/ros2_ws/src/cd~/ros2_ws&&colcon build --packages-select erdi_lrf_ros2sourceinstall/setup.bash ros2 run erdi_lrf_ros2 range_node --ros-args-pport:=/dev/ttyUSB0-pmodel:=LRF3000A1-prate:=10.0-pframe_id:=lrf_link节点发布sensor_msgs/Range,min_range/max_range取自型号手册的量程行;field_of_view默认 0(手册协议部分没有束散角),需要的话按你型号的数据手册自己设。
7. 手册自己打架的地方(我们没替你选)
- SPD1200D03:协议章节写 115200,技术表写 15200/9600,手册自己要求先确认交付配置。驱动要求你显式给波特率,也不输出米制距离。
- LRF1200A1 / LRF3000A1:连续测距请求用 0x89、记录的应答却是 0x88,手册明说"不授权连续应答解析"。单次测距不受影响,连续模式要手动确认后才能开。
- LRF50VB 的串口读取示例校验与手册自己的公式对不上。
遇到这类地方,写进工单问厂商,比猜一个值要省时间。
还没验证的部分
- 文中没有实测数据,没有精度、响应时间之类的结论,需要的数值请看你那个型号的手册。
- ROS2 节点目前是软件回放层面的测试,没有宣称在真实 ROS2 运行时和硬件上验证过。
- 所有驱动代码和 pytest 用例都是按手册里印出来的帧写的。
资料
- 开源驱动(MIT):https://github.com/yu911517778-a11y/erdi-lrf-drivers
- Arduino 库:https://github.com/yu911517778-a11y/ErdiLRF
- 技术笔记(DOI):https://doi.org/10.5281/zenodo.23297197
- 型号目录与资料:https://erdilrf.com/models/
厂商披露:本文作者属 ERDI TECH LTD(ERDILRF)。样品、数据手册和协议问题可通过 https://erdilrf.com 或 tommy@erdimail.com 联系。