In mobile-robot exploration, the robot has to select its next navigational goals autonomously. In exploration, the goal selection show follows information-rich regions of interest. The existing solution is to use the so-called free edges (border between the free and unknown parts of the map) that are called frontiers. The main task is to implement a function to find the free-edge cells and cluster them to obtain a list of free-edge representatives from which the next navigational goals for exploration can be selected.
Files | Frontiers.py - File to be implemented utils.py - Helpers for evaluation, drawing, and saving figures data - Scenarios and reference solutions in pkl files t1e-frontiers.py - Evaluation script |
Resources | redcp.zip, t1e-frontiers.zip - Initial files and evaluation script |
Frontiers.find_free_edge_frontiers_representatives()
in Frontiers.py
,
Mapper.update_free()
in Mapper.py
,
Map.update_occupied()
in Mapper.py
.
In Frontiers.py
, implement the find_free_edge_frontiers_representatives()
function to find the representatives of free-edge frontiers that are centroids of the cells at the border between the free and unknown cells.
A free-edge cell is a free cell that neighborhoods with at least one unknown cell.
Free-edges are sets of free-edge cells connected into the connected component (8-neighborhood, a.k.a. 2 jumps connected component, is considered).
The considered representatives of the free-edge frontiers are centroids of the segmented free edges.
The input parameter of the function is:
grid_map
- OccupancyGrid - grid map (possibly after obstacle growing to ensure the robot can reach the frontiers; however, it still needs to have unknown cells.The function returns:
None
- if there are no representatives determined.
The find_free_edge_frontiers_representatives()
function in the Frontiers.py
class has the following prescription.
def find_free_edge_frontiers_representatives(self, grid_map): """Method to find the representatives of free-edge frontiers (edge clusters between the free and unknown areas) Args: grid_map: OccupancyGrid - grid map of the environment Returns: pose_list: Pose[] - list of the representatives of the free edges """
There are several ways how to accomplish the determination of the frontier-based navigational goals for the exploration.
The recommended approach for detecting representatives of the free-edge frontiers consists of the following three steps. - Detection of free-edge cells; - Connecting free edges into the connected components; - Calculation of the free-edge centroids.
The individual steps are detailed in the rest of the presented description.
First, the detection of the free-edge cells is performed. The free-edge cell $m_i$ is a free cell that is incident with an unknown cell. Even though we can initialize the occupancy grid with 0.5 for the unknown state of the cell, we can further threshold occupancy probability to be free for the threshold less or equal $CELL\_FREE = 0.4$ and occupied for the threshold above or equal $CELL\_OCC = 0.6$. Thus, a cell is a free-edge cell if the following holds.
An efficient approach to free-cell detection is using the 2D convolution with subsequent thresholding. The task is to find a 2D convolution mask to distinguish between the different constitutions of cell 8-neighborhood consisting of free, unknown, and occupied cells.Hint
The 2D convolution itself can be done using the scipy.ndimage
library using the following code:
import scipy.ndimage as ndimg data_c = ndimg.convolve(data, mask, mode='constant', cval=0.0)Generally, the expected output is a grid with
1
wherever the free-edge cell is and 0
elsewhere.
An example of the convolution result and subsequent thresholding to obtain the free cells is visualized in the following figure.
The second step is to perform the connected component analysis on the free-edge cells. For inspiration, you can see an explanatory overview connected component analysis. The main idea is to connect the free-edge cells that coincide with the connected component to effectively reduce the number of frontiers and select only the representatives of the whole cluster.
For the connectivity analysis, you can use the following code:
import skimage.measure as skm labeled_image, num_labels = skm.label(free_cells, connectivity=2, return_num=True)An example of the connected free-edge clusters is visualized in the following figure, with free-edge centroids marked by red points.
Finally, obtaining the cluster centroids as the mean of $x, y$ coordinates of connected free-edge is necessary.
The code can be evaluated using the script t1e-frontiers.py
).
frontiers = Frontiers() dataset = pickle.load( open( "data/frontier_detection_eval.pkl", "rb" ) ) reference_frontiers = pickle.load( open( "data/frontier_reference.pkl", "rb" ) ) for idx, gridmap in enumerate(dataset): print("Process scenario %2d" % idx) goal_locations_ref = reference_frontiers[idx] #load the reference result if goal_locations_ref is None: print("WARN: Reference goal locations None!") break goal_locations = frontiers.find_free_edge_frontiers_representatives(gridmap) #find free edges if goal_locations is None: print("WARN: Goal locations None!") break # compare goal_locations with goal_locations_ref