random_walk.cpp
Go to the documentation of this file.
00001 /*********************************************************************
00002 *
00003 * Software License Agreement (BSD License)
00004 *
00005 *  Copyright (c) 2010, ISR University of Coimbra.
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 ISR University of Coimbra 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 * Author: Gonçalo Cabrita on 05/03/2011
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         // Subscribe to topics
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                 /*double yaw = (rand() % 628 - 314)/100.0;
00179                 double step = (rand() % 75 + 25)/100.0;
00180 
00181                 goal.target_pose.pose.position.x = robot_pose_.pose.position.x + step * cos(tf::getYaw(robot_pose_.pose.orientation) + yaw);
00182                 goal.target_pose.pose.position.y = robot_pose_.pose.position.y + step * sin(tf::getYaw(robot_pose_.pose.orientation) + yaw);
00183                 goal.target_pose.pose.orientation = tf::createQuaternionMsgFromYaw(angles::normalize_angle(tf::getYaw(robot_pose_.pose.orientation) + yaw));*/
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                 //ROS_INFO("RandomWalk - %s - Testing %lf %lf...", __FUNCTION__, goal.target_pose.pose.position.x, goal.target_pose.pose.position.y);
00193                 
00194                 if(!n_.ok())
00195                 {
00196                         ROS_INFO("RandomWalk - %s - Exiting...", __FUNCTION__);
00197                         return;
00198                 }
00199         }
00200         while(!checkCell(x, y));
00201         //while(!checkGoal(&goal));
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         // 1. If goal is out of bounds, discard it!
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         // 1. If goal is an obstacle or too close to one on the map, discard it!
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         // 2. If goal is too close to an obstacle, discard it!
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         // 3. If goal is too close to an inflated obstacle, discard it!
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                 // Transform the odom into a pose in the map frame
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         //if(state.state_ == actionlib::SimpleClientGoalState::SUCCEEDED) ;     
00319         //if(state.state_ == actionlib::SimpleClientGoalState::ABORTED) ;
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 // EOF
00354 


random_walk
Author(s): Gonçalo Cabrita
autogenerated on Mon Jan 6 2014 11:28:41