Skip to main content
Explore ERDILRF

Press ↑↓ to move, Enter to open, Esc to close.

Read a Laser Distance Module With Arduino Over UART

Explore knowledge

Short answer: LR1000E2 and LR1200E2 document 8-byte 55 AA messages and a 115200 bps baud rate. Their electrical setup must be confirmed for the delivered module before connecting an Arduino. In particular, do not infer signal voltage, enable polarity or serial framing from a generic sketch. The examples below explain byte handling; they are not a complete hardware setup.

Two protocols, not one

Identify the exact model before writing code. The four models compared below illustrate command/response and streamed-output layouts, but a family name does not settle electrical settings, start/stop behavior or every frame length. Confirm the delivered configuration and operating mode before expecting output.

Property LR1000E2 LR1200E2 LRF22VB LRF50H
Protocol family A A B B
Frame header 55 AA 55 AA 5C 5C
Frame length 8 bytes 8 bytes 4 bytes 4 bytes
Baud rate 115200 115200 460800 (adjustable) 460800 (adjustable)
Mode command / response command / response Confirm configured output mode 1 kHz default; confirm output mode
Distance encoding actual value × 10 actual value × 10 little-endian, millimetres little-endian, centimetres
Supply voltage 3.3–5 V 3.3–5 V 3.0–3.6 V DC 9–36 V DC

Look at the distance-encoding row carefully. LRF22VB reports millimetres and LRF50H reports centimetres out of an identically shaped 4-byte frame, and nothing in the bytes tells you which. Hard-code the wrong one and every reading is off by a factor of ten.

Confirm wiring and electrical requirements first

The LR1200E2 source lists pin 6 as SW-SHOT, with both “Function Enable (active high)” and a note about compatibility with an active-low control requirement. The LR1000E2 source likewise contains both statements. Preserve both; do not choose the delivered unit’s GPIO polarity from this article. Confirm the control requirement, connector viewing direction and electrical limits before connecting or driving the pin. Do not infer a wire color from a pin number.

Two non-optional cautions:

  • Supply and UART signal voltage are separate requirements. The LR1200E2 manual does not separately specify a numerical TXD/RXD logic level. The LR1000E2 manual likewise does not add written signal-level evidence to its supply row. Confirm the delivered electrical requirement in writing before connecting a host; adding an unspecified level shifter is not a substitute for knowing both sides’ limits.
  • Use the exact supply requirement. LRF22VB lists 3.0–3.6 V DC; LRF50H lists 9–36 V DC. Check the actual board and supply design against the module’s current document, including its connector definition. Do not apply one model’s supply or signal limits to another.

LR1000E2 and LR1200E2: byte-handling helpers

The retained helper functions illustrate the documented LR1000E2/LR1200E2 command and reply byte handling. They are excerpts, not a standalone sketch: LRF denotes an already configured serial stream. They do not initialize a UART or drive an enable pin. The helper’s 500 ms default is an illustrative host-side read timeout, not a sensor response specification. LR1000E2’s source states 8 data bits but does not specify parity or stop bits; do not infer 8N1 from an Arduino default. Resolve missing serial settings, electrical levels and the enable configuration before using the current model-specific driver resources.

// Byte-handling excerpts for LR1000E2 / LR1200E2 only.
// LRF is an already configured stream; this is not hardware setup code.
// Confirm wiring, UART framing and the delivered enable configuration first.
const uint8_t FN_SINGLE = 0x88;

// Transmit checksum: function code + the four data bytes ONLY.
uint8_t txChecksum(uint8_t fn, const uint8_t *d) {
  uint16_t s = fn;
  for (uint8_t i = 0; i < 4; i++) s += d[i];
  return (uint8_t)(s & 0xFF);
}

// Reply checksum: BOTH header bytes + function code + the four data bytes.
uint8_t rxChecksum(const uint8_t *f) {
  uint16_t s = 0;
  for (uint8_t i = 0; i < 7; i++) s += f[i];
  return (uint8_t)(s & 0xFF);
}

void sendCommand(uint8_t fn) {
  uint8_t d[4] = {0xFF, 0xFF, 0xFF, 0xFF};
  uint8_t frame[8] = {0x55, 0xAA, fn, d[0], d[1], d[2], d[3], txChecksum(fn, d)};
  LRF.write(frame, 8);
}

bool readMeasurement(float &metres, uint32_t timeoutMs = 500) {
  uint8_t frame[8], n = 0;
  uint32_t start = millis();
  while (millis() - start < timeoutMs) {
    if (!LRF.available()) continue;
    uint8_t b = LRF.read();
    if (n == 0) { if (b == 0x55) frame[n++] = b; continue; }
    if (n == 1) { if (b == 0xAA) frame[n++] = b; else n = (b == 0x55) ? 1 : 0; continue; }
    frame[n++] = b;
    if (n < 8) continue;
    n = 0;                                        // resync for the next frame
    if (rxChecksum(frame) != frame[7]) continue;  // corrupt: wait for the next
    if (frame[2] != FN_SINGLE) continue;         // accept only single-shot replies
    if (frame[3] != 0x01) continue;               // STA != 1: measurement failed
    metres = (float)(((uint16_t)frame[5] << 8) | frame[6]) / 10.0f;
    return true;
  }
  return false;
}

readMeasurement accepts only single-shot replies whose function byte is FN_SINGLE (0x88), with the documented successful status and checksum. Continuous-ranging replies and other response types require separate handling against the exact model protocol; do not pass them through this single-shot helper. For these two source-documented examples, 0x89 and 0x8E identify the listed continuous and stop commands. Confirm their applicability and configuration before sending them. This article does not choose a startup delay or command rate for an unverified setup.

Keep command and reply checksum scopes separate

In the two documented models used by these helpers, the transmit and reply byte scopes differ. Keep txChecksum and rxChecksum separate, and compare the exact received message with the model source before accepting a distance. Other models may have source conflicts or driver restrictions; consult the current driver resources rather than extrapolating these helpers across the catalog.

LRF22VB and LRF50H: a four-byte parsing example

For the documented LRF22VB/LRF50H four-byte layout, the checksum is the inverted sum of the distance bytes. Confirm output mode before expecting a stream. This helper only returns raw values; its caller must handle the exact model’s invalid-result marker and unit before using a distance. It does not cover the five-byte LRF1500H frame.

// Four-byte 5C parsing example; confirm actual output configuration first.
// LRF22VB raw units are MILLIMETRES; LRF50H raw units are CENTIMETRES.
bool readFamilyB(uint16_t &raw) {
  static uint8_t f[4], n = 0;
  while (LRF.available()) {
    uint8_t b = LRF.read();
    if (n == 0) { if (b == 0x5C) f[n++] = b; continue; }
    f[n++] = b;
    if (n < 4) continue;
    n = 0;
    uint8_t sum = f[1] + f[2];              // 2nd byte through 2nd-last byte
    if ((uint8_t)(~sum) != f[3]) continue;  // checksum is the inverted sum
    raw = (uint16_t)f[1] | ((uint16_t)f[2] << 8);   // little-endian
    return true;
  }
  return false;
}

Check it against the manual’s own example, 5C 02 11 EC: the sum of 02 and 11 is 0x13, inverted is 0xEC, and the little-endian distance 0x1102 is 4354 — 4354 mm on LRF22VB, 4354 cm on LRF50H. Treat an out-of-range reading as a distinct state rather than a distance: LRF22VB outputs 20000 (its range is 0–20000), LRF50H outputs 65535 (range 0–65535).

Measure the actual report cadence and host receive behavior before choosing buffer sizes or a processing rate. A listed measurement frequency does not prove that a particular Arduino, driver or application receives every valid report.

Frequently asked questions

Why do I get valid frames but every checksum fails?

A wrong checksum scope is one possible cause, but not the only one. For the two LR examples here, the reply checksum includes the header bytes while the command checksum does not. Also verify the exact frame layout, byte alignment and source-defined rule before changing the decoder.

My distances are exactly 10× too large or too small. Why?

For the exact examples here, LR1000E2/LR1200E2 use the documented value-times-ten representation; LRF22VB uses millimetres and LRF50H uses centimetres. Confirm the model, status and unit instead of assuming one rule for an entire family.

Can I use I²C instead of UART?

On LRF22VB, yes — it exposes a shared UART/I²C interface at default address 0x52 (7-bit), with a maximum clock of 400 kHz, on the same pins 3 and 4. The H-series modules in this comparison are UART only, and their manuals register no I²C address.

Does this code work for every ERDILRF model?

No. The helpers are limited to the named layouts and do not set up electrical connections, enable pins or serial framing. LRF1500H has a five-byte frame with a three-byte distance field and a source checksum-example conflict. Do not use the four-byte helper for it or resolve the conflicting example by assumption.

Frames not decoding on your board? Send the exact model, manual revision, host configuration and a short byte trace with private data removed. Get in touch or email tommy@erdimail.com for a model-specific review. Find the current documents and driver resources before selecting a wiring or setup example.

ERDI TECH LTD · 905 nm laser rangefinder modules · tommy@erdimail.com · WhatsApp +86 133 0819 5790 · erdilrf.com