RPLidar

Build StatusHex.pmDocumentation

Library for interfacing with the RPLidar family of 360-degree LiDAR sensors.

Note: While it should work on the entire line of RPLidar Triangulation LiDARs, this library has been tested on the RPLidar A1M8 sensor.

Sample RPLidar A1 Scan

Installation

Add rplidar to your list of dependencies in mix.exs:

def deps do
  [
    {:rplidar, "~> 0.1.0"}
  ]
end

Basic Usage

Once the RPLidar process is started, calling enable_motor will start the motor spinning and calling start_scan will start to receive and decode the packets from the sensor. The calling process (or a PID passed to the start_link function) will start to receive :lidar_packet messages as each one is received from the sensor. These packets contain the decoded information for each sensed point in the format {:lidar_packet, angle, range, quality, received_at}:

def init(_) do
  {:ok, pid} = RPLidar.start_link(uart_device: "ttyS0", motor_enable_pin: 18)
  
  :ok = RPLidar.enable_motor(pid)
  :ok = RPLidar.start_scan(pid)
  # ...
end

def handle_info({:lidar_packet, angle, range, quality, received_at}, state) do
  # ...
  {:noreply, state}
end

To convert from angle and range to (x,y) coordinates (in meters):

r = angle * Math.pi() / 180.0
d = range / 1000
x = :math.sin(r) * d
y = :math.cos(r) * d

Options

Framer

While it's sometimes useful to receive individual points from the LiDAR, in most cases, it's more useful to receive an entire "frame" from the sensor after it has completed a full 360 degrees of rotation. The RPLidar.Framer module can automatically combine points into frames such that your application receives one message each 360-degree scan containing all the points in (x, y) coordinates.

def init(_) do
  {:ok, framer} = RPLidar.Framer.start_link(scale: 0.001, quality_threshold: 80)
  {:ok, pid} = RPLidar.start_link(uart_device: "ttyS0", motor_enable_pin: 18, parent: framer, filter: true)
  
  :ok = RPLidar.enable_motor(pid)
  :ok = RPLidar.start_scan(pid)
  # ...
end

def handle_info({:lidar_frame, %RPLidar.Frame{} = frame}, state) do
  # ...
  {:noreply, state}
end

The RPLidar.Frame struct contains the points as a parameter points. Each point is a tuple {angle, range, x, y} containnig:

Options

Performance Considerations

Its possible for the A1 to send up to 8,000 points per second and A2 and A3 models to send up to 16,000 points per second, which can push the trigonometric performance of the BEAM. Depending on your hardware, it's possible for the Framer to get behind the points coming in. Make sure to monitor the message queue length for the Framer process and the timestamps on the Frame struct to detect lag caused by performance issues.