4: Modification - Grantham00/rplidar_detection GitHub Wiki

The code in this script has been heavily commented with the goal of being easy to understand. That being said, we didn't know python ourselves when we wrote this. It is written more as a top-to-bottom script MATLAB style than a proper object-oriented program.

Scan Values

Below is a screenshot of the scanvals variable as viewed within the Spyder IDE: scanvals

Scan data is stored as a 2D numpy array. Each row represents one point in the lidar scan. Any additional attributes for the points are added in the form of a new column. The data layout is as follows:

Column 0: Scan intensity - this is the intensity of the reflected laser. The RPLIDAR returns a value of 47 for perfect reflections and a value of 0 for beams that never returned to the sensor. All points with a value of 0 are thrown out in the getScan method.

Column 1: Angle - This is the radial angle at which the RPLIDAR scanned this point. This value ranges from -180 to 180.

Column 2: Range - This is the distance of the point from the sensor to the detected point in milimeters.

Column 3: Segment - This is a calculated value not returned by the sensor. Our segmenting algorithm attempts to distinguish groups of points from each other. Points that share the same value in column 3 belong to the same segment. When scanvals is created, all points are given a value of zero on this column. The segment values are calculated in a later method, segment or splitseg.

Segmentation

Segmentation is an important task in object detection. In order to distinguish features from each other, groups of points must be separated form each other. There are many approaches to this problem, some more appropriate than others depending on what type of features the user wants to detect.

In this script, we take a simplistic approach: given a set of points and a threshold value segthreshold (default 150), we ascend through the scan values and increment the segment number every time the next point is more than 150mm farther or closer to the sensor than the previous point. Observe the relationship between the values in Column 2 (Range) and Column 3 (Segment) in the screenshot above. This segmenting strategy looks as follows:

segthreshold

It does a pretty good job distinguishing features from each other in the room, however it does not do well at separating the walls. This may be important if the feature the user wants to find is the corners of the walls. We could check for corners after the fact, but is there a different segmentation approach that will separate adjacent walls from each other in one go?

Observe lines 66 and 67 in RPLidar_Scan.py. At this point in the script, the point data has been brought and stored in scanvals. Line 66 calls rpl.segment. This is the "threshold" approach described above. However line 67, commented out, calls rpl.splitSeg. Commenting line 67 rpl.segment and Un-commenting rpl.splitSeg will use an alternate segmenting algorithm.

rpl.splitSeg works as follows: instead of determining segments based on change in distance from sensor, we increment the segment based on line 89 of RPLFunctions.py. It works as follows: given the x,y coordinates of each detected point,determined from scanvals, iterate the segment when either:

-The absolute value of the change in x is greater than the absolute value of the change in y.

OR

-The absolute value of the change in y is greater than the absolute value of the change in x.

The results are as follows:

splitSeg

This algorithm does a pretty good job separating adjacent walls from each other! However, it is less good at grouping objects that are not walls. On top of that, the algorithm seems to break down as the angles of the walls approach 45 degrees. Why is that?

We highly encourage you to think of a way to segment lidar points yourself. Pick up a pencil and paper and brainstorm. Consider what type of objects you want to detect. Is a combination of different methods appropriate? Are there edge cases when your method breaks down, and if so is it a big deal? Think of a method, write it, and try it! Comment out lines 66 and 67 of RPLidar_Scan.py and write your own function. The Numpy library for Python captures almost all of MATLAB's functionality for python! Use the Numpy Reference and explore the functions available to you. Important: In order to plug in seamlessly with the rest of the script, your segmenting algorithm must group the values in scanvals together by modifying Column 3 so that points that belong to the same segment share the same value in Column 3.

Object Detection

This script was written with the goal of detecting walls and corners. This is achieved using simple linear regression on the points. We also obtain the r value aka "goodness of fit" to determine how well the line of best fit actually fits. Through testing, we selected an arbitrary threshold beneath which a group of points decidedly does not form a line.

Simple Linear Regression

Big Challenge: What other shapes can you detect? Can you take a segment of points and determine if it forms a circular arc? Code it and test it!

Next: Shortcomings and Lessons Learned