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. Ensure the adapter board is fitted correctly onto the sensor per the instructions in the manual.
PyGame
We'll be using the 2.8" PiTFT display. See this guide for instructions on installing and configuring the required support software. We'll also need pyGame to provide that data plotting capabilities. See the pyGame site for installation instructions.
The Code
To use the RPLIDAR, you need to start the motor spinning and tell it to start taking readings. It will then stream each reading it takes until you tell it to stop. Each reading includes the distance sensed, and the angle of the reading. To make things easier, the Skoltech library provides a convenient wrapper for this functionality, and that's what we'll use for this guide.
This example will consume data from the RPLIDAR and display it on a 2.8" PiTFT display. We start by setting up a few things.
import os from math import cos, sin, pi, floor import pygame from adafruit_rplidar import RPLidar # Set up pygame and the display os.putenv('SDL_FBDEV', '/dev/fb1') pygame.init() lcd = pygame.display.set_mode((320,240)) pygame.mouse.set_visible(False) lcd.fill((0,0,0)) pygame.display.update() # Setup the RPLidar PORT_NAME = '/dev/ttyUSB0' lidar = RPLidar(None, PORT_NAME) # used to scale data to fit on the screen max_distance = 0
Next we create a buffer in which to keep distance data. Each item in the list stores the distance measured at each degree for a complete rotation. We use this to maintain the most recent set of measurements even though each scan will be incomplete.
scan_data = [0]*360
We use the iter_scans
function of the RPLIDAR object. This starts the motor and the scanning for us so we can skip that in our code. iter_scans
accumulates measurements for a single rotation and returns a list of tuples, from which we are interested in the second and third items. These are the angle and the distance measured at that angle. Both are floating point values.
Once we have a scan, we step through each data point. The floor of the angle is taken and used as the index at which to store the measurement value. Because it is possible that multiple consecutive measurements in a scan could be close to the same angle (and thus having the same floor value) there is a small chance that some measurements are lost. But there is no real disadvantage to this, so it can be disregarded.
scan_data = [0]*360 try: print(lidar.info) for scan in lidar.iter_scans(): for (_, angle, distance) in scan: scan_data[min([359, floor(angle)])] = distance process_data(scan_data) except KeyboardInterrupt: print('Stoping.') lidar.stop() lidar.disconnect()
Once we have updated scan_data
, it is passed to the process_data
function.
The process_data
function can do anything from finding the closest object, to choosing the best direction to move in. The only requirement is that it be as fast as possible. If it takes too long to process a scan, data from the RPLIDAR will eventually be dropped. Since we're constantly reading fresh data, dropping an occasional scan shouldn't be an issue.
In this example we display the distance data on a PiTFT.
The first step of a pass is to clear the display. Then it looks at each angle: 0-359. If the distance recorded for that angle is zero, it's because a reading hasn't be acquired for that angle yet, and we can safely ignore it. If there is a distance recorded for the angle, max_distance
is adjusted as necessary to keep the display scaled to fit on the screen. The angle is converted to radians (from degrees) and the vector for the reading is converted to a cartesian coordinate which is then used to plot the data point on the display.
After all measurements have been plotted, the display is updated.
def process_data(data): global max_distance lcd.fill((0,0,0)) for angle in range(360): distance = data[angle] if distance > 0: # ignore initially ungathered data points max_distance = max([min([5000, distance]), max_distance]) radians = angle * pi / 180.0 x = distance * cos(radians) y = distance * sin(radians) point = (160 + int(x / max_distance * 119), 120 + int(y / max_distance * 119)) lcd.set_at(point, pygame.Color(255, 255, 255)) pygame.display.update()
# SPDX-FileCopyrightText: 2019 Dave Astels for Adafruit Industries # # SPDX-License-Identifier: MIT """ Consume LIDAR measurement file and create an image for display. Adafruit invests time and resources providing this open source code. Please support Adafruit and open source hardware by purchasing products from Adafruit! Written by Dave Astels for Adafruit Industries Copyright (c) 2019 Adafruit Industries Licensed under the MIT license. All text above must be included in any redistribution. """ import os from math import cos, sin, pi, floor import pygame from adafruit_rplidar import RPLidar # Set up pygame and the display os.putenv('SDL_FBDEV', '/dev/fb1') pygame.init() lcd = pygame.display.set_mode((320,240)) pygame.mouse.set_visible(False) lcd.fill((0,0,0)) pygame.display.update() # Setup the RPLidar PORT_NAME = '/dev/ttyUSB0' lidar = RPLidar(None, PORT_NAME) # used to scale data to fit on the screen max_distance = 0 #pylint: disable=redefined-outer-name,global-statement def process_data(data): global max_distance lcd.fill((0,0,0)) for angle in range(360): distance = data[angle] if distance > 0: # ignore initially ungathered data points max_distance = max([min([5000, distance]), max_distance]) radians = angle * pi / 180.0 x = distance * cos(radians) y = distance * sin(radians) point = (160 + int(x / max_distance * 119), 120 + int(y / max_distance * 119)) lcd.set_at(point, pygame.Color(255, 255, 255)) pygame.display.update() scan_data = [0]*360 try: print(lidar.info) for scan in lidar.iter_scans(): for (_, angle, distance) in scan: scan_data[min([359, floor(angle)])] = distance process_data(scan_data) except KeyboardInterrupt: print('Stoping.') lidar.stop() lidar.disconnect()
Page last edited January 19, 2025
Text editor powered by tinymce.