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 #include <explore_hrl/explore.h>
00038 #include <explore_hrl/explore_frontier.h>
00039 #include <explore_hrl/isDone_srv.h>
00040
00041 #include <boost/thread.hpp>
00042 #include <boost/bind.hpp>
00043
00044 using namespace costmap_2d;
00045 using namespace navfn;
00046 using namespace visualization_msgs;
00047 using namespace geometry_msgs;
00048 using namespace explore_hrl;
00049
00050 namespace explore {
00051
00052 double sign(double x){
00053 return x < 0.0 ? -1.0 : 1.0;
00054 }
00055
00056 Explore::Explore() :
00057 node_(),
00058 tf_(ros::Duration(10.0)),
00059 explore_costmap_ros_(NULL),
00060 move_base_client_("move_base"),
00061 planner_(NULL),
00062 done_exploring_(false),
00063 preempt_(false),
00064 explorer_(NULL),
00065 goal_pose_last_(),
00066 goal_pose_last_defined_(false)
00067 {
00068 ros::NodeHandle private_nh("~");
00069
00070
00071 if (! ros::service::exists("~explore_done", false)){
00072 isDone_srv_ = private_nh.advertiseService("explore_done", &Explore::isDone, this );
00073 }
00074
00075 marker_publisher_ = node_.advertise<Marker>("visualization_marker",10);
00076 marker_array_publisher_ = node_.advertise<MarkerArray>("visualization_marker_array",10);
00077 map_publisher_ = private_nh.advertise<nav_msgs::OccupancyGrid>("map", 1, true);
00078 map_server_ = private_nh.advertiseService("explore_map", &Explore::mapCallback, this);
00079
00080 private_nh.param("navfn/robot_base_frame", robot_base_frame_, std::string("base_link"));
00081 private_nh.param("graph_update_frequency", graph_update_frequency_, 1.0);
00082 private_nh.param("visualize", visualize_, 1);
00083 double loop_closure_addition_dist_min;
00084 double loop_closure_loop_dist_min;
00085 double loop_closure_loop_dist_max;
00086 double loop_closure_slam_entropy_max;
00087 private_nh.param("loop_closure_addition_dist_min", loop_closure_addition_dist_min, 2.5);
00088 private_nh.param("loop_closure_loop_dist_min", loop_closure_loop_dist_min, 6.0);
00089 private_nh.param("loop_closure_loop_dist_max", loop_closure_loop_dist_max, 20.0);
00090 private_nh.param("loop_closure_slam_entropy_max", loop_closure_slam_entropy_max, 3.0);
00091 private_nh.param("potential_scale", potential_scale_, 1e-3);
00092 private_nh.param("orientation_scale", orientation_scale_, .318);
00093 private_nh.param("gain_scale", gain_scale_, 1.0);
00094
00095 explore_costmap_ros_ = new Costmap2DROS(std::string("explore_costmap"), tf_);
00096 explore_costmap_ros_->clearRobotFootprint();
00097
00098 planner_ = new navfn::NavfnROS(std::string("explore_planner"), explore_costmap_ros_);
00099 explorer_ = new ExploreFrontier();
00100 loop_closure_ = new LoopClosure(loop_closure_addition_dist_min,
00101 loop_closure_loop_dist_min,
00102 loop_closure_loop_dist_max,
00103 loop_closure_slam_entropy_max,
00104 graph_update_frequency_,
00105 move_base_client_,
00106 *explore_costmap_ros_,
00107 client_mutex_,
00108 boost::bind(&Explore::makePlan, this));
00109 ROS_INFO( "Done making Explore" );
00110 }
00111
00112 Explore::~Explore() {
00113
00114
00115 if (visualize_ and explorer_ != NULL) {
00116 ROS_INFO("explore: Destroy old markers");
00117 std::vector<Marker> markers;
00118 explorer_->getVisualizationMarkers(markers);
00119 visualization_msgs::MarkerArray marker_array;
00120 marker_array.set_markers_size(markers.size());
00121 for (unsigned int i=0; i < markers.size(); i++){
00122 marker_array.markers[i] = markers[i];
00123 marker_array.markers[i].action = Marker::DELETE;
00124 }
00125 marker_array_publisher_.publish(marker_array);
00126 ROS_INFO("explore: Done.");
00127 }
00128
00129 if(loop_closure_ != NULL){
00130 ROS_INFO("explore: Action Destroying old explore loop_closure");
00131 delete loop_closure_;
00132 ROS_INFO("Done.");
00133 }
00134
00135 if(planner_ != NULL) {
00136 ROS_INFO("explore: Action Destroying old explore planner");
00137 delete planner_;
00138 ROS_INFO("Done.");
00139 }
00140
00141 if(explorer_ != NULL) {
00142 ROS_INFO("explore: Action Destroying old explore explorer");
00143 delete explorer_;
00144 ROS_INFO("Done.");
00145 }
00146
00147 if(explore_costmap_ros_ != NULL){
00148 ROS_INFO("explore: Action Destroying old explore costmap (WARN: New one might not have probs)");
00149 delete explore_costmap_ros_;
00150 ROS_INFO("Done.");
00151 }
00152 }
00153
00154 bool Explore::isDone( explore_hrl::isDone_srv::Request &req, explore_hrl::isDone_srv::Response &res ){
00155 res.status = done_exploring_;
00156 return true;
00157 }
00158
00159
00160 bool Explore::mapCallback(nav_msgs::GetMap::Request &req,
00161 nav_msgs::GetMap::Response &res)
00162 {
00163 ROS_DEBUG("mapCallback");
00164 Costmap2D explore_costmap;
00165 explore_costmap_ros_->getCostmapCopy(explore_costmap);
00166
00167 res.map.info.width = explore_costmap.getSizeInCellsX();
00168 res.map.info.height = explore_costmap.getSizeInCellsY();
00169 res.map.info.resolution = explore_costmap.getResolution();
00170 res.map.info.origin.position.x = explore_costmap.getOriginX();
00171 res.map.info.origin.position.y = explore_costmap.getOriginY();
00172 res.map.info.origin.position.z = 0;
00173 res.map.info.origin.orientation.x = 0;
00174 res.map.info.origin.orientation.y = 0;
00175 res.map.info.origin.orientation.z = 0;
00176 res.map.info.origin.orientation.w = 1;
00177
00178 int size = res.map.info.width * res.map.info.height;
00179 const unsigned char* map = explore_costmap.getCharMap();
00180
00181 res.map.set_data_size(size);
00182 for (int i=0; i<size; i++) {
00183 if (map[i] == NO_INFORMATION)
00184 res.map.data[i] = -1;
00185 else if (map[i] == LETHAL_OBSTACLE)
00186 res.map.data[i] = 100;
00187 else
00188 res.map.data[i] = 0;
00189
00190
00191
00192
00193
00194
00195 }
00196
00197 return true;
00198 }
00199
00200 void Explore::publishMap() {
00201 nav_msgs::OccupancyGrid map;
00202 map.header.stamp = ros::Time::now();
00203
00204 Costmap2D explore_costmap;
00205 explore_costmap_ros_->getCostmapCopy(explore_costmap);
00206
00207 map.info.width = explore_costmap.getSizeInCellsX();
00208 map.info.height = explore_costmap.getSizeInCellsY();
00209 map.info.resolution = explore_costmap.getResolution();
00210 map.info.origin.position.x = explore_costmap.getOriginX();
00211 map.info.origin.position.y = explore_costmap.getOriginY();
00212 map.info.origin.position.z = 0;
00213 map.info.origin.orientation.x = 0;
00214 map.info.origin.orientation.y = 0;
00215 map.info.origin.orientation.z = 0;
00216 map.info.origin.orientation.w = 1;
00217
00218 int size = map.info.width * map.info.height;
00219 const unsigned char* char_map = explore_costmap.getCharMap();
00220
00221 map.set_data_size(size);
00222 for (int i=0; i<size; i++) {
00223 if (char_map[i] == NO_INFORMATION)
00224 map.data[i] = -1;
00225 else if (char_map[i] == LETHAL_OBSTACLE)
00226 map.data[i] = 100;
00227 else
00228 map.data[i] = 0;
00229 }
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239 map_publisher_.publish(map);
00240 }
00241
00242 void Explore::publishGoal(const geometry_msgs::Pose& goal){
00243 visualization_msgs::Marker marker;
00244 marker.header.frame_id = "map";
00245 marker.header.stamp = ros::Time::now();
00246 marker.ns = "explore_goal";
00247 marker.id = 0;
00248 marker.type = visualization_msgs::Marker::ARROW;
00249 marker.pose = goal;
00250 marker.scale.x = 0.5;
00251 marker.scale.y = 1.0;
00252 marker.scale.z = 1.0;
00253 marker.color.a = 1.0;
00254 marker.color.r = 0.0;
00255 marker.color.g = 1.0;
00256 marker.color.b = 0.0;
00257 marker.lifetime = ros::Duration(5);
00258 marker_publisher_.publish(marker);
00259 }
00260
00261 void Explore::getRobotPose(std::string frame, tf::Stamped<tf::Pose>& pose){
00262 tf::Stamped<tf::Pose> robot_pose;
00263 robot_pose.setIdentity();
00264 robot_pose.frame_id_ = robot_base_frame_;
00265 robot_pose.stamp_ = ros::Time();
00266
00267 try{
00268 tf_.transformPose(frame, robot_pose, pose);
00269 }
00270 catch(tf::LookupException& ex) {
00271 ROS_ERROR("No Transform available Error: %s\n", ex.what());
00272 return;
00273 }
00274 catch(tf::ConnectivityException& ex) {
00275 ROS_ERROR("Connectivity Error: %s\n", ex.what());
00276 return;
00277 }
00278 catch(tf::ExtrapolationException& ex) {
00279 ROS_ERROR("Extrapolation Error: %s\n", ex.what());
00280 }
00281 }
00282
00283
00284 void Explore::makePlan() {
00285
00286 if(explore_costmap_ros_ == NULL)
00287 return;
00288
00289
00290
00291 if (true){
00292 tf::Stamped<tf::Pose> robot_pose;
00293 getRobotPose(explore_costmap_ros_->getGlobalFrameID(), robot_pose);
00294 geometry_msgs::Point robot_point;
00295 robot_point.x = robot_pose.getOrigin().x();
00296 robot_point.y = robot_pose.getOrigin().y();
00297 robot_point.z = robot_pose.getOrigin().z();
00298
00299 std::vector<geometry_msgs::Pose> goals;
00300 explore_costmap_ros_->clearRobotFootprint();
00301 explorer_->getExplorationGoals(*explore_costmap_ros_, robot_point, planner_, goals, potential_scale_, orientation_scale_, gain_scale_);
00302
00303 bool valid_plan = false;
00304 std::vector<geometry_msgs::PoseStamped> plan;
00305 PoseStamped goal_pose, robot_pose_msg;
00306 tf::poseStampedTFToMsg(robot_pose, robot_pose_msg);
00307
00308 bool found_exploration_goal = false;
00309 goal_pose.header.frame_id = explore_costmap_ros_->getGlobalFrameID();
00310 goal_pose.header.stamp = ros::Time::now();
00311 int blacklist_count = 0;
00312 for (unsigned int i=0; i<goals.size(); i++) {
00313 goal_pose.pose = goals[i];
00314
00315 valid_plan = ((planner_->makePlan(robot_pose_msg, goal_pose, plan)) &&
00316 (!plan.empty()));
00317
00318 if (valid_plan) {
00319 if(!goalOnBlacklist(goal_pose)){
00320 found_exploration_goal = true;
00321 break;
00322 }
00323 else{
00324
00325 blacklist_count++;
00326 }
00327 }
00328 }
00329
00330 done_exploring_ = !found_exploration_goal;
00331
00332
00333 if (visualize_) {
00334 std::vector<Marker> markers;
00335 explorer_->getVisualizationMarkers(markers);
00336 visualization_msgs::MarkerArray marker_array;
00337 marker_array.set_markers_size(markers.size());
00338 for (unsigned int i=0; i < markers.size(); i++){
00339 marker_array.markers[i] = markers[i];
00340 }
00341 marker_array_publisher_.publish(marker_array);
00342 }
00343
00344 if (valid_plan) {
00345
00346 move_base_msgs::MoveBaseGoal goal;
00347 goal.target_pose = goal_pose;
00348
00349 if (isRepeatGoal( goal.target_pose )){
00350 ROS_INFO("Explore: This appears to be a duplicate goal.");
00351 frontier_blacklist_.push_back( goal.target_pose );
00352 if (!done_exploring_){
00353 makePlan();
00354 }
00355 }
00356 else {
00357 move_base_client_.sendGoal(goal, boost::bind(&Explore::reachedGoal, this, _1, _2, goal_pose));
00358 }
00359
00360 if (visualize_) {
00361 publishGoal(goal_pose.pose);
00362 publishMap();
00363 }
00364 } else {
00365 ROS_WARN("Done exploring with %d goals left that could not be reached. There are %d goals on our blacklist, and %d of the frontier goals are too close to them to pursue. The rest had global planning fail to them. \n", (int)goals.size(), (int)frontier_blacklist_.size(), blacklist_count);
00366 ROS_INFO("We finsihed exploring the map. Hooray.");
00367 }
00368
00369
00370 if (visualize_) {
00371 publishMap();
00372 }
00373
00374 client_mutex_.unlock();
00375 }
00376 else {
00377 ROS_WARN("Explore: Mutex acquire failed!");
00378 }
00379 }
00380
00381 bool Explore::isRepeatGoal(const geometry_msgs::PoseStamped& goal){
00382
00383
00384
00385
00386
00387 if (!goal_pose_last_defined_){
00388 goal_pose_last_defined_ = true;
00389 goal_pose_last_ = goal;
00390 return false;
00391 }
00392
00393 double x_diff = fabs(goal.pose.position.x - goal_pose_last_.pose.position.x);
00394 double y_diff = fabs(goal.pose.position.y - goal_pose_last_.pose.position.y);
00395 double ang_diff = tf::getYaw( goal.pose.orientation ) - tf::getYaw( goal_pose_last_.pose.orientation );
00396
00397
00398 goal_pose_last_ = goal;
00399
00400 while (ang_diff < -3.14159) ang_diff += 2.0 * 3.14159;
00401 while (ang_diff > 3.14159) ang_diff -= 2.0 * 3.14159;
00402
00403 ROS_INFO( "Differences: %3.2f %3.2f %3.2f", x_diff, y_diff, ang_diff );
00404
00405 if (x_diff < 2 * explore_costmap_ros_->getResolution() &&
00406 y_diff < 2 * explore_costmap_ros_->getResolution() &&
00407 fabs( ang_diff ) < 5.0 * (3.14158 / 180.0)){
00408 return true;
00409 }
00410 else {
00411 return false;
00412 }
00413 }
00414
00415 bool Explore::goalOnBlacklist(const geometry_msgs::PoseStamped& goal){
00416
00417 for(unsigned int i = 0; i < frontier_blacklist_.size(); ++i){
00418 double x_diff = fabs(goal.pose.position.x - frontier_blacklist_[i].pose.position.x);
00419 double y_diff = fabs(goal.pose.position.y - frontier_blacklist_[i].pose.position.y);
00420
00421 if(x_diff < 2 * explore_costmap_ros_->getResolution() && y_diff < 2 * explore_costmap_ros_->getResolution())
00422 return true;
00423 }
00424 return false;
00425 }
00426
00427 void Explore::reachedGoal(const actionlib::SimpleClientGoalState& status,
00428 const move_base_msgs::MoveBaseResultConstPtr& result, geometry_msgs::PoseStamped frontier_goal){
00429 if(status == actionlib::SimpleClientGoalState::ABORTED){
00430 frontier_blacklist_.push_back(frontier_goal);
00431 ROS_ERROR("Adding current goal to blacklist");
00432 }
00433
00434
00435
00436
00437
00438
00439
00440
00441 }
00442
00443 void Explore::execute() {
00444 while (! move_base_client_.waitForServer(ros::Duration(5,0)))
00445 ROS_WARN("Waiting to connect to move_base server");
00446
00447 ROS_INFO("Connected to move_base server");
00448 goal_pose_last_defined_ = false;
00449
00450
00451 ROS_INFO("explore: ONE");
00452 makePlan();
00453 ROS_INFO("explore: TWO");
00454
00455
00456 ros::Rate r(5.0);
00457 ros::Time time_last_moving = ros::Time::now();
00458 tf::Stamped<tf::Pose> robot_pose;
00459 geometry_msgs::PoseStamped new_pose, ref_pose;
00460
00461 getRobotPose(explore_costmap_ros_->getGlobalFrameID(), robot_pose);
00462 ROS_INFO("explore: THREE");
00463
00464
00465 tf::poseStampedTFToMsg( robot_pose, new_pose );
00466 ref_pose = new_pose;
00467 ROS_INFO("explore: FOUR");
00468
00469 while (node_.ok() && (!done_exploring_) && (!preempt_)) {
00470
00471 getRobotPose(explore_costmap_ros_->getGlobalFrameID(), robot_pose);
00472 tf::poseStampedTFToMsg( robot_pose, new_pose );
00473 loop_closure_->updateGraph(robot_pose);
00474
00475
00476 if (move_base_client_.getState() == actionlib::SimpleClientGoalState::ACTIVE){
00477
00478 float dx,dy,da;
00479
00480 dx = new_pose.pose.position.x - ref_pose.pose.position.x;
00481 dy = new_pose.pose.position.y - ref_pose.pose.position.y;
00482 da = tf::getYaw(new_pose.pose.orientation) - tf::getYaw(ref_pose.pose.orientation);
00483 if (dx*dx+dy*dy > 0.02 or da*da > 5 * 3.14159 / 180.0){
00484 time_last_moving = ros::Time::now();
00485 ref_pose = new_pose;
00486 }
00487
00488
00489 if (ros::Time::now() - time_last_moving > ros::Duration( 5 )){
00490 ROS_INFO( "We appear to not be moving... aborting goal." );
00491 move_base_client_.cancelAllGoals();
00492 }
00493 }
00494 else{
00495 makePlan();
00496 ref_pose = new_pose;
00497 time_last_moving = ros::Time::now();
00498 }
00499 r.sleep();
00500 }
00501 move_base_client_.cancelAllGoals();
00502 }
00503
00504 void Explore::spin() {
00505 ROS_INFO("Entering Explore:spin()");
00506 ros::spinOnce();
00507 boost::thread t(boost::bind( &Explore::execute, this ));
00508 ros::spin();
00509 t.join();
00510 }
00511
00512 void Explore::setPreemptFlag( bool state ) {
00513 ROS_INFO("Explore preempt state set to %d.", state);
00514 preempt_ = state;
00515 }
00516
00517 bool Explore::doneExploring( ) {
00518 return done_exploring_;
00519 }
00520
00521 }
00522
00523 int main(int argc, char** argv){
00524 ros::init(argc, argv, "explore");
00525
00526 explore::Explore explore;
00527 explore.spin();
00528
00529 return(0);
00530 }
00531