Go to the documentation of this file.00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 
00031 
00032 
00033 
00034 
00035 
00036 
00037 
00038 
00039 
00040 
00041 
00042 #include <explore/explore_frontier.h>
00043 
00044 
00045 using namespace visualization_msgs;
00046 using namespace costmap_2d;
00047 
00048 namespace explore {
00049 
00050 ExploreFrontier::ExploreFrontier() :
00051   map_(),
00052   lastMarkerCount_(0),
00053   planner_(NULL),
00054   frontiers_()
00055 {
00056 }
00057 
00058 ExploreFrontier::~ExploreFrontier()
00059 {
00060 
00061 }
00062 
00063 bool ExploreFrontier::getFrontiers(Costmap2DROS& costmap, std::vector<geometry_msgs::Pose>& frontiers)
00064 {
00065   findFrontiers(costmap);
00066   if (frontiers_.size() == 0)
00067     return false;
00068 
00069   frontiers.clear();
00070   for (uint i=0; i < frontiers_.size(); i++) {
00071     geometry_msgs::Pose frontier;
00072     frontiers.push_back(frontiers_[i].pose);
00073   }
00074 
00075   return (frontiers.size() > 0);
00076 }
00077 
00078 float ExploreFrontier::getFrontierCost(const Frontier& frontier) {
00079   ROS_DEBUG("cost of frontier: %f, at position: (%.2f, %.2f, %.2f)", planner_->getPointPotential(frontier.pose.position),
00080       frontier.pose.position.x, frontier.pose.position.y, tf::getYaw(frontier.pose.orientation));
00081   if (planner_ != NULL)
00082     return planner_->getPointPotential(frontier.pose.position); 
00083   else
00084     return 1.0;
00085 }
00086 
00087 
00088 double ExploreFrontier::getOrientationChange(const Frontier& frontier, const tf::Stamped<tf::Pose>& robot_pose){
00089   double robot_yaw = tf::getYaw(robot_pose.getRotation());
00090   double robot_atan2 = atan2(robot_pose.getOrigin().y() + sin(robot_yaw), robot_pose.getOrigin().x() + cos(robot_yaw));
00091   double frontier_atan2 = atan2(frontier.pose.position.x, frontier.pose.position.y);
00092   double orientation_change = robot_atan2 - frontier_atan2;
00093 
00094   return orientation_change;
00095 }
00096 
00097 float ExploreFrontier::getFrontierGain(const Frontier& frontier, double map_resolution) {
00098   return frontier.size * map_resolution;
00099 }
00100 
00101 bool ExploreFrontier::getExplorationGoals(Costmap2DROS& costmap, tf::Stamped<tf::Pose> robot_pose, navfn::NavfnROS* planner, std::vector<geometry_msgs::Pose>& goals, double potential_scale, double orientation_scale, double gain_scale)
00102 {
00103   findFrontiers(costmap);
00104   if (frontiers_.size() == 0)
00105     return false;
00106 
00107   geometry_msgs::Point start;
00108   start.x = robot_pose.getOrigin().x();
00109   start.y = robot_pose.getOrigin().y();
00110   start.z = robot_pose.getOrigin().z();
00111 
00112   planner->computePotential(start);
00113 
00114   planner_ = planner;
00115   costmapResolution_ = costmap.getResolution();
00116 
00117   
00118   
00119   float step = -1.0 * costmapResolution_;
00120   int c = ceil(costmap.getCircumscribedRadius() / costmapResolution_);
00121   WeightedFrontier goal;
00122   std::vector<WeightedFrontier> weightedFrontiers;
00123   weightedFrontiers.reserve(frontiers_.size() * c);
00124   for (uint i=0; i < frontiers_.size(); i++) {
00125     Frontier& frontier = frontiers_[i];
00126     WeightedFrontier weightedFrontier;
00127     weightedFrontier.frontier = frontier;
00128 
00129     tf::Point p(frontier.pose.position.x, frontier.pose.position.y, frontier.pose.position.z);
00130     tf::Quaternion bt;
00131     tf::quaternionMsgToTF(frontier.pose.orientation, bt);
00132     tf::Vector3 v(cos(bt.getAngle()), sin(bt.getAngle()), 0.0);
00133 
00134     for (int j=0; j <= c; j++) {
00135       tf::Vector3 check_point = p + (v * (step * j));
00136       weightedFrontier.frontier.pose.position.x = check_point.x();
00137       weightedFrontier.frontier.pose.position.y = check_point.y();
00138       weightedFrontier.frontier.pose.position.z = check_point.z();
00139 
00140       weightedFrontier.cost = potential_scale * getFrontierCost(weightedFrontier.frontier) + orientation_scale * getOrientationChange(weightedFrontier.frontier, robot_pose) - gain_scale * getFrontierGain(weightedFrontier.frontier, costmapResolution_);
00141 
00142 
00143 
00144 
00145 
00146 
00147 
00148 
00149 
00150       weightedFrontiers.push_back(weightedFrontier);
00151     }
00152   }
00153 
00154   goals.clear();
00155   goals.reserve(weightedFrontiers.size());
00156   std::sort(weightedFrontiers.begin(), weightedFrontiers.end());
00157   for (uint i = 0; i < weightedFrontiers.size(); i++) {
00158     goals.push_back(weightedFrontiers[i].frontier.pose);
00159   }
00160   return (goals.size() > 0);
00161 }
00162 
00163 void ExploreFrontier::findFrontiers(Costmap2DROS& costmap_) {
00164   frontiers_.clear();
00165 
00166   Costmap2D costmap;
00167   costmap_.getCostmapCopy(costmap);
00168 
00169   int idx;
00170   int w = costmap.getSizeInCellsX();
00171   int h = costmap.getSizeInCellsY();
00172   int size = (w * h);
00173 
00174   map_.info.width = w;
00175   map_.info.height = h;
00176   map_.data.resize((size_t)size);
00177   map_.info.resolution = costmap.getResolution();
00178   map_.info.origin.position.x = costmap.getOriginX();
00179   map_.info.origin.position.y = costmap.getOriginY();
00180 
00181   
00182   const unsigned char* map = costmap.getCharMap();
00183   for (idx = 0; idx < size; idx++) {
00184 
00185 
00186 
00187 
00188 
00189 
00190     
00191 
00192     bool valid_point = (map[idx] < LETHAL_OBSTACLE);
00193 
00194     if ((valid_point && map) &&
00195         (((idx+1 < size) && (map[idx+1] == NO_INFORMATION)) ||
00196          ((idx-1 >= 0) && (map[idx-1] == NO_INFORMATION)) ||
00197          ((idx+w < size) && (map[idx+w] == NO_INFORMATION)) ||
00198          ((idx-w >= 0) && (map[idx-w] == NO_INFORMATION))))
00199     {
00200       map_.data[idx] = -128;
00201     } else {
00202       map_.data[idx] = -127;
00203     }
00204   }
00205 
00206   
00207   idx = map_.info.height - 1;
00208   for (unsigned int y=0; y < map_.info.width; y++) {
00209     map_.data[idx] = -127;
00210     idx += map_.info.height;
00211   }
00212 
00213   
00214   int segment_id = 127;
00215   std::vector< std::vector<FrontierPoint> > segments;
00216   for (int i = 0; i < size; i++) {
00217     if (map_.data[i] == -128) {
00218       std::vector<int> neighbors;
00219       std::vector<FrontierPoint> segment;
00220       neighbors.push_back(i);
00221 
00222       
00223       while (neighbors.size() > 0) {
00224         int idx = neighbors.back();
00225         neighbors.pop_back();
00226         map_.data[idx] = segment_id;
00227 
00228         btVector3 tot(0,0,0);
00229         int c = 0;
00230         if ((idx+1 < size) && (map[idx+1] == NO_INFORMATION)) {
00231           tot += btVector3(1,0,0);
00232           c++;
00233         }
00234         if ((idx-1 >= 0) && (map[idx-1] == NO_INFORMATION)) {
00235           tot += btVector3(-1,0,0);
00236           c++;
00237         }
00238         if ((idx+w < size) && (map[idx+w] == NO_INFORMATION)) {
00239           tot += btVector3(0,1,0);
00240           c++;
00241         }
00242         if ((idx-w >= 0) && (map[idx-w] == NO_INFORMATION)) {
00243           tot += btVector3(0,-1,0);
00244           c++;
00245         }
00246         assert(c > 0);
00247         segment.push_back(FrontierPoint(idx, tot / c));
00248 
00249         
00250         if (((idx-1)>0) && (map_.data[idx-1] == -128))
00251           neighbors.push_back(idx-1);
00252         if (((idx+1)<size) && (map_.data[idx+1] == -128))
00253           neighbors.push_back(idx+1);
00254         if (((idx-map_.info.width)>0) && (map_.data[idx-map_.info.width] == -128))
00255           neighbors.push_back(idx-map_.info.width);
00256         if (((idx-map_.info.width+1)>0) && (map_.data[idx-map_.info.width+1] == -128))
00257           neighbors.push_back(idx-map_.info.width+1);
00258         if (((idx-map_.info.width-1)>0) && (map_.data[idx-map_.info.width-1] == -128))
00259           neighbors.push_back(idx-map_.info.width-1);
00260         if (((idx+(int)map_.info.width)<size) && (map_.data[idx+map_.info.width] == -128))
00261           neighbors.push_back(idx+map_.info.width);
00262         if (((idx+(int)map_.info.width+1)<size) && (map_.data[idx+map_.info.width+1] == -128))
00263           neighbors.push_back(idx+map_.info.width+1);
00264         if (((idx+(int)map_.info.width-1)<size) && (map_.data[idx+map_.info.width-1] == -128))
00265           neighbors.push_back(idx+map_.info.width-1);
00266       }
00267 
00268       segments.push_back(segment);
00269       segment_id--;
00270       if (segment_id < -127)
00271         break;
00272     }
00273   }
00274 
00275   int num_segments = 127 - segment_id;
00276   if (num_segments <= 0)
00277     return;
00278 
00279   for (unsigned int i=0; i < segments.size(); i++) {
00280     Frontier frontier;
00281     std::vector<FrontierPoint>& segment = segments[i];
00282     uint size = segment.size();
00283 
00284     
00285     if (size * costmap.getResolution() < costmap.getInscribedRadius())
00286       continue;
00287 
00288     float x = 0, y = 0;
00289     btVector3 d(0,0,0);
00290 
00291     for (uint j=0; j<size; j++) {
00292       d += segment[j].d;
00293       int idx = segment[j].idx;
00294       x += (idx % map_.info.width);
00295       y += (idx / map_.info.width);
00296     }
00297     d = d / size;
00298     frontier.pose.position.x = map_.info.origin.position.x + map_.info.resolution * (x / size);
00299     frontier.pose.position.y = map_.info.origin.position.y + map_.info.resolution * (y / size);
00300     frontier.pose.position.z = 0.0;
00301 
00302     frontier.pose.orientation = tf::createQuaternionMsgFromYaw(btAtan2(d.y(), d.x()));
00303     frontier.size = size;
00304 
00305     frontiers_.push_back(frontier);
00306   }
00307 
00308 }
00309 
00310 void ExploreFrontier::getVisualizationMarkers(std::vector<Marker>& markers)
00311 {
00312   Marker m;
00313   m.header.frame_id = "map";
00314   m.header.stamp = ros::Time::now();
00315   m.id = 0;
00316   m.ns = "frontiers";
00317   m.type = Marker::ARROW;
00318   m.pose.position.x = 0.0;
00319   m.pose.position.y = 0.0;
00320   m.pose.position.z = 0.0;
00321   m.scale.x = 1.0;
00322   m.scale.y = 1.0;
00323   m.scale.z = 1.0;
00324   m.color.r = 0;
00325   m.color.g = 0;
00326   m.color.b = 255;
00327   m.color.a = 255;
00328   m.lifetime = ros::Duration(0);
00329 
00330   m.action = Marker::ADD;
00331   uint id = 0;
00332   for (uint i=0; i<frontiers_.size(); i++) {
00333     Frontier frontier = frontiers_[i];
00334     m.id = id;
00335     m.pose = frontier.pose;
00336     markers.push_back(Marker(m));
00337     id++;
00338   }
00339 
00340   m.action = Marker::DELETE;
00341   for (; id < lastMarkerCount_; id++) {
00342     m.id = id;
00343     markers.push_back(Marker(m));
00344   }
00345 
00346   lastMarkerCount_ = markers.size();
00347 }
00348 
00349 }