Tekkotsu Homepage
Demos
Overview
Downloads
Dev. Resources
Reference
Credits

GenericRRT.h

Go to the documentation of this file.
00001 //-*-c++-*-
00002 #ifndef _GENERIC_RRT_H_
00003 #define _GENERIC_RRT_H_
00004 
00005 #include <vector>
00006 #include <ostream>
00007 #include <cmath>
00008 
00009 #include "Shared/Measures.h"  // AngTwoPi
00010 
00011 using namespace DualCoding;
00012 
00013 //================ RRTNodeBase ================
00014 
00015 //! Base class for RRT nodes used by GenericRRT
00016 /*! Subclasses of RRTNodeBase must provide a NodeValue_t type, a
00017   CollisionChecker class, and the following methods: distance,
00018   generateSample, interpolate, toString.
00019 */
00020 class RRTNodeBase {
00021 public:
00022   RRTNodeBase(unsigned int p) : parent(p) {}
00023   unsigned int parent;
00024   enum Interp_t { COLLISION, APPROACHED, REACHED };
00025   //! returns a value in the range [minVal, maxVal), i.e. inclusive minVal, exclusive maxVal
00026   static float randRange(float minVal, float maxVal) {
00027     return (maxVal - minVal) * (rand()/((float)RAND_MAX)) + minVal;
00028   }
00029   virtual ~RRTNodeBase() {}
00030   virtual std::string toString() const = 0;
00031 };
00032 
00033 //================ AdmissibilityPredicate ================
00034 
00035 //! Base class for admissibility predicates to determine whether a node is admissible.
00036 /*! Subclasses of AdmissibilityPredicateBase must provide the following method:
00037   admissible(NodeValue_t, std::vector<NODE>&, unsigned int);
00038 */
00039 
00040 template<typename NODE>
00041 class AdmissibilityPredicate {
00042 public:
00043   //! constructor
00044   AdmissibilityPredicate() {}
00045   
00046   //! destructor
00047   virtual ~AdmissibilityPredicate() {}
00048   
00049   //! test to see if node is admissible
00050   virtual bool admissible(typename NODE::NodeValue_t q, std::vector<NODE>& tree, unsigned int parent) = 0;
00051 };
00052 
00053 //================ GenericRRT ================
00054 
00055 class GenericRRTBase {
00056 public:
00057   enum PlanPathResultCode {SUCCESS, START_COLLIDES, END_COLLIDES, MAX_ITER};
00058   
00059   //! Relays planner success/failure, as well as obstacles in the case of initial collision states
00060   /*! If a collision occurs, the colliding obstacles will also be included.
00061    Otherwise, they will be set to NULL. */
00062   template <size_t N>
00063   class PlannerResult {
00064   public:
00065     GenericRRTBase::PlanPathResultCode code;
00066     PlannerObstacle<N> *movingObstacle;
00067     PlannerObstacle<N> *collidingObstacle;
00068     
00069     PlannerResult() : code(), movingObstacle(NULL), collidingObstacle(NULL) {}
00070     
00071     ~PlannerResult() {
00072       delete movingObstacle;
00073       delete collidingObstacle;
00074     }
00075 
00076     //! Copy constructor
00077     PlannerResult(const PlannerResult &other) : 
00078       code(other.code), 
00079       movingObstacle(other.movingObstacle ? dynamic_cast<PlannerObstacle<N>*>(other.movingObstacle->clone()) : NULL), 
00080       collidingObstacle(other.collidingObstacle ? dynamic_cast<PlannerObstacle<N>*>(other.collidingObstacle->clone()) : NULL) {}
00081 
00082     //! Assignment operator
00083     PlannerResult& operator=(const PlannerResult &other) {
00084       delete movingObstacle;
00085       delete collidingObstacle;
00086       code = other.code;
00087       movingObstacle = other.movingObstacle ? dynamic_cast<PlannerObstacle<N>*>(other.movingObstacle->clone()) : NULL;
00088       collidingObstacle = other.collidingObstacle ? dynamic_cast<PlannerObstacle<N>*>(other.collidingObstacle->clone()) : NULL;
00089       return *this;
00090     }
00091 
00092   };
00093   
00094   virtual ~GenericRRTBase() {}
00095 
00096   typedef PlannerResult<2> PlannerResult2D;
00097   typedef PlannerResult<3> PlannerResult3D;
00098 };
00099 
00100 //! Generic RRT implementation that makes no assumptions about the nature of the state space; those details are handled by the NODE template argument, which must be a subclass of RRTNodeBase
00101 template<typename NODE, size_t N>
00102 class GenericRRT : public GenericRRTBase {
00103 public:
00104   typedef typename NODE::NodeValue_t NodeValue_t;
00105 protected:
00106   //! lower limits on state q
00107   NodeValue_t lowerLimits;
00108   //! upper limits on state q
00109   NodeValue_t upperLimits;
00110   //! interpolation steps for q while extending
00111   NodeValue_t extendingInterpolationStep;
00112   //! interpolation steps for q while smoothing
00113   NodeValue_t smoothingInterpolationStep;
00114 
00115   //! collision checker
00116   typename NODE::CollisionChecker *cc;
00117 
00118   //! admissibility predicate
00119   AdmissibilityPredicate<NODE> *predicate;
00120 
00121 public:
00122   //! Constructor; will delete @a collCheck argument when destructed
00123   GenericRRT(typename NODE::CollisionChecker *collCheck,
00124        AdmissibilityPredicate<NODE> *predicate=NULL);
00125 
00126   //! Copy constructor
00127   GenericRRT(const GenericRRT &other) :
00128     GenericRRTBase(other), 
00129     lowerLimits(other.lowerLimits), upperLimits(other.upperLimits),
00130     extendingInterpolationStep(other.extendingInterpolationStep),
00131     smoothingInterpolationStep(other.smoothingInterpolationStep),
00132     cc(other.cc), predicate(other.predicate) {}
00133 
00134 
00135   //! Destructor: deletes the collision checker
00136   virtual ~GenericRRT() { delete cc; delete predicate; }
00137 
00138   //! Set lower and upper value limits for each dimension of the space
00139   void setLimits(const NodeValue_t &_lowerLimits, const NodeValue_t &_upperLimits) {
00140     lowerLimits = _lowerLimits;
00141     upperLimits = _upperLimits;
00142   }
00143 
00144   //! Set interpolation step size for each dimension of the space for both extending and smoothing
00145   virtual void setInterpolation(const NodeValue_t &_interpolationStep) { setSmoothingInterpolation(_interpolationStep); setExtendingInterpolation(_interpolationStep); }
00146 
00147   //! Set interpolation step size for each dimension of the space for extending
00148   virtual void setExtendingInterpolation(const NodeValue_t &_extendingInterpolationStep) { extendingInterpolationStep = _extendingInterpolationStep; }
00149 
00150   //! Set interpolation step size for each dimension of the space for smoothing
00151   virtual void setSmoothingInterpolation(const NodeValue_t &_smoothingInterpolationStep) { smoothingInterpolationStep = _smoothingInterpolationStep; }
00152 
00153   //! Plan a path from start to end
00154   virtual PlannerResult<N> planPath(const NodeValue_t &start,
00155                                     const NodeValue_t &end,
00156                                     unsigned int maxIterations,
00157                                     std::vector<NodeValue_t> *pathResult=NULL,
00158                                     std::vector<NODE> *treeStartResult=NULL,
00159                                     std::vector<NODE> *treeEndResult=NULL);
00160 
00161   virtual void dumpTree(const std::vector<NODE> &tree, const std::string &header="");
00162 
00163   void addObstaclesToShapeSpace(ShapeSpace &space) const;
00164 
00165 protected:
00166   //! Set up initial search trees
00167   virtual void initialize(const NodeValue_t &start, std::vector<NODE> &treeStartResult,
00168         const NodeValue_t &end, std::vector<NODE> &treeEndResult);
00169   virtual void buildPath(const std::vector<NODE> *treeStart, const std::vector<NODE> *treeEnd, 
00170        std::vector<NodeValue_t> &path);
00171 
00172   void addNode(std::vector<NODE> *tree, const NodeValue_t &q, unsigned int parent);
00173 
00174 private:
00175   unsigned int nearestNode(std::vector<NODE> *tree, const NodeValue_t &target);
00176   RRTNodeBase::Interp_t extend(std::vector<NODE> *tree, const NodeValue_t &q, bool truncate, bool fromOtherTree);
00177 
00178   GenericRRT& operator=(const GenericRRT&);   //!< Don't call this
00179 };
00180 
00181 //================ IMPLEMENTATION ================
00182 
00183 template<typename NODE, size_t N>
00184 GenericRRT<NODE, N>::GenericRRT(typename NODE::CollisionChecker *collCheck,
00185            AdmissibilityPredicate<NODE> *_predicate) :
00186   lowerLimits(), upperLimits(), extendingInterpolationStep(), smoothingInterpolationStep(), cc(collCheck), predicate(_predicate) {}
00187 
00188 template<typename NODE, size_t N>
00189 void GenericRRT<NODE, N>::initialize(const NodeValue_t &start, std::vector<NODE> &treeStart,
00190           const NodeValue_t &end, std::vector<NODE> &treeEnd) {
00191   addNode(&treeStart, start, 0);
00192   addNode(&treeEnd, end, 0);
00193 }
00194 
00195 template<typename NODE, size_t N>
00196 GenericRRTBase::PlannerResult<N>
00197 GenericRRT<NODE, N>::planPath(const NodeValue_t &start, const NodeValue_t &end,
00198                               unsigned int maxIterations,
00199                               std::vector<NodeValue_t> *pathResult,
00200                               std::vector<NODE> *treeStartResult, std::vector<NODE> *treeEndResult) {
00201   PlannerResult<N> result;
00202   
00203   // check start/end configurations
00204   if ( cc->collides(start, &result) ) {
00205     result.code = START_COLLIDES;
00206     return result;
00207   }
00208   
00209   if ( cc->collides(end, &result) ) {
00210     result.code = END_COLLIDES;
00211     return result;
00212   }
00213 
00214   // setup state storage
00215   std::vector<NODE> privateTreeStart, privateTreeEnd;
00216   std::vector<NODE> *treeStart = treeStartResult ? treeStartResult : &privateTreeStart;
00217   std::vector<NODE> *treeEnd = treeEndResult ? treeEndResult : &privateTreeEnd;
00218   treeStart->clear();
00219   treeEnd->clear();
00220 
00221   // add initial configs in
00222   initialize(start, *treeStart, end, *treeEnd);
00223 
00224   std::vector<NODE> *A = treeStart;
00225   std::vector<NODE> *B = treeEnd;
00226   
00227   unsigned int iter = 0;
00228   // test for direct path from start to end
00229   if ( extend(A, end, false, false) != RRTNodeBase::REACHED ) {
00230     // if there is no direct path, build the tree
00231     while ( iter < maxIterations ) {
00232       NodeValue_t qrand;
00233       NODE::generateSample(lowerLimits,upperLimits,qrand);
00234       if ( cc->collides(qrand) )
00235         continue;
00236       if ( extend(A, qrand, true, false) != RRTNodeBase::COLLISION )
00237         if ( extend(B, A->back().q, true, true) == RRTNodeBase::REACHED )
00238           break;
00239       swap(A,B);
00240       iter++;
00241     }
00242   }
00243 
00244   if ( iter >= maxIterations ) {
00245     // dumpTree(*treeStart,"treeStart: ================");
00246     // dumpTree(*treeEnd,"treeEnd: ================");
00247     result.code = MAX_ITER;
00248     return result;
00249   }
00250 
00251   if ( pathResult != NULL )
00252     buildPath(treeStart, treeEnd, *pathResult);
00253 
00254   result.code = SUCCESS;
00255   return result;
00256 }
00257 
00258 // nearestNode
00259 template<typename NODE, size_t N>
00260 unsigned int GenericRRT<NODE, N>::nearestNode(std::vector<NODE> *tree, const NodeValue_t &target) {
00261   unsigned int nearest = 0;
00262   float dist = (*tree)[nearest].distance(target);
00263   for (unsigned int i = 1; i < tree->size(); i++) {
00264     float d = (*tree)[i].distance(target);
00265     if (d < dist) {
00266       nearest = i;
00267       dist = d;
00268     }
00269   }
00270   return nearest;
00271 }
00272 
00273 // extend
00274 template<typename NODE, size_t N>
00275 RRTNodeBase::Interp_t GenericRRT<NODE, N>::extend(std::vector<NODE> *tree, const NodeValue_t &target, bool truncate, bool fromOtherTree) {
00276   unsigned int nearest = nearestNode(tree, target);
00277   NodeValue_t reached;
00278   // interpolate towards target
00279   RRTNodeBase::Interp_t result = NODE::interpolate((*tree)[nearest].q, target, extendingInterpolationStep, truncate, cc, reached, fromOtherTree);
00280   if ( result != RRTNodeBase::COLLISION ) {
00281     if ( predicate != NULL && predicate->admissible(reached, *tree, nearest) == false )
00282       result = RRTNodeBase::COLLISION;  // pretend inadmissible node causes a collision
00283     else
00284       addNode(tree, reached, nearest);
00285   }
00286   return result;
00287 }
00288 
00289 // addNode
00290 template<typename NODE, size_t N>
00291 void GenericRRT<NODE, N>::addNode(std::vector<NODE> *tree, const NodeValue_t &q, unsigned int parent) {
00292   tree->push_back(NODE(q, parent));
00293 }
00294 
00295 // buildPath
00296 template<typename NODE, size_t N>
00297 void GenericRRT<NODE, N>::buildPath(const std::vector<NODE> *treeStart, const std::vector<NODE> *treeEnd,
00298           std::vector<NodeValue_t> &path) {
00299 
00300   // connection point is last value in each tree
00301   unsigned int n = treeStart->size() - 1;
00302   while (n != 0) {
00303     n = (*treeStart)[n].parent;
00304     path.push_back((*treeStart)[n].q);
00305   }
00306 
00307   std::reverse(path.begin(), path.end());
00308   path.push_back(treeEnd->back().q);
00309 
00310   n = treeEnd->size() - 1;
00311   while (n != 0) {
00312     n = (*treeEnd)[n].parent;
00313     path.push_back((*treeEnd)[n].q);
00314   }
00315 
00316   // smooth path
00317   size_t maxIter = max((size_t)20, 2*path.size());
00318 
00319   for (size_t i = 0; i < maxIter; i++) {
00320     int a = rand() % path.size();
00321     int b = rand() % path.size();
00322     if (a > b)
00323       std::swap(a,b);
00324     else if (a == b)
00325       continue;
00326 
00327     NodeValue_t dummy;
00328     if ( NODE::interpolate(path[a], path[b], smoothingInterpolationStep, 
00329                            false, cc, dummy, true) == RRTNodeBase::REACHED ) {
00330       // remove a -> b
00331       //      cout << "Erasing " << a << " to " << b << endl;
00332       //      cout << path.size() << endl;
00333       path.erase(path.begin()+a+1,path.begin()+b);
00334       //      cout << path.size() << endl;
00335     }
00336   }
00337 
00338   for (size_t i = 0; i+2 < path.size(); i++) {
00339     size_t j;
00340     for (j = i + 2; j < path.size(); j++) {
00341       NodeValue_t dummy;
00342       if ( NODE::interpolate(path[i], path[j], smoothingInterpolationStep, false, cc, dummy, true) != RRTNodeBase::REACHED )
00343   break;
00344     }
00345     if (j > i + 3 && j < path.size())
00346       path.erase(path.begin()+i+1, path.begin()+j-1);
00347   }
00348 }
00349 
00350 template<typename NODE, size_t N>
00351 void GenericRRT<NODE, N>::dumpTree(const std::vector<NODE> &tree, const std::string &header) {
00352   if ( header.size() > 0 )
00353     std::cout << header << std::endl;
00354   for ( size_t i = 0; i < tree.size(); i++ )
00355     if ( tree[i].parent != 0 )
00356       std::cout << " " << tree[i].toString() << "   " << tree[tree[i].parent].toString() << std::endl;
00357 }
00358 
00359 template<typename NODE, size_t N>
00360 void GenericRRT<NODE, N>::addObstaclesToShapeSpace(ShapeSpace &space) const {
00361   cc->addObstaclesToShapeSpace(space);
00362 }
00363 
00364 #endif

Tekkotsu v5.1CVS
Generated Sat May 4 06:32:49 2013 by Doxygen 1.6.3