DEV Community

xiao Mayer
xiao Mayer

Posted on

Interfacing an Industrial Laser Distance Sensor with Raspberry Pi via Python

Ultrasonic sensors (like the HC-SR04) and infrared proximity detectors are common starting points for distance measurement. However, when outdoor ambient lighting degrades IR readings or precision down to ±1 mm is required over several tens of meters, industrial-grade optical sensors become necessary.

This tutorial covers wiring, configuring, and parsing data from an industrial phase-shift laser distance meter using a Raspberry Pi and Python.


Hardware Overview

For this guide, we use an ultra-compact phase-shift optical module—specifically the LDL-T series (datasheet available via [lasersensor.net]).

  • Measurement Range: 0.03 m up to 60 m / 80 m / 100 m
  • Accuracy: ±(1 mm + D * 10^-4)
  • Measurement Frequency: 5 Hz / 30 Hz / 100 Hz
  • Operating Voltage / Logic: 3.3V TTL (Power consumption < 80 mA @ 3.3V)
  • Interface Options: USART / RS-485 / Modbus


Because the module operates directly on a 3.3V logic level, it connects directly to the Raspberry Pi GPIO serial pins without requiring a 5V-to-3.3V logic shifter.


Pinout and Wiring

Connect the sensor module to the Raspberry Pi 40-pin header as follows:

Sensor Pin Raspberry Pi Pin Pin Description
VCC Pin 1 or Pin 17 3.3V Power
GND Pin 6 or Pin 9 Ground
TXD Pin 10 (GPIO 15) RXD (Pi receives data)
RXD Pin 8 (GPIO 14) TXD (Pi transmits data)

Note: Ensure TX on the sensor connects to RX on the Pi, and RX on the sensor connects to TX on the Pi.


Raspberry Pi Configuration

  1. Open a terminal and run sudo raspi-config.
  2. Navigate to Interface Options -> Serial Port.
  3. Select No for "Would you like a login shell to be accessible over serial?".
  4. Select Yes for "Would you like the serial port hardware to be enabled?".
  5. Finish and reboot the Pi: sudo reboot.
  6. Install pyserial:

bash
pip install pyserial

Protocol Structure
Industrial phase-shift sensors typically communicate using ASCII or Hex frame commands. The common single-measurement HEX frame sequence is:

Trigger Single Shot: AA 00 00 20 00 01 00 21

Response Frame (Typical): AA 00 00 22 [D0 D1 D2 D3] [CS]

AA 00 00 22: Response header

D0 - D3: 4-byte distance value in millimeters (Big-Endian integer)

CS: Checksum byte (sum of all preceding bytes modulo 256)

Implementation Code
Create a file named read_sensor.py:

import serial
import time

SERIAL_PORT = "/dev/serial0"  # Default primary UART on Raspberry Pi
BAUD_RATE = 19200            # Standard default baud rate for industrial modules

def calculate_checksum(data: bytes) -> int:
    """Calculates single-byte sum modulo 256."""
    return sum(data) & 0xFF

def read_laser_distance(ser):
    # Single-shot command frame: Header (0xAA) + Address + Command + Parameter
    cmd_single_shot = bytes([0xAA, 0x00, 0x00, 0x20, 0x00, 0x01, 0x00, 0x21])
    ser.write(cmd_single_shot)

    # Wait for sensor turnaround and processing
    time.sleep(0.05)

    # Read response header
    response = ser.read(9)
    if len(response) < 9:
        print("Error: Incomplete packet received")
        return None

    # Validate header and checksum
    if response[0] != 0xAA or response[3] != 0x22:
        print(f"Error: Invalid header: {response.hex()}")
        return None

    expected_checksum = calculate_checksum(response[:-1])
    received_checksum = response[-1]

    if expected_checksum != received_checksum:
        print("Error: Checksum mismatch")
        return None

    # Parse 4-byte distance (millimeters)
    distance_mm = int.from_bytes(response[4:8], byteorder="big")
    return distance_mm / 1000.0  # Convert to meters

def main():
    try:
        ser = serial.Serial(
            port=SERIAL_PORT,
            baudrate=BAUD_RATE,
            timeout=1.0,
            parity=serial.PARITY_NONE,
            stopbits=serial.STOPBITS_ONE,
            bytesize=serial.EIGHTBITS
        )
        print("Connected to distance sensor. Starting loop...")

        while True:
            dist_m = read_laser_distance(ser)
            if dist_m is not None:
                print(f"Measured Distance: {dist_m:.3f} m")
            time.sleep(0.2)  # Sampling cycle

    except serial.SerialException as e:
        print(f"Serial port failure: {e}")
    except KeyboardInterrupt:
        print("\nMeasurement terminated.")
    finally:
        if 'ser' in locals() and ser.is_open:
            ser.close()

if __name__ == "__main__":
    main()

Troubleshooting Tips
Permission Denied: Add your user to the dialout group via sudo usermod -a -G dialout $USER, then log out and log back in.

Timeout Errors: Check that physical pin 8 and pin 10 are not reversed, and confirm that the module's supply pin is receiving a steady 3.3V rail.

Erratic Values: If measuring low-reflectivity or transparent surfaces, place an opaque, matte-white target board perpendicular to the laser line.
Enter fullscreen mode Exit fullscreen mode

Top comments (0)