Nav2 Navigation Stack - humble  humble
ROS 2 Navigation Stack
navfn.cpp
1 // Copyright (c) 2008, Willow Garage, Inc.
2 // All rights reserved.
3 //
4 // Software License Agreement (BSD License 2.0)
5 //
6 // Redistribution and use in source and binary forms, with or without
7 // modification, are permitted provided that the following conditions
8 // are met:
9 //
10 // * Redistributions of source code must retain the above copyright
11 // notice, this list of conditions and the following disclaimer.
12 // * Redistributions in binary form must reproduce the above
13 // copyright notice, this list of conditions and the following
14 // disclaimer in the documentation and/or other materials provided
15 // with the distribution.
16 // * Neither the name of the Willow Garage nor the names of its
17 // contributors may be used to endorse or promote products derived
18 // from this software without specific prior written permission.
19 //
20 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 // COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 // ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 // POSSIBILITY OF SUCH DAMAGE.
32 
33 //
34 // Navigation function computation
35 // Uses Dijkstra's method
36 // Modified for Euclidean-distance computation
37 //
38 // Path calculation uses no interpolation when pot field is at max in
39 // nearby cells
40 //
41 // Path calc has sanity check that it succeeded
42 //
43 
44 #include "nav2_navfn_planner/navfn.hpp"
45 
46 #include <algorithm>
47 #include "rclcpp/rclcpp.hpp"
48 
49 namespace nav2_navfn_planner
50 {
51 
52 //
53 // function to perform nav fn calculation
54 // keeps track of internal buffers, will be more efficient
55 // if the size of the environment does not change
56 //
57 
58 // Example usage:
59 /*
60 int
61 create_nav_plan_astar(
62  COSTTYPE * costmap, int nx, int ny,
63  int * goal, int * start,
64  float * plan, int nplan)
65 {
66  static NavFn * nav = NULL;
67 
68  if (nav == NULL) {
69  nav = new NavFn(nx, ny);
70  }
71 
72  if (nav->nx != nx || nav->ny != ny) { // check for compatibility with previous call
73  delete nav;
74  nav = new NavFn(nx, ny);
75  }
76 
77  nav->setGoal(goal);
78  nav->setStart(start);
79 
80  nav->costarr = costmap;
81  nav->setupNavFn(true);
82 
83  // calculate the nav fn and path
84  nav->priInc = 2 * COST_NEUTRAL;
85  nav->propNavFnAstar(std::max(nx * ny / 20, nx + ny));
86 
87  // path
88  int len = nav->calcPath(nplan);
89 
90  if (len > 0) { // found plan
91  RCLCPP_DEBUG(rclcpp::get_logger("rclcpp"), "[NavFn] Path found, %d steps\n", len);
92  } else {
93  RCLCPP_DEBUG(rclcpp::get_logger("rclcpp"), "[NavFn] No path found\n");
94  }
95 
96  if (len > 0) {
97  for (int i = 0; i < len; i++) {
98  plan[i * 2] = nav->pathx[i];
99  plan[i * 2 + 1] = nav->pathy[i];
100  }
101  }
102 
103  return len;
104 }
105 */
106 
107 //
108 // create nav fn buffers
109 //
110 
111 NavFn::NavFn(int xs, int ys)
112 {
113  // create cell arrays
114  costarr = NULL;
115  potarr = NULL;
116  pending = NULL;
117  gradx = grady = NULL;
118  setNavArr(xs, ys);
119 
120  // priority buffers
121  pb1 = new int[PRIORITYBUFSIZE];
122  pb2 = new int[PRIORITYBUFSIZE];
123  pb3 = new int[PRIORITYBUFSIZE];
124 
125  // for Dijkstra (breadth-first), set to COST_NEUTRAL
126  // for A* (best-first), set to COST_NEUTRAL
127  priInc = 2 * COST_NEUTRAL;
128 
129  // goal and start
130  goal[0] = goal[1] = 0;
131  start[0] = start[1] = 0;
132 
133  // display function
134  // displayFn = NULL;
135  // displayInt = 0;
136 
137  // path buffers
138  npathbuf = npath = 0;
139  pathx = pathy = NULL;
140  pathStep = 0.5;
141 }
142 
143 
144 NavFn::~NavFn()
145 {
146  if (costarr) {
147  delete[] costarr;
148  }
149  if (potarr) {
150  delete[] potarr;
151  }
152  if (pending) {
153  delete[] pending;
154  }
155  if (gradx) {
156  delete[] gradx;
157  }
158  if (grady) {
159  delete[] grady;
160  }
161  if (pathx) {
162  delete[] pathx;
163  }
164  if (pathy) {
165  delete[] pathy;
166  }
167  if (pb1) {
168  delete[] pb1;
169  }
170  if (pb2) {
171  delete[] pb2;
172  }
173  if (pb3) {
174  delete[] pb3;
175  }
176 }
177 
178 
179 //
180 // set goal, start positions for the nav fn
181 //
182 
183 void
185 {
186  goal[0] = g[0];
187  goal[1] = g[1];
188  RCLCPP_DEBUG(rclcpp::get_logger("rclcpp"), "[NavFn] Setting goal to %d,%d\n", goal[0], goal[1]);
189 }
190 
191 void
193 {
194  start[0] = g[0];
195  start[1] = g[1];
196  RCLCPP_DEBUG(
197  rclcpp::get_logger("rclcpp"), "[NavFn] Setting start to %d,%d\n", start[0],
198  start[1]);
199 }
200 
201 //
202 // Set/Reset map size
203 //
204 
205 void
206 NavFn::setNavArr(int xs, int ys)
207 {
208  RCLCPP_DEBUG(rclcpp::get_logger("rclcpp"), "[NavFn] Array is %d x %d\n", xs, ys);
209 
210  nx = xs;
211  ny = ys;
212  ns = nx * ny;
213 
214  if (costarr) {
215  delete[] costarr;
216  }
217  if (potarr) {
218  delete[] potarr;
219  }
220  if (pending) {
221  delete[] pending;
222  }
223 
224  if (gradx) {
225  delete[] gradx;
226  }
227  if (grady) {
228  delete[] grady;
229  }
230 
231  costarr = new COSTTYPE[ns]; // cost array, 2d config space
232  memset(costarr, 0, ns * sizeof(COSTTYPE));
233  potarr = new float[ns]; // navigation potential array
234  pending = new bool[ns];
235  memset(pending, 0, ns * sizeof(bool));
236  gradx = new float[ns];
237  grady = new float[ns];
238 }
239 
240 
241 //
242 // set up cost array, usually from ROS
243 //
244 
245 void
246 NavFn::setCostmap(const COSTTYPE * cmap, bool isROS, bool allow_unknown)
247 {
248  COSTTYPE * cm = costarr;
249  if (isROS) { // ROS-type cost array
250  for (int i = 0; i < ny; i++) {
251  int k = i * nx;
252  for (int j = 0; j < nx; j++, k++, cmap++, cm++) {
253  // This transforms the incoming cost values:
254  // COST_OBS -> COST_OBS (incoming "lethal obstacle")
255  // COST_OBS_ROS -> COST_OBS (incoming "inscribed inflated obstacle")
256  // values in range 0 to 252 -> values from COST_NEUTRAL to COST_OBS_ROS.
257  *cm = COST_OBS;
258  int v = *cmap;
259  if (v < COST_OBS_ROS) {
260  v = COST_NEUTRAL + COST_FACTOR * v;
261  if (v >= COST_OBS) {
262  v = COST_OBS - 1;
263  }
264  *cm = v;
265  } else if (v == COST_UNKNOWN_ROS && allow_unknown) {
266  v = COST_OBS - 1;
267  *cm = v;
268  }
269  }
270  }
271  } else { // not a ROS map, just a PGM
272  for (int i = 0; i < ny; i++) {
273  int k = i * nx;
274  for (int j = 0; j < nx; j++, k++, cmap++, cm++) {
275  *cm = COST_OBS;
276  if (i < 7 || i > ny - 8 || j < 7 || j > nx - 8) {
277  continue; // don't do borders
278  }
279  int v = *cmap;
280  if (v < COST_OBS_ROS) {
281  v = COST_NEUTRAL + COST_FACTOR * v;
282  if (v >= COST_OBS) {
283  v = COST_OBS - 1;
284  }
285  *cm = v;
286  } else if (v == COST_UNKNOWN_ROS) {
287  v = COST_OBS - 1;
288  *cm = v;
289  }
290  }
291  }
292  }
293 }
294 
295 bool
297 {
298  setupNavFn(true);
299 
300  // calculate the nav fn and path
301  return propNavFnDijkstra(std::max(nx * ny / 20, nx + ny), atStart);
302 }
303 
304 
305 //
306 // calculate navigation function, given a costmap, goal, and start
307 //
308 
309 bool
311 {
312  setupNavFn(true);
313 
314  // calculate the nav fn and path
315  return propNavFnAstar(std::max(nx * ny / 20, nx + ny));
316 }
317 
318 //
319 // returning values
320 //
321 
322 float * NavFn::getPathX() {return pathx;}
323 float * NavFn::getPathY() {return pathy;}
324 int NavFn::getPathLen() {return npath;}
325 
326 // inserting onto the priority blocks
327 #define push_cur(n) {if (n >= 0 && n < ns && !pending[n] && \
328  costarr[n] < COST_OBS && curPe < PRIORITYBUFSIZE) \
329  {curP[curPe++] = n; pending[n] = true;}}
330 #define push_next(n) {if (n >= 0 && n < ns && !pending[n] && \
331  costarr[n] < COST_OBS && nextPe < PRIORITYBUFSIZE) \
332  {nextP[nextPe++] = n; pending[n] = true;}}
333 #define push_over(n) {if (n >= 0 && n < ns && !pending[n] && \
334  costarr[n] < COST_OBS && overPe < PRIORITYBUFSIZE) \
335  {overP[overPe++] = n; pending[n] = true;}}
336 
337 
338 // Set up navigation potential arrays for new propagation
339 
340 void
341 NavFn::setupNavFn(bool keepit)
342 {
343  // reset values in propagation arrays
344  for (int i = 0; i < ns; i++) {
345  potarr[i] = POT_HIGH;
346  if (!keepit) {
347  costarr[i] = COST_NEUTRAL;
348  }
349  gradx[i] = grady[i] = 0.0;
350  }
351 
352  // outer bounds of cost array
353  COSTTYPE * pc;
354  pc = costarr;
355  for (int i = 0; i < nx; i++) {
356  *pc++ = COST_OBS;
357  }
358  pc = costarr + (ny - 1) * nx;
359  for (int i = 0; i < nx; i++) {
360  *pc++ = COST_OBS;
361  }
362  pc = costarr;
363  for (int i = 0; i < ny; i++, pc += nx) {
364  *pc = COST_OBS;
365  }
366  pc = costarr + nx - 1;
367  for (int i = 0; i < ny; i++, pc += nx) {
368  *pc = COST_OBS;
369  }
370 
371  // priority buffers
372  curT = COST_OBS;
373  curP = pb1;
374  curPe = 0;
375  nextP = pb2;
376  nextPe = 0;
377  overP = pb3;
378  overPe = 0;
379  memset(pending, 0, ns * sizeof(bool));
380 
381  // set goal
382  int k = goal[0] + goal[1] * nx;
383  initCost(k, 0);
384 
385  // find # of obstacle cells
386  pc = costarr;
387  int ntot = 0;
388  for (int i = 0; i < ns; i++, pc++) {
389  if (*pc >= COST_OBS) {
390  ntot++; // number of cells that are obstacles
391  }
392  }
393  nobs = ntot;
394 }
395 
396 
397 // initialize a goal-type cost for starting propagation
398 
399 void
400 NavFn::initCost(int k, float v)
401 {
402  potarr[k] = v;
403  push_cur(k + 1);
404  push_cur(k - 1);
405  push_cur(k - nx);
406  push_cur(k + nx);
407 }
408 
409 
410 //
411 // Critical function: calculate updated potential value of a cell,
412 // given its neighbors' values
413 // Planar-wave update calculation from two lowest neighbors in a 4-grid
414 // Quadratic approximation to the interpolated value
415 // No checking of bounds here, this function should be fast
416 //
417 
418 #define INVSQRT2 0.707106781
419 
420 inline void
422 {
423  // get neighbors
424  float u, d, l, r;
425  l = potarr[n - 1];
426  r = potarr[n + 1];
427  u = potarr[n - nx];
428  d = potarr[n + nx];
429  // ROS_INFO("[Update] c: %0.1f l: %0.1f r: %0.1f u: %0.1f d: %0.1f\n",
430  // potarr[n], l, r, u, d);
431  // ROS_INFO("[Update] cost: %d\n", costarr[n]);
432 
433  // find lowest, and its lowest neighbor
434  float ta, tc;
435  if (l < r) {tc = l;} else {tc = r;}
436  if (u < d) {ta = u;} else {ta = d;}
437 
438  // do planar wave update
439  if (costarr[n] < COST_OBS) { // don't propagate into obstacles
440  float hf = static_cast<float>(costarr[n]); // traversability factor
441  float dc = tc - ta; // relative cost between ta,tc
442  if (dc < 0) { // ta is lowest
443  dc = -dc;
444  ta = tc;
445  }
446 
447  // calculate new potential
448  float pot;
449  if (dc >= hf) { // if too large, use ta-only update
450  pot = ta + hf;
451  } else { // two-neighbor interpolation update
452  // use quadratic approximation
453  // might speed this up through table lookup, but still have to
454  // do the divide
455  float d = dc / hf;
456  float v = -0.2301 * d * d + 0.5307 * d + 0.7040;
457  pot = ta + hf * v;
458  }
459 
460  // ROS_INFO("[Update] new pot: %d\n", costarr[n]);
461 
462  // now add affected neighbors to priority blocks
463  if (pot < potarr[n]) {
464  float le = INVSQRT2 * static_cast<float>(costarr[n - 1]);
465  float re = INVSQRT2 * static_cast<float>(costarr[n + 1]);
466  float ue = INVSQRT2 * static_cast<float>(costarr[n - nx]);
467  float de = INVSQRT2 * static_cast<float>(costarr[n + nx]);
468  potarr[n] = pot;
469  if (pot < curT) { // low-cost buffer block
470  if (l > pot + le) {push_next(n - 1);}
471  if (r > pot + re) {push_next(n + 1);}
472  if (u > pot + ue) {push_next(n - nx);}
473  if (d > pot + de) {push_next(n + nx);}
474  } else { // overflow block
475  if (l > pot + le) {push_over(n - 1);}
476  if (r > pot + re) {push_over(n + 1);}
477  if (u > pot + ue) {push_over(n - nx);}
478  if (d > pot + de) {push_over(n + nx);}
479  }
480  }
481  }
482 }
483 
484 //
485 // Use A* method for setting priorities
486 // Critical function: calculate updated potential value of a cell,
487 // given its neighbors' values
488 // Planar-wave update calculation from two lowest neighbors in a 4-grid
489 // Quadratic approximation to the interpolated value
490 // No checking of bounds here, this function should be fast
491 //
492 
493 #define INVSQRT2 0.707106781
494 
495 inline void
497 {
498  // get neighbors
499  float u, d, l, r;
500  l = potarr[n - 1];
501  r = potarr[n + 1];
502  u = potarr[n - nx];
503  d = potarr[n + nx];
504  // ROS_INFO("[Update] c: %0.1f l: %0.1f r: %0.1f u: %0.1f d: %0.1f\n",
505  // potarr[n], l, r, u, d);
506  // ROS_INFO("[Update] cost of %d: %d\n", n, costarr[n]);
507 
508  // find lowest, and its lowest neighbor
509  float ta, tc;
510  if (l < r) {tc = l;} else {tc = r;}
511  if (u < d) {ta = u;} else {ta = d;}
512 
513  // do planar wave update
514  if (costarr[n] < COST_OBS) { // don't propagate into obstacles
515  float hf = static_cast<float>(costarr[n]); // traversability factor
516  float dc = tc - ta; // relative cost between ta,tc
517  if (dc < 0) { // ta is lowest
518  dc = -dc;
519  ta = tc;
520  }
521 
522  // calculate new potential
523  float pot;
524  if (dc >= hf) { // if too large, use ta-only update
525  pot = ta + hf;
526  } else { // two-neighbor interpolation update
527  // use quadratic approximation
528  // might speed this up through table lookup, but still have to
529  // do the divide
530  float d = dc / hf;
531  float v = -0.2301 * d * d + 0.5307 * d + 0.7040;
532  pot = ta + hf * v;
533  }
534 
535  // ROS_INFO("[Update] new pot: %d\n", costarr[n]);
536 
537  // now add affected neighbors to priority blocks
538  if (pot < potarr[n]) {
539  float le = INVSQRT2 * static_cast<float>(costarr[n - 1]);
540  float re = INVSQRT2 * static_cast<float>(costarr[n + 1]);
541  float ue = INVSQRT2 * static_cast<float>(costarr[n - nx]);
542  float de = INVSQRT2 * static_cast<float>(costarr[n + nx]);
543 
544  // calculate distance
545  int x = n % nx;
546  int y = n / nx;
547  float dist = hypot(x - start[0], y - start[1]) * static_cast<float>(COST_NEUTRAL);
548 
549  potarr[n] = pot;
550  pot += dist;
551  if (pot < curT) { // low-cost buffer block
552  if (l > pot + le) {push_next(n - 1);}
553  if (r > pot + re) {push_next(n + 1);}
554  if (u > pot + ue) {push_next(n - nx);}
555  if (d > pot + de) {push_next(n + nx);}
556  } else {
557  if (l > pot + le) {push_over(n - 1);}
558  if (r > pot + re) {push_over(n + 1);}
559  if (u > pot + ue) {push_over(n - nx);}
560  if (d > pot + de) {push_over(n + nx);}
561  }
562  }
563  }
564 }
565 
566 
567 //
568 // main propagation function
569 // Dijkstra method, breadth-first
570 // runs for a specified number of cycles,
571 // or until it runs out of cells to update,
572 // or until the Start cell is found (atStart = true)
573 //
574 
575 bool
576 NavFn::propNavFnDijkstra(int cycles, bool atStart)
577 {
578  int nwv = 0; // max priority block size
579  int nc = 0; // number of cells put into priority blocks
580  int cycle = 0; // which cycle we're on
581 
582  // set up start cell
583  int startCell = start[1] * nx + start[0];
584 
585  for (; cycle < cycles; cycle++) { // go for this many cycles, unless interrupted
586  if (curPe == 0 && nextPe == 0) { // priority blocks empty
587  break;
588  }
589 
590  // stats
591  nc += curPe;
592  if (curPe > nwv) {
593  nwv = curPe;
594  }
595 
596  // reset pending flags on current priority buffer
597  int * pb = curP;
598  int i = curPe;
599  while (i-- > 0) {
600  pending[*(pb++)] = false;
601  }
602 
603  // process current priority buffer
604  pb = curP;
605  i = curPe;
606  while (i-- > 0) {
607  updateCell(*pb++);
608  }
609 
610  // if (displayInt > 0 && (cycle % displayInt) == 0) {
611  // displayFn(this);
612  // }
613 
614  // swap priority blocks curP <=> nextP
615  curPe = nextPe;
616  nextPe = 0;
617  pb = curP; // swap buffers
618  curP = nextP;
619  nextP = pb;
620 
621  // see if we're done with this priority level
622  if (curPe == 0) {
623  curT += priInc; // increment priority threshold
624  curPe = overPe; // set current to overflow block
625  overPe = 0;
626  pb = curP; // swap buffers
627  curP = overP;
628  overP = pb;
629  }
630 
631  // check if we've hit the Start cell
632  if (atStart) {
633  if (potarr[startCell] < POT_HIGH) {
634  break;
635  }
636  }
637  }
638 
639  RCLCPP_DEBUG(
640  rclcpp::get_logger("rclcpp"),
641  "[NavFn] Used %d cycles, %d cells visited (%d%%), priority buf max %d\n",
642  cycle, nc, (int)((nc * 100.0) / (ns - nobs)), nwv);
643 
644  return (cycle < cycles) ? true : false;
645 }
646 
647 //
648 // main propagation function
649 // A* method, best-first
650 // uses Euclidean distance heuristic
651 // runs for a specified number of cycles,
652 // or until it runs out of cells to update,
653 // or until the Start cell is found (atStart = true)
654 //
655 
656 bool
658 {
659  int nwv = 0; // max priority block size
660  int nc = 0; // number of cells put into priority blocks
661  int cycle = 0; // which cycle we're on
662 
663  // set initial threshold, based on distance
664  float dist = hypot(goal[0] - start[0], goal[1] - start[1]) * static_cast<float>(COST_NEUTRAL);
665  curT = dist + curT;
666 
667  // set up start cell
668  int startCell = start[1] * nx + start[0];
669 
670  // do main cycle
671  for (; cycle < cycles; cycle++) { // go for this many cycles, unless interrupted
672  if (curPe == 0 && nextPe == 0) { // priority blocks empty
673  break;
674  }
675 
676  // stats
677  nc += curPe;
678  if (curPe > nwv) {
679  nwv = curPe;
680  }
681 
682  // reset pending flags on current priority buffer
683  int * pb = curP;
684  int i = curPe;
685  while (i-- > 0) {
686  pending[*(pb++)] = false;
687  }
688 
689  // process current priority buffer
690  pb = curP;
691  i = curPe;
692  while (i-- > 0) {
693  updateCellAstar(*pb++);
694  }
695 
696  // if (displayInt > 0 && (cycle % displayInt) == 0) {
697  // displayFn(this);
698  // }
699 
700  // swap priority blocks curP <=> nextP
701  curPe = nextPe;
702  nextPe = 0;
703  pb = curP; // swap buffers
704  curP = nextP;
705  nextP = pb;
706 
707  // see if we're done with this priority level
708  if (curPe == 0) {
709  curT += priInc; // increment priority threshold
710  curPe = overPe; // set current to overflow block
711  overPe = 0;
712  pb = curP; // swap buffers
713  curP = overP;
714  overP = pb;
715  }
716 
717  // check if we've hit the Start cell
718  if (potarr[startCell] < POT_HIGH) {
719  break;
720  }
721  }
722 
723  last_path_cost_ = potarr[startCell];
724 
725  RCLCPP_DEBUG(
726  rclcpp::get_logger("rclcpp"),
727  "[NavFn] Used %d cycles, %d cells visited (%d%%), priority buf max %d\n",
728  cycle, nc, (int)((nc * 100.0) / (ns - nobs)), nwv);
729 
730  if (potarr[startCell] < POT_HIGH) {
731  return true; // finished up here}
732  } else {
733  return false;
734  }
735 }
736 
737 
739 {
740  return last_path_cost_;
741 }
742 
743 
744 //
745 // Path construction
746 // Find gradient at array points, interpolate path
747 // Use step size of pathStep, usually 0.5 pixel
748 //
749 // Some sanity checks:
750 // 1. Stuck at same index position
751 // 2. Doesn't get near goal
752 // 3. Surrounded by high potentials
753 //
754 
755 int
756 NavFn::calcPath(int n, int * st)
757 {
758  // test write
759  // savemap("test");
760 
761  // check path arrays
762  if (npathbuf < n) {
763  if (pathx) {delete[] pathx;}
764  if (pathy) {delete[] pathy;}
765  pathx = new float[n];
766  pathy = new float[n];
767  npathbuf = n;
768  }
769 
770  // set up start position at cell
771  // st is always upper left corner for 4-point bilinear interpolation
772  if (st == NULL) {st = start;}
773  int stc = st[1] * nx + st[0];
774 
775  // set up offset
776  float dx = 0;
777  float dy = 0;
778  npath = 0;
779 
780  // go for <n> cycles at most
781  for (int i = 0; i < n; i++) {
782  // check if near goal
783  int nearest_point = std::max(
784  0,
785  std::min(
786  nx * ny - 1, stc + static_cast<int>(round(dx)) +
787  static_cast<int>(nx * round(dy))));
788  if (potarr[nearest_point] < COST_NEUTRAL) {
789  pathx[npath] = static_cast<float>(goal[0]);
790  pathy[npath] = static_cast<float>(goal[1]);
791  return ++npath; // done!
792  }
793 
794  if (stc < nx || stc > ns - nx) { // would be out of bounds
795  RCLCPP_DEBUG(rclcpp::get_logger("rclcpp"), "[PathCalc] Out of bounds");
796  return 0;
797  }
798 
799  // add to path
800  pathx[npath] = stc % nx + dx;
801  pathy[npath] = stc / nx + dy;
802  npath++;
803 
804  bool oscillation_detected = false;
805  if (npath > 2 &&
806  pathx[npath - 1] == pathx[npath - 3] &&
807  pathy[npath - 1] == pathy[npath - 3])
808  {
809  RCLCPP_DEBUG(
810  rclcpp::get_logger("rclcpp"),
811  "[PathCalc] oscillation detected, attempting fix.");
812  oscillation_detected = true;
813  }
814 
815  int stcnx = stc + nx;
816  int stcpx = stc - nx;
817 
818  // check for potentials at eight positions near cell
819  if (potarr[stc] >= POT_HIGH ||
820  potarr[stc + 1] >= POT_HIGH ||
821  potarr[stc - 1] >= POT_HIGH ||
822  potarr[stcnx] >= POT_HIGH ||
823  potarr[stcnx + 1] >= POT_HIGH ||
824  potarr[stcnx - 1] >= POT_HIGH ||
825  potarr[stcpx] >= POT_HIGH ||
826  potarr[stcpx + 1] >= POT_HIGH ||
827  potarr[stcpx - 1] >= POT_HIGH ||
828  oscillation_detected)
829  {
830  RCLCPP_DEBUG(
831  rclcpp::get_logger("rclcpp"),
832  "[Path] Pot fn boundary, following grid (%0.1f/%d)", potarr[stc], npath);
833 
834  // check eight neighbors to find the lowest
835  int minc = stc;
836  int minp = potarr[stc];
837  int st = stcpx - 1;
838  if (potarr[st] < minp) {minp = potarr[st]; minc = st;}
839  st++;
840  if (potarr[st] < minp) {minp = potarr[st]; minc = st;}
841  st++;
842  if (potarr[st] < minp) {minp = potarr[st]; minc = st;}
843  st = stc - 1;
844  if (potarr[st] < minp) {minp = potarr[st]; minc = st;}
845  st = stc + 1;
846  if (potarr[st] < minp) {minp = potarr[st]; minc = st;}
847  st = stcnx - 1;
848  if (potarr[st] < minp) {minp = potarr[st]; minc = st;}
849  st++;
850  if (potarr[st] < minp) {minp = potarr[st]; minc = st;}
851  st++;
852  if (potarr[st] < minp) {minp = potarr[st]; minc = st;}
853  stc = minc;
854  dx = 0;
855  dy = 0;
856 
857  RCLCPP_DEBUG(
858  rclcpp::get_logger("rclcpp"), "[Path] Pot: %0.1f pos: %0.1f,%0.1f",
859  potarr[stc], pathx[npath - 1], pathy[npath - 1]);
860 
861  if (potarr[stc] >= POT_HIGH) {
862  RCLCPP_DEBUG(rclcpp::get_logger("rclcpp"), "[PathCalc] No path found, high potential");
863  // savemap("navfn_highpot");
864  return 0;
865  }
866  } else { // have a good gradient here
867  // get grad at four positions near cell
868  gradCell(stc);
869  gradCell(stc + 1);
870  gradCell(stcnx);
871  gradCell(stcnx + 1);
872 
873 
874  // get interpolated gradient
875  float x1 = (1.0 - dx) * gradx[stc] + dx * gradx[stc + 1];
876  float x2 = (1.0 - dx) * gradx[stcnx] + dx * gradx[stcnx + 1];
877  float x = (1.0 - dy) * x1 + dy * x2; // interpolated x
878  float y1 = (1.0 - dx) * grady[stc] + dx * grady[stc + 1];
879  float y2 = (1.0 - dx) * grady[stcnx] + dx * grady[stcnx + 1];
880  float y = (1.0 - dy) * y1 + dy * y2; // interpolated y
881 
882 #if 0
883  // show gradients
884  RCLCPP_DEBUG(
885  rclcpp::get_logger("rclcpp"),
886  "[Path] %0.2f,%0.2f %0.2f,%0.2f %0.2f,%0.2f %0.2f,%0.2f; final x=%.3f, y=%.3f\n",
887  gradx[stc], grady[stc], gradx[stc + 1], grady[stc + 1],
888  gradx[stcnx], grady[stcnx], gradx[stcnx + 1], grady[stcnx + 1],
889  x, y);
890 #endif
891 
892  // check for zero gradient, failed
893  if (x == 0.0 && y == 0.0) {
894  RCLCPP_DEBUG(rclcpp::get_logger("rclcpp"), "[PathCalc] Zero gradient");
895  return 0;
896  }
897 
898  // move in the right direction
899  float ss = pathStep / hypot(x, y);
900  dx += x * ss;
901  dy += y * ss;
902 
903  // check for overflow
904  if (dx > 1.0) {stc++; dx -= 1.0;}
905  if (dx < -1.0) {stc--; dx += 1.0;}
906  if (dy > 1.0) {stc += nx; dy -= 1.0;}
907  if (dy < -1.0) {stc -= nx; dy += 1.0;}
908  }
909 
910  // ROS_INFO("[Path] Pot: %0.1f grad: %0.1f,%0.1f pos: %0.1f,%0.1f\n",
911  // potarr[stc], x, y, pathx[npath-1], pathy[npath-1]);
912  }
913 
914  // return npath; // out of cycles, return failure
915  RCLCPP_DEBUG(rclcpp::get_logger("rclcpp"), "[PathCalc] No path found, path too long");
916  // savemap("navfn_pathlong");
917  return 0; // out of cycles, return failure
918 }
919 
920 
921 //
922 // gradient calculations
923 //
924 
925 // calculate gradient at a cell
926 // positive value are to the right and down
927 float
929 {
930  if (gradx[n] + grady[n] > 0.0) { // check this cell
931  return 1.0;
932  }
933 
934  if (n < nx || n > ns - nx) { // would be out of bounds
935  return 0.0;
936  }
937 
938  float cv = potarr[n];
939  float dx = 0.0;
940  float dy = 0.0;
941 
942  // check for in an obstacle
943  if (cv >= POT_HIGH) {
944  if (potarr[n - 1] < POT_HIGH) {
945  dx = -COST_OBS;
946  } else if (potarr[n + 1] < POT_HIGH) {
947  dx = COST_OBS;
948  }
949  if (potarr[n - nx] < POT_HIGH) {
950  dy = -COST_OBS;
951  } else if (potarr[n + nx] < POT_HIGH) {
952  dy = COST_OBS;
953  }
954  } else { // not in an obstacle
955  // dx calc, average to sides
956  if (potarr[n - 1] < POT_HIGH) {
957  dx += potarr[n - 1] - cv;
958  }
959  if (potarr[n + 1] < POT_HIGH) {
960  dx += cv - potarr[n + 1];
961  }
962 
963  // dy calc, average to sides
964  if (potarr[n - nx] < POT_HIGH) {
965  dy += potarr[n - nx] - cv;
966  }
967  if (potarr[n + nx] < POT_HIGH) {
968  dy += cv - potarr[n + nx];
969  }
970  }
971 
972  // normalize
973  float norm = hypot(dx, dy);
974  if (norm > 0) {
975  norm = 1.0 / norm;
976  gradx[n] = norm * dx;
977  grady[n] = norm * dy;
978  }
979  return norm;
980 }
981 
982 
983 //
984 // display function setup
985 // <n> is the number of cycles to wait before displaying,
986 // use 0 to turn it off
987 
988 // void
989 // NavFn::display(void fn(NavFn * nav), int n)
990 // {
991 // displayFn = fn;
992 // displayInt = n;
993 // }
994 
995 
996 //
997 // debug writes
998 // saves costmap and start/goal
999 //
1000 
1001 // void
1002 // NavFn::savemap(const char * fname)
1003 // {
1004 // char fn[4096];
1005 
1006 // RCLCPP_DEBUG(rclcpp::get_logger("rclcpp"), "[NavFn] Saving costmap and start/goal points");
1007 // // write start and goal points
1008 // snprintf(fn, sizeof(fn), "%s.txt", fname);
1009 // FILE * fp = fopen(fn, "w");
1010 // if (!fp) {
1011 // RCLCPP_WARN(rclcpp::get_logger("rclcpp"), "Can't open file %s", fn);
1012 // return;
1013 // }
1014 // fprintf(fp, "Goal: %d %d\nStart: %d %d\n", goal[0], goal[1], start[0], start[1]);
1015 // fclose(fp);
1016 
1017 // // write cost array
1018 // if (!costarr) {
1019 // return;
1020 // }
1021 // snprintf(fn, sizeof(fn), "%s.pgm", fname);
1022 // fp = fopen(fn, "wb");
1023 // if (!fp) {
1024 // RCLCPP_WARN(rclcpp::get_logger("rclcpp"), "Can't open file %s", fn);
1025 // return;
1026 // }
1027 // fprintf(fp, "P5\n%d\n%d\n%d\n", nx, ny, 0xff);
1028 // fwrite(costarr, 1, nx * ny, fp);
1029 // fclose(fp);
1030 // }
1031 
1032 } // namespace nav2_navfn_planner
int getPathLen()
Accessor for the length of a path.
Definition: navfn.cpp:324
bool propNavFnDijkstra(int cycles, bool atStart=false)
Run propagation for <cycles> iterations, or until start is reached using breadth-first Dijkstra metho...
Definition: navfn.cpp:576
float * getPathX()
Accessor for the x-coordinates of a path.
Definition: navfn.cpp:322
float gradCell(int n)
Calculate gradient at a cell.
Definition: navfn.cpp:928
void updateCell(int n)
Updates the cell at index n.
Definition: navfn.cpp:421
int calcPath(int n, int *st=NULL)
Calculates the path for at mose <n> cycles.
Definition: navfn.cpp:756
float getLastPathCost()
Gets the cost of the path found the last time a navigation function was computed.
Definition: navfn.cpp:738
bool calcNavFnDijkstra(bool atStart=false)
Caclulates the full navigation function using Dijkstra.
Definition: navfn.cpp:296
void updateCellAstar(int n)
Updates the cell at index n using the A* heuristic.
Definition: navfn.cpp:496
void initCost(int k, float v)
Initialize cell k with cost v for propagation.
Definition: navfn.cpp:400
void setNavArr(int nx, int ny)
Sets or resets the size of the map.
Definition: navfn.cpp:206
NavFn(int nx, int ny)
Constructs the planner.
Definition: navfn.cpp:111
void setCostmap(const COSTTYPE *cmap, bool isROS=true, bool allow_unknown=true)
Set up the cost array for the planner, usually from ROS.
Definition: navfn.cpp:246
void setupNavFn(bool keepit=false)
Set up navigation potential arrays for new propagation.
Definition: navfn.cpp:341
bool propNavFnAstar(int cycles)
Run propagation for <cycles> iterations, or until start is reached using the best-first A* method wit...
Definition: navfn.cpp:657
bool calcNavFnAstar()
Calculates a plan using the A* heuristic, returns true if one is found.
Definition: navfn.cpp:310
void setGoal(int *goal)
Sets the goal position for the planner. Note: the navigation cost field computed gives the cost to ge...
Definition: navfn.cpp:184
float * getPathY()
Accessor for the y-coordinates of a path.
Definition: navfn.cpp:323
void setStart(int *start)
Sets the start position for the planner. Note: the navigation cost field computed gives the cost to g...
Definition: navfn.cpp:192