This repository contains a Python-based simulator for a 2‑D lidar sensor operating in a square environment populated with randomly placed obstacles (rocks). The core components are:
The design separates the scan generation, GUI, and processing into different threads/processes so that the simulator can run at full speed while still maintaining a responsive user interface, or can connect to a real lidar system via websocket or com port (alpha, may not work).
This was developed for application in the NASA Lunabotics Competition where Lidar can be used within a bounded arena, but any scan of the walls must be systematically removed from the data so that only obstacle data is used for localization.
The code is written for Python 3 and has the following third‑party dependencies:
guizero– simple GUI toolkit used for visualizing the environment and scans.pyserial– required byRealIntegrationwhen reading from a serial port.
These packages can be installed with pip:
pip install guizero pyserialIf you only intend to run the simulator (Main.py), pyserial is not
required.
The entry point is Main.py. Execute it with Python to launch a window that
shows the environment and lidar scans:
python Main.pyThe default configuration creates a 30‑foot field, a robot at the center, and
15 randomly placed rocks. You can customize parameters by editing Main.py
or by constructing a Sim.LidarSim instance in your own script.
While the GUI is open you can use the arrow keys to move the robot and A/
D to rotate it and the arrow keys to navigate. A sidebar allows you to change the view mode (Robot,
Absolute, Processed) and tweak scale settings.
The RealIntegration.RealLidar class connects to a scan source over serial
(pyserial) and visualises the incoming points with the same GUI used by the
simulator. To use it, uncomment and modify the example lines in Main.py.
Alternatively, SocketIntegration.WIFIRealLidar can read data from a TCP
server; it takes an IP address and port number.
Both classes take optional Processor, ShowGui, GuiScale, and SideSize
arguments. The processor must implement the same interface as
DigitalProcessing.LidarDataProcessor.
The DigitalProcessing module contains algorithms for detecting and
discarding scan points that correspond to the borders of the environment or
other linear features. The default behavior is invoked automatically by the
simulation and real‑data wrappers; no manual steps are required.
The algorithm I developed to determine if the points are a wall or obstacle in the arena started by trying to determine if the cluster in the area of insert mapped onto a parabola or a line using linear and quadratic regression. This fundamentally assumes the obstacles are always quadratic, round, convex objects, and the area borders are always lines.
Trying to improve this, I switched to the assumptions the robot is always inside the borders and can generally see all sides of the arena. From this we can assume the walls a near the convex hull of all of the data points, with the obstacles being further inside. This generally works in this simulation for a bounded area lidar but is obviously flawed for general purpose lidar.
- The code uses Python's
multiprocessingandthreadingmodules to split the workload. LidarSimspawns worker processes that callEnvironment.ScanLidarfor a slice of the full 360° scan and then aggregates the results.- Additional processing logic can be added to
DigitalProcessingor by supplying a customProcessorobject and updatingSim.py'sProcessThread.
For questions or enhancements, review the individual module docstrings and comments.


