00001 #include "ShapeSpacePlannerXYTheta.h"
00002 #include "Shared/mathutils.h"
00003
00004
00005
00006 const AngSignPi RRTNodeXYTheta::turnLimit = M_PI;
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
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
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
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
00050 AngSignPi diff(targetNew.second - start.second);
00051 AngSignPi signedTurn(diff > 0 ? turnLimit : AngSignPi(-turnLimit));
00052 AngTwoPi newAngle(start.second + signedTurn);
00053
00054
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
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;
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
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
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;
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
00143 return true;
00144 }
00145 }
00146 return false;
00147 }
00148
00149
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;
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
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
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
00207
00208
00209 path.erase(path.begin()+a+1,path.begin()+b);
00210
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
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++ )
00277 graphics->add(new GraphicsData::LineElement("branch", tree[tree[i].parent].q.first, tree[i].q.first, color));
00278 }