Disclosure: I work for the manufacturer of these modules (ERDILRF, Chengdu). Every frame, baud rate and unit below is transcribed from the manufacturer manuals and implemented in an MIT-licensed driver. I am not publishing bench measurements here, and the last section lists what has not been verified.
The two classic first-integration failures with a UART laser rangefinder are a silent serial port and readings that are off by a factor of ten. Both usually trace back to protocol details, not wiring. This walkthrough goes in the order that saves time: identify the protocol family, wire it, then run code.
Parts
- One ERDI 905 nm module (this write-up uses the LRF3000A1 as the worked example)
- An Arduino with a spare hardware UART (Mega, ESP32, etc.), a Raspberry Pi with a USB-TTL adapter, or a ROS 2 machine
- Jumper wires and a supply that matches your exact model
Step 1: Identify the protocol family
ERDI's 905 nm catalogue uses two UART protocols.
Family A: 8-byte 55 AA command/response. LR1000E2/E4, LR1200E2/E4, LR1500E2/E4, LR2000E2/E4, LRF1200A1, LRF3000A1, SPD1200N0/N2/N4, SPD1200D03. Default 115200 bps.
Family B: free-running 5C frames. LRF50H/100H/200H/300H/600H/1500H and LRF22VB/LRF50VB. Default 460800 bps (adjustable), 8 data bits, 1 stop bit, no parity, little-endian.
Step 2: Know the frames
Family A request, single shot: 55 AA 88 FF FF FF FF 84.
Reply: 55 AA 88 STA FF DIS_H DIS_L SUM. STA = 1 means success. Distance is DIS_H<<8 | DIS_L, and the manual states results are output as the real value x 10, so one count is 0.1 m.
The classic trap: transmit and reply checksums cover different bytes.
- Transmit: low 8 bits of Function + D1..D4
- Reply: low 8 bits of 0x55 + 0xAA + Function + D1..D4
They differ by exactly 0xFF. Use the transmit formula on replies and you will be off by one on almost every frame. A hand-computed example (constructed, not captured from hardware): 55 AA 88 01 FF 04 D2 5D sums to 0x35D, low byte 0x5D, and the distance 0x04D2 = 1234 counts = 123.4 m.
Family B frame: 5C dist_lo dist_hi check, e.g. 5C 02 11 EC. The check byte is the bitwise inverse of the sum of the bytes between the header and the check: ~(0x02 + 0x11) = 0xEC.
Units are per model, not per family. The same four bytes 5C 02 11 EC mean 43.54 m on an H-series module (centimetres) and 4.354 m on a VB-series module (millimetres). LRF1500H is the only 5-byte frame, with a 3-byte distance field.
Step 3: Wire it
Supply voltage and UART signal level are separate specifications. Do not infer one from the other.
LRF3000A1, 6-pin connector (A1002WV-S-6P) per its manual:
| Pin | Signal | Note |
|---|---|---|
| 1 | GND | Ground |
| 2 | Power | 3.3-5 V DC |
| 3 | NC | Reserved |
| 4 | TTL_TXD | Module transmit, 3.3 V TTL |
| 5 | TTL_RXD | Module receive, 3.3 V TTL |
| 6 | Enable | Power ON at low level |
Module TX goes to host RX, module RX to host TX, and grounds are common. Other models differ: LRF50H takes 9-36 V and LRF22VB takes 3.0-3.6 V, and some manuals do not state a signal level at all. If yours does not, get the level confirmed in writing before connecting. Never reuse another model's electrical numbers.
Step 4: Arduino
Install ErdiLRF from the Library Manager (or PlatformIO: erdi-tech/ErdiLRF).
#include <ErdiLRF.h>
ErdiLRF lrf(Serial1, ERDI_LRF3000A1);
void setup() {
Serial.begin(115200);
Serial1.begin(erdiDefaultBaud(ERDI_LRF3000A1)); // 115200 for family A, 460800 for family B
}
void loop() {
ErdiMeasurement m;
if (lrf.measure(&m) == ERDI_OK) Serial.println(m.metres, 3);
delay(500);
}
Note: SoftwareSerial on an Uno cannot reach 460800 bps. Family B needs a hardware UART, or set the module to a lower documented rate first.
Step 5: Raspberry Pi (Python)
pip install https://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 --model LRF3000A1 measure
from erdi_lrf import ErdiLRF
with ErdiLRF("/dev/ttyUSB0", model="LRF3000A1") as lrf:
print(f"{lrf.measure().metres:.1f} m")
with ErdiLRF("/dev/ttyUSB0", model="LRF100H") as lrf:
for m in lrf.stream():
print(m.metres, "(out of range)" if m.out_of_range else "")
The frame codecs are pure functions with no serial dependency, so you can unit-test them offline.
Step 6: ROS 2
cp -r ros2/erdi_lrf_ros2 ~/ros2_ws/src/
cd ~/ros2_ws && colcon build --packages-select erdi_lrf_ros2
source install/setup.bash
ros2 run erdi_lrf_ros2 range_node --ros-args -p port:=/dev/ttyUSB0 -p model:=LRF3000A1 -p rate:=10.0 -p frame_id:=lrf_link
The node publishes sensor_msgs/Range; min_range/max_range come from the model manual, and field_of_view defaults to 0 because the protocol manuals carry no beam divergence.
Where the manuals disagree with themselves
- SPD1200D03: the protocol section says 115200 bps, the technical table says 15200/9600, and the manual says to confirm the delivered configuration first. The driver demands an explicit baud and returns no metric distance.
- LRF1200A1 / LRF3000A1: continuous ranging is requested with 0x89 but the recorded reply uses 0x88, and the manual declines to authorise a reply parser. Single-shot is unaffected.
- LRF50VB: the printed serial-number request fails the manual's own checksum function.
The drivers surface these instead of guessing.
What is not verified
- No measurement results or performance claims are made here. Read the datasheet for your model.
- The ROS 2 node has been tested in software replay only, not against a live ROS 2 runtime with hardware.
- The driver tests are built from the frames printed in the manuals.
Links
- Driver repo (MIT): https://github.com/yu911517778-a11y/erdi-lrf-drivers
- Arduino library: https://github.com/yu911517778-a11y/ErdiLRF
- Technical note with DOI: https://doi.org/10.5281/zenodo.23297197
- Model catalogue: https://erdilrf.com/models/
Vendor disclosure: the author is affiliated with ERDI TECH LTD (ERDILRF). For samples, datasheets or protocol questions, see https://erdilrf.com or tommy@erdimail.com.
Top comments (0)