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

Tekkotsu v5.1CVS
Generated Fri Mar 16 05:26:40 2012 by Doxygen 1.6.3