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 <explore/explore.h>
00039 #include <explore/explore_frontier.h>
00040
00041 #include <thread>
00042
00043 namespace explore {
00044
00045 Explore::Explore() :
00046 private_nh_("~"),
00047 tf_listener_(ros::Duration(10.0)),
00048 costmap_client_(private_nh_, relative_nh_, &tf_listener_),
00049 planner_("explore_planner", costmap_client_.getCostmap(),
00050 costmap_client_.getGlobalFrameID()),
00051 move_base_client_("move_base"),
00052 explorer_(&costmap_client_, &planner_),
00053 prev_plan_size_(0),
00054 done_exploring_(false)
00055 {
00056 private_nh_.param("planner_frequency", planner_frequency_, 1.0);
00057 private_nh_.param("progress_timeout", progress_timeout_, 30.0);
00058 private_nh_.param("visualize", visualize_, false);
00059 private_nh_.param("potential_scale", potential_scale_, 1e-3);
00060 private_nh_.param("orientation_scale", orientation_scale_, 0.0);
00061 private_nh_.param("gain_scale", gain_scale_, 1.0);
00062
00063 if(visualize_) {
00064 marker_array_publisher_ = private_nh_.advertise<visualization_msgs::MarkerArray>("frontiers", 10);
00065 }
00066 }
00067
00068 void Explore::publishFrontiers() {
00069 visualization_msgs::MarkerArray markers;
00070 explorer_.getVisualizationMarkers(markers);
00071 ROS_DEBUG("publishing %lu markers", markers.markers.size());
00072 marker_array_publisher_.publish(markers);
00073 }
00074
00075 void Explore::makePlan() {
00076
00077 std::lock_guard<std::mutex> lock(planning_mutex_);
00078
00079 tf::Stamped<tf::Pose> robot_pose;
00080 costmap_client_.getRobotPose(robot_pose);
00081
00082 std::vector<geometry_msgs::Pose> goals;
00083
00084 explorer_.getExplorationGoals(robot_pose, goals, potential_scale_, orientation_scale_, gain_scale_);
00085 if (goals.size() == 0) {
00086 done_exploring_ = true;
00087 ROS_DEBUG("no explorations goals found");
00088 } else {
00089 ROS_DEBUG("found %lu explorations goals", goals.size());
00090 }
00091
00092
00093 if (visualize_) {
00094 publishFrontiers();
00095 }
00096
00097 bool valid_plan = false;
00098 std::vector<geometry_msgs::PoseStamped> plan;
00099 geometry_msgs::PoseStamped goal_pose, robot_pose_msg;
00100 tf::poseStampedTFToMsg(robot_pose, robot_pose_msg);
00101
00102 goal_pose.header.frame_id = costmap_client_.getGlobalFrameID();
00103 goal_pose.header.stamp = ros::Time::now();
00104 planner_.computePotential(robot_pose_msg.pose.position);
00105 size_t blacklist_count = 0;
00106 for (auto& goal : goals) {
00107 goal_pose.pose = goal;
00108 if (goalOnBlacklist(goal_pose)) {
00109 ++blacklist_count;
00110 continue;
00111 }
00112
00113 valid_plan = planner_.getPlanFromPotential(goal_pose, plan) && !plan.empty();
00114 if (valid_plan) {
00115 ROS_DEBUG("got valid plan");
00116 break;
00117 } else {
00118 ROS_DEBUG("got invalid plan");
00119 }
00120 }
00121
00122 if (valid_plan) {
00123 if (prev_plan_size_ != plan.size()) {
00124 time_since_progress_ = 0.0;
00125 } else {
00126 double dx = prev_goal_.pose.position.x - goal_pose.pose.position.x;
00127 double dy = prev_goal_.pose.position.y - goal_pose.pose.position.y;
00128 double dist = sqrt(dx*dx+dy*dy);
00129 if (dist < 0.01) {
00130 time_since_progress_ += 1.0 / planner_frequency_;
00131 }
00132 }
00133
00134
00135 if (time_since_progress_ > progress_timeout_) {
00136 frontier_blacklist_.push_back(goal_pose);
00137 ROS_DEBUG("Adding current goal to black list");
00138 }
00139
00140 prev_plan_size_ = plan.size();
00141 prev_goal_ = goal_pose;
00142
00143 move_base_msgs::MoveBaseGoal goal;
00144 goal.target_pose = goal_pose;
00145 move_base_client_.sendGoal(goal, boost::bind(&Explore::reachedGoal, this, _1, _2, goal_pose));
00146
00147 } else {
00148 ROS_WARN("Done exploring with %lu goals left that could not be reached."
00149 "There are %lu goals on our blacklist, and %lu of the frontier goals are too close to"
00150 "them to pursue. The rest had global planning fail to them. \n",
00151 goals.size(), frontier_blacklist_.size(), blacklist_count);
00152 ROS_INFO("Exploration finished. Hooray.");
00153 done_exploring_ = true;
00154 }
00155 }
00156
00157 bool Explore::goalOnBlacklist(const geometry_msgs::PoseStamped& goal){
00158 costmap_2d::Costmap2D *costmap2d = costmap_client_.getCostmap();
00159
00160
00161 for(auto& frontier_goal : frontier_blacklist_) {
00162 double x_diff = fabs(goal.pose.position.x - frontier_goal.pose.position.x);
00163 double y_diff = fabs(goal.pose.position.y - frontier_goal.pose.position.y);
00164
00165 if(x_diff < 2 * costmap2d->getResolution() && y_diff < 2 * costmap2d->getResolution())
00166 return true;
00167 }
00168 return false;
00169 }
00170
00171 void Explore::reachedGoal(
00172 const actionlib::SimpleClientGoalState& status,
00173 const move_base_msgs::MoveBaseResultConstPtr&,
00174 const geometry_msgs::PoseStamped& frontier_goal){
00175
00176 ROS_DEBUG("Reached goal");
00177 if(status == actionlib::SimpleClientGoalState::ABORTED){
00178 frontier_blacklist_.push_back(frontier_goal);
00179 ROS_DEBUG("Adding current goal to black list");
00180 }
00181
00182
00183 makePlan();
00184 }
00185
00186 void Explore::execute() {
00187 while (!move_base_client_.waitForServer(ros::Duration(5,0)))
00188 ROS_WARN("Waiting to connect to move_base server");
00189
00190 ROS_INFO("Connected to move_base server");
00191
00192
00193 makePlan();
00194
00195 ros::Rate r(planner_frequency_);
00196 while (relative_nh_.ok() && (!done_exploring_)) {
00197 makePlan();
00198 r.sleep();
00199 }
00200
00201 move_base_client_.cancelAllGoals();
00202 }
00203
00204 void Explore::spin() {
00205 ros::spinOnce();
00206 std::thread t(&Explore::execute, this);
00207 ros::spin();
00208 if (t.joinable())
00209 t.join();
00210 }
00211
00212 }
00213
00214 int main(int argc, char** argv){
00215 ros::init(argc, argv, "explore");
00216
00217 explore::Explore explore;
00218 explore.spin();
00219
00220 return(0);
00221 }
00222