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 #include <ros/ros.h>
00039 #include <angles/angles.h>
00040
00041 #include <move_base_msgs/MoveBaseAction.h>
00042 #include <actionlib/client/simple_action_client.h>
00043
00044 #include <nav_msgs/GridCells.h>
00045 #include <nav_msgs/OccupancyGrid.h>
00046 #include <nav_msgs/Odometry.h>
00047 #include <geometry_msgs/PoseStamped.h>
00048
00049 #include <tf/transform_listener.h>
00050 #include <tf/message_filter.h>
00051 #include <message_filters/subscriber.h>
00052
00053 #include <vector>
00054 #include <list>
00055
00056 typedef actionlib::SimpleActionClient<move_base_msgs::MoveBaseAction> MoveBaseClient;
00057
00058 class RandomWalk
00059 {
00060 public:
00061 RandomWalk();
00062 ~RandomWalk();
00063
00064 private:
00066 nav_msgs::GridCells obstacles_;
00068 nav_msgs::GridCells inflated_;
00069
00071 nav_msgs::OccupancyGrid map_;
00072
00074 geometry_msgs::PoseStamped robot_pose_;
00075
00077 ros::NodeHandle n_;
00078
00080 ros::Subscriber map_sub_;
00082 ros::Subscriber obstacles_sub_;
00084 ros::Subscriber inflated_sub_;
00086 ros::Subscriber cells_sub_;
00087
00089 message_filters::Subscriber<nav_msgs::Odometry> odom_sub_;
00090 tf::TransformListener tf_;
00091 tf::MessageFilter<nav_msgs::Odometry> * tf_filter_;
00092
00094 nav_msgs::GridCells cells_;
00095
00097 int map_known_cells_;
00098
00100 MoveBaseClient ac_;
00101
00103 double inflation_radius_;
00104
00105 ros::Time start_time_;
00106
00107 void setGoal();
00108 bool checkGoal(move_base_msgs::MoveBaseGoal * goal);
00109 bool checkCell(int goal_cell_x, int goal_cell_y);
00110
00111 void odomCallback(const boost::shared_ptr<const nav_msgs::Odometry>& msg);
00112 void obstaclesCallback(const nav_msgs::GridCells::ConstPtr& msg);
00113 void inflatedCallback(const nav_msgs::GridCells::ConstPtr& msg);
00114 void mapCallback(const nav_msgs::OccupancyGrid::ConstPtr& msg);
00115 void cellsCallback(const nav_msgs::GridCells::ConstPtr& msg);
00116
00117 void goalDoneCallback(const actionlib::SimpleClientGoalState &state, const move_base_msgs::MoveBaseResultConstPtr &result);
00118 void goalActiveCallback();
00119 void goalFeedbackCallback(const move_base_msgs::MoveBaseFeedbackConstPtr &feedback);
00120 };
00121
00122 RandomWalk::RandomWalk() : ac_("move_base", true)
00123 {
00124 ROS_INFO("RandomWalk -- Waiting for the move_base action server to come online...");
00125 bool ac_online = false;
00126 for(int i=0 ; i<3 ; i++)
00127 {
00128 if(ac_.waitForServer(ros::Duration(1.0)))
00129 {
00130 ac_online = true;
00131 break;
00132 }
00133
00134 ROS_INFO("RandomWalk -- Unable to find the move_base action server, retrying...");
00135 }
00136 if(!ac_online)
00137 {
00138 ROS_FATAL("RandomWalk -- Forgot to launch move_base now did we?");
00139 ROS_BREAK();
00140 return;
00141 }
00142 ROS_INFO("RandomWalk -- Found it!");
00143
00144
00145 odom_sub_.subscribe(n_, "odom", 10);
00146 tf_filter_ = new tf::MessageFilter<nav_msgs::Odometry>(odom_sub_, tf_, "map", 10);
00147 tf_filter_->registerCallback( boost::bind(&RandomWalk::odomCallback, this, _1) );
00148
00149 map_sub_ = n_.subscribe("map", 1, &RandomWalk::mapCallback, this);
00150 obstacles_sub_ = n_.subscribe("move_base/local_costmap/obstacles", 1, &RandomWalk::obstaclesCallback, this);
00151 inflated_sub_ = n_.subscribe("move_base/local_costmap/inflated_obstacles", 1, &RandomWalk::inflatedCallback, this);
00152 cells_sub_ = n_.subscribe("/visited_cells", 1, &RandomWalk::cellsCallback, this);
00153
00154 n_.param("move_base/local_costmap/inflation_radius", inflation_radius_, 0.20);
00155
00156 map_known_cells_ = 0;
00157
00158 start_time_ = ros::Time::now();
00159 }
00160
00161 RandomWalk::~RandomWalk()
00162 {
00163 ros::Duration time_spent = ros::Time::now() - start_time_;
00164 ROS_INFO("RandomWalk -- Took %lf seconds to complete the exploration! Got %lf%% of explored area!", time_spent.toSec(), (cells_.cell_height*cells_.cell_width*cells_.cells.size())/(map_.info.resolution*map_.info.resolution*map_known_cells_));
00165 }
00166
00167 void RandomWalk::setGoal()
00168 {
00169 move_base_msgs::MoveBaseGoal goal;
00170
00171 int x, y;
00172
00173 do
00174 {
00175 goal.target_pose.header.frame_id = "/map";
00176 goal.target_pose.header.stamp = ros::Time::now();
00177
00178
00179
00180
00181
00182
00183
00184
00185 x = rand() % map_.info.width;
00186 y = rand() % map_.info.height;
00187
00188 goal.target_pose.pose.position.x = x*map_.info.resolution;
00189 goal.target_pose.pose.position.y = y*map_.info.resolution;
00190 goal.target_pose.pose.orientation = tf::createQuaternionMsgFromYaw(0.0);
00191
00192
00193
00194 if(!n_.ok())
00195 {
00196 ROS_INFO("RandomWalk - %s - Exiting...", __FUNCTION__);
00197 return;
00198 }
00199 }
00200 while(!checkCell(x, y));
00201
00202
00203 ROS_INFO("RandomWalk - %s - Sending robot to %lf %lf", __FUNCTION__, goal.target_pose.pose.position.x, goal.target_pose.pose.position.y);
00204
00205 ac_.sendGoal(goal, boost::bind(&RandomWalk::goalDoneCallback, this, _1, _2), boost::bind(&RandomWalk::goalActiveCallback, this), boost::bind(&RandomWalk::goalFeedbackCallback, this, _1));
00206 }
00207
00208 bool RandomWalk::checkGoal(move_base_msgs::MoveBaseGoal * goal)
00209 {
00210 int goal_cell_x = goal->target_pose.pose.position.x / map_.info.resolution;
00211 int goal_cell_y = goal->target_pose.pose.position.y / map_.info.resolution;
00212
00213
00214 if(goal_cell_x > map_.info.width-1 || goal_cell_x < 0 || goal_cell_y > map_.info.height-1 || goal_cell_y < 0)
00215 {
00216 return false;
00217 }
00218
00219 if(!checkCell(goal_cell_x, goal_cell_y)) return false;
00220
00221 return true;
00222 }
00223
00224 bool RandomWalk::checkCell(int goal_cell_x, int goal_cell_y)
00225 {
00226 std::vector<geometry_msgs::Point>::iterator obstacle;
00227
00228
00229 if(map_.data[goal_cell_y*map_.info.width+goal_cell_x] != 0) return false;
00230
00231 int cir = ceil(inflation_radius_/map_.info.resolution)+1;
00232 for(int i=(goal_cell_x-cir<0 ? 0 : goal_cell_x-cir) ; i<(goal_cell_x+cir>map_.info.width ? map_.info.width : goal_cell_x+cir) ; i++)
00233 {
00234 for(int j=(goal_cell_y-cir<0 ? 0 : goal_cell_y-cir) ; j<(goal_cell_y+cir>map_.info.height ? map_.info.height : goal_cell_y+cir) ; j++)
00235 {
00236 if(map_.data[j*map_.info.width+i] != 0 && sqrt((goal_cell_x-i)*(goal_cell_x-i)+(goal_cell_y-j)*(goal_cell_y-j)) <= (float)cir-1.0)
00237 {
00238 return false;
00239 }
00240 }
00241 }
00242
00243
00244 for(obstacle = obstacles_.cells.begin() ; obstacle != obstacles_.cells.end() ; obstacle++)
00245 {
00246 if(goal_cell_x >= obstacle->x && goal_cell_x <= obstacle->x+obstacles_.cell_width && goal_cell_y >= obstacle->y && goal_cell_y <= obstacle->y+obstacles_.cell_height)
00247 return false;
00248 }
00249
00250
00251 for(obstacle = inflated_.cells.begin() ; obstacle != inflated_.cells.end() ; obstacle++)
00252 {
00253 if(goal_cell_x >= obstacle->x && goal_cell_x <= obstacle->x+obstacles_.cell_width && goal_cell_y >= obstacle->y && goal_cell_y <= obstacle->y+obstacles_.cell_height)
00254 return false;
00255 }
00256
00257 return true;
00258 }
00259
00260 void RandomWalk::mapCallback(const nav_msgs::OccupancyGrid::ConstPtr& msg)
00261 {
00262 ROS_INFO("RandomWalk - %s - Got the map!", __FUNCTION__);
00263 map_ = *msg;
00264
00265 if(map_known_cells_ == 0)
00266 {
00267 for(int i=0 ; i<map_.info.width ; i++)
00268 {
00269 for(int j=0 ; j<map_.info.height ; j++)
00270 {
00271 if(map_.data[j*map_.info.width+i] == 0) map_known_cells_++;
00272 }
00273 }
00274 }
00275
00276 setGoal();
00277 }
00278
00279 void RandomWalk::odomCallback(const boost::shared_ptr<const nav_msgs::Odometry>& msg)
00280 {
00281 ROS_DEBUG("RandomWalk - %s - Got an odom msg!", __FUNCTION__);
00282
00283 geometry_msgs::PoseStamped odom;
00284 odom.header.frame_id = msg->header.frame_id;
00285 odom.header.stamp = msg->header.stamp;
00286 odom.pose.position.x = msg->pose.pose.position.x;
00287 odom.pose.position.y = msg->pose.pose.position.y;
00288 odom.pose.orientation = msg->pose.pose.orientation;
00289
00290 try
00291 {
00292
00293 tf_.transformPose("map", odom, robot_pose_);
00294 }
00295 catch(tf::TransformException &ex)
00296 {
00297 ROS_ERROR("RandomWalk - %s - Error: %s", __FUNCTION__, ex.what());
00298 return;
00299 }
00300 }
00301
00302 void RandomWalk::obstaclesCallback(const nav_msgs::GridCells::ConstPtr& msg)
00303 {
00304 ROS_DEBUG("RandomWalk - %s - Got an obstacles msg!", __FUNCTION__);
00305 obstacles_ = *msg;
00306 }
00307
00308 void RandomWalk::inflatedCallback(const nav_msgs::GridCells::ConstPtr& msg)
00309 {
00310 ROS_DEBUG("RandomWalk - %s - Got an inflated obstacles msg!", __FUNCTION__);
00311 inflated_ = *msg;
00312 }
00313
00314 void RandomWalk::goalDoneCallback(const actionlib::SimpleClientGoalState &state, const move_base_msgs::MoveBaseResultConstPtr &result)
00315 {
00316 ROS_INFO("RandomWalk - %s - Already visited %lf%% of the map.", __FUNCTION__, (cells_.cell_height*cells_.cell_width*cells_.cells.size())/(map_.info.resolution*map_.info.resolution*map_known_cells_));
00317
00318
00319
00320 setGoal();
00321 }
00322
00323 void RandomWalk::cellsCallback(const nav_msgs::GridCells::ConstPtr& msg)
00324 {
00325 ROS_DEBUG("RandomWalk - %s - Got a visited cells msg!", __FUNCTION__);
00326 cells_ = *msg;
00327 }
00328
00329 void RandomWalk::goalActiveCallback()
00330 {
00331
00332 }
00333
00334 void RandomWalk::goalFeedbackCallback(const move_base_msgs::MoveBaseFeedbackConstPtr &feedback)
00335 {
00336
00337 }
00338
00339 int main(int argc, char **argv)
00340 {
00341 ros::init(argc, argv, "random_walk_node");
00342
00343 ROS_INFO("RandomWalk for ROS v1.0");
00344
00345 srand(time(NULL));
00346
00347 RandomWalk rw;
00348 ros::spin();
00349
00350 return(0);
00351 }
00352
00353
00354