Skip to main content

Protocol B - free-running 5C data frames, 5A command frames

Used by 8 models: LRF50H, LRF100H, LRF200H, LRF300H, LRF600H, LRF1500H, LRF22VB, LRF50VB.

Models covered in the original document: LRF50H, LRF100H, LRF200H, LRF300H, LRF600H, LRF1500H, LRF22VB, LRF50VB. LRF10VB uses the same 4-byte 5C frame in millimetres with out-of-range marker 65535, see its model page.

These modules stream distance continuously once powered; there is no request/response for measurements. Configuration uses a separate 5A frame.

Every row ends with the manual sentence it came from.

FieldValueSource
InterfaceUART (VB series and most H models also expose I²C)"6. Communication Protocol: UART" - LRF22VB
Default baud460800, adjustable"UART Baud Rate 460800 (adjustable) Data Bit 8 Stop Bit 1 Parity Bit None" - LRF100H
Data / stop / parity8 / 1 / nonesame row (LRF22VB prints "Parity Bit N/A")
Byte orderlittle-endian, both directions"this product adopts Hexadecimal Little-Endian Mode" - LRF100H
I²C address (VB series)0x52, 7-bit, ≤400 kHz"The default address is 0x52 (7bit address mode)." - LRF22VB

460800 bps is out of reach for AVR SoftwareSerial. Use a hardware UART, or set the module to a lower documented rate first with the baud command below.

Data frame​

Four-byte form - every model except LRF1500H:

byte 0 1 2 3
5C dist_lo dist_hi check

Five-byte form - LRF1500H only:

byte 0 1 2 3 4
5C dist_lo dist_mid dist_hi check

Sources: "Frame Header | Distance 2 Bytes | Check Byte / 5C 02 11 EC" - LRF100H; "Frame Header | Distance 3 Bytes | Check Byte / 5C 02 11 03 EC" - LRF1500H.

Checksum​

The manuals print both the sentence and the C function:

"Begin with the second byte and end with the last second byte, find the inverse of the sum."

uint8_t Check_Sum(uint8_t *_pbuff, uint16_t _cmdLen)
{
uint8_t cmd_sum = 0;
uint16_t i;
for (i = 0; i < _cmdLen; i++) { cmd_sum += _pbuff[i]; }
cmd_sum = (~cmd_sum);
return cmd_sum;
}

Worked check: 5C 02 11 EC → ~(0x02 + 0x11) = ~0x13 = 0xEC. Yes

Units - per model, never per family​

ModelsRaw count isOut-of-range markerSource
LRF50H, LRF100H, LRF200H, LRF300H, LRF600H, LRF1500Hcentimetres65535 (16777215 on LRF1500H)"the measuring distance is 4354cm, little-endian, range 0-65535cm. When out of range, it would output 65535cm." - LRF100H
LRF22VBmillimetres20000"the measuring distance is 4354mm, little-endian, Range:0- 20000, When out of range, its output is 20000." - LRF22VB
LRF50VBmillimetres50000"the measuring distance is 4354mm, little-endian, range 0-50000. When out of range, output would be 50000." - LRF50VB

The same four bytes 5C 02 11 EC mean 43.54 m on an H module and 4.354 m on a VB module. Reading the wrong table is a 10x error, which is why this repository never derives the unit from the family.

The factory's own serial tool confirms the VB row: its VB22A(cm) display mode divides the millimetre frame value by 10 on the PC and sends nothing to the module. See vendor-host-tool.md. A bench log from the factory confirms both rows against the same 1.9 m wall: an LRF22VB logs ~1709 in the tool's (mm) entry and an LRF50H logs ~196 as WT50A, so the VB frame is millimetres and the H frame is centimetres. That LRF50H log also holds a few checksum-valid frames far beyond the 50 m rating that are not 0xFFFF, so a driver should reject frames past the configured maximum rather than average them. Files and numbers: evidence/ardupilot-bench-20261105.

Command frame​

byte 0 1 2 3 .. 3+len-1 last
5A cmd len data... check

The reply echoes the command byte with bit 7 set (0x0D → 0x8D). The checksum covers cmd, len and data - the same Check_Sum function.

#CommandSendReturnSource
1Read serial no.5A 0D 02 0D 0D D65A 8D 02 10 01 00 00 5FLRF50H / LRF1500H
1bRead serial no. (VB 4-byte form)5A 0D 04 0D 0D 0D 0D BA5A 8D 04 10 01 00 00 5DLRF22VB. "10 01 00 00 means the serial no. is 272: little-endian"
2Read software version5A 16 02 16 16 BB5A 96 02 03 02 62"03 02 means the software version no. is V2.3 … Add a point (.) in the middle."
3Set baud rate5A 06 02 80 04 735A 86 02 80 04 F3"80 04 as a decimal is 1152: little-endian, it means the baud rate is set to 115200=1152*100"
4Set frequency5A 0B 02 E7 03 085A 8B 02 E7 03 88"E7 03 (little-endian) represents the frequency divisor: 999."
5Read frequency5A 1B 02 1B 1B AC5A 9B 02 31 00 31"31 00 (little-endian) indicates the current divisor: 49."
6Switch to I²C5A 1F 02 1F 1F A05A 9F 02 1F 1F 20VB series. "Response confirms successful switch."
7Stop ranging5A 0A 02 00 00 F35A 8A 02 00 00 73LRF50H, LRF22VB, LRF50VB
8Start ranging5A 0A 02 02 00 F15A 8A 02 02 00 71LRF50H, LRF22VB, LRF50VB

Every frame in this table verifies against the manual's own Check_Sum function; python/tests/test_protocol_b.py asserts all of them.

Baud-rate codes​

The two data bytes are bps ÷ 100, little-endian:

BytesDecimalBaud
60 00969600
C0 0019219200
80 0138438400
80 041152115200
00 092304230400
00 0A2560256000
00 124608460800

"Any other baud rate is not available" - LRF22VB. "Other baud rate settings would not get respond." - LRF1500H.

Output frequency - the divisor base is model specific​

f = base / (divisor + 1)

ModelsBaseSource
LRF22VB, LRF50VB10 kHz"Output frequency: f=10000/(999+1)=10Hz"
LRF50H, LRF100H, LRF200H1 MHz"the corresponding serial data output frequency f=1000000/(999+1)=1000Hz"
LRF300H, LRF600H, LRF1500Hnot documentedno divisor formula appears in these manuals

The drivers refuse to set or read frequency on the three models with no published formula rather than borrowing a sibling's base.

I²C register map (VB series)​

AddressDefinitionAccessRemarks
0x00Distance, high byteR2 bytes for distance
0x01Distance, low byteR
0x02Laser controlW0 = laser off, 1 = laser on
0x03LiDAR IDRdefault 0x4A, for read/write tests
0x04 / 0x05I²C → UART switchW"Write 0xA5 to register 0x04 and 0x5A to register 0x05 simultaneously"
0x06 / 0x07Software version, high / lowR
0x08–0x0BSerial number, high → lowR4 bytes, range 1–4294967294
0x0CI²C slave addressR/W7-bit, range 0–127
0x0DFactory resetWwrite 0x01

Note the I²C distance registers are documented high byte first, while the UART data frame is little-endian. Both are reproduced as printed.

This repository's drivers implement the UART path only; the register map is included so an I²C integrator does not have to open the PDF.

Known gaps​

GapWhat the manual does or does not say
LRF1500H example frame vs its own checksumThe manual prints 5C 02 11 03 EC, but its own Check_Sum gives ~(0x02+0x11+0x03) = 0xE9. 0xEC is the correct byte for the four-byte frame 5C 02 11 EC used by the other models, so the example looks copied. The drivers implement the printed function; a test asserts the discrepancy so it cannot be silently "corrected".
LRF1500H out-of-range valueSection 5.2 says the field is 3 bytes and out-of-range outputs 16777215; section 6 says "it would output 0xFFFF (16777215)", and 0xFFFF is 65535. The drivers use 16777215, matching the stated field width. Reported, not resolved.
LRF50VB serial-read example checksumThe printed request 5A 0D 02 0D 0D 0D 0D BC does not satisfy Check_Sum for either length byte (0x02 → 0xBE, 0x04 → 0xBA); its printed reply does verify. The drivers build the request with Check_Sum.
LRF300H, LRF600H, LRF1500H frequencyNo divisor formula published; set/read frequency is not exposed for these models.
LRF50H, LRF100H, LRF300H, LRF600H, LRF1500H I²C addressNot stated in their manuals (LRF200H states 0x33, the VB series 0x52). Nothing is extrapolated.
Start/stop rangingDocumented only for LRF50H, LRF22VB and LRF50VB. The other five free-run from power-up and the drivers do not send a start command to them.
LRF22VB default output frequencyListed as unresolved in our engineering notes; the supported set is documented (200/100/50/20/10/1 Hz) but the power-on default is not.
LRF50VB supported frequency listThe set-frequency row lists 100/50/20/10/1 Hz and the read-frequency row lists 200/100/50/20/10/1 Hz. Both are reproduced; the manual does not reconcile them.
VB 55 AA 81 00 FA pollThe factory serial tool sends these five bytes once a second to VB modules and accepts an 8-byte 55 AA … FA reply as a millimetre distance. No VB manual describes it; the drivers do not use it. See vendor-host-tool.md.