navfn.cpp
Go to the documentation of this file.
00001 /*********************************************************************
00002 * Software License Agreement (BSD License)
00003 * 
00004 *  Copyright (c) 2008, Willow Garage, Inc.
00005 *  All rights reserved.
00006 * 
00007 *  Redistribution and use in source and binary forms, with or without
00008 *  modification, are permitted provided that the following conditions
00009 *  are met:
00010 * 
00011 *   * Redistributions of source code must retain the above copyright
00012 *     notice, this list of conditions and the following disclaimer.
00013 *   * Redistributions in binary form must reproduce the above
00014 *     copyright notice, this list of conditions and the following
00015 *     disclaimer in the documentation and/or other materials provided
00016 *     with the distribution.
00017 *   * Neither the name of the Willow Garage nor the names of its
00018 *     contributors may be used to endorse or promote products derived
00019 *     from this software without specific prior written permission.
00020 * 
00021 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00022 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00023 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00024 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00025 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00026 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00027 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00028 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00029 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00030 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00031 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00032 *  POSSIBILITY OF SUCH DAMAGE.
00033 *********************************************************************/
00034 /********************************************************************
00035 * IRI Modifications of Original Willow Garage Navfn
00036 * 
00037 * Added a BSpline computation to avoid straight lines and rotations in place 
00038 * during global planner algorithm, specifically using Dijkstra method.
00039 *
00040 */
00041 //
00042 // Navigation function computation
00043 // Uses Dijkstra's method with the potential field modified by a BSpline
00044 // Modified for Euclidean-distance computation
00045 // 
00046 // Path calculation uses no interpolation when pot field is at max in
00047 //   nearby cells
00048 //
00049 // Path calc has sanity check that it succeeded
00050 //
00051 
00052 
00053 
00054 #include <iri_bspline_navfn/navfn.h>
00055 #include <ros/console.h>
00056 #include <costmap_2d/costmap_2d_ros.h>
00057 
00058 
00059 namespace iri_bspline_navfn {
00060 
00061   //
00062   // function to perform nav fn calculation
00063   // keeps track of internal buffers, will be more efficient
00064   //   if the size of the environment does not change
00065   //
00066 
00067   int
00068     create_nav_plan_astar(COSTTYPE *costmap, int nx, int ny,
00069         int* goal, int* start,
00070         float *plan, int nplan)
00071     {
00072       static NavFn *nav = NULL;
00073 
00074       if (nav == NULL)
00075         nav = new NavFn(nx,ny);
00076 
00077       if (nav->nx != nx || nav->ny != ny) // check for compatibility with previous call
00078       {
00079         delete nav;
00080         nav = new NavFn(nx,ny);      
00081       }
00082 
00083       nav->setGoal(goal);
00084       nav->setStart(start);
00085 
00086       nav->costarr = costmap;
00087       nav->setupNavFn(true);
00088 
00089       // calculate the nav fn and path
00090       nav->priInc = 2*COST_NEUTRAL;
00091       nav->propNavFnAstar(std::max(nx*ny/20,nx+ny));
00092 
00093       // path
00094       int len = nav->calcPath(nplan);
00095 
00096       if (len > 0)                      // found plan
00097         ROS_DEBUG("[NavFn] Path found, %d steps\n", len);
00098       else
00099         ROS_DEBUG("[NavFn] No path found\n");
00100 
00101       if (len > 0)
00102       {
00103         for (int i=0; i<len; i++)
00104         {
00105           plan[i*2] = nav->pathx[i];
00106           plan[i*2+1] = nav->pathy[i];
00107         }
00108       }
00109 
00110       return len;
00111     }
00112 
00113 
00114 
00115 
00116   //
00117   // create nav fn buffers 
00118   //
00119 
00120   NavFn::NavFn(int xs, int ys)
00121   {  
00122     // create cell arrays
00123     obsarr = costarr = NULL;
00124     potarr = NULL;
00125     pending = NULL;
00126     gradx = grady = NULL;
00127     setNavArr(xs,ys);
00128 
00129     // priority buffers
00130     pb1 = new int[PRIORITYBUFSIZE];
00131     pb2 = new int[PRIORITYBUFSIZE];
00132     pb3 = new int[PRIORITYBUFSIZE];
00133 
00134     // for Dijkstra (breadth-first), set to COST_NEUTRAL
00135     // for A* (best-first), set to COST_NEUTRAL
00136     priInc = 2*COST_NEUTRAL;    
00137 
00138     // goal and start
00139     goal[0] = goal[1] = 0;
00140     start[0] = start[1] = 0;
00141 
00142     // display function
00143     displayFn = NULL;
00144     displayInt = 0;
00145 
00146     // path buffers
00147     npathbuf = npath = 0;
00148     pathx = pathy = NULL;
00149     pathStep = 0.5;
00150   }
00151 
00152 
00153   NavFn::~NavFn()
00154   {
00155     if(obsarr)
00156       delete[] obsarr;
00157     if(costarr)
00158       delete[] costarr;
00159     if(potarr)
00160       delete[] potarr;
00161     if(pending)
00162       delete[] pending;
00163     if(gradx)
00164       delete[] gradx;
00165     if(grady)
00166       delete[] grady;
00167     if(pathx)
00168       delete[] pathx;
00169     if(pathy)
00170       delete[] pathy;
00171     if(pb1)
00172       delete[] pb1;
00173     if(pb2)
00174       delete[] pb2;
00175     if(pb3)
00176       delete[] pb3;
00177   }
00178 
00179 
00180   //
00181   // set goal, start positions for the nav fn
00182   //
00183 
00184   void
00185     NavFn::setGoal(int *g)
00186     {
00187       goal[0] = g[0];
00188       goal[1] = g[1];
00189       ROS_DEBUG("[NavFn] Setting goal to %d,%d\n", goal[0], goal[1]);
00190     }
00191 
00192   void
00193     NavFn::setStart(int *g)
00194     {
00195       start[0] = g[0];
00196       start[1] = g[1];
00197       ROS_DEBUG("[NavFn] Setting start to %d,%d\n", start[0], start[1]);
00198     }
00199 
00200   //
00201   // Set/Reset map size
00202   //
00203 
00204   void
00205     NavFn::setNavArr(int xs, int ys)
00206     {
00207       ROS_DEBUG("[NavFn] Array is %d x %d\n", xs, ys);
00208 
00209       nx = xs;
00210       ny = ys;
00211       ns = nx*ny;
00212 
00213       if(obsarr)
00214         delete[] obsarr;
00215       if(costarr)
00216         delete[] costarr;
00217       if(potarr)
00218         delete[] potarr;
00219       if(pending)
00220         delete[] pending;
00221 
00222       if(gradx)
00223         delete[] gradx;
00224       if(grady)
00225         delete[] grady;
00226 
00227       obsarr = new COSTTYPE[ns];        // obstacles, 255 is obstacle
00228       memset(obsarr, 0, ns*sizeof(COSTTYPE));
00229       costarr = new COSTTYPE[ns]; // cost array, 2d config space
00230       memset(costarr, 0, ns*sizeof(COSTTYPE));
00231       potarr = new float[ns];   // navigation potential array
00232       pending = new bool[ns];
00233       memset(pending, 0, ns*sizeof(bool));
00234       gradx = new float[ns];
00235       grady = new float[ns];
00236     }
00237 
00238 
00239   //
00240   // set up cost array, usually from ROS
00241   //
00242 
00243   void
00244     NavFn::setCostmap(const COSTTYPE *cmap, bool isROS, bool allow_unknown)
00245     {
00246       COSTTYPE *cm = costarr;
00247       if (isROS)                        // ROS-type cost array
00248       {
00249         for (int i=0; i<ny; i++)
00250         {
00251           int k=i*nx;
00252           for (int j=0; j<nx; j++, k++, cmap++, cm++)
00253           {
00254             *cm = COST_OBS;
00255             int v = *cmap;
00256             if (v < COST_OBS_ROS)
00257             {
00258               v = COST_NEUTRAL+COST_FACTOR*v;
00259               if (v >= COST_OBS)
00260                 v = COST_OBS-1;
00261               *cm = v;
00262             }
00263             else if(v == COST_UNKNOWN_ROS && allow_unknown)
00264             {
00265               v = COST_OBS-1;
00266               *cm = v;
00267             }
00268           }
00269         }
00270       }
00271 
00272       else                              // not a ROS map, just a PGM
00273       {
00274         for (int i=0; i<ny; i++)
00275         {
00276           int k=i*nx;
00277           for (int j=0; j<nx; j++, k++, cmap++, cm++)
00278           {
00279             *cm = COST_OBS;
00280             if (i<7 || i > ny-8 || j<7 || j > nx-8)
00281               continue; // don't do borders
00282             int v = *cmap;
00283             if (v < COST_OBS_ROS)
00284             {
00285               v = COST_NEUTRAL+COST_FACTOR*v;
00286               if (v >= COST_OBS)
00287                 v = COST_OBS-1;
00288               *cm = v;
00289             }
00290             else if(v == COST_UNKNOWN_ROS)
00291             {
00292               v = COST_OBS-1;
00293               *cm = v;
00294             }
00295           }
00296         }
00297 
00298       }
00299     }
00300 
00301 void NavFn::setNavPoses(const geometry_msgs::PoseStamped& goal_, const geometry_msgs::PoseStamped& start_, const double resolution_, const double costmap_ox_, const double costmap_oy_)
00302 {
00303   w_goal = goal_;
00304   w_start = start_;
00305   resolution = resolution_;
00306   costmap_ox=costmap_ox_;
00307   costmap_oy=costmap_oy_;
00308 }
00309 
00310   bool NavFn::calcNavFnDijkstra(bool atStart)
00311     {
00312       setupNavFn(true);
00313 
00314       
00315       // calculate the nav fn and path
00316       propNavFnDijkstra(std::max(nx*ny/20,nx+ny),atStart);
00317 
00318       // path
00319       int len = calcPath(nx*4);
00320 
00321       if (len > 0)                      // found plan
00322       {
00323         ROS_DEBUG("[NavFn] Path found, %d steps\n", len);
00324         return true;
00325       }
00326       else
00327       {
00328         ROS_DEBUG("[NavFn] No path found\n");
00329         return false;
00330       }
00331 
00332     }
00333 
00334 
00335   //
00336   // calculate navigation function, given a costmap, goal, and start
00337   //
00338 
00339   bool
00340     NavFn::calcNavFnAstar()
00341     {
00342       setupNavFn(true);
00343 
00344       // calculate the nav fn and path
00345       propNavFnAstar(std::max(nx*ny/20,nx+ny));
00346 
00347       // path
00348       int len = calcPath(nx*4);
00349 
00350       if (len > 0)                      // found plan
00351       {
00352         ROS_DEBUG("[NavFn] Path found, %d steps\n", len);
00353         return true;
00354       }
00355       else
00356       {
00357         ROS_DEBUG("[NavFn] No path found\n");
00358         return false;
00359       }
00360     }
00361 
00362 
00363   //
00364   // returning values
00365   //
00366 
00367   float *NavFn::getPathX() { return pathx; }
00368   float *NavFn::getPathY() { return pathy; }
00369   int    NavFn::getPathLen() { return npath; }
00370 
00371 
00372   //
00373   // simple obstacle setup for tests
00374   //
00375 
00376   void
00377     NavFn::setObs()
00378     {
00379 #if 0
00380       // set up a simple obstacle
00381       ROS_INFO("[NavFn] Setting simple obstacle\n");
00382       int xx = nx/3;
00383       for (int i=ny/3; i<ny; i++)
00384         costarr[i*nx + xx] = COST_OBS;
00385       xx = 2*nx/3;
00386       for (int i=ny/3; i<ny; i++)
00387         costarr[i*nx + xx] = COST_OBS;
00388 
00389       xx = nx/4;
00390       for (int i=20; i<ny-ny/3; i++)
00391         costarr[i*nx + xx] = COST_OBS;
00392       xx = nx/2;
00393       for (int i=20; i<ny-ny/3; i++)
00394         costarr[i*nx + xx] = COST_OBS;
00395       xx = 3*nx/4;
00396       for (int i=20; i<ny-ny/3; i++)
00397         costarr[i*nx + xx] = COST_OBS;
00398 #endif
00399     }
00400 
00401 
00402   // inserting onto the priority blocks
00403 #define push_cur(n)  { if (n>=0 && n<ns && !pending[n] && \
00404     costarr[n]<COST_OBS && curPe<PRIORITYBUFSIZE) \
00405   { curP[curPe++]=n; pending[n]=true; }}
00406 #define push_next(n) { if (n>=0 && n<ns && !pending[n] && \
00407     costarr[n]<COST_OBS && nextPe<PRIORITYBUFSIZE) \
00408   { nextP[nextPe++]=n; pending[n]=true; }}
00409 #define push_over(n) { if (n>=0 && n<ns && !pending[n] && \
00410     costarr[n]<COST_OBS && overPe<PRIORITYBUFSIZE) \
00411   { overP[overPe++]=n; pending[n]=true; }}
00412 
00413 
00414   // Set up navigation potential arrays for new propagation
00415 
00416   void
00417     NavFn::setupNavFn(bool keepit)
00418     {
00419       // reset values in propagation arrays
00420       for (int i=0; i<ns; i++)
00421       {
00422         potarr[i] = POT_HIGH;
00423         
00424         if (!keepit) costarr[i] = COST_NEUTRAL;
00425         gradx[i] = grady[i] = 0.0;
00426       }
00427 
00428       // outer bounds of cost array
00429       COSTTYPE *pc;
00430       pc = costarr;
00431       for (int i=0; i<nx; i++)
00432         *pc++ = COST_OBS;
00433       pc = costarr + (ny-1)*nx;
00434       for (int i=0; i<nx; i++)
00435         *pc++ = COST_OBS;
00436       pc = costarr;
00437       for (int i=0; i<ny; i++, pc+=nx)
00438         *pc = COST_OBS;
00439       pc = costarr + nx - 1;
00440       for (int i=0; i<ny; i++, pc+=nx)
00441         *pc = COST_OBS;
00442 
00443       // priority buffers
00444       curT = COST_OBS;
00445       curP = pb1; 
00446       curPe = 0;
00447       nextP = pb2;
00448       nextPe = 0;
00449       overP = pb3;
00450       overPe = 0;
00451       memset(pending, 0, ns*sizeof(bool));
00452 
00453       // set goal
00454       int k = goal[0] + goal[1]*nx;
00455       initCost(k,0);
00456 
00457       // find # of obstacle cells
00458       pc = costarr;
00459       int ntot = 0;
00460       for (int i=0; i<ns; i++, pc++)
00461       {
00462         if (*pc >= COST_OBS)
00463           ntot++;                       // number of cells that are obstacles
00464       }
00465       nobs = ntot;
00466     }
00467 
00468 
00469   // initialize a goal-type cost for starting propagation
00470 
00471   void
00472     NavFn::initCost(int k, float v)
00473     {
00474       potarr[k] = v;
00475       push_cur(k+1);
00476       push_cur(k-1);
00477       push_cur(k-nx);
00478       push_cur(k+nx);
00479     }
00480 
00481 
00482   // 
00483   // Critical function: calculate updated potential value of a cell,
00484   //   given its neighbors' values
00485   // Planar-wave update calculation from two lowest neighbors in a 4-grid
00486   // Quadratic approximation to the interpolated value 
00487   // No checking of bounds here, this function should be fast
00488   //
00489 
00490 #define INVSQRT2 0.707106781
00491 
00494   inline void
00495     NavFn::updateCell(int n)
00496     {
00497       // get neighbors
00498       float u,d,l,r;
00499       l = potarr[n-1];
00500       r = potarr[n+1];          
00501       u = potarr[n-nx];
00502       d = potarr[n+nx];
00503       //  ROS_INFO("[Update] c: %0.1f  l: %0.1f  r: %0.1f  u: %0.1f  d: %0.1f\n", 
00504       //         potarr[n], l, r, u, d);
00505       //  ROS_INFO("[Update] cost: %d\n", costarr[n]);
00506 
00507       // find lowest, and its lowest neighbor
00508       float ta, tc, hf;
00509       if (l<r) tc=l; else tc=r;
00510       if (u<d) ta=u; else ta=d;
00511 
00512 
00513       // do planar wave update
00514       if (costarr[n] < COST_OBS)        // don't propagate into obstacles
00515       {
00516         hf = (float)costarr[n]; // traversability factor
00517         
00518         float dc = tc-ta;               // relative cost between ta,tc
00519         if (dc < 0)             // ta is lowest
00520         {
00521           dc = -dc;
00522           ta = tc;
00523         }
00524 
00525         // calculate new potential
00526         float pot;
00527         if (dc >= hf)           // if too large, use ta-only update
00528           pot = ta+hf;
00529         else                    // two-neighbor interpolation update
00530         {
00531           // use quadratic approximation
00532           // might speed this up through table lookup, but still have to 
00533           //   do the divide
00534           float d = dc/hf;
00535           float v = -0.2301*d*d + 0.5307*d + 0.7040;
00536           pot = ta + hf*v;
00537         }
00538         
00539           bool inspline;
00540   
00541          for (int i=0;i<3*world_s;i++) 
00542         {
00543           if (n==S_map[i][0]+nx*S_map[i][1])
00544           {
00545           inspline=true;
00546           break;
00547           }
00548           else { 
00549           inspline=false;
00550           }
00551         }
00552         
00553         if (inspline==false)
00554         {
00555           pot=pot+100.0;
00556         }
00557 
00558 //      ROS_INFO("[Update] new pot: %d\n", costarr[n]);
00559 
00560         // now add affected neighbors to priority blocks
00561         if (pot < potarr[n])
00562         {
00563           float le = INVSQRT2*(float)costarr[n-1];
00564           float re = INVSQRT2*(float)costarr[n+1];
00565           float ue = INVSQRT2*(float)costarr[n-nx];
00566           float de = INVSQRT2*(float)costarr[n+nx];
00567           potarr[n] = pot;
00568           
00569           
00570           if (pot < curT)       // low-cost buffer block 
00571           {
00572             if (l > pot+le) push_next(n-1);
00573             if (r > pot+re) push_next(n+1);
00574             if (u > pot+ue) push_next(n-nx);
00575             if (d > pot+de) push_next(n+nx);
00576           }
00577           else                  // overflow block
00578           {
00579             if (l > pot+le) push_over(n-1);
00580             if (r > pot+re) push_over(n+1);
00581             if (u > pot+ue) push_over(n-nx);
00582             if (d > pot+de) push_over(n+nx);
00583           }
00584         }
00585 
00586       }
00587 
00588     }
00589 
00595   //
00596   // Use A* method for setting priorities
00597   // Critical function: calculate updated potential value of a cell,
00598   //   given its neighbors' values
00599   // Planar-wave update calculation from two lowest neighbors in a 4-grid
00600   // Quadratic approximation to the interpolated value 
00601   // No checking of bounds here, this function should be fast
00602   //
00603 
00604 #define INVSQRT2 0.707106781
00605 
00606   inline void
00607     NavFn::updateCellAstar(int n)
00608     {
00609       
00610       // get neighbors
00611       float u,d,l,r;
00612       l = potarr[n-1];
00613       r = potarr[n+1];          
00614       u = potarr[n-nx];
00615       d = potarr[n+nx];
00616       //ROS_INFO("[Update] c: %0.1f  l: %0.1f  r: %0.1f  u: %0.1f  d: %0.1f\n", 
00617       //         potarr[n], l, r, u, d);
00618       // ROS_INFO("[Update] cost of %d: %d\n", n, costarr[n]);
00619       // find lowest, and its lowest neighbor
00620       float ta, tc;
00621       if (l<r) tc=l; else tc=r;
00622       if (u<d) ta=u; else ta=d;
00623 
00624       // do planar wave update
00625       if (costarr[n] < COST_OBS)        // don't propagate into obstacles
00626       {
00627         float hf = (float)costarr[n]; // traversability factor
00628         float dc = tc-ta;               // relative cost between ta,tc
00629         if (dc < 0)             // ta is lowest
00630         {
00631           dc = -dc;
00632           ta = tc;
00633         }
00634 
00635         // calculate new potential
00636         float pot;
00637         if (dc >= hf)           // if too large, use ta-only update
00638           pot = ta+hf;
00639         else                    // two-neighbor interpolation update
00640         {
00641           // use quadratic approximation
00642           // might speed this up through table lookup, but still have to 
00643           //   do the divide
00644           float d = dc/hf;
00645           float v = -0.2301*d*d + 0.5307*d + 0.7040;
00646           pot = ta + hf*v;
00647         }
00648 
00649         //ROS_INFO("[Update] new pot: %d\n", costarr[n]);
00650 
00651         // now add affected neighbors to priority blocks
00652         if (pot < potarr[n])
00653         {
00654           float le = INVSQRT2*(float)costarr[n-1];
00655           float re = INVSQRT2*(float)costarr[n+1];
00656           float ue = INVSQRT2*(float)costarr[n-nx];
00657           float de = INVSQRT2*(float)costarr[n+nx];
00658 
00659           // calculate distance
00660           int x = n%nx;
00661           int y = n/nx;
00662           float dist = (x-start[0])*(x-start[0]) + (y-start[1])*(y-start[1]);
00663           dist = sqrtf(dist)*(float)COST_NEUTRAL;
00664 
00665           potarr[n] = pot;
00666           pot += dist;
00667           if (pot < curT)       // low-cost buffer block 
00668           {
00669             if (l > pot+le) push_next(n-1);
00670             if (r > pot+re) push_next(n+1);
00671             if (u > pot+ue) push_next(n-nx);
00672             if (d > pot+de) push_next(n+nx);
00673           }
00674           else
00675           {
00676 
00677             if (l > pot+le) push_over(n-1);
00678             if (r > pot+re) push_over(n+1);
00679             if (u > pot+ue) push_over(n-nx);
00680             if (d > pot+de) push_over(n+nx);
00681           }
00682         }
00683 
00684       }
00685 
00686     }
00687 
00688 
00689 
00690   //
00691   // main propagation function
00692   // Dijkstra method, breadth-first
00693   // runs for a specified number of cycles,
00694   //   or until it runs out of cells to update,
00695   //   or until the Start cell is found (atStart = true)
00696   //
00697 
00698   bool
00699     NavFn::propNavFnDijkstra(int cycles, bool atStart)  
00700     {
00701       int nwv = 0;                      // max priority block size
00702       int nc = 0;                       // number of cells put into priority blocks
00703       int cycle = 0;            // which cycle we're on
00704 
00705       // set up start cell
00706       int startCell = start[1]*nx + start[0];
00707         /* *********************************************************************************************************** */     
00708         spline();
00709         
00710         /* *********************************************************************************************************** */  
00711 
00712 
00713         
00714       for (; cycle < cycles; cycle++) // go for this many cycles, unless interrupted
00715       {
00716         
00717         // 
00718         if (curPe == 0 && nextPe == 0) // priority blocks empty
00719           break;
00720 
00721         // stats
00722         nc += curPe;
00723         if (curPe > nwv)
00724           nwv = curPe;
00725 
00726         // reset pending flags on current priority buffer
00727         int *pb = curP;
00728         int i = curPe;                  
00729         while (i-- > 0)         
00730           pending[*(pb++)] = false;
00731 
00732         // process current priority buffer
00733         pb = curP; 
00734         i = curPe;
00735         while (i-- > 0) 
00736         {
00737           updateCell(*pb++);
00738         }
00739         if (displayInt > 0 &&  (cycle % displayInt) == 0)
00740           displayFn(this);
00741 
00742         // swap priority blocks curP <=> nextP
00743         curPe = nextPe;
00744         nextPe = 0;
00745         pb = curP;              // swap buffers
00746         curP = nextP;
00747         nextP = pb;
00748         
00749         
00750         // see if we're done with this priority level
00751         if (curPe == 0)
00752         {
00753           curT += priInc;       // increment priority threshold
00754           curPe = overPe;       // set current to overflow block
00755           overPe = 0;
00756           pb = curP;            // swap buffers
00757           curP = overP;
00758           overP = pb;
00759         }
00760 
00761         // check if we've hit the Start cell
00762         if (atStart)
00763           if (potarr[startCell] < POT_HIGH)
00764             break;
00765       }
00766 
00767       ROS_DEBUG("[NavFn] Used %d cycles, %d cells visited (%d%%), priority buf max %d\n", 
00768           cycle,nc,(int)((nc*100.0)/(ns-nobs)),nwv);
00769 
00770       if (cycle < cycles) return true; // finished up here
00771       else return false;
00772     }
00773 
00774 
00775   //
00776   // main propagation function
00777   // A* method, best-first
00778   // uses Euclidean distance heuristic
00779   // runs for a specified number of cycles,
00780   //   or until it runs out of cells to update,
00781   //   or until the Start cell is found (atStart = true)
00782   //
00783 
00784   bool
00785     NavFn::propNavFnAstar(int cycles)   
00786     {
00787       int nwv = 0;                      // max priority block size
00788       int nc = 0;                       // number of cells put into priority blocks
00789       int cycle = 0;            // which cycle we're on
00790 
00791       // set initial threshold, based on distance
00792       float dist = (goal[0]-start[0])*(goal[0]-start[0]) + (goal[1]-start[1])*(goal[1]-start[1]);
00793       dist = sqrtf(dist)*(float)COST_NEUTRAL;
00794       curT = dist + curT;
00795 
00796       // set up start cell
00797       int startCell = start[1]*nx + start[0];
00798 
00799       // do main cycle
00800       for (; cycle < cycles; cycle++) // go for this many cycles, unless interrupted
00801       {
00802         // 
00803         if (curPe == 0 && nextPe == 0) // priority blocks empty
00804           break;
00805 
00806         // stats
00807         nc += curPe;
00808         if (curPe > nwv)
00809           nwv = curPe;
00810 
00811         // reset pending flags on current priority buffer
00812         int *pb = curP;
00813         int i = curPe;                  
00814         while (i-- > 0)         
00815           pending[*(pb++)] = false;
00816 
00817         // process current priority buffer
00818         pb = curP; 
00819         i = curPe;
00820         while (i-- > 0)         
00821           updateCellAstar(*pb++);
00822 
00823         if (displayInt > 0 &&  (cycle % displayInt) == 0)
00824           displayFn(this);
00825 
00826         // swap priority blocks curP <=> nextP
00827         curPe = nextPe;
00828         nextPe = 0;
00829         pb = curP;              // swap buffers
00830         curP = nextP;
00831         nextP = pb;
00832 
00833         // see if we're done with this priority level
00834         if (curPe == 0)
00835         {
00836           curT += priInc;       // increment priority threshold
00837           curPe = overPe;       // set current to overflow block
00838           overPe = 0;
00839           pb = curP;            // swap buffers
00840           curP = overP;
00841           overP = pb;
00842         }
00843 
00844         // check if we've hit the Start cell
00845         if (potarr[startCell] < POT_HIGH)
00846           break;
00847 
00848       }
00849 
00850       last_path_cost_ = potarr[startCell];
00851 
00852       ROS_DEBUG("[NavFn] Used %d cycles, %d cells visited (%d%%), priority buf max %d\n", 
00853           cycle,nc,(int)((nc*100.0)/(ns-nobs)),nwv);
00854 
00855 
00856       if (potarr[startCell] < POT_HIGH) return true; // finished up here
00857       else return false;
00858     }
00859 
00861 void NavFn::spline()
00862 {
00863  
00864 //      m_goal[0] = (w_goal.pose.position.x - costmap_ox) / resolution;
00865 //      m_goal[1] = (w_goal.pose.position.y - costmap_oy) / resolution; 
00866 //      m_start[0] = (w_start.pose.position.x - costmap_ox) / resolution;
00867 //      m_start[1] = (w_start.pose.position.y - costmap_oy) / resolution;       
00868 
00869 
00870   theta1 = tf::getYaw(w_start.pose.orientation);
00871   theta4 = tf::getYaw(w_goal.pose.orientation);
00872   p1[0] = w_start.pose.position.x;
00873   p1[1] = w_start.pose.position.y;
00874   p4[0] = w_goal.pose.position.x;
00875   p4[1] = w_goal.pose.position.y;
00876 
00877   float v=1.0;
00878   float w=0.0;
00879   float dt=0.5;
00880   
00881   float world_x = nx*resolution;
00882   float world_y = ny*resolution;
00883 //  int world_s = world_x * world_y;
00884   world_s = 101;
00885 
00886   
00888   p2[0] = p1[0] + v*dt*cos(theta1);
00889   p2[1] = p1[1] + v*dt*sin(theta1);
00890   theta2 = theta1 + w*dt;
00891   
00892   p3[0] = p4[0] - v*dt*cos(theta4);
00893   p3[1] = p4[1] - v*dt*sin(theta4);
00894   theta3 = theta4 - w*dt;
00895 
00896  
00897 //   ROS_INFO("theta_goal %1.4f", resolution);
00898   Eigen::Matrix4f M;
00899   M(0,0)=-1;
00900   M(0,1)=3;
00901   M(0,2)=-3;
00902   M(0,3)=1;
00903   M(1,0)=3;
00904   M(1,1)=-6;
00905   M(1,2)=3;
00906   M(1,3)=0;
00907   M(2,0)=-3;
00908   M(2,1)=0;
00909   M(2,2)=3;
00910   M(2,3)=0;
00911   M(3,0)=1;
00912   M(3,1)=4;
00913   M(3,2)=1;
00914   M(3,3)=0;
00915 //   
00916    Eigen::MatrixXf P1(4,2);
00917    P1(0,0)= p1[0];
00918    P1(0,1)= p1[1];
00919    P1(1,0)= p1[0];
00920    P1(1,1)= p1[1];
00921    P1(2,0)= p2[0];
00922    P1(2,1)= p2[1];
00923    P1(3,0)= p3[0];
00924    P1(3,1)= p3[1];
00925    
00926    
00927    Eigen::MatrixXf P2(4,2);
00928    P2(0,0)= p1[0];
00929    P2(0,1)= p1[1];
00930    P2(1,0)= p2[0];
00931    P2(1,1)= p2[1];
00932    P2(2,0)= p3[0];
00933    P2(2,1)= p3[1];
00934    P2(3,0)= p4[0];
00935    P2(3,1)= p4[1];   
00936    
00937    
00938    Eigen::MatrixXf P3(4,2);
00939    P3(0,0)= p2[0];
00940    P3(0,1)= p2[1];
00941    P3(1,0)= p3[0];
00942    P3(1,1)= p3[1];
00943    P3(2,0)= p4[0];
00944    P3(2,1)= p4[1];
00945    P3(3,0)= p4[0];
00946    P3(3,1)= p4[1];  
00947 
00948    float res = 1.0 / (world_s-1); 
00949    
00950 //   
00951    Eigen::MatrixXf t(world_s,1);
00952 
00953    t(0,0)=0;   
00954    for (int i=1;i<world_s;i++)
00955     {
00956       t(i,0)=t(i-1,0)+res;
00957     }
00958     
00959 
00960 
00961   Eigen::MatrixXf tt(world_s,4);
00962 
00963   tt.col(0) = t.array().pow(3);
00964   tt.col(1) = t.array().pow(2);
00965   tt.col(2) = t;
00966   tt.col(3) = Eigen::MatrixXf::Ones(world_s,1);
00967 
00968 
00969   
00970   Eigen::MatrixXf S1(world_s,2);
00971   Eigen::MatrixXf S2(world_s,2);
00972   Eigen::MatrixXf S3(world_s,2);
00973 //  Eigen::MatrixXf S_map(world_s,2);
00974   
00975   S1 = tt * (1.0 / 6.0) * M * P1;
00976   S2 = tt * (1.0 / 6.0) * M * P2;
00977   S3 = tt * (1.0 / 6.0) * M * P3;
00978 
00979 
00980   
00981    Eigen::MatrixXf S(3*world_s,2);
00982 
00983    S << S1, S2, S3; 
00984  
00985   
00986    for (int i=0;i<3*world_s;i++) 
00987    {
00988     S_map[i][0] = (int)((ceil)((S(i,0) - costmap_ox) / resolution));
00989     S_map[i][1] = (int)((ceil)((S(i,1) - costmap_oy) / resolution));
00990    }
00991 
00992         m_goal[0] = (int)((ceil)((w_goal.pose.position.x - costmap_ox) / resolution));
00993         m_goal[1] = (int)((ceil)((w_goal.pose.position.y - costmap_oy) / resolution));  
00994 
00995 //   std::cout << "-- S--" << std::endl << S << std::endl;
00996 
00997         
00998 //          for (int i=0;i<world_s;i++) 
00999 //      {
01000 // //     splinearr[S_map[i][0]+nx*S_map[i][1]]=splinearr[S_map[i-1][0]+nx*S_map[i-1][1]]-d;
01001 //        initCost(S_map[i][0]+nx*S_map[i][1],0);
01002 //      }
01003 
01004   
01005 }
01006 
01011   float NavFn::getLastPathCost()
01012   {
01013     return last_path_cost_;
01014   }
01015 
01016 
01017   //
01018   // Path construction
01019   // Find gradient at array points, interpolate path
01020   // Use step size of pathStep, usually 0.5 pixel
01021   //
01022   // Some sanity checks:
01023   //  1. Stuck at same index position
01024   //  2. Doesn't get near goal
01025   //  3. Surrounded by high potentials
01026   //
01027 
01028   int
01029     NavFn::calcPath(int n, int *st)
01030     {
01031       // test write
01032       //savemap("test");
01033 
01034       // check path arrays
01035       if (npathbuf < n)
01036       {
01037         if (pathx) delete [] pathx;
01038         if (pathy) delete [] pathy;
01039         pathx = new float[n];
01040         pathy = new float[n];
01041         npathbuf = n;
01042       }
01043 
01044       // set up start position at cell
01045       // st is always upper left corner for 4-point bilinear interpolation 
01046       if (st == NULL) st = start;
01047       int stc = st[1]*nx + st[0];
01048 
01049       // set up offset
01050       float dx=0;
01051       float dy=0;
01052       npath = 0;
01053 
01054       // go for <n> cycles at most
01055       for (int i=0; i<n; i++)
01056       {
01057         // check if near goal
01058         int nearest_point=std::max(0,std::min(nx*ny-1,stc+(int)round(dx)+(int)(nx*round(dy))));
01059         if (potarr[nearest_point] < COST_NEUTRAL)
01060         {
01061           pathx[npath] = (float)goal[0];
01062           pathy[npath] = (float)goal[1];
01063           return ++npath;       // done!
01064         }
01065 
01066         if (stc < nx || stc > ns-nx) // would be out of bounds
01067         {
01068           ROS_DEBUG("[PathCalc] Out of bounds");
01069           return 0;
01070         }
01071 
01072         // add to path
01073         pathx[npath] = stc%nx + dx;
01074         pathy[npath] = stc/nx + dy;
01075         npath++;
01076 
01077         int stcnx = stc+nx;
01078         int stcpx = stc-nx;
01079 
01080         // check for potentials at eight positions near cell
01081         if (potarr[stc] >= POT_HIGH ||
01082             potarr[stc+1] >= POT_HIGH ||
01083             potarr[stc-1] >= POT_HIGH ||
01084             potarr[stcnx] >= POT_HIGH ||
01085             potarr[stcnx+1] >= POT_HIGH ||
01086             potarr[stcnx-1] >= POT_HIGH ||
01087             potarr[stcpx] >= POT_HIGH ||
01088             potarr[stcpx+1] >= POT_HIGH ||
01089             potarr[stcpx-1] >= POT_HIGH)
01090 
01091         {
01092           ROS_DEBUG("[Path] Pot fn boundary, following grid (%0.1f/%d)", potarr[stc], npath);
01093           // check eight neighbors to find the lowest
01094           int minc = stc;
01095           int minp = potarr[stc];
01096           int st = stcpx - 1;
01097           if (potarr[st] < minp) {minp = potarr[st]; minc = st; }
01098           st++;
01099           if (potarr[st] < minp) {minp = potarr[st]; minc = st; }
01100           st++;
01101           if (potarr[st] < minp) {minp = potarr[st]; minc = st; }
01102           st = stc-1;
01103           if (potarr[st] < minp) {minp = potarr[st]; minc = st; }
01104           st = stc+1;
01105           if (potarr[st] < minp) {minp = potarr[st]; minc = st; }
01106           st = stcnx-1;
01107           if (potarr[st] < minp) {minp = potarr[st]; minc = st; }
01108           st++;
01109           if (potarr[st] < minp) {minp = potarr[st]; minc = st; }
01110           st++;
01111           if (potarr[st] < minp) {minp = potarr[st]; minc = st; }
01112           stc = minc;
01113           dx = 0;
01114           dy = 0;
01115 
01116           ROS_DEBUG("[Path] Pot: %0.1f  pos: %0.1f,%0.1f",
01117               potarr[stc], pathx[npath-1], pathy[npath-1]);
01118 
01119           if (potarr[stc] >= POT_HIGH)
01120           {
01121             ROS_DEBUG("[PathCalc] No path found, high potential");
01122             //savemap("navfn_highpot");
01123             return 0;
01124           }
01125         }
01126 
01127         // have a good gradient here
01128         else                    
01129         {
01130 
01131           // get grad at four positions near cell
01132           gradCell(stc);
01133           gradCell(stc+1);
01134           gradCell(stcnx);
01135           gradCell(stcnx+1);
01136 
01137 
01138           // show gradients
01139           ROS_DEBUG("[Path] %0.2f,%0.2f  %0.2f,%0.2f  %0.2f,%0.2f  %0.2f,%0.2f\n",
01140               gradx[stc], grady[stc], gradx[stc+1], grady[stc+1], 
01141               gradx[stcnx], grady[stcnx], gradx[stcnx+1], grady[stcnx+1]);
01142 
01143           // get interpolated gradient
01144           float x1 = (1.0-dx)*gradx[stc] + dx*gradx[stc+1];
01145           float x2 = (1.0-dx)*gradx[stcnx] + dx*gradx[stcnx+1];
01146           float x = (1.0-dy)*x1 + dy*x2; // interpolated x
01147           float y1 = (1.0-dx)*grady[stc] + dx*grady[stc+1];
01148           float y2 = (1.0-dx)*grady[stcnx] + dx*grady[stcnx+1];
01149           float y = (1.0-dy)*y1 + dy*y2; // interpolated y
01150 
01151           // check for zero gradient, failed
01152           if (x == 0.0 && y == 0.0)
01153           {
01154             ROS_DEBUG("[PathCalc] Zero gradient");        
01155             return 0;
01156           }
01157 
01158           // move in the right direction
01159           float ss = pathStep/sqrt(x*x+y*y);
01160           dx += x*ss;
01161           dy += y*ss;
01162 
01163           // check for overflow
01164           if (dx > 1.0) { stc++; dx -= 1.0; }
01165           if (dx < -1.0) { stc--; dx += 1.0; }
01166           if (dy > 1.0) { stc+=nx; dy -= 1.0; }
01167           if (dy < -1.0) { stc-=nx; dy += 1.0; }
01168 
01169         }
01170 
01171         //      ROS_INFO("[Path] Pot: %0.1f  grad: %0.1f,%0.1f  pos: %0.1f,%0.1f\n",
01172         //           potarr[stc], x, y, pathx[npath-1], pathy[npath-1]);
01173       }
01174 
01175       //  return npath;                 // out of cycles, return failure
01176       ROS_DEBUG("[PathCalc] No path found, path too long");
01177       //savemap("navfn_pathlong");
01178       return 0;                 // out of cycles, return failure
01179     }
01180 
01181 
01182   //
01183   // gradient calculations
01184   //
01185 
01186   // calculate gradient at a cell
01187   // positive value are to the right and down
01188   float                         
01189     NavFn::gradCell(int n)
01190     {
01191       if (gradx[n]+grady[n] > 0.0)      // check this cell
01192         return 1.0;                     
01193 
01194       if (n < nx || n > ns-nx)  // would be out of bounds
01195         return 0.0;
01196 
01197       float cv = potarr[n];
01198       float dx = 0.0;
01199       float dy = 0.0;
01200 
01201       // check for in an obstacle
01202       if (cv >= POT_HIGH) 
01203       {
01204         if (potarr[n-1] < POT_HIGH)
01205           dx = -COST_OBS;
01206         else if (potarr[n+1] < POT_HIGH)
01207           dx = COST_OBS;
01208 
01209         if (potarr[n-nx] < POT_HIGH)
01210           dy = -COST_OBS;
01211         else if (potarr[nx+1] < POT_HIGH)
01212           dy = COST_OBS;
01213       }
01214 
01215       else                              // not in an obstacle
01216       {
01217         // dx calc, average to sides
01218         if (potarr[n-1] < POT_HIGH)
01219           dx += potarr[n-1]- cv;        
01220         if (potarr[n+1] < POT_HIGH)
01221           dx += cv - potarr[n+1]; 
01222 
01223         // dy calc, average to sides
01224         if (potarr[n-nx] < POT_HIGH)
01225           dy += potarr[n-nx]- cv;       
01226         if (potarr[n+nx] < POT_HIGH)
01227           dy += cv - potarr[n+nx]; 
01228       }
01229 
01230       // normalize
01231       float norm = sqrtf(dx*dx+dy*dy);
01232       if (norm > 0)
01233       {
01234         norm = 1.0/norm;
01235         gradx[n] = norm*dx;
01236         grady[n] = norm*dy;
01237       }
01238       return norm;
01239     }
01240 
01241 
01242   //
01243   // display function setup
01244   // <n> is the number of cycles to wait before displaying,
01245   //     use 0 to turn it off
01246 
01247   void
01248     NavFn::display(void fn(NavFn *nav), int n)
01249     {
01250       displayFn = fn;
01251       displayInt = n;
01252     }
01253 
01254 
01255   //
01256   // debug writes
01257   // saves costmap and start/goal
01258   //
01259 
01260   void 
01261     NavFn::savemap(const char *fname)
01262     {
01263       char fn[4096];
01264 
01265       ROS_DEBUG("[NavFn] Saving costmap and start/goal points");
01266       // write start and goal points
01267       sprintf(fn,"%s.txt",fname);
01268       FILE *fp = fopen(fn,"w");
01269       if (!fp)
01270       {
01271         ROS_WARN("Can't open file %s", fn);
01272         return;
01273       }
01274       fprintf(fp,"Goal: %d %d\nStart: %d %d\n",goal[0],goal[1],start[0],start[1]);
01275       fclose(fp);
01276 
01277       // write cost array
01278       if (!costarr) return;
01279       sprintf(fn,"%s.pgm",fname);
01280       fp = fopen(fn,"wb");
01281       if (!fp)
01282       {
01283         ROS_WARN("Can't open file %s", fn);
01284         return;
01285       }
01286       fprintf(fp,"P5\n%d\n%d\n%d\n", nx, ny, 0xff);
01287       fwrite(costarr,1,nx*ny,fp);
01288       fclose(fp);
01289     }
01290 };


iri_bspline_navfn
Author(s): Maintained by IRI Robotics Lab
autogenerated on Fri Dec 6 2013 23:43:14