LIDAR Basics

Lidar, an acronym of LIght Detection And Ranging is a method for determining ranges by targeting an object or a surface with a laser and measuring the time for the reflected light to return to the receiver. Lidar may operate in a fixed direction (e.g., vertical) or it may scan directions, in a special combination of 3D scanning and laser scanning.

SLAMTEC RPLIDAR C1

The Slamtec RPLIDAR C1 is a compact 360° 2D LiDAR. It uses a fusion of triangulation and Direct Time-of-Flight (DTOF) ranging technology to deliver reliable distance measurements up to about 12 meters for well-reflective surfaces, with a typical angular resolution of around 0.72° and a scan rate near 10 Hz. The device samples rapidly (about 5000 Hz) to build detailed planar scans of its surroundings. It’s lightweight and easy to integrate via a TTL UART interface, and supports SDKs as well as middleware such as ROS/ROS2 for development of robot positioning, mapping, and obstacle avoidance systems. Its laser meets Class 1 eye safety standards and it’s suitable for use in home robotics, educational projects, hobby builds, and light commercial robots.

Setup

The simplest way to use the RPLIDAR with a Raspberry Pi is to interface through the bundled USB adapter. Connect a USB cable on the Raspberry Pi and then plug the other end into the LIDAR USB adapter board. However, I had the following problem: No matter which library I tried, none of them worked properly.But ultimately it wasn't a problem: I simply queried the data at a low level via the serial interface. But to do that, one needs to take a closer look at the technology and data formats of LiDAR.

The software setup is quick and easy, because you basically only need access to the serial interface.

pip install pyserial    

To check if the device is available, you can use the following Pyton script:

import serial.tools.list_ports

ports = serial.tools.list_ports.comports()
for p in ports:
    print(p.device, p.description)    

Depending on the operating system, you usually get a tty (Linux) or a COM port (Windows), like:

/dev/ttyUSB0
# or
COM5

Working States and Commands

RPLIDAR has the following 4 major states: Idle, Scanning, Request Processing and the Protection Stop state:

PLIDAR will exit the current scanning state once it receives the Stop (0x25) Request sent by a host system. The laser diode and the measurement system will be disabled and the Idle state will be entered. This request will be ignored when RPLIDAR is in the Idle or Protection Stop state. Since RPLIDAR won’t send response packet for this request, host systems should wait for at least 10 millisecond (ms) before sending another request

Commands can be sent to the LiDAR as follows:

0xA5 = SYNC BYTE (Startbyte for commands)

Command	        Bytes	    Meaning
===============================================
Start Scan      A5 20       Start scanning
Stop            A5 25       Stop scanning
Reset           A5 40       Reset the scan
Get Info        A5 50       Device information
Get Healt       A5 52       Status

Sending Commands with Python

Functions for sending commands in Python could look like this, for example:

def send_cmd(ser, cmd_bytes):
    ser.write(cmd_bytes)
    time.sleep(0.05)

def start_scan(ser):
    send_cmd(ser, b'\xA5\x20')  # START SCAN

def stop_scan(ser):
    send_cmd(ser, b'\xA5\x25')  # STOP

def reset(ser):
    send_cmd(ser, b'\xA5\x40')  # RESET

What's coming back?

Good question! It wasn't easy to find out. But luckily, there's very good documentation for the C1 RPLIDAR that explains the exact structure of the data packet:

RPLIDAR encapsulates each measurement sample into a data response packet with the format showed in the above figure and send the packet out. Warning: you really need to be careful here! If you look closely at the data, you'll notice that angle and distance each consist of two bytes.

BUT: for the angle, the bit with index 0 is set as a synchronization bit and does not belong to the value. The 15th bit is not used; the value consists of only 14 bits. This must be taken into account when converting data with Python.
To obtain the correct value for the quality, you simply need to shift by 2 bits.

angle = ((b1 >> 1) | (b2 << 7)) / 64.0
distance = (b3 | (b4 << 8)) / 4.0  # mm
quality = b0 >> 2    

The Coordinate System

To interpret the data correctly, you need to know how to interpret the angles. Good documentation helps with this as well. The geometric definition of the included angle and distance value is shown as below: