fbpixel
Tags: , ,

In this tutorial, we’ll look at how to set up a Lidar sensor map in Python. The lidar sensor is used for spatial orientation and mapping.

Lidar sensor description

The lidar sensor is a laser distance sensor coupled to a motor that drives it. It behaves like a radar, detecting obstacles at 360 degrees and mapping space. It is often used in robotics to map and locate an environment and enable autonomous movement.

The Lidar sensor uses a serial interface card to connect it to a computer via a USB port.

To find out which port the device is connected to, go to the Device Manager in the Ports (COM and LPT) section (here com3).

lidar-x4-port-com Using a Lidar sensor with Python

Lidar testing with the official Tool

You can download the Tool interface from the official website. This tool allows you to visualize the cartography obtained using Lidar.

Once the software has been launched, simply select the device port and Lidar model. Once the Lidar is connected, you can start acquisition.

lidar-x4-tool Using a Lidar sensor with Python

Installing the Python package

To use the Lidar sensor with Python, we use the PyLidar3 library.

python -m pip install Pylidar3

 

Lidar test script

To check Pylidar installation, you can use the following script, which simply displays the device information.

import PyLidar3
port = "COM3" #input("Enter port name which lidar is connected:") #windows
Obj = PyLidar3.YdLidarX4(port)
print("connecting to {}".format(port))

ret = Obj.Connect()
if(1): 
	print(ret)
	print("device info: ",Obj.GetDeviceInfo())
	Obj.Disconnect()
else:
	print("Error connecting to device")

Scan result display

For our first mapping, we’ll initialize the PyLidar3 object and connect to the device.

Obj = PyLidar3.YdLidarX4(port)
ret = Obj.Connect()

Next, we’ll define a few scan parameters:

  • scan duration scanDuration
  • data threshold to be recorded dataThr
  • winLim window limit

Finally, we’ll launch the lidar measurement and display the acquisition with matplotlib

import PyLidar3
import matplotlib.pyplot as plt
import math
import time

#init lidar
port =  "COM3" #input("Enter port name which lidar is connected:") #windows
Obj = PyLidar3.YdLidarX4(port) #PyLidar3.your_version_of_lidar(port,chunk_size)

ret = Obj.Connect()
print(ret)
#ret = Obj.Connect()
#print(ret)

#parameters
scanDuration = 30 #scan for 30 seconds
dataThr = 1000 # disgard data below this value
winLim = 5000 # window limit in X and Y

#init data list on 360deg
x=[]
y=[]
for _ in range(360):
	x.append(0)
	y.append(0)

if(1):
	deviceInfo = Obj.GetDeviceInfo()
	print("device info : ",deviceInfo)
	
	gen = Obj.StartScanning()
	t = time.time() # start time
	while (time.time() - t) < scanDuration:
		data = next(gen)
		for angle in range(0,360):
			if(data[angle]>dataThr):
				#x[angle] = data[angle] * math.cos(math.radians(angle))
				#y[angle] = data[angle] * math.sin(math.radians(angle))
				x[angle] = (x[angle] + data[angle] * math.cos(math.radians(angle))) / 2
				y[angle] = (y[angle] + data[angle] * math.sin(math.radians(angle))) / 2
				
		plt.clf()
		plt.axis([-winLim,winLim,-winLim,winLim])
		plt.title("Model: X4 Firmware: {} Hardware: {} SN: {}".format(deviceInfo['firmware_version'], deviceInfo['hardware_version'],deviceInfo['serial_number']))
		plt.scatter(y, x, c='r', s=8)
		plt.draw()
		plt.pause(0.1)

	Obj.StopScanning()
	Obj.Disconnect()
else:
	print("Error connecting to device")

plt.show()

 

Results

Once the script has run, we can see the mapping process in action and the map updating in real time.

lidar-x4-pylidar3-test Using a Lidar sensor with Python

Lidar management with threading

It is possible to manage the measurement in a different process from the display, for greater fluidity. As an example, we use the threading library. We’ll create a scan() data acquisition function, which we’ll then place in a thread.

threading.Thread(target=scan).start()

 

In this way, we can process the mapping data without disrupting the acquisition of the measurement.

import PyLidar3 
import matplotlib.pyplot as plt
import math
import time
import numpy as np
import threading


#init lidar
port =  "COM3" #input("Enter port name which lidar is connected:") #windows
Obj = PyLidar3.YdLidarX4(port) #PyLidar3.your_version_of_lidar(port,chunk_size)

ret = Obj.Connect()
print(ret)
#ret = Obj.Connect()
#print(ret)

#parameters
scanDuration = 30 #scan for 30 seconds
dataThr = 1000 # disgard data below this value
winLim = 5000 # window limit in X and Y
buffnum = 1 # matrix size to average position

#init data list on 360deg
x = np.zeros((buffnum, 360))
y = np.zeros((buffnum, 360))

def scan():
	nb=0
	while is_scanning:
		data = next(gen)
		if nb>=buffnum-1:
			nb=0
		else:
			nb+=1

		for angle in range(0,360):
			if(data[angle]>dataThr):
				x[nb][angle] = data[angle] * math.cos(math.radians(angle))
				y[nb][angle] = data[angle] * math.sin(math.radians(angle))
		

if(1):
	deviceInfo = Obj.GetDeviceInfo()
	print("device info : ",deviceInfo)
	
	gen = Obj.StartScanning()
	t = time.time() # start time
	is_scanning = True
	threading.Thread(target=scan).start()
	while (time.time() - t) < scanDuration:
		xmean = np.mean(x, axis=0)
		ymean = np.mean(y, axis=0)
		plt.clf()
		plt.axis([-winLim,winLim,-winLim,winLim])
		plt.title("Model: X4 Firmware: {} Hardware: {} SN: {}".format(deviceInfo['firmware_version'], deviceInfo['hardware_version'],deviceInfo['serial_number']))
		#plt.scatter(y,x,c='r',s=8)
		plt.scatter(ymean,xmean,c='r',s=8)
		plt.draw()
		plt.pause(0.05)
		
	is_scanning = False
	Obj.StopScanning()
	Obj.Disconnect()
else:
	print("Error connecting to device")

plt.show() #keep figure open at the end

Application

Sources