00001 #include "ShapeSpacePlannerXYTheta.h"
00002 #include "Shared/mathutils.h"
00003
00004
00005
00006
00007
00008 const AngSignPi RRTNodeXYTheta::turnLimit = M_PI;
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
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
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
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
00052 AngSignPi diff(targetNew.second - start.second);
00053 AngSignPi signedTurn(diff > 0 ? turnLimit : AngSignPi(-turnLimit));
00054 AngTwoPi newAngle(start.second + signedTurn);
00055
00056
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
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;
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
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
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);
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);
00142 result->movingObstacle->name = os.str();
00143 result->collidingObstacle = dynamic_cast<PlannerObstacle2D*>(obstacles[i]->clone());
00144 }
00145
00146 return true;
00147 }
00148 return false;
00149 }
00150
00151
00152
00153
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;
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
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
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
00211
00212
00213 path.erase(path.begin()+a+1,path.begin()+b);
00214
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
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++ )
00283 graphics->add(new GraphicsData::LineElement(tree[tree[i].parent].q.first, tree[i].q.first, color));
00284 }