explore_server.cpp
Go to the documentation of this file.
1 #include <ros/ros.h>
6 
7 #include <geometry_msgs/PolygonStamped.h>
8 
9 #include <frontier_exploration/ExploreTaskAction.h>
10 #include <frontier_exploration/GetNextFrontier.h>
11 #include <frontier_exploration/UpdateBoundaryPolygon.h>
12 
13 #include <tf/transform_listener.h>
14 
15 #include <move_base_msgs/MoveBaseAction.h>
16 
18 
19 namespace frontier_exploration{
20 
26 {
27 
28 public:
29 
34  FrontierExplorationServer(std::string name) :
35  tf_listener_(ros::Duration(10.0)),
36  private_nh_("~"),
37  as_(nh_, name, boost::bind(&FrontierExplorationServer::executeCb, this, _1), false),
38  move_client_("move_base",true),
39  retry_(5)
40  {
41  private_nh_.param<double>("frequency", frequency_, 0.0);
42  private_nh_.param<double>("goal_aliasing", goal_aliasing_, 0.1);
43 
45 
47  as_.start();
48  }
49 
50 private:
51 
56 
60  int retry_;
61 
62  boost::mutex move_client_lock_;
63  frontier_exploration::ExploreTaskFeedback feedback_;
65  move_base_msgs::MoveBaseGoal move_client_goal_;
66 
72  void executeCb(const frontier_exploration::ExploreTaskGoalConstPtr &goal)
73  {
74 
75  success_ = false;
76  moving_ = false;
77 
78  explore_costmap_ros_->resetLayers();
79 
80  //create costmap services
81  ros::ServiceClient updateBoundaryPolygon = private_nh_.serviceClient<frontier_exploration::UpdateBoundaryPolygon>("explore_costmap/explore_boundary/update_boundary_polygon");
82  ros::ServiceClient getNextFrontier = private_nh_.serviceClient<frontier_exploration::GetNextFrontier>("explore_costmap/explore_boundary/get_next_frontier");
83 
84  //wait for move_base and costmap services
85  if(!move_client_.waitForServer() || !updateBoundaryPolygon.waitForExistence() || !getNextFrontier.waitForExistence()){
86  as_.setAborted();
87  return;
88  }
89 
90  //set region boundary on costmap
91  if(ros::ok() && as_.isActive()){
92  frontier_exploration::UpdateBoundaryPolygon srv;
93  srv.request.explore_boundary = goal->explore_boundary;
94  if(updateBoundaryPolygon.call(srv)){
95  ROS_INFO("Region boundary set");
96  }else{
97  ROS_ERROR("Failed to set region boundary");
98  as_.setAborted();
99  return;
100  }
101  }
102 
103  //loop until all frontiers are explored
104  ros::Rate rate(frequency_);
105  while(ros::ok() && as_.isActive()){
106 
107  frontier_exploration::GetNextFrontier srv;
108 
109  //placeholder for next goal to be sent to move base
110  geometry_msgs::PoseStamped goal_pose;
111 
112  //get current robot pose in frame of exploration boundary
113  tf::Stamped<tf::Pose> robot_pose;
114  explore_costmap_ros_->getRobotPose(robot_pose);
115 
116  //provide current robot pose to the frontier search service request
117  tf::poseStampedTFToMsg(robot_pose,srv.request.start_pose);
118 
119  //evaluate if robot is within exploration boundary using robot_pose in boundary frame
120  geometry_msgs::PoseStamped eval_pose = srv.request.start_pose;
121  if(eval_pose.header.frame_id != goal->explore_boundary.header.frame_id){
122  tf_listener_.transformPose(goal->explore_boundary.header.frame_id, srv.request.start_pose, eval_pose);
123  }
124 
125  //check if robot is not within exploration boundary and needs to return to center of search area
126  if(goal->explore_boundary.polygon.points.size() > 0 && !pointInPolygon(eval_pose.pose.position,goal->explore_boundary.polygon)){
127 
128  //check if robot has explored at least one frontier, and promote debug message to warning
129  if(success_){
130  ROS_WARN("Robot left exploration boundary, returning to center");
131  }else{
132  ROS_DEBUG("Robot not initially in exploration boundary, traveling to center");
133  }
134  //get current robot position in frame of exploration center
135  geometry_msgs::PointStamped eval_point;
136  eval_point.header = eval_pose.header;
137  eval_point.point = eval_pose.pose.position;
138  if(eval_point.header.frame_id != goal->explore_center.header.frame_id){
139  geometry_msgs::PointStamped temp = eval_point;
140  tf_listener_.transformPoint(goal->explore_center.header.frame_id, temp, eval_point);
141  }
142 
143  //set goal pose to exploration center
144  goal_pose.header = goal->explore_center.header;
145  goal_pose.pose.position = goal->explore_center.point;
146  goal_pose.pose.orientation = tf::createQuaternionMsgFromYaw( yawOfVector(eval_point.point, goal->explore_center.point) );
147 
148  }else if(getNextFrontier.call(srv)){ //if in boundary, try to find next frontier to search
149 
150  ROS_DEBUG("Found frontier to explore");
151  success_ = true;
152  goal_pose = feedback_.next_frontier = srv.response.next_frontier;
153  retry_ = 5;
154 
155  }else{ //if no frontier found, check if search is successful
156  ROS_DEBUG("Couldn't find a frontier");
157 
158  //search is succesful
159  if(retry_ == 0 && success_){
160  ROS_WARN("Finished exploring room");
161  as_.setSucceeded();
162  boost::unique_lock<boost::mutex> lock(move_client_lock_);
164  return;
165 
166  }else if(retry_ == 0 || !ros::ok()){ //search is not successful
167 
168  ROS_ERROR("Failed exploration");
169  as_.setAborted();
170  return;
171  }
172 
173  ROS_DEBUG("Retrying...");
174  retry_--;
175  //try to find frontier again, without moving robot
176  continue;
177  }
178  //if above conditional does not escape this loop step, search has a valid goal_pose
179 
180  //check if new goal is close to old goal, hence no need to resend
181  if(!moving_ || !pointsNearby(move_client_goal_.target_pose.pose.position,goal_pose.pose.position,goal_aliasing_*0.5)){
182  ROS_DEBUG("New exploration goal");
183  move_client_goal_.target_pose = goal_pose;
184  boost::unique_lock<boost::mutex> lock(move_client_lock_);
185  if(as_.isActive()){
186  move_client_.sendGoal(move_client_goal_, boost::bind(&FrontierExplorationServer::doneMovingCb, this, _1, _2),0,boost::bind(&FrontierExplorationServer::feedbackMovingCb, this, _1));
187  moving_ = true;
188  }
189  lock.unlock();
190  }
191 
192  //check if continuous goal updating is enabled
193  if(frequency_ > 0){
194  //sleep for specified frequency and then continue searching
195  rate.sleep();
196  }else{
197  //wait for movement to finish before continuing
198  while(ros::ok() && as_.isActive() && moving_){
199  ros::WallDuration(0.1).sleep();
200  }
201  }
202  }
203 
204  //goal should never be active at this point
205  ROS_ASSERT(!as_.isActive());
206 
207  }
208 
209 
213  void preemptCb(){
214 
215  boost::unique_lock<boost::mutex> lock(move_client_lock_);
217  ROS_WARN("Current exploration task cancelled");
218 
219  if(as_.isActive()){
220  as_.setPreempted();
221  }
222 
223  }
224 
229  void feedbackMovingCb(const move_base_msgs::MoveBaseFeedbackConstPtr& feedback){
230 
231  feedback_.base_position = feedback->base_position;
232  as_.publishFeedback(feedback_);
233 
234  }
235 
241  void doneMovingCb(const actionlib::SimpleClientGoalState& state, const move_base_msgs::MoveBaseResultConstPtr& result){
242 
244  ROS_ERROR("Failed to move");
245  as_.setAborted();
247  moving_ = false;
248  }
249 
250  }
251 
252 };
253 
254 }
255 
256 int main(int argc, char** argv)
257 {
258  ros::init(argc, argv, "explore_server");
259 
261  ros::spin();
262  return 0;
263 }
ServiceClient serviceClient(const std::string &service_name, bool persistent=false, const M_string &header_values=M_string())
boost::shared_ptr< costmap_2d::Costmap2DROS > explore_costmap_ros_
void publishFeedback(const FeedbackConstPtr &feedback)
actionlib::SimpleActionServer< frontier_exploration::ExploreTaskAction > as_
bool waitForServer(const ros::Duration &timeout=ros::Duration(0, 0)) const
void preemptCb()
Preempt callback for the server, cancels the current running goal and all associated movement actions...
static void poseStampedTFToMsg(const Stamped< Pose > &bt, geometry_msgs::PoseStamped &msg)
FrontierExplorationServer(std::string name)
Constructor for the server, sets up this node&#39;s ActionServer for exploration and ActionClient to move...
ROSCPP_DECL void init(int &argc, char **argv, const std::string &name, uint32_t options=0)
bool call(MReq &req, MRes &res)
bool pointsNearby(const T &one, const S &two, const double &proximity)
Evaluate whether two points are approximately adjacent, within a specified proximity distance...
ROSCPP_DECL const std::string & getName()
void doneMovingCb(const actionlib::SimpleClientGoalState &state, const move_base_msgs::MoveBaseResultConstPtr &result)
Done callback for the move_base client, checks for errors and aborts exploration task if necessary...
void transformPoint(const std::string &target_frame, const geometry_msgs::PointStamped &stamped_in, geometry_msgs::PointStamped &stamped_out) const
move_base_msgs::MoveBaseGoal move_client_goal_
#define ROS_WARN(...)
void setSucceeded(const Result &result=Result(), const std::string &text=std::string(""))
void feedbackMovingCb(const move_base_msgs::MoveBaseFeedbackConstPtr &feedback)
Feedback callback for the move_base client, republishes as feedback for the exploration server...
ROSCPP_DECL void spin(Spinner &spinner)
Server for frontier exploration action, runs the state machine associated with a structured frontier ...
void executeCb(const frontier_exploration::ExploreTaskGoalConstPtr &goal)
Execute callback for actionserver, run after accepting a new goal.
void setPreempted(const Result &result=Result(), const std::string &text=std::string(""))
bool sleep() const
actionlib::SimpleActionClient< move_base_msgs::MoveBaseAction > move_client_
bool waitForExistence(ros::Duration timeout=ros::Duration(-1))
#define ROS_INFO(...)
bool param(const std::string &param_name, T &param_val, const T &default_val) const
ROSCPP_DECL bool ok()
void registerPreemptCallback(boost::function< void()> cb)
void cancelGoalsAtAndBeforeTime(const ros::Time &time)
bool sleep()
frontier_exploration::ExploreTaskFeedback feedback_
void setAborted(const Result &result=Result(), const std::string &text=std::string(""))
void sendGoal(const Goal &goal, SimpleDoneCallback done_cb=SimpleDoneCallback(), SimpleActiveCallback active_cb=SimpleActiveCallback(), SimpleFeedbackCallback feedback_cb=SimpleFeedbackCallback())
static geometry_msgs::Quaternion createQuaternionMsgFromYaw(double yaw)
void transformPose(const std::string &target_frame, const geometry_msgs::PoseStamped &stamped_in, geometry_msgs::PoseStamped &stamped_out) const
double yawOfVector(const T &origin, const S &end)
Calculate the yaw of vector defined by origin and end points.
static Time now()
#define ROS_ASSERT(cond)
bool pointInPolygon(const T &point, const geometry_msgs::Polygon &polygon)
Evaluate if point is inside area defined by polygon. Undefined behaviour for points on line...
#define ROS_ERROR(...)
int main(int argc, char **argv)
#define ROS_DEBUG(...)


frontier_exploration
Author(s): Paul Bovbel
autogenerated on Mon Jun 10 2019 13:25:00