Skip to content

Commit 6fed446

Browse files
committed
Fix infinite loop error and improved heading decision of path planning algorithm
1 parent 174ea81 commit 6fed446

File tree

5 files changed

+213
-117
lines changed

5 files changed

+213
-117
lines changed

include/full_coverage_path_planner/common.h

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,11 +136,18 @@ std::list<Point_t> map_2_goals(std::vector<std::vector<bool> > const& grid, bool
136136

137137
/**
138138
* Prints pathNodes in the terminal
139+
* @param pathNodes pathNodes to be printed in the terminal
139140
*/
140141
void printPathNodes(std::list<gridNode_t> pathNodes);
141142

142143
/**
143144
* returns true only if the desired move is valid
145+
* @param x2 x coordinate of desired position
146+
* @param y2 y coordinate of desired position
147+
* @param nCols
148+
* @param nRows
149+
* @param grid internal map representation - 2D grid of bools. true == occupied/blocked/obstacle
150+
* @param visited 2D grid of bools. true == visited
144151
*/
145152
bool validMove(int x2, int y2, int nCols, int nRows,
146153
std::vector<std::vector<bool> > const& grid,
@@ -149,7 +156,16 @@ bool validMove(int x2, int y2, int nCols, int nRows,
149156
/**
150157
* Adds node in (x2, y2) into the list of pathNodes, and marks the node as visited
151158
*/
152-
bool addNodeToList(int x2, int y2, gridNode_t prev, std::list<gridNode_t> pathNodes,
159+
void addNodeToList(int x2, int y2, std::list<gridNode_t>& pathNodes,
153160
std::vector<std::vector<bool>>& visited);
154161

162+
/**
163+
* Returns direction in which most free space is visible when given the robot's current location
164+
* @param ignoreDir ignores a single direction specified. Pass 0 (point) to consider all four directions.
165+
*/
166+
int dirWithMostSpace(int x2, int y2, int nCols, int nRows,
167+
std::vector<std::vector<bool> > const& grid,
168+
std::vector<std::vector<bool> > const& visited,
169+
int ignoreDir);
170+
155171
#endif // FULL_COVERAGE_PATH_PLANNER_COMMON_H

include/full_coverage_path_planner/full_coverage_path_planner.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,22 @@ class FullCoveragePathPlanner
8585
void parsePointlist2Plan(const geometry_msgs::PoseStamped& start, std::list<Point_t> const& goalpoints,
8686
std::vector<geometry_msgs::PoseStamped>& plan);
8787

88+
/**
89+
* Convert ROS Occupancy grid to internal grid representation, given the size of a single tile
90+
* @param costmap_grid_ Costmap representation. Cells higher that 65 are considered occupied
91+
* @param grid internal map representation
92+
* @param tileSize size (in meters) of a cell. This can be the robot's size
93+
* @param realStart Start position of the robot (in meters)
94+
* @param scaledStart Start position of the robot on the grid
95+
* @return success
96+
*/
97+
bool parseCostmap(costmap_2d::Costmap2D* costmap_grid_,
98+
std::vector<std::vector<bool> >& grid,
99+
float robotRadius,
100+
float toolRadius,
101+
geometry_msgs::PoseStamped const& realStart,
102+
Point_t& scaledStart);
103+
88104
/**
89105
* Convert ROS Occupancy grid to internal grid representation, given the size of a single tile
90106
* @param cpp_grid_ ROS occupancy grid representation. Cells higher that 65 are considered occupied
@@ -103,6 +119,9 @@ class FullCoveragePathPlanner
103119
ros::Publisher plan_pub_;
104120
ros::ServiceClient cpp_grid_client_;
105121
nav_msgs::OccupancyGrid cpp_grid_;
122+
// Using costmap instead of Occupancy Grid from map server as the costmap updates periodically.
123+
costmap_2d::Costmap2DROS* costmap_ros_;
124+
costmap_2d::Costmap2D* costmap_;
106125
float robot_radius_;
107126
float tool_radius_;
108127
float plan_resolution_;

src/common.cpp

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -328,7 +328,7 @@ bool validMove(int x2, int y2, int nCols, int nRows,
328328
&& (grid[y2][x2] == eNodeOpen && visited[y2][x2] == eNodeOpen); // the path node is unvisited
329329
}
330330

331-
void addNodeToList(int x2, int y2, gridNode_t prev, std::list<gridNode_t>& pathNodes,
331+
void addNodeToList(int x2, int y2, std::list<gridNode_t>& pathNodes,
332332
std::vector<std::vector<bool>>& visited) {
333333
Point_t new_point = { x2, y2 };
334334
gridNode_t new_node =
@@ -337,8 +337,52 @@ void addNodeToList(int x2, int y2, gridNode_t prev, std::list<gridNode_t>& pathN
337337
0, // Cost
338338
0, // Heuristic
339339
};
340-
prev = pathNodes.back();
341340
pathNodes.push_back(new_node);
342341
visited[y2][x2] = eNodeVisited; // Close node
342+
return;
343343
}
344344

345+
int dirWithMostSpace(int x_init, int y_init, int nCols, int nRows,
346+
std::vector<std::vector<bool> > const& grid,
347+
std::vector<std::vector<bool> > const& visited,
348+
int ignoreDir) {
349+
// this array stores how far the robot can travel in a straight line for each direction
350+
int free_space_in_dir[5] = {0};
351+
// for each direction
352+
for (int i = 1; i < 5; i++) {
353+
// start from starting pos
354+
int x2 = x_init;
355+
int y2 = y_init;
356+
do { // loop until hit wall
357+
switch (i) {
358+
case east:
359+
x2++;
360+
break;
361+
case west:
362+
x2--;
363+
break;
364+
case north:
365+
y2++;
366+
break;
367+
case south:
368+
y2--;
369+
break;
370+
default:
371+
break;
372+
}
373+
free_space_in_dir[i]++;
374+
} while (validMove(x2, y2, nCols, nRows, grid, visited));
375+
}
376+
377+
// set initial direction towards direction with most travel possible
378+
int robot_dir = 0;
379+
int indexValue = 0;
380+
for (int i = 1; i <= 4; i++) {
381+
// std::cout << "free space in " << i << ": " << free_space_in_dir[i] << std::endl;
382+
if (free_space_in_dir[i] > indexValue && i != ignoreDir) {
383+
robot_dir = i;
384+
indexValue = free_space_in_dir[i];
385+
}
386+
}
387+
return robot_dir;
388+
}

src/full_coverage_path_planner.cpp

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,67 @@ void FullCoveragePathPlanner::parsePointlist2Plan(const geometry_msgs::PoseStamp
185185
ROS_INFO("Plan ready containing %lu goals!", plan.size());
186186
}
187187

188+
bool FullCoveragePathPlanner::parseCostmap(costmap_2d::Costmap2D* costmap_grid_,
189+
std::vector<std::vector<bool> >& grid,
190+
float robotRadius,
191+
float toolRadius,
192+
geometry_msgs::PoseStamped const& realStart,
193+
Point_t& scaledStart)
194+
{
195+
int ix, iy, nodeRow, nodeCol;
196+
uint32_t nodeSize = dmax(floor(toolRadius / costmap_grid_->getResolution()), 1); // Size of node in pixels/units
197+
uint32_t nRows = costmap_grid_->getSizeInCellsY(), nCols = costmap_grid_->getSizeInCellsX();
198+
ROS_INFO("nRows: %u nCols: %u nodeSize: %d", nRows, nCols, nodeSize);
199+
200+
if (nRows == 0 || nCols == 0)
201+
{
202+
return false;
203+
}
204+
205+
// Save map origin and scaling
206+
tile_size_ = nodeSize * costmap_grid_->getResolution(); // Size of a tile in meters
207+
grid_origin_.x = costmap_grid_->getOriginX(); // x-origin in meters
208+
grid_origin_.y = costmap_grid_->getOriginY(); // y-origin in meters
209+
ROS_INFO("costmap resolution: %g", costmap_grid_->getResolution());
210+
ROS_INFO("tile size: %g", tile_size_);
211+
ROS_INFO("grid origin: (%g, %g)", grid_origin_.x, grid_origin_.y);
212+
213+
// Scale starting point
214+
scaledStart.x = static_cast<unsigned int>(clamp((realStart.pose.position.x - grid_origin_.x) / tile_size_, 0.0,
215+
floor(nCols / tile_size_)));
216+
scaledStart.y = static_cast<unsigned int>(clamp((realStart.pose.position.y - grid_origin_.y) / tile_size_, 0.0,
217+
floor(nRows / tile_size_)));
218+
ROS_INFO("real start: (%g, %g)", realStart.pose.position.x, realStart.pose.position.y);
219+
ROS_INFO("scaled start: (%u, %u)", scaledStart.x, scaledStart.y);
220+
221+
// Scale grid
222+
for (iy = 0; iy < nRows; iy = iy + nodeSize)
223+
{
224+
std::vector<bool> gridRow;
225+
for (ix = 0; ix < nCols; ix = ix + nodeSize)
226+
{
227+
bool nodeOccupied = false;
228+
for (nodeRow = 0; (nodeRow < nodeSize) && ((iy + nodeRow) < nRows) && (nodeOccupied == false); ++nodeRow)
229+
{
230+
for (nodeCol = 0; (nodeCol < nodeSize) && ((ix + nodeCol) < nCols); ++nodeCol)
231+
{
232+
double mx = grid_origin_.x + ix + nodeCol;
233+
double my = grid_origin_.y + iy + nodeRow;
234+
if (costmap_grid_->getCost(mx, my) > costmap_2d::INSCRIBED_INFLATED_OBSTACLE)
235+
{
236+
nodeOccupied = true;
237+
ROS_INFO("(%f, %f) marked occupied", mx, my);
238+
break;
239+
}
240+
}
241+
}
242+
gridRow.push_back(nodeOccupied);
243+
}
244+
grid.push_back(gridRow);
245+
}
246+
return true;
247+
}
248+
188249
bool FullCoveragePathPlanner::parseGrid(nav_msgs::OccupancyGrid const& cpp_grid_,
189250
std::vector<std::vector<bool> >& grid,
190251
float robotRadius,
@@ -207,12 +268,17 @@ bool FullCoveragePathPlanner::parseGrid(nav_msgs::OccupancyGrid const& cpp_grid_
207268
tile_size_ = nodeSize * cpp_grid_.info.resolution; // Size of a tile in meters
208269
grid_origin_.x = cpp_grid_.info.origin.position.x; // x-origin in meters
209270
grid_origin_.y = cpp_grid_.info.origin.position.y; // y-origin in meters
271+
ROS_INFO("costmap resolution: %g", cpp_grid_.info.resolution);
272+
ROS_INFO("tile size: %g", tile_size_);
273+
ROS_INFO("grid origin: (%g, %g)", grid_origin_.x, grid_origin_.y);
210274

211275
// Scale starting point
212276
scaledStart.x = static_cast<unsigned int>(clamp((realStart.pose.position.x - grid_origin_.x) / tile_size_, 0.0,
213277
floor(cpp_grid_.info.width / tile_size_)));
214278
scaledStart.y = static_cast<unsigned int>(clamp((realStart.pose.position.y - grid_origin_.y) / tile_size_, 0.0,
215279
floor(cpp_grid_.info.height / tile_size_)));
280+
ROS_INFO("real start: (%g, %g)", realStart.pose.position.x, realStart.pose.position.y);
281+
ROS_INFO("scaled start: (%u, %u)", scaledStart.x, scaledStart.y);
216282

217283
// Scale grid
218284
for (iy = 0; iy < nRows; iy = iy + nodeSize)

0 commit comments

Comments
 (0)