Tekkotsu Homepage
Demos
Overview
Downloads
Dev. Resources
Reference
Credits

PathPlanner.cc

Go to the documentation of this file.
00001 //-*-c++-*-
00002 #include "PathPlanner.h"
00003 #include "Shared/ProjectInterface.h"
00004 #include "Vision/SegmentedColorGenerator.h"
00005 #include <iostream>
00006 #include <ctime>
00007 #include <vector>
00008 #include <queue>
00009 #include <map>
00010 #include <math.h>
00011 
00012 using namespace std;
00013 
00014 namespace DualCoding {
00015 
00016 using ProjectInterface::defSegmentedColorGenerator;
00017 
00018 PathPlanner::PathPlanner(coordinate_t xMax, coordinate_t xMin, coordinate_t yMax, coordinate_t yMin)
00019   : allStates(), unreached(NULL), reached(), 
00020     numX((unsigned int) ((xMax-xMin)/size)+1), numY((unsigned int) ((yMax-yMin)/size)+1), 
00021     minX(xMin), minY(yMin), dX((xMax-xMin)/numX), dY((yMax-yMin)/numY), 
00022     start(), goal(), maxDistance(800), costs(), 
00023     startPt(), goalPt(),startOrientation(), goalOrientation(),
00024     costMap(NULL), landmarks(), lmCosts(), obstacles()
00025 {
00026   unreached = new vector<state*>[numX*numY*4];
00027   costMap = new unsigned int [numX*numY];
00028   // default costs; these can be modefied anytime before calling findPath()
00029   costs[transF] = 1;
00030   costs[transB] = 2;
00031   costs[transY] = 4;
00032   costs[rotate] = 3;
00033   costs[noLM] = 20;
00034   costs[oneLM] = 10;
00035 }
00036 
00037 void PathPlanner::findPath() {
00038   initialize();
00039   while (!reached.empty()) {
00040     edge top = reached.top();
00041     if (top.from != NULL && top.from->dst == NULL) { // best action not determined yet for this state
00042       top.from->cost = top.cost;
00043       top.from->dst = top.to;
00044       vector<state*>& lms = unreached[top.from->loc.pos*4 + top.from->loc.dir];
00045       for (vector<state*>::iterator it = lms.begin();
00046      it != lms.end(); it++)
00047   if ((*it)->lms == top.from->lms) {
00048     lms.erase(it);
00049     break;
00050   }
00051       if (top.from->loc==start) {
00052   cout << "best path:\n";
00053   state* s = top.from;
00054   while(s) {
00055     cout << toString(*s)  << endl;
00056     s = s->dst;
00057   }
00058   cout << endl;
00059   break;
00060       }
00061       else
00062   findLinks(*top.from);
00063     }
00064     reached.pop();
00065   }
00066   cout << "done: " << reached.empty() << endl;
00067 }
00068 
00069 void PathPlanner::findLinks(state& s) {
00070   unsigned int newCostMotion = s.cost+lmCosts[s.lms.first]+lmCosts[s.lms.second]+1;
00071   if (s.lms.first < 0) {
00072     if (s.lms.second < 0)
00073       newCostMotion += costs[noLM];
00074     else
00075       newCostMotion += costs[oneLM];
00076   }
00077   { //translate
00078     if (s.loc.pos%numY+1 < numY) { // go west
00079       if (state* it = thereIs(s.loc.pos+1,s.loc.dir,s.lms)) {
00080   if (s.loc.dir==direction::E)
00081     reached.push(edge(*it,s,newCostMotion+costMap[s.loc.pos]+costs[transB]));
00082   else if (s.loc.dir == direction::W)
00083     reached.push(edge(*it,s,newCostMotion+costMap[s.loc.pos]+costs[transF]));
00084   else
00085     reached.push(edge(*it,s,newCostMotion+costMap[s.loc.pos]+costs[transY]));
00086       }
00087     }
00088     if (s.loc.pos%numY > 0) { // go east
00089       if (state* it = thereIs(s.loc.pos-1,s.loc.dir,s.lms)) {
00090   if (s.loc.dir==direction::E)
00091     reached.push(edge(*it,s,newCostMotion+costMap[s.loc.pos]+costs[transF]));
00092   else if (s.loc.dir == direction::W)
00093     reached.push(edge(*it,s,newCostMotion+costMap[s.loc.pos]+costs[transB]));
00094   else
00095     reached.push(edge(*it,s,newCostMotion+costMap[s.loc.pos]+costs[transY]));
00096       }
00097     }
00098     if (s.loc.pos < numY*(numX-1)) { // go north
00099       if (state* it = thereIs(s.loc.pos+numY,s.loc.dir,s.lms)) {
00100   if (s.loc.dir==direction::N)
00101     reached.push(edge(*it,s,newCostMotion+costMap[s.loc.pos]+costs[transF]));
00102   else if (s.loc.dir == direction::S)
00103     reached.push(edge(*it,s,newCostMotion+costMap[s.loc.pos]+costs[transB]));
00104   else
00105     reached.push(edge(*it,s,newCostMotion+costMap[s.loc.pos]+costs[transY]));
00106       }
00107     }
00108     if (s.loc.pos >= numY) { // go south
00109       if (state* it = thereIs(s.loc.pos-numY,s.loc.dir,s.lms)) {
00110   if (s.loc.dir==direction::N)
00111     reached.push(edge(*it,s,newCostMotion+costMap[s.loc.pos]+costs[transB]));
00112   else if (s.loc.dir == direction::S)
00113     reached.push(edge(*it,s,newCostMotion+costMap[s.loc.pos]+costs[transF]));
00114   else
00115     reached.push(edge(*it,s,newCostMotion+costMap[s.loc.pos]+costs[transY]));
00116       }
00117     }
00118   }
00119   { //rotate
00120     const int newRotateCost = newCostMotion+costs[rotate];
00121     if (state* it = thereIs(s.loc.pos,s.loc.dir.cw(),s.lms))
00122       reached.push(edge(*it,s,newRotateCost+costMap[s.loc.pos]));
00123     if (state* it = thereIs(s.loc.pos,s.loc.dir.ccw(),s.lms))
00124       reached.push(edge(*it,s,newRotateCost+costMap[s.loc.pos]));
00125   }
00126   { //switch landmarks
00127     vector<pair<int,int> > lms = findLMs(s.loc);
00128     for (vector<pair<int,int> >::const_iterator it = lms.begin();
00129    it != lms.end(); it++)
00130       if (*it != s.lms)
00131   reached.push(edge(*(thereIs(s.loc.pos,s.loc.dir,*it)),s,s.cost+1));
00132   }
00133 }
00134 
00135 
00136 Point PathPlanner::findWorldCoords(unsigned int pos) {
00137   return Point (minX+dX*(pos/numY),minY+dY*(pos%numY),0);
00138 }
00139 
00140 
00141 void PathPlanner::computeLandmarkCosts() {
00142   map<unsigned int, float> distSum; // maps id of landmark against sum of distance with other landmarks of same color
00143   map<unsigned int, vector<unsigned int> > lmsSortedByColor; // maps color index against vector of idlandmarks' id having the color
00144   for (map<unsigned int, PointData>::const_iterator it1 = landmarks.begin();
00145        it1 != landmarks.end(); it1++) {
00146     map<unsigned int, PointData>::const_iterator it2 = it1; // cannot write it2 = it1+1?
00147     it2++;
00148     for (; it2 != landmarks.end(); it2++)
00149       if (it1->second.getColor() == it2->second.getColor()) {
00150   float dist = it1->second.getCentroid().xyDistanceFrom(it2->second);
00151   float cost = 10000/(dist*dist);
00152   distSum[it1->first] += cost;
00153   distSum[it2->first] += cost;
00154       }
00155     lmsSortedByColor[defSegmentedColorGenerator->getColorIndex(it1->second.getColor())].push_back(it1->first);
00156   }
00157   for (map<unsigned int, vector<unsigned int> >::const_iterator col_it = lmsSortedByColor.begin();
00158        col_it != lmsSortedByColor.end(); col_it++)
00159     for (vector<unsigned int>::const_iterator lm_it = col_it->second.begin();
00160    lm_it != col_it->second.end(); lm_it++)
00161       lmCosts[*lm_it] = (unsigned int) distSum[*lm_it];
00162 }
00163 
00164 void PathPlanner::initialize() {
00165   // set start and goal
00166   float minStartDist = findWorldCoords(0).distanceFrom(startPt);
00167   float minGoalDist = findWorldCoords(0).distanceFrom(goalPt);
00168   unsigned int startIdx=0, goalIdx=0;
00169   for (unsigned int pos = 1; pos < numX*numY; pos++) {
00170     float startDist = findWorldCoords(pos).distanceFrom(startPt);
00171     float goalDist = findWorldCoords(pos).distanceFrom(goalPt);
00172     if (startDist < minStartDist) {
00173       minStartDist = startDist;
00174       startIdx = pos;
00175     }
00176     if (goalDist < minGoalDist) {
00177       minGoalDist = goalDist;
00178       goalIdx = pos;
00179     }
00180   }
00181   start.pos = startIdx;
00182   goal.pos = goalIdx;
00183   
00184   if (startOrientation > M_PI/4) {
00185     if (startOrientation < M_PI*3/4)
00186       start.dir = direction::W;
00187     else if (startOrientation < M_PI*5/4)
00188       start.dir = direction::S;
00189     else if (startOrientation < M_PI*7/4)
00190       start.dir = direction::E;
00191   }
00192   else
00193     start.dir = direction::N;
00194 
00195   if (goalOrientation > M_PI/4) {
00196     if (goalOrientation < M_PI*3/4)
00197       goal.dir = direction::W;
00198     else if (goalOrientation < M_PI*5/4)
00199       goal.dir = direction::S;
00200     else if (goalOrientation < M_PI*7/4)
00201       goal.dir = direction::E;
00202   }
00203   else
00204     goal.dir = direction::N;
00205 
00206 
00207   // initialize cost map
00208   for (unsigned int pos = 0; pos < numX*numY; pos++) {
00209     costMap[pos] = 0;
00210     for (vector<pair<Point, unsigned int> >::const_iterator it = obstacles.begin();
00211    it != obstacles.end(); it++) {
00212       Point vec = findWorldCoords(pos)-it->first;
00213       float distSq = (vec.coordX()*vec.coordX() + vec.coordY()*vec.coordY())/10000; // cm^2
00214       costMap[pos] += (unsigned int) ((distSq > 0) ? it->second/distSq : -1U);
00215     }
00216   }
00217   computeLandmarkCosts();
00218   cout << "costs:\n";
00219   cout << " costs[transF]: " << costs[transF] << endl;
00220   cout << " costs[transB]: " << costs[transB] << endl;
00221   cout << " costs[transY]: " << costs[transY] << endl;
00222   cout << " costs[rotate]: " << costs[rotate] << endl;
00223   cout << " costs[noLM]: " << costs[noLM] << endl;
00224   cout << " costs[oneLM]: " << costs[oneLM] << endl;
00225   
00226   cout << "landmarks:\n"; 
00227   for (map<unsigned int, PointData>::const_iterator it = landmarks.begin();
00228        it != landmarks.end(); it++)
00229     cout<< "lm id " << it->first << " at " << it->second
00230       //  << ", color index=" << defSegmentedColorGenerator->getColorIndex(it->second.getColor())
00231   << ", cost=" << lmCosts[it->first] << endl;
00232   
00233   cout << "obstacles:\n";
00234   for (vector<pair<Point, unsigned int> >::const_iterator it = obstacles.begin();
00235        it != obstacles.end(); it++)
00236     cout << " " << it->first << ": " << it->second << endl;
00237 
00238   // print map
00239   cout << "costMap:\n";
00240   for (int j = numX-1; j >= 0; j--) {
00241     for (int i = numY-1; i >= 0; i--)
00242       if (i+j*numY == start.pos)
00243   cout << " S";
00244       else if (i+j*numY == goal.pos)
00245   cout << " G";
00246       else
00247   cout << " " << costMap[i+j*numY];
00248     cout << endl;
00249   }
00250 
00251   while (!reached.empty()) 
00252     reached.pop();
00253   for (unsigned int i = 0; i < numX*numY*4; i++)
00254     unreached[i].clear();
00255   while (!allStates.empty())
00256     allStates.pop();
00257 
00258   // find all possible vertices (states)
00259   vector<state*> goals;
00260   fillState(0,goal.pos);
00261   for (unsigned int i = 0; i < 4; i++) {
00262     location loc (goal.pos,i);
00263     vector<pair<int,int> > lms = findLMs(loc);
00264     for (vector<pair<int,int> >::const_iterator it = lms.begin();
00265    it < lms.end(); it++) {
00266       allStates.push(state(loc,*it));
00267       if (i == goal.dir)
00268   goals.push_back(&allStates.back());
00269       else
00270   unreached[loc.pos*4 + loc.dir].push_back(&(allStates.back()));
00271     }
00272   }
00273   fillState(goal.pos+1,numX*numY);
00274 
00275   cout << "start state:\n";
00276   cout << " " << findWorldCoords(start.pos) << endl;
00277   //  for (vector<
00278   //   cout << " is lm 1 visible ? " << isLMVisible(start,pt) << endl;
00279 
00280   cout << "goal state(s):\n";
00281   for (vector<state*>::iterator it = goals.begin();
00282        it != goals.end(); it++) {
00283     (*it)->cost = 0;
00284     findLinks(**it);
00285     cout << " " << toString(**it) <<  " => " << findWorldCoords((*it)->loc.pos) << endl;
00286   }
00287 }
00288 
00289 void PathPlanner::fillState(unsigned int low, unsigned int high) {
00290   for (unsigned int pos = low; pos < high; pos++) {
00291     for (unsigned int i = 0; i < 4; i++) {
00292       location loc(pos,i);
00293       vector<pair<int,int> > lms = findLMs(loc);
00294       for (vector<pair<int,int> >::const_iterator it = lms.begin();
00295      it < lms.end(); it++) {
00296   allStates.push(state(loc,*it));
00297   unreached[loc.pos*4 + loc.dir].push_back(&(allStates.back()));
00298       }
00299     }
00300   }
00301 }
00302   
00303 PathPlanner::state* PathPlanner::thereIs(unsigned int pos, PathPlanner::direction dir, std::pair<int,int> lms) {
00304   //  cout << "thereIs: " << pos << ',' << dir << ',' << (pos+dir) << endl;
00305   const vector<state*>& states = unreached[pos*4 + (unsigned int) dir];
00306   for (vector<state*>::const_iterator it = states.begin();
00307        it < states.end(); it++)
00308     if ((*it)->lms == lms)
00309       return *it;
00310   return NULL;
00311 }
00312 
00313 
00314 std::vector<std::pair<int,int> > PathPlanner::findLMs(location loc) {
00315   vector<int> lms;
00316   lms.push_back(-1); // no landmark is also an option
00317   for (map<unsigned int, PointData>::const_iterator it = landmarks.begin();
00318        it != landmarks.end(); it++)
00319     if (isLMVisible(loc,it->second)) lms.push_back(it->first);
00320   vector<pair<int,int> > lmPairs;
00321   lmPairs.push_back(pair<int,int>(-1,-1));
00322   for(vector<int>::const_iterator it1 = lms.begin();
00323       it1 != lms.end(); it1++)
00324     for(vector<int>::const_iterator it2 = it1+1;
00325   it2 != lms.end(); it2++)
00326       lmPairs.push_back(pair<int,int>(*it1,*it2));
00327   return lmPairs;
00328 }
00329 
00330 bool PathPlanner::isLMVisible(location l, const Point& lm) {
00331   Point agent = findWorldCoords(l.pos);
00332   float dx = lm.coordX()-agent.coordX();
00333   float dy = lm.coordY()-agent.coordY();
00334   float distance = sqrt(dx*dx + dy*dy);
00335   //  cout << "distance: " << distance << endl;
00336   if (distance > maxDistance || distance < 200) return false; // too far or too close
00337   AngTwoPi angle = atan2(dy,dx);
00338   //  cout << "angle: " << angle << endl;
00339   switch (l.dir) {
00340   case direction::N: return (angle < M_PI/3 || angle > M_PI*5/3);
00341   case direction::W: return (angle > M_PI/6 && angle < M_PI*5/6);
00342   case direction::S: return (angle > M_PI*2/3 && angle < M_PI*4/3);
00343   case direction::E: return (angle > M_PI*7/6 && angle < M_PI*11/6);
00344   };
00345   return false;
00346 }
00347 
00348 std::string PathPlanner::toString(const PathPlanner::state &s) {
00349   stringstream ss;
00350   ss << "[(" << (s.loc.pos/numY) << ',' << (s.loc.pos%numY) << ','
00351      << s.loc.dir << "), (" << s.lms.first << ',' << s.lms.second << "), " << s.cost << ']';
00352   return ss.str();
00353 }
00354 
00355 std::ostream& operator<<(std::ostream& out, const PathPlanner::direction& d) {
00356   switch (d) {
00357   case PathPlanner::direction::N: out << "N"; break;
00358   case PathPlanner::direction::W: out << "W"; break;
00359   case PathPlanner::direction::S: out << "S"; break;
00360   default: out << "E"; break;
00361   };
00362   return out;
00363 }
00364 
00365 
00366 }

DualCoding 5.1CVS
Generated Fri Mar 16 05:23:46 2012 by Doxygen 1.6.3