MRPT  1.9.9
PlannerSimple2D.cpp
Go to the documentation of this file.
1 /* +------------------------------------------------------------------------+
2  | Mobile Robot Programming Toolkit (MRPT) |
3  | http://www.mrpt.org/ |
4  | |
5  | Copyright (c) 2005-2018, Individual contributors, see AUTHORS file |
6  | See: http://www.mrpt.org/Authors - All rights reserved. |
7  | Released under BSD License. See details in http://www.mrpt.org/License |
8  +------------------------------------------------------------------------+ */
9 
10 #include "nav-precomp.h" // Precompiled headers
11 
13 
14 using namespace mrpt;
15 using namespace mrpt::maps;
16 using namespace mrpt::math;
17 using namespace mrpt::poses;
18 using namespace mrpt::nav;
19 using namespace std;
20 
21 /*---------------------------------------------------------------
22  Constructor
23  ---------------------------------------------------------------*/
24 PlannerSimple2D::PlannerSimple2D()
25  : occupancyThreshold(0.5f), minStepInReturnedPath(0.4f), robotRadius(0.35f)
26 {
27 }
28 
29 /*---------------------------------------------------------------
30  computePath
31  ---------------------------------------------------------------*/
33  const COccupancyGridMap2D& theMap, const CPose2D& origin_,
34  const CPose2D& target_, std::deque<math::TPoint2D>& path, bool& notFound,
35  float maxSearchPathLength) const
36 {
37 #define CELL_ORIGIN 0x0000
38 #define CELL_EMPTY 0x8000
39 #define CELL_OBSTACLE 0xFFFF
40 #define CELL_TARGET 0xFFFE
41 
42  const TPoint2D origin = TPoint2D(origin_.asTPose());
43  const TPoint2D target = TPoint2D(target_.asTPose());
44 
45  std::vector<uint16_t> grid;
46  int size_x, size_y, i, n, m;
47  int x, y;
48  bool searching;
49  uint16_t minNeigh = CELL_EMPTY, maxNeigh = CELL_EMPTY, v = 0, c;
50  int passCellFound_x = -1, passCellFound_y = -1;
51  std::vector<uint16_t> pathcells_x, pathcells_y;
52 
53  // Check that origin and target falls inside the grid theMap!!
54  // -----------------------------------------------------------
55  ASSERT_(
56  origin.x > theMap.getXMin() && origin.x < theMap.getXMax() &&
57  origin.y > theMap.getYMin() && origin.y < theMap.getYMax());
58  ASSERT_(
59  target.x > theMap.getXMin() && target.x < theMap.getXMax() &&
60  target.y > theMap.getYMin() && target.y < theMap.getYMax());
61 
62  // Check for the special case of origin and target in the same cell:
63  // -----------------------------------------------------------------
64  if (theMap.x2idx(origin.x) == theMap.x2idx(target.x) &&
65  theMap.y2idx(origin.y) == theMap.y2idx(target.y))
66  {
67  path.clear();
68  path.push_back(TPoint2D(target.x, target.y));
69  notFound = false;
70  return;
71  }
72 
73  // Get the grid size:
74  // -----------------------------------------------------------
75  size_x = theMap.getSizeX();
76  size_y = theMap.getSizeY();
77 
78  // Fill the grid content with free-space and obstacles:
79  // -----------------------------------------------------------
80  grid.resize(size_x * size_y);
81  for (y = 0; y < size_y; y++)
82  {
83  int row = y * size_x;
84  for (x = 0; x < size_x; x++)
85  {
86  grid[x + row] = (theMap.getCell(x, y) > occupancyThreshold)
87  ? CELL_EMPTY
88  : CELL_OBSTACLE;
89  }
90  }
91 
92  // Enlarge obstacles with the robot radius:
93  // -----------------------------------------------------------
94  int obsEnlargement = (int)(ceil(robotRadius / theMap.getResolution()));
95  for (int nEnlargements = 0; nEnlargements < obsEnlargement; nEnlargements++)
96  {
97  // int size_y_1 = size_y-1;
98  // int size_x_1 = size_x-1;
99 
100  // For all cells(x,y)=EMPTY:
101  // -----------------------------
102  for (y = 2; y < size_y - 2; y++)
103  {
104  int row = y * size_x;
105  int row_1 = (y + 1) * size_x;
106  int row__1 = (y - 1) * size_x;
107 
108  for (x = 2; x < size_x - 2; x++)
109  {
110  uint16_t val = (CELL_OBSTACLE - nEnlargements);
111 
112  // A cell near an obstacle found??
113  // -----------------------------------------------------
114  if (grid[x - 1 + row__1] >= val || grid[x + row__1] >= val ||
115  grid[x + 1 + row__1] >= val || grid[x - 1 + row] >= val ||
116  grid[x + 1 + row] >= val || grid[x - 1 + row_1] >= val ||
117  grid[x + row_1] >= val || grid[x + 1 + row_1] >= val)
118  {
119  grid[x + row] =
120  max((uint16_t)grid[x + row], (uint16_t)(val - 1));
121  }
122  }
123  }
124  }
125 
126  // Definitevely set new obstacles as obstacles
127  for (y = 1; y < size_y - 1; y++)
128  {
129  int row = y * size_x;
130  for (x = 1; x < size_x - 1; x++)
131  {
132  if (grid[x + row] > CELL_EMPTY) grid[x + row] = CELL_OBSTACLE;
133  }
134  }
135 
136  // Put the special cell codes for the origin and target:
137  // -----------------------------------------------------------
138  grid[theMap.x2idx(origin.x) + size_x * theMap.y2idx(origin.y)] =
139  CELL_ORIGIN;
140  grid[theMap.x2idx(target.x) + size_x * theMap.y2idx(target.y)] =
141  CELL_TARGET;
142 
143  // The main path search loop:
144  // -----------------------------------------------------------
145  searching = true; // Will become false on path found.
146  notFound =
147  false; // Will be set true inside the loop if a path is not found.
148 
149  int range_x_min =
150  min(theMap.x2idx(origin.x) - 1, theMap.x2idx(target.x) - 1);
151  int range_x_max =
152  max(theMap.x2idx(origin.x) + 1, theMap.x2idx(target.x) + 1);
153  int range_y_min =
154  min(theMap.y2idx(origin.y) - 1, theMap.y2idx(target.y) - 1);
155  int range_y_max =
156  max(theMap.y2idx(origin.y) + 1, theMap.y2idx(target.y) + 1);
157 
158  do
159  {
160  notFound = true;
161  bool wave1Found = false, wave2Found = false;
162  int size_y_1 = size_y - 1;
163  int size_x_1 = size_x - 1;
164  int longestPathInCellsMetric = 0;
165 
166  range_x_min = max(1, range_x_min - 1);
167  range_x_max = min(size_x_1, range_x_max + 1);
168  range_y_min = max(1, range_y_min - 1);
169  range_y_max = min(size_y_1, range_y_max + 1);
170 
171  // For all cells(x,y)=EMPTY:
172  // -----------------------------
173  for (y = range_y_min; y < range_y_max && passCellFound_x == -1; y++)
174  {
175  int row = y * size_x;
176  int row_1 = (y + 1) * size_x;
177  int row__1 = (y - 1) * size_x;
178  char metric; // =2 horz.vert, =3 diagonal <-- Since 3/2 ~= sqrt(2)
179 
180  for (x = range_x_min; x < range_x_max; x++)
181  {
182  if (grid[x + row] == CELL_EMPTY)
183  {
184  // Look in the neighboorhood:
185  // -----------------------------
186  minNeigh = maxNeigh = CELL_EMPTY;
187  metric = 2;
188  v = grid[x + row__1];
189  if (v + 2 < minNeigh) minNeigh = v + 2;
190  if (v - 2 > maxNeigh && v != CELL_OBSTACLE)
191  maxNeigh = v - 2;
192  v = grid[x - 1 + row];
193  if (v + 2 < minNeigh) minNeigh = v + 2;
194  if (v - 2 > maxNeigh && v != CELL_OBSTACLE)
195  maxNeigh = v - 2;
196  v = grid[x + 1 + row];
197  if (v + 2 < minNeigh) minNeigh = v + 2;
198  if (v - 2 > maxNeigh && v != CELL_OBSTACLE)
199  maxNeigh = v - 2;
200  v = grid[x + row_1];
201  if (v + 2 < minNeigh) minNeigh = v + 2;
202  if (v - 2 > maxNeigh && v != CELL_OBSTACLE)
203  maxNeigh = v - 2;
204 
205  v = grid[x - 1 + row__1];
206  if ((v + 3) < minNeigh)
207  {
208  metric = 3;
209  minNeigh = (v + 3);
210  }
211  if ((v - 3) > maxNeigh && v != CELL_OBSTACLE)
212  {
213  metric = 3;
214  maxNeigh = v - 3;
215  }
216  v = grid[x + 1 + row__1];
217  if ((v + 3) < minNeigh)
218  {
219  metric = 3;
220  minNeigh = (v + 3);
221  }
222  if ((v - 3) > maxNeigh && v != CELL_OBSTACLE)
223  {
224  metric = 3;
225  maxNeigh = v - 3;
226  }
227  v = grid[x - 1 + row_1];
228  if ((v + 3) < minNeigh)
229  {
230  metric = 3;
231  minNeigh = (v + 3);
232  }
233  if ((v - 3) > maxNeigh && v != CELL_OBSTACLE)
234  {
235  metric = 3;
236  maxNeigh = v - 3;
237  }
238  v = grid[x + 1 + row_1];
239  if ((v + 3) < minNeigh)
240  {
241  metric = 3;
242  minNeigh = (v + 3);
243  }
244  if ((v - 3) > maxNeigh && v != CELL_OBSTACLE)
245  {
246  metric = 3;
247  maxNeigh = v - 3;
248  }
249 
250  // Convergence cell found? = The shortest path found
251  // -----------------------------------------------------
252  if (minNeigh < CELL_EMPTY && maxNeigh > CELL_EMPTY)
253  {
254  // Stop the search:
255  passCellFound_x = x;
256  passCellFound_y = y;
257  searching = false;
258  longestPathInCellsMetric = 0;
259  break;
260  }
261  else if (minNeigh < CELL_EMPTY)
262  {
263  wave1Found = true;
264 
265  // Cell in the expansion-wave from origin
266  grid[x + row] = minNeigh + metric;
267  ASSERT_(minNeigh + metric < CELL_EMPTY);
268 
269  longestPathInCellsMetric = max(
270  longestPathInCellsMetric, CELL_EMPTY - minNeigh);
271  }
272  else if (maxNeigh > CELL_EMPTY)
273  {
274  wave2Found = true;
275 
276  // Cell in the expansion-wave from the target
277  grid[x + row] = maxNeigh - metric;
278  ASSERT_(maxNeigh - metric > CELL_EMPTY);
279 
280  longestPathInCellsMetric = max(
281  longestPathInCellsMetric, maxNeigh - CELL_EMPTY);
282  }
283  else
284  { // Nothing to do: A free cell inside of all also free
285  // cells.
286  }
287  } // if cell empty
288  } // end for x
289  } // end for y
290 
291  notFound = !wave1Found && !wave2Found;
292 
293  // Exceeded the max. desired search length??
294  if (maxSearchPathLength > 0)
295  if (theMap.getResolution() * longestPathInCellsMetric * 0.5f >
296  1.5f * maxSearchPathLength)
297  {
298  // printf_debug("[PlannerSimple2D::computePath]
299  // Path
300  // exceeded desired length! (length=%f m)\n",
301  // theMap.getResolution() * longestPathInCellsMetric * 0.5f);
302  notFound = true;
303  }
304 
305  } while (!notFound && searching);
306 
307  // Path not found:
308  if (notFound) return;
309 
310  // Rebuild the optimal path from the two-waves convergence cell
311  // ----------------------------------------------------------------
312 
313  // STEP 1: Trace-back to origin
314  //-------------------------------------
315  pathcells_x.reserve(
316  (minNeigh + 1) +
317  (CELL_TARGET -
318  maxNeigh)); // An (exact?) estimation of the final vector size:
319  pathcells_y.reserve((minNeigh + 1) + (CELL_TARGET - maxNeigh));
320  x = passCellFound_x;
321  y = passCellFound_y;
322 
323  while ((v = grid[x + size_x * y]) != CELL_ORIGIN)
324  {
325  // Add cell to the path (in inverse order, now we go backward!!) Later
326  // is will be reversed
327  pathcells_x.push_back(x);
328  pathcells_y.push_back(y);
329 
330  // Follow the "negative gradient" toward the origin:
331  static signed char dx = 0, dy = 0;
332  if ((c = grid[x - 1 + size_x * y]) < v)
333  {
334  v = c;
335  dx = -1;
336  dy = 0;
337  }
338  if ((c = grid[x + 1 + size_x * y]) < v)
339  {
340  v = c;
341  dx = 1;
342  dy = 0;
343  }
344  if ((c = grid[x + size_x * (y - 1)]) < v)
345  {
346  v = c;
347  dx = 0;
348  dy = -1;
349  }
350  if ((c = grid[x + size_x * (y + 1)]) < v)
351  {
352  v = c;
353  dx = 0;
354  dy = 1;
355  }
356 
357  if ((c = grid[x - 1 + size_x * (y - 1)]) < v)
358  {
359  v = c;
360  dx = -1;
361  dy = -1;
362  }
363  if ((c = grid[x + 1 + size_x * (y - 1)]) < v)
364  {
365  v = c;
366  dx = 1;
367  dy = -1;
368  }
369  if ((c = grid[x - 1 + size_x * (y + 1)]) < v)
370  {
371  v = c;
372  dx = -1;
373  dy = 1;
374  }
375  if ((c = grid[x + 1 + size_x * (y + 1)]) < v)
376  {
377  v = c;
378  dx = 1;
379  dy = 1;
380  }
381 
382  ASSERT_(dx != 0 || dy != 0);
383  x += dx;
384  y += dy;
385  }
386 
387  // STEP 2: Reverse the path, since we want it from the origin
388  // toward the convergence cell
389  //--------------------------------------------------------------
390  n = pathcells_x.size();
391  m = n / 2;
392  for (i = 0; i < m; i++)
393  {
394  v = pathcells_x[i];
395  pathcells_x[i] = pathcells_x[n - 1 - i];
396  pathcells_x[n - 1 - i] = v;
397 
398  v = pathcells_y[i];
399  pathcells_y[i] = pathcells_y[n - 1 - i];
400  pathcells_y[n - 1 - i] = v;
401  }
402 
403  // STEP 3: Trace-foward toward the target
404  //-------------------------------------
405  x = passCellFound_x;
406  y = passCellFound_y;
407 
408  while ((v = grid[x + size_x * y]) != CELL_TARGET)
409  {
410  // Add cell to the path
411  pathcells_x.push_back(x);
412  pathcells_y.push_back(y);
413 
414  // Follow the "positive gradient" toward the target:
415  static signed char dx = 0, dy = 0;
416  c = grid[x - 1 + size_x * y];
417  if (c > v && c != CELL_OBSTACLE)
418  {
419  v = c;
420  dx = -1;
421  dy = 0;
422  }
423  c = grid[x + 1 + size_x * y];
424  if (c > v && c != CELL_OBSTACLE)
425  {
426  v = c;
427  dx = 1;
428  dy = 0;
429  }
430  c = grid[x + size_x * (y - 1)];
431  if (c > v && c != CELL_OBSTACLE)
432  {
433  v = c;
434  dx = 0;
435  dy = -1;
436  }
437  c = grid[x + size_x * (y + 1)];
438  if (c > v && c != CELL_OBSTACLE)
439  {
440  v = c;
441  dx = 0;
442  dy = 1;
443  }
444 
445  c = grid[x - 1 + size_x * (y - 1)];
446  if (c > v && c != CELL_OBSTACLE)
447  {
448  v = c;
449  dx = -1;
450  dy = -1;
451  }
452  c = grid[x + 1 + size_x * (y - 1)];
453  if (c > v && c != CELL_OBSTACLE)
454  {
455  v = c;
456  dx = 1;
457  dy = -1;
458  }
459  c = grid[x - 1 + size_x * (y + 1)];
460  if (c > v && c != CELL_OBSTACLE)
461  {
462  v = c;
463  dx = -1;
464  dy = 1;
465  }
466  c = grid[x + 1 + size_x * (y + 1)];
467  if (c > v && c != CELL_OBSTACLE)
468  {
469  v = c;
470  dx = 1;
471  dy = 1;
472  }
473 
474  ASSERT_(dx != 0 || dy != 0);
475  x += dx;
476  y += dy;
477  }
478 
479  // STEP 4: Translate the path-of-cells to a path-of-2d-points with
480  // subsampling
481  //-------------------------------------------------------------------------------
482  path.clear();
483  n = pathcells_x.size();
484  float xx, yy;
485  float last_xx = origin.x, last_yy = origin.y;
486  for (i = 0; i < n; i++)
487  {
488  // Get cell coordinates:
489  xx = theMap.idx2x(pathcells_x[i]);
490  yy = theMap.idx2y(pathcells_y[i]);
491 
492  // Enough distance??
493  if (sqrt(square(xx - last_xx) + square(yy - last_yy)) >
495  {
496  // Add to the path:
497  path.push_back(TPoint2D(xx, yy));
498 
499  // For the next iteration:
500  last_xx = xx;
501  last_yy = yy;
502  }
503  }
504 
505  // Add the target point:
506  path.push_back(TPoint2D(target.x, target.y));
507 
508  // That's all!! :-)
509 }
#define CELL_ORIGIN
#define CELL_EMPTY
#define CELL_OBSTACLE
#define CELL_TARGET
A class for storing an occupancy grid map.
float getResolution() const
Returns the resolution of the grid map.
float getYMin() const
Returns the "y" coordinate of top side of grid map.
float idx2y(const size_t cy) const
unsigned int getSizeX() const
Returns the horizontal size of grid map in cells count.
float getCell(int x, int y) const
Read the real valued [0,1] contents of a cell, given its index.
int x2idx(float x) const
Transform a coordinate value into a cell index.
float getXMax() const
Returns the "x" coordinate of right side of grid map.
float getYMax() const
Returns the "y" coordinate of bottom side of grid map.
unsigned int getSizeY() const
Returns the vertical size of grid map in cells count.
float getXMin() const
Returns the "x" coordinate of left side of grid map.
float idx2x(const size_t cx) const
Transform a cell index into a coordinate value.
void computePath(const mrpt::maps::COccupancyGridMap2D &theMap, const mrpt::poses::CPose2D &origin, const mrpt::poses::CPose2D &target, std::deque< mrpt::math::TPoint2D > &path, bool &notFound, float maxSearchPathLength=-1) const
This method compute the optimal path for a circular robot, in the given occupancy grid map,...
float occupancyThreshold
The maximum occupancy probability to consider a cell as an obstacle, default=0.5
float robotRadius
The aproximate robot radius used in the planification.
float minStepInReturnedPath
The minimum distance between points in the returned found path (default=0.4); Notice that full grid r...
A class used to store a 2D pose, including the 2D coordinate point and a heading (phi) angle.
Definition: CPose2D.h:39
mrpt::math::TPose2D asTPose() const
Definition: CPose2D.cpp:441
#define ASSERT_(f)
Defines an assertion mechanism.
Definition: exceptions.h:113
GLenum GLsizei n
Definition: glext.h:5074
GLenum GLenum GLvoid * row
Definition: glext.h:3576
const GLdouble * v
Definition: glext.h:3678
const GLubyte * c
Definition: glext.h:6313
GLenum GLint GLint y
Definition: glext.h:3538
GLenum GLint x
Definition: glext.h:3538
int val
Definition: mrpt_jpeglib.h:955
This base provides a set of functions for maths stuff.
Classes for 2D/3D geometry representation, both of single values and probability density distribution...
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
T square(const T x)
Inline function for the square of a number.
#define min(a, b)
unsigned __int16 uint16_t
Definition: rptypes.h:44
Lightweight 2D point.
double x
X,Y coordinates.



Page generated by Doxygen 1.9.1 for MRPT 1.9.9 Git: 814d80880 Fri Aug 24 01:51:28 2018 +0200 at mar 26 may 2026 12:30:59 CEST