Tekkotsu Homepage
Demos
Overview
Downloads
Dev. Resources
Reference
Credits

ShapeSpacePlannerXYTheta.cc

Go to the documentation of this file.
00001 #include "ShapeSpacePlannerXYTheta.h"
00002 #include "Shared/mathutils.h" // for isnan fix
00003 
00004 //================ RRTNodeXYTheta ================
00005 
00006 const AngSignPi RRTNodeXYTheta::turnLimit = M_PI;  // was M_PI/18;
00007 
00008 float RRTNodeXYTheta::distance(const NodeValue_t &target) {
00009   return (q.first.first-target.first.first)*(q.first.first-target.first.first) +
00010   (q.first.second-target.first.second)*(q.first.second-target.first.second);
00011 }
00012 
00013 void RRTNodeXYTheta::generateSample(const NodeValue_t &lower, 
00014                                     const NodeValue_t &upper,
00015                                     NodeValue_t &sample) {
00016   sample.first.first = randRange(lower.first.first, upper.first.first);
00017   sample.first.second = randRange(lower.first.second, upper.first.second);
00018   sample.second = randRange(lower.second, upper.second);
00019 }
00020 
00021 RRTNodeBase::Interp_t RRTNodeXYTheta::interpolate(const NodeValue_t &start, const NodeValue_t &target, const NodeValue_t &interp, 
00022                                                   bool truncate, CollisionChecker *cc, NodeValue_t &reached, bool fromOtherTree) {
00023   const float stepLength = interp.first.first;
00024   
00025   // length of vector
00026   float dist = sqrt( pow(target.first.first-start.first.first, 2) + pow(target.first.second-start.first.second, 2) );
00027   
00028   if (fromOtherTree) {
00029     // if distance to nearest neighbor is very small and the angle is within turn limit, consider it done; extending from one tree to another
00030     if (dist < stepLength && abs(AngSignPi((float)start.second - (float)target.second - M_PI)) < turnLimit) {
00031       reached = target;
00032       reached.second += M_PI;
00033       bool collision = cc->collides(reached);
00034       reached.second -= M_PI;
00035       if ( collision )
00036         return COLLISION;
00037       else
00038         return REACHED;
00039     }
00040   }
00041   
00042   // determine heading
00043   NodeValue_t targetNew;
00044   targetNew.second = AngTwoPi(atan2(target.first.second-start.first.second, target.first.first-start.first.first));
00045   targetNew.first.first = start.first.first + cos(targetNew.second) * stepLength;
00046   targetNew.first.second = start.first.second + sin(targetNew.second) * stepLength;
00047   
00048   if (!goodAngle(start, targetNew)) {
00049     // limit angle if it's too much.
00050     AngSignPi diff(targetNew.second - start.second);
00051     AngSignPi signedTurn(diff > 0 ? turnLimit : AngSignPi(-turnLimit));
00052     AngTwoPi newAngle(start.second + signedTurn);
00053     
00054     // new position
00055     targetNew.first.first = start.first.first + cos(newAngle) * stepLength;
00056     targetNew.first.second = start.first.second + sin(newAngle) * stepLength;
00057     targetNew.second = newAngle;
00058   }
00059   
00060   // recalculate heading
00061   targetNew.second = AngTwoPi(atan2(targetNew.first.second-start.first.second, targetNew.first.first-start.first.first));
00062   reached = targetNew;
00063   
00064   if (fromOtherTree)
00065     reached.second += M_PI;
00066   bool collision = cc->collides(reached);
00067   if (fromOtherTree)
00068     reached.second -= M_PI;
00069   if ( collision )
00070     return COLLISION;
00071   else
00072     return APPROACHED;
00073 }
00074 
00075 RRTNodeBase::Interp_t RRTNodeXYTheta::smoothInterpolate(const NodeValue_t &start, const NodeValue_t &target, const NodeValue_t &interp, CollisionChecker *cc) {
00076   if (abs(AngSignPi(start.second - target.second)) > turnLimit)
00077     return COLLISION; // pretend we collided if angle is bad
00078   
00079   int xsteps = int(fabs(target.first.first-start.first.first)/interp.first.first);
00080   int ysteps = int(fabs(target.first.second-start.first.second)/interp.first.second);
00081   int numSteps = std::max(xsteps,ysteps);
00082   float deltaX = (target.first.first-start.first.first)/float(numSteps);
00083   float deltaY = (target.first.second-start.first.second)/float(numSteps);
00084   
00085   // Interpolate along the path and check for collisions
00086   NodeValue_t reached = start;
00087   for (int t = 0; t < numSteps; t++) {
00088     reached.first.first += deltaX;
00089     reached.first.second += deltaY;
00090     if ( cc->collides(reached) )
00091       return COLLISION;
00092   }
00093   
00094   if ( cc->collides(target) )
00095     return COLLISION;
00096   else
00097     return REACHED;
00098 }
00099 
00100 bool RRTNodeXYTheta::goodAngle(const NodeValue_t &q1, const NodeValue_t &qnew) {
00101   AngSignPi currentAngle(q1.second);
00102   AngSignPi newAngle(atan2(qnew.first.second - q1.first.second, qnew.first.first - q1.first.first));
00103   return abs(AngSignPi(newAngle-currentAngle)) < turnLimit;
00104 }
00105 
00106 std::string RRTNodeXYTheta::toString() const {
00107   char buff[100];
00108   sprintf(buff, "%7.2f %7.2f %7.2f", q.first.first, q.first.second, (float)(q.second));
00109   return string(buff);
00110 }
00111 
00112 bool RRTNodeXYTheta::CollisionChecker::collides(const NodeValue_t &qnew, GenericRRTBase::PlannerResult2D* result) {
00113   // treat as collision if outside world bounds
00114   if ( worldBounds.isValid() && !worldBounds->isInside(Point(qnew.first.first, qnew.first.second)) ) {
00115     if (result) {
00116       ostringstream os;
00117       os << VRmixin::theAgent->getName() << "-" << VRmixin::theAgent->getId();
00118       result->movingObstacle = new HierarchicalObstacle; // there really is none
00119       result->movingObstacle->name = os.str();
00120       ostringstream os2;
00121       os2 << worldBounds->getName() << "-" << worldBounds->getId();
00122       result->collidingObstacle = new HierarchicalObstacle;
00123       result->collidingObstacle->name = os2.str();
00124     }
00125     return true;
00126   }
00127   
00128   body.updatePosition(fmat::pack(qnew.first.first, qnew.first.second));
00129   body.updateRotation(fmat::rotation2D(qnew.second));
00130   
00131   for (size_t i = 0; i < obstacles.size(); i++) {
00132     if (obstacles[i]->isBodyObstacle())
00133       continue;
00134     if (obstacles[i]->collides(body)) {
00135       if (result) {
00136         ostringstream os;
00137         os << VRmixin::theAgent->getName() << "-" << VRmixin::theAgent->getId();
00138         result->movingObstacle = dynamic_cast<PlannerObstacle2D*>(body.clone());
00139         result->movingObstacle->name = os.str();
00140         result->collidingObstacle = dynamic_cast<PlannerObstacle2D*>(obstacles[i]->clone());
00141       }
00142       // std::cout << "Collision: " << robot.toString() << " with " << obstacles[i]->toString() << std::endl;
00143       return true;
00144     }
00145   }
00146   return false;
00147 }
00148 
00149 //================ ShapeSpacePlannerXYTheta ================
00150 
00151 ShapeSpacePlannerXYTheta::ShapeSpacePlannerXYTheta(ShapeSpace &shs, const Shape<PolygonData> &worldBounds,
00152                                                    float inflation) :
00153   GenericRRT<NodeType_t, 2>(new NodeType_t::CollisionChecker(shs, worldBounds, inflation)), targetHeading() {
00154   NodeValue_t interp;
00155   interp.first.first = interp.first.second = 25; // step size in mm
00156   setInterpolation(interp);
00157 }
00158 
00159 void ShapeSpacePlannerXYTheta::initialize(const NodeValue_t &start, std::vector<NodeType_t> &treeStartResult,
00160                                           const NodeValue_t &end, std::vector<NodeType_t> &treeEndResult) {
00161   GenericRRT<NodeType_t, 2>::initialize(start, treeStartResult, end, treeEndResult);
00162   if (std::isnan((float)targetHeading)) {
00163     for (float theta = 0; theta < 2*M_PI; theta += M_PI/9) {
00164       NodeValue_t qnew;
00165       qnew.first.first = end.first.first + cos(theta) * extendingInterpolationStep.first.first;
00166       qnew.first.second = end.first.second + sin(theta) * extendingInterpolationStep.first.first;
00167       qnew.second = theta;
00168       addNode(&treeEndResult, qnew, 0);
00169     }
00170   }
00171 }
00172 
00173 void ShapeSpacePlannerXYTheta::buildPath(const std::vector<NodeType_t> *treeStart, const std::vector<NodeType_t> *treeEnd,
00174                                          std::vector<NodeValue_t> &path) {
00175   
00176   // connection point is last value in each tree
00177   unsigned int n = treeStart->size() - 1;
00178   while (n != 0) {
00179     n = (*treeStart)[n].parent;
00180     path.push_back((*treeStart)[n].q);
00181   }
00182   
00183   std::reverse(path.begin(), path.end());
00184   path.push_back(treeEnd->back().q);
00185   
00186   n = treeEnd->size() - 1;
00187   while (n != 0) {
00188     n = (*treeEnd)[n].parent;
00189     NodeValue_t value = (*treeEnd)[n].q;
00190     value.second = AngSignPi((float)value.second + M_PI);
00191     path.push_back(value);
00192   }
00193   
00194   // smooth path
00195   size_t maxIter = path.size();
00196   
00197   for (size_t i = 0; i < maxIter; i++) {
00198     int a = rand() % path.size();
00199     int b = rand() % path.size();
00200     if (a > b)
00201       std::swap(a,b);
00202     else if (a == b)
00203       continue;
00204     
00205     if ( NodeType_t::smoothInterpolate(path[a], path[b], smoothingInterpolationStep, cc) == RRTNodeBase::REACHED ) {
00206       // remove a -> b
00207       //      cout << "Erasing " << a << " to " << b << endl;
00208       //      cout << path.size() << endl;
00209       path.erase(path.begin()+a+1,path.begin()+b);
00210       //      cout << path.size() << endl;
00211     }
00212   }
00213   
00214   for (size_t i = 0; i+2 < path.size(); i++) {
00215     size_t j;
00216     for (j = i + 2; j < path.size(); j++) {
00217       if ( NodeType_t::smoothInterpolate(path[i], path[j], smoothingInterpolationStep, cc) != RRTNodeBase::REACHED )
00218         break;
00219     }
00220     if (j > i + 3 && j < path.size())
00221       path.erase(path.begin()+i+1, path.begin()+j-1);
00222   }
00223 }
00224 
00225 GenericRRTBase::PlannerResult2D
00226 ShapeSpacePlannerXYTheta::planPath(const Point& start, const Point &end,
00227                                    const AngTwoPi &initialHeading,
00228                                    const AngTwoPi &_targetHeading,
00229                                    unsigned int maxIterations,
00230                                    std::vector<NodeValue_t> *pathResult,
00231                                    std::vector<NodeType_t> *treeStartResult,
00232                                    std::vector<NodeType_t> *treeEndResult) {
00233   NodeValue_t lower, upper;
00234   if ( cc->getWorldBounds().isValid() ) {
00235     BoundingBox2D b = cc->getWorldBounds()->getBoundingBox();
00236     lower.first.first = b.min[0]; lower.first.second = b.min[1];
00237     upper.first.first = b.max[0]; upper.first.second = b.max[1];
00238   } else {
00239     // combine with obstacles + start and end points
00240     BoundingBox2D b = cc->getObstacleBoundingBox();
00241     b.expand(fmat::SubVector<2,const fmat::fmatReal>(start.coords));
00242     b.expand(fmat::SubVector<2,const fmat::fmatReal>(end.coords));
00243     fmat::Column<2> robotBounds = cc->getBodyBoundingBox().getDimensions();
00244     float extra = std::max(robotBounds[0], robotBounds[1]);
00245     lower.first.first =  b.min[0] - 2*extra;
00246     lower.first.second = b.min[1] - 2*extra;
00247     upper.first.first =  b.max[0] + 2*extra;
00248     upper.first.second = b.max[1] + 2*extra;
00249   }
00250   lower.second = 0; upper.second = 2*M_PI;
00251   std::cout << "World bounds: [" << lower.first.first << "," << lower.first.second << "," << lower.second
00252   << "]  to  [" << upper.first.first << "," << upper.first.second << "," << upper.second << "]" << std::endl;
00253   setLimits(lower,upper);
00254   
00255   targetHeading = _targetHeading;
00256   float endHeading = std::isnan((float)_targetHeading) ? 0 : targetHeading - M_PI;
00257   
00258   std::pair<float, float> startvalpos(start.coordX(), start.coordY());
00259   NodeValue_t startval(startvalpos, initialHeading);
00260   std::pair<float, float> endvalpos(end.coordX(), end.coordY());
00261   NodeValue_t endval(endvalpos, AngTwoPi(endHeading));
00262   return GenericRRT<NodeType_t, 2>::planPath(startval, endval, maxIterations, 
00263                                           pathResult, treeStartResult, treeEndResult);
00264 }
00265 
00266 void ShapeSpacePlannerXYTheta::plotPath(const std::vector<NodeValue_t> &path,
00267           Shape<GraphicsData> &graphics,
00268           rgb color) {
00269   for ( unsigned int i = 1; i < path.size(); i++ )
00270     graphics->add(new GraphicsData::LineElement("seg", path[i-1].first, path[i].first, color));
00271 }
00272 
00273 void ShapeSpacePlannerXYTheta::plotTree(const std::vector<NodeType_t> &tree,
00274                                         Shape<GraphicsData> &graphics,
00275                                         rgb color) {
00276   for ( unsigned int i = 1; i < tree.size(); i++ ) // start from 1 because root has no parent
00277     graphics->add(new GraphicsData::LineElement("branch", tree[tree[i].parent].q.first, tree[i].q.first, color));
00278 }

Tekkotsu v5.1CVS
Generated Sat May 4 06:33:01 2013 by Doxygen 1.6.3