explore_frontier.cpp
Go to the documentation of this file.
00001 /*********************************************************************
00002  *
00003  * Software License Agreement (BSD License)
00004  *
00005  *  Copyright (c) 2008, Robert Bosch LLC.
00006  *  All rights reserved.
00007  *
00008  *  Redistribution and use in source and binary forms, with or without
00009  *  modification, are permitted provided that the following conditions
00010  *  are met:
00011  *
00012  *   * Redistributions of source code must retain the above copyright
00013  *     notice, this list of conditions and the following disclaimer.
00014  *   * Redistributions in binary form must reproduce the above
00015  *     copyright notice, this list of conditions and the following
00016  *     disclaimer in the documentation and/or other materials provided
00017  *     with the distribution.
00018  *   * Neither the name of the Robert Bosch nor the names of its
00019  *     contributors may be used to endorse or promote products derived
00020  *     from this software without specific prior written permission.
00021  *
00022  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00023  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00024  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00025  *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00026  *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00027  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00028  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00029  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00030  *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00031  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00032  *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00033  *  POSSIBILITY OF SUCH DAMAGE.
00034  *
00035  *********************************************************************/
00036 
00037 /*
00038  *  Created on: Apr 6, 2009
00039  *      Author: duhadway
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); // / 20000.0;
00083   else
00084     return 1.0;
00085 }
00086 
00087 // TODO: what is this doing exactly?
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 //  ROS_DEBUG("Orientation change: %.3f degrees, (%.3f radians)", orientation_change * (180.0 / M_PI), orientation_change);
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   //we'll make sure that we set goals for the frontier at least the circumscribed
00118   //radius away from unknown space
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 //      weightedFrontier.cost = getFrontierCost(weightedFrontier.frontier) - getFrontierGain(weightedFrontier.frontier, costmapResolution_);
00142 //      ROS_DEBUG("cost: %f (%f * %f + %f * %f - %f * %f)",
00143 //          weightedFrontier.cost,
00144 //          potential_scale,
00145 //          getFrontierCost(weightedFrontier.frontier),
00146 //          orientation_scale,
00147 //          getOrientationChange(weightedFrontier.frontier, robot_pose),
00148 //          gain_scale,
00149 //          getFrontierGain(weightedFrontier.frontier, costmapResolution_) );
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   // Find all frontiers (open cells next to unknown cells).
00182   const unsigned char* map = costmap.getCharMap();
00183   for (idx = 0; idx < size; idx++) {
00184 //    //get the world point for the index
00185 //    unsigned int mx, my;
00186 //    costmap.indexToCells(idx, mx, my);
00187 //    geometry_msgs::Point p;
00188 //    costmap.mapToWorld(mx, my, p.x, p.y);
00189 //
00190     //check if the point has valid potential and is next to unknown space
00191 //    bool valid_point = planner_->validPointPotential(p);
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   // Clean up frontiers detected on separate rows of the map
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   // Group adjoining map_ pixels
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       // claim all neighbors
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         // consider 8 neighborhood
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     //we want to make sure that the frontier is big enough for the robot to fit through
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 }


explore
Author(s): Charles DuHadway (maintained by Benjamin Pitzer)
autogenerated on Sun Oct 5 2014 23:56:48