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

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