Skip to content

Commit 95db633

Browse files
authored
Merge pull request #1 from MapaRobo/path_planner_algorithm
Path planner algorithm Implementation
2 parents ae79feb + 7cf3594 commit 95db633

File tree

6 files changed

+232
-74
lines changed

6 files changed

+232
-74
lines changed

include/full_coverage_path_planner/common.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,15 @@ enum
6161
eNodeVisited = true
6262
};
6363

64+
enum
65+
{
66+
point = 0,
67+
east = 1,
68+
west = 2,
69+
north = 3,
70+
south = 4
71+
};
72+
6473
/**
6574
* Find the distance from poi to the closest point in goals
6675
* @param poi Starting point
@@ -124,4 +133,23 @@ void printGrid(std::vector<std::vector<bool> > const& grid);
124133
* @return a list of points that have the given value_to_search
125134
*/
126135
std::list<Point_t> map_2_goals(std::vector<std::vector<bool> > const& grid, bool value_to_search);
136+
137+
/**
138+
* Prints pathNodes in the terminal
139+
*/
140+
void printPathNodes(std::list<gridNode_t> pathNodes);
141+
142+
/**
143+
* returns true only if the desired move is valid
144+
*/
145+
bool validMove(int x2, int y2, int nCols, int nRows,
146+
std::vector<std::vector<bool> > const& grid,
147+
std::vector<std::vector<bool> > const& visited);
148+
149+
/**
150+
* Adds node in (x2, y2) into the list of pathNodes, and marks the node as visited
151+
*/
152+
bool addNodeToList(int x2, int y2, gridNode_t prev, std::list<gridNode_t> pathNodes,
153+
std::vector<std::vector<bool>>& visited);
154+
127155
#endif // FULL_COVERAGE_PATH_PLANNER_COMMON_H

maps/square.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
image: square.png
2+
resolution: 0.05
3+
origin: [-5, -5, 0.0]
4+
negate: 0
5+
occupied_thresh: 0.65
6+
free_thresh: 0.196

src/common.cpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,3 +309,36 @@ std::list<Point_t> map_2_goals(std::vector<std::vector<bool> > const& grid, bool
309309
}
310310
return goals;
311311
}
312+
313+
314+
void printPathNodes(std::list<gridNode_t> pathNodes)
315+
{
316+
for (gridNode_t node : pathNodes) {
317+
std::cout << "(" << node.pos.x << ", " << node.pos.y << ")" << ": " << node.cost << " " << node.he << std::endl;
318+
}
319+
std:: cout << "--------------------------------------" << std::endl;
320+
321+
}
322+
323+
bool validMove(int x2, int y2, int nCols, int nRows,
324+
std::vector<std::vector<bool>> const& grid,
325+
std::vector<std::vector<bool>> const& visited)
326+
{
327+
return (x2 >= 0 && x2 < nCols && y2 >= 0 && y2 < nRows) // path node is within the map
328+
&& (grid[y2][x2] == eNodeOpen && visited[y2][x2] == eNodeOpen); // the path node is unvisited
329+
}
330+
331+
void addNodeToList(int x2, int y2, gridNode_t prev, std::list<gridNode_t>& pathNodes,
332+
std::vector<std::vector<bool>>& visited) {
333+
Point_t new_point = { x2, y2 };
334+
gridNode_t new_node =
335+
{
336+
new_point, // Point: x,y
337+
0, // Cost
338+
0, // Heuristic
339+
};
340+
prev = pathNodes.back();
341+
pathNodes.push_back(new_node);
342+
visited[y2][x2] = eNodeVisited; // Close node
343+
}
344+

src/spiral_stc.cpp

Lines changed: 162 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -40,64 +40,167 @@ void SpiralSTC::initialize(std::string name, costmap_2d::Costmap2DROS* costmap_r
4040
std::list<gridNode_t> SpiralSTC::spiral(std::vector<std::vector<bool> > const& grid, std::list<gridNode_t>& init,
4141
std::vector<std::vector<bool> >& visited)
4242
{
43-
int dx, dy, dx_prev, x2, y2, i, nRows = grid.size(), nCols = grid[0].size();
44-
// Spiral filling of the open space
43+
int dx, dy, x2, y2, i, nRows = grid.size(), nCols = grid[0].size();
44+
// Mountain pattern filling of the open space
4545
// Copy incoming list to 'end'
46-
std::list<gridNode_t> pathNodes(init);
47-
// Create iterator for gridNode_t list and let it point to the last element of end
48-
std::list<gridNode_t>::iterator it = --(pathNodes.end());
49-
if (pathNodes.size() > 1) // if list is length 1, keep iterator at end
50-
it--; // Let iterator point to second to last element
46+
std::list<gridNode_t> pathNodes(init);
47+
48+
// set initial direction towards longest side
49+
int robot_dir = point;
50+
int pattern_dir = point;
51+
if (nRows >= nCols) {
52+
if (pathNodes.back().pos.y < nRows / 2) {
53+
robot_dir = north;
54+
dy = 1;
55+
}
56+
else {
57+
robot_dir = south;
58+
dy = -1;
59+
}
60+
} else {
61+
if (pathNodes.back().pos.x < nCols / 2) {
62+
robot_dir = east;
63+
dx = 1;
64+
}
65+
else {
66+
robot_dir = west;
67+
dx = -1;
68+
}
69+
}
5170

52-
gridNode_t prev = *(it);
5371
bool done = false;
5472
while (!done)
5573
{
56-
if (it != pathNodes.begin())
57-
{
58-
// turn ccw
59-
dx = pathNodes.back().pos.x - prev.pos.x;
60-
dy = pathNodes.back().pos.y - prev.pos.y;
61-
dx_prev = dx;
62-
dx = -dy;
63-
dy = dx_prev;
64-
}
65-
else
66-
{
67-
// Initialize spiral direction towards y-axis
68-
dx = 0;
69-
dy = 1;
70-
}
71-
done = true;
72-
73-
for (int i = 0; i < 4; ++i)
74-
{
74+
// 1. drive straight until hit wall
75+
bool hitWall = false;
76+
while(!hitWall) {
7577
x2 = pathNodes.back().pos.x + dx;
7678
y2 = pathNodes.back().pos.y + dy;
77-
if (x2 >= 0 && x2 < nCols && y2 >= 0 && y2 < nRows)
79+
if (!validMove(x2, y2, nCols, nRows, grid, visited))
7880
{
79-
if (grid[y2][x2] == eNodeOpen && visited[y2][x2] == eNodeOpen)
80-
{
81+
hitWall = true;
82+
x2 = pathNodes.back().pos.x;
83+
y2 = pathNodes.back().pos.y;
84+
break;
85+
}
86+
if (!hitWall) {
8187
Point_t new_point = { x2, y2 };
8288
gridNode_t new_node =
8389
{
8490
new_point, // Point: x,y
8591
0, // Cost
8692
0, // Heuristic
8793
};
88-
prev = pathNodes.back();
8994
pathNodes.push_back(new_node);
90-
it = --(pathNodes.end());
9195
visited[y2][x2] = eNodeVisited; // Close node
92-
done = false;
93-
break;
96+
}
97+
}
98+
99+
// 2. check left and right after hitting wall, then change direction
100+
if (robot_dir == north || robot_dir == south)
101+
{
102+
if (!validMove(x2 + 1, y2, nCols, nRows, grid, visited)
103+
&& !validMove(x2 - 1, y2, nCols, nRows, grid, visited)) {
104+
// dead end, exit
105+
done = true;
106+
break;
107+
} else if (!validMove(x2 + 1, y2, nCols, nRows, grid, visited)) {
108+
// east is occupied, travel towards west
109+
x2--;
110+
pattern_dir = west;
111+
} else if (!validMove(x2 - 1, y2, nCols, nRows, grid, visited)) {
112+
// west is occupied, travel towards east
113+
x2++;
114+
pattern_dir = east;
115+
} else {
116+
// both sides are opened. If don't have a prefered turn direction, travel towards farthest edge
117+
if (!(pattern_dir == east || pattern_dir == west)) {
118+
if (x2 < nCols / 2) { // east
119+
pattern_dir = east;
120+
} else { // west
121+
pattern_dir = west;
122+
}
123+
}
124+
if (pattern_dir = east) {
125+
x2++;
126+
} else if (pattern_dir = west) {
127+
x2--;
94128
}
95129
}
96-
// try next direction cw
97-
dx_prev = dx;
98-
dx = dy;
99-
dy = -dx_prev;
130+
131+
// add Nodes to List
132+
Point_t new_point = { x2, y2 };
133+
gridNode_t new_node =
134+
{
135+
new_point, // Point: x,y
136+
0, // Cost
137+
0, // Heuristic
138+
};
139+
pathNodes.push_back(new_node);
140+
visited[y2][x2] = eNodeVisited; // Close node
141+
142+
// change direction 180 deg
143+
if (robot_dir == north) {
144+
robot_dir = south;
145+
dy = -1;
146+
} else if (robot_dir == south) {
147+
robot_dir = north;
148+
dy = 1;
149+
}
100150
}
151+
else if (robot_dir == east || robot_dir == west)
152+
{
153+
if (!validMove(x2, y2 + 1, nCols, nRows, grid, visited)
154+
&& !validMove(x2, y2 - 1, nCols, nRows, grid, visited)) {
155+
// dead end, exit
156+
done = true;
157+
break;
158+
} else if (!validMove(x2, y2 + 1, nCols, nRows, grid, visited)) {
159+
// north is occupied, travel towards south
160+
y2--;
161+
pattern_dir = south;
162+
} else if (!validMove(x2, y2 - 1, nCols, nRows, grid, visited)) {
163+
// south is occupied, travel towards north
164+
y2++;
165+
pattern_dir = north;
166+
} else {
167+
// both sides are opened. If don't have a prefered turn direction, travel towards farthest edge
168+
if (!(pattern_dir == north || pattern_dir == south)) {
169+
if (y2 < nRows / 2) { // north
170+
pattern_dir = north;
171+
} else { // south
172+
pattern_dir = south;
173+
}
174+
}
175+
if (pattern_dir = north) {
176+
y2++;
177+
} else if (pattern_dir = south) {
178+
y2--;
179+
}
180+
}
181+
182+
// add Nodes to List
183+
Point_t new_point = { x2, y2 };
184+
gridNode_t new_node =
185+
{
186+
new_point, // Point: x,y
187+
0, // Cost
188+
0, // Heuristic
189+
};
190+
pathNodes.push_back(new_node);
191+
visited[y2][x2] = eNodeVisited; // Close node
192+
193+
// change direction 180 deg
194+
if (robot_dir == east) {
195+
robot_dir = west;
196+
dx = -1;
197+
} else if (robot_dir == west) {
198+
robot_dir = east;
199+
dx = 1;
200+
}
201+
}
202+
// Log
203+
printPathNodes(pathNodes);
101204
}
102205
return pathNodes;
103206
}
@@ -117,6 +220,7 @@ std::list<Point_t> SpiralSTC::spiral_stc(std::vector<std::vector<bool> > const&
117220
x = init.x;
118221
y = init.y;
119222

223+
// add initial point to pathNodes
120224
Point_t new_point = { x, y };
121225
gridNode_t new_node =
122226
{
@@ -129,31 +233,34 @@ std::list<Point_t> SpiralSTC::spiral_stc(std::vector<std::vector<bool> > const&
129233
pathNodes.push_back(new_node);
130234
visited[y][x] = eNodeVisited;
131235

236+
std::list<Point_t> goals = map_2_goals(visited, eNodeOpen); // Retrieve all goalpoints (Cells not visited)
237+
std::list<gridNode_t>::iterator it;
238+
132239
#ifdef DEBUG_PLOT
133240
ROS_INFO("Grid before walking is: ");
134241
printGrid(grid, visited, fullPath);
135242
#endif
136243

137-
pathNodes = SpiralSTC::spiral(grid, pathNodes, visited); // First spiral fill
138-
std::list<Point_t> goals = map_2_goals(visited, eNodeOpen); // Retrieve remaining goalpoints
139-
// Add points to full path
140-
std::list<gridNode_t>::iterator it;
141-
for (it = pathNodes.begin(); it != pathNodes.end(); ++it)
244+
while (goals.size() != 0)
142245
{
143-
Point_t newPoint = { it->pos.x, it->pos.y };
144-
visited_counter++;
145-
fullPath.push_back(newPoint);
146-
}
147-
// Remove all elements from pathNodes list except last element
148-
pathNodes.erase(pathNodes.begin(), --(pathNodes.end()));
246+
// Spiral fill from current position
247+
// TODO: Convert to U-turn pattern
248+
pathNodes = spiral(grid, pathNodes, visited);
149249

150250
#ifdef DEBUG_PLOT
151-
ROS_INFO("Current grid after first spiral is");
152-
printGrid(grid, visited, fullPath);
153-
ROS_INFO("There are %d goals remaining", goals.size());
251+
ROS_INFO("Visited grid updated after spiral:");
252+
printGrid(grid, visited, pathNodes, SpiralStart, pathNodes.back());
154253
#endif
155-
while (goals.size() != 0)
156-
{
254+
255+
goals = map_2_goals(visited, eNodeOpen); // Retrieve remaining goalpoints
256+
257+
for (it = pathNodes.begin(); it != pathNodes.end(); ++it)
258+
{
259+
Point_t newPoint = { it->pos.x, it->pos.y };
260+
visited_counter++;
261+
fullPath.push_back(newPoint);
262+
}
263+
157264
// Remove all elements from pathNodes list except last element.
158265
// The last point is the starting point for a new search and A* extends the path from there on
159266
pathNodes.erase(pathNodes.begin(), --(pathNodes.end()));
@@ -189,23 +296,7 @@ std::list<Point_t> SpiralSTC::spiral_stc(std::vector<std::vector<bool> > const&
189296
gridNode_t SpiralStart = pathNodes.back();
190297
printGrid(grid, visited, pathNodes, pathNodes.front(), pathNodes.back());
191298
#endif
192-
193-
// Spiral fill from current position
194-
pathNodes = spiral(grid, pathNodes, visited);
195-
196-
#ifdef DEBUG_PLOT
197-
ROS_INFO("Visited grid updated after spiral:");
198-
printGrid(grid, visited, pathNodes, SpiralStart, pathNodes.back());
199-
#endif
200-
201-
goals = map_2_goals(visited, eNodeOpen); // Retrieve remaining goalpoints
202-
203-
for (it = pathNodes.begin(); it != pathNodes.end(); ++it)
204-
{
205-
Point_t newPoint = { it->pos.x, it->pos.y };
206-
visited_counter++;
207-
fullPath.push_back(newPoint);
208-
}
299+
209300
}
210301

211302
return fullPath;

test/full_coverage_path_planner/test_full_coverage_path_planner.launch

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
<?xml version="1.0"?>
22

33
<launch>
4-
<arg name="map" default="$(find full_coverage_path_planner)/maps/grid.yaml"/>
4+
<arg name="map" default="$(find full_coverage_path_planner)/maps/square.yaml"/>
55
<arg name="coverage_area_offset" default="-2.5 -2.5 0 0 0 0"/>
66
<arg name="coverage_area_size_x" default="10"/>
77
<arg name="coverage_area_size_y" default="10"/>
88
<arg name="target_x_vel" default="0.5"/>
99
<arg name="target_yaw_vel" default="0.4"/>
1010
<arg name="robot_radius" default="0.3"/>
11-
<arg name="tool_radius" default="0.3"/>
11+
<arg name="tool_radius" default="0.2"/>
1212
<arg name="rviz" default="true"/>
1313

1414
<!--Move base flex, using the full_coverage_path_planner-->

test/full_coverage_path_planner/test_full_coverage_path_planner_plugin.launch

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<?xml version="1.0"?>
22

33
<launch>
4-
<arg name="map" default="$(find full_coverage_path_planner)/maps/grid.yaml"/>
4+
<arg name="map" default="$(find full_coverage_path_planner)/maps/square.yaml"/>
55
<arg name="robot_radius" default="0.3"/>
66
<arg name="tool_radius" default="0.2"/>
77

0 commit comments

Comments
 (0)