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 #include "hector_exploration_planner/hector_exploration_planner.h"
00030
00031 #include <visualization_msgs/Marker.h>
00032 #include <visualization_msgs/MarkerArray.h>
00033 #include <hector_nav_msgs/GetRobotTrajectory.h>
00034 #include <Eigen/Geometry>
00035
00036 #include <hector_exploration_planner/ExplorationPlannerConfig.h>
00037
00038 #define STRAIGHT_COST 100
00039 #define DIAGONAL_COST 141
00040
00041
00042
00043
00044 using namespace hector_exploration_planner;
00045
00046 HectorExplorationPlanner::HectorExplorationPlanner()
00047 : costmap_ros_(0)
00048 , occupancy_grid_array_(0)
00049 , exploration_trans_array_(0)
00050 , obstacle_trans_array_(0)
00051 , frontier_map_array_(0)
00052 , is_goal_array_(0)
00053 , initialized_(false)
00054 , map_width_(0)
00055 , map_height_(0)
00056 , num_map_cells_(0)
00057 {}
00058
00059 HectorExplorationPlanner::~HectorExplorationPlanner(){
00060 this->deleteMapData();
00061 }
00062
00063 HectorExplorationPlanner::HectorExplorationPlanner(std::string name, costmap_2d::Costmap2DROS *costmap_ros_in) :
00064 costmap_ros_(NULL), initialized_(false) {
00065 HectorExplorationPlanner::initialize(name, costmap_ros_in);
00066 }
00067
00068 void HectorExplorationPlanner::initialize(std::string name, costmap_2d::Costmap2DROS *costmap_ros_in){
00069
00070 last_mode_ = FRONTIER_EXPLORE;
00071
00072
00073 if(initialized_){
00074 ROS_ERROR("[hector_exploration_planner] HectorExplorationPlanner is already initialized_! Please check why initialize() got called twice.");
00075 return;
00076 }
00077
00078 ROS_INFO("[hector_exploration_planner] Initializing HectorExplorationPlanner");
00079
00080
00081 this->costmap_ros_ = costmap_ros_in;
00082 this->setupMapData();
00083
00084
00085 ros::NodeHandle private_nh_("~/" + name);
00086 ros::NodeHandle nh;
00087 visualization_pub_ = private_nh_.advertise<visualization_msgs::Marker>("visualization_marker", 0);
00088
00089 dyn_rec_server_.reset(new dynamic_reconfigure::Server<hector_exploration_planner::ExplorationPlannerConfig>());
00090
00091 dyn_rec_server_->setCallback(boost::bind(&HectorExplorationPlanner::dynRecParamCallback, this, _1, _2));
00092
00093 path_service_client_ = nh.serviceClient<hector_nav_msgs::GetRobotTrajectory>("trajectory");
00094
00095 ROS_INFO("[hector_exploration_planner] Parameter set. security_const: %f, min_obstacle_dist: %d, plan_in_unknown: %d, use_inflated_obstacle: %d, p_goal_angle_penalty_:%d , min_frontier_size: %d, p_dist_for_goal_reached_: %f, same_frontier: %f", p_alpha_, p_min_obstacle_dist_, p_plan_in_unknown_, p_use_inflated_obs_, p_goal_angle_penalty_, p_min_frontier_size_,p_dist_for_goal_reached_,p_same_frontier_dist_);
00096
00097
00098 this->name = name;
00099 this->initialized_ = true;
00100 this->previous_goal_ = -1;
00101
00102 vis_.reset(new ExplorationTransformVis("exploration_transform"));
00103 inner_vis_.reset(new ExplorationTransformVis("inner_exploration_transform"));
00104
00105 }
00106
00107 void HectorExplorationPlanner::dynRecParamCallback(hector_exploration_planner::ExplorationPlannerConfig &config, uint32_t level)
00108 {
00109 if (p_plan_in_unknown_ != config.plan_in_unknown){
00110 p_plan_in_unknown_ = config.plan_in_unknown;
00111 }
00112
00113 if (p_use_inflated_obs_ != config.use_inflated_obstacles){
00114 p_use_inflated_obs_ = config.use_inflated_obstacles;
00115 }
00116
00117 if (p_goal_angle_penalty_ != config.goal_angle_penalty){
00118 p_goal_angle_penalty_ = config.goal_angle_penalty;
00119 }
00120
00121 if (p_alpha_ != config.security_constant){
00122 p_alpha_ = config.security_constant;
00123 }
00124
00125 if (p_dist_for_goal_reached_ != config.dist_for_goal_reached){
00126 p_dist_for_goal_reached_ = config.dist_for_goal_reached;
00127 }
00128
00129 if (p_same_frontier_dist_ != config.same_frontier_distance){
00130 p_same_frontier_dist_ = config.same_frontier_distance;
00131 }
00132
00133 if (p_min_frontier_size_ != config.min_frontier_size){
00134 p_min_frontier_size_ = config.min_frontier_size;
00135 }
00136
00137 p_min_obstacle_dist_ = config.min_obstacle_dist * STRAIGHT_COST;
00138
00139 }
00140
00141
00142
00143 bool HectorExplorationPlanner::makePlan(const geometry_msgs::PoseStamped &start, const geometry_msgs::PoseStamped &original_goal, std::vector<geometry_msgs::PoseStamped> &plan){
00144
00145 this->setupMapData();
00146
00147
00148
00149 if ((original_goal.pose.orientation.w == 0.0) && (original_goal.pose.orientation.x == 0.0) &&
00150 (original_goal.pose.orientation.y == 0.0) && (original_goal.pose.orientation.z == 0.0)){
00151 ROS_ERROR("Trying to plan with invalid quaternion, this shouldn't be done anymore, but we'll start exploration for now.");
00152 return doExploration(start,plan);
00153 }
00154
00155
00156
00157 ROS_INFO("[hector_exploration_planner] planning: starting to make a plan to given goal point");
00158
00159
00160 resetMaps();
00161 plan.clear();
00162
00163 std::vector<geometry_msgs::PoseStamped> goals;
00164
00165
00166 buildobstacle_trans_array_(p_use_inflated_obs_);
00167
00168 geometry_msgs::PoseStamped adjusted_goal;
00169 if (!this->getObservationPose(original_goal, 0.5, adjusted_goal)){
00170 ROS_ERROR("getObservationPose returned false, no area around target point available to drive to!");
00171 return false;
00172 }
00173
00174
00175 goals.push_back(adjusted_goal);
00176
00177
00178 if(!buildexploration_trans_array_(start,goals,true)){
00179 return false;
00180 }
00181 if(!getTrajectory(start,goals,plan)){
00182 return false;
00183 }
00184
00185
00186 plan.push_back(adjusted_goal);
00187 unsigned int mx,my;
00188 costmap_.worldToMap(adjusted_goal.pose.position.x,adjusted_goal.pose.position.y,mx,my);
00189 previous_goal_ = costmap_.getIndex(mx,my);
00190
00191 ROS_INFO("[hector_exploration_planner] planning: plan has been found! plansize: %u ", (unsigned int)plan.size());
00192 return true;
00193 }
00194
00195 bool HectorExplorationPlanner::doExploration(const geometry_msgs::PoseStamped &start, std::vector<geometry_msgs::PoseStamped> &plan){
00196
00197 ROS_INFO("[hector_exploration_planner] exploration: starting exploration");
00198
00199 this->setupMapData();
00200
00201
00202
00203 resetMaps();
00204 clearFrontiers();
00205 plan.clear();
00206
00207 std::vector<geometry_msgs::PoseStamped> goals;
00208
00209
00210 buildobstacle_trans_array_(p_use_inflated_obs_);
00211
00212
00213 if(findFrontiers(goals)){
00214
00215 last_mode_ = FRONTIER_EXPLORE;
00216 ROS_INFO("[hector_exploration_planner] exploration: found %u frontiers!", (unsigned int)goals.size());
00217 } else {
00218 ROS_INFO("[hector_exploration_planner] exploration: no frontiers have been found! starting inner-exploration");
00219 return doInnerExploration(start,plan);
00220 }
00221
00222
00223 if(!buildexploration_trans_array_(start,goals,true)){
00224 return false;
00225 }
00226
00227 vis_->publishVisOnDemand(costmap_, exploration_trans_array_);
00228
00229 if(!getTrajectory(start,goals,plan)){
00230 ROS_INFO("[hector_exploration_planner] exploration: could not plan to frontier, starting inner-exploration");
00231 return doInnerExploration(start,plan);
00232 }
00233
00234
00235 if(!plan.empty()){
00236 geometry_msgs::PoseStamped thisgoal = plan.back();
00237 unsigned int mx,my;
00238 costmap_.worldToMap(thisgoal.pose.position.x,thisgoal.pose.position.y,mx,my);
00239 previous_goal_ = costmap_.getIndex(mx,my);
00240 }
00241
00242
00243 ROS_INFO("[hector_exploration_planner] exploration: plan to a frontier has been found! plansize: %u", (unsigned int)plan.size());
00244 return true;
00245 }
00246
00247 bool HectorExplorationPlanner::doInnerExploration(const geometry_msgs::PoseStamped &start, std::vector<geometry_msgs::PoseStamped> &plan){
00248 ROS_INFO("[hector_exploration_planner] inner-exploration: starting exploration");
00249
00250
00251
00252 resetMaps();
00253 clearFrontiers();
00254 plan.clear();
00255
00256 std::vector<geometry_msgs::PoseStamped> goals;
00257
00258
00259 buildobstacle_trans_array_(p_use_inflated_obs_);
00260
00261
00262 if (last_mode_ == INNER_EXPLORE){
00263
00264 tf::Stamped<tf::Pose> robotPose;
00265 if(!costmap_ros_->getRobotPose(robotPose)){
00266 ROS_WARN("[hector_exploration_planner]: Failed to get RobotPose");
00267 }
00268
00269 unsigned int xm, ym;
00270 costmap_.indexToCells(previous_goal_, xm, ym);
00271
00272 double xw, yw;
00273 costmap_.mapToWorld(xm, ym, xw, yw);
00274
00275 double dx = xw - robotPose.getOrigin().getX();
00276 double dy = yw - robotPose.getOrigin().getY();
00277
00278
00279 if ( (dx*dx + dy*dy) > 0.5*0.5){
00280
00281 geometry_msgs::PoseStamped robotPoseMsg;
00282 tf::poseStampedTFToMsg(robotPose, robotPoseMsg);
00283
00284 geometry_msgs::PoseStamped goalMsg;
00285 goalMsg.pose.position.x = xw;
00286 goalMsg.pose.position.y = yw;
00287 goalMsg.pose.orientation.w = 1.0;
00288
00289 if(makePlan(robotPoseMsg, goalMsg, plan)){
00290
00291 ROS_INFO("[hector_exploration_planner] inner-exploration: Planning to previous inner frontier");
00292 last_mode_ = INNER_EXPLORE;
00293 return true;
00294 }
00295 }
00296 }
00297
00298
00299 if(findInnerFrontier(goals)){
00300 ROS_INFO("[hector_exploration_planner] inner-exploration: found %u inner-frontiers!", (unsigned int)goals.size());
00301 } else {
00302 ROS_WARN("[hector_exploration_planner] inner-exploration: no inner-frontiers have been found! exploration failed!");
00303 return false;
00304 }
00305
00306
00307 if(!buildexploration_trans_array_(start,goals,false)){
00308 ROS_WARN("[hector_exploration_planner] inner-exploration: Creating exploration transform failed!");
00309 return false;
00310 }
00311 if(!getTrajectory(start,goals,plan)){
00312 ROS_WARN("[hector_exploration_planner] inner-exploration: could not plan to inner-frontier. exploration failed!");
00313 return false;
00314 }
00315
00316
00317
00318 int plansize = plan.size() - 5;
00319 if(plansize > 0 ){
00320 plan.resize(plansize);
00321 }
00322
00323
00324 if(!plan.empty()){
00325 const geometry_msgs::PoseStamped& thisgoal = plan.back();
00326 unsigned int mx,my;
00327 costmap_.worldToMap(thisgoal.pose.position.x,thisgoal.pose.position.y,mx,my);
00328 previous_goal_ = costmap_.getIndex(mx,my);
00329 last_mode_ = INNER_EXPLORE;
00330 }
00331
00332 ROS_INFO("[hector_exploration_planner] inner-exploration: plan to an inner-frontier has been found! plansize: %u", (unsigned int)plan.size());
00333 return true;
00334 }
00335
00336 bool HectorExplorationPlanner::getObservationPose(const geometry_msgs::PoseStamped& observation_pose, const double desired_distance, geometry_msgs::PoseStamped& new_observation_pose)
00337 {
00338
00339
00340
00341
00342 unsigned int mxs,mys;
00343 costmap_.worldToMap(observation_pose.pose.position.x, observation_pose.pose.position.y, mxs, mys);
00344
00345 double pose_yaw = tf::getYaw(observation_pose.pose.orientation);
00346
00347 Eigen::Vector2f obs_pose_dir_vec (cos(pose_yaw), sin(pose_yaw));
00348
00349 this->buildobstacle_trans_array_(true);
00350
00351 int searchSize = 2.0 / costmap_.getResolution();
00352
00353 int min_x = mxs - searchSize/2;
00354 int min_y = mys - searchSize/2;
00355
00356 if (min_x < 0){
00357 min_x = 0;
00358 }
00359
00360 if (min_y < 0){
00361 min_y = 0;
00362 }
00363
00364 int max_x = mxs + searchSize/2;
00365 int max_y = mys + searchSize/2;
00366
00367 if (max_x > static_cast<int>(costmap_.getSizeInCellsX())){
00368 max_x = static_cast<int>(costmap_.getSizeInCellsX()-1);
00369 }
00370
00371 if (max_y > static_cast<int>(costmap_.getSizeInCellsY())){
00372 max_y = static_cast<int>(costmap_.getSizeInCellsY()-1);
00373 }
00374
00375 int closest_x = -1;
00376 int closest_y = -1;
00377
00378 int closest_sqr_dist = INT_MAX;
00379
00380 for (int x = min_x; x < max_x; ++x){
00381 for (int y = min_y; y < max_y; ++y){
00382
00383 unsigned int obstacle_trans_val = obstacle_trans_array_[costmap_.getIndex(x,y)];
00384 if ( (obstacle_trans_val != INT_MAX) && (obstacle_trans_val != 0) ){
00385 int diff_x = (int)mxs - x;
00386 int diff_y = (int)mys - y;
00387
00388 int sqr_dist = diff_x*diff_x + diff_y*diff_y;
00389
00390
00391
00392 if (sqr_dist < closest_sqr_dist){
00393
00394 Eigen::Vector2f curr_dir_vec(static_cast<float>(diff_x), static_cast<float>(diff_y));
00395 curr_dir_vec.normalize();
00396
00397 if (curr_dir_vec.dot(obs_pose_dir_vec) > 0){
00398
00399 closest_x = (unsigned int)x;
00400 closest_y = (unsigned int)y;
00401 closest_sqr_dist = sqr_dist;
00402 }
00403 }
00404 }
00405 }
00406 }
00407
00408
00409
00410
00411
00412 if ((closest_x > -1) && (closest_y > -1)){
00413
00414 Eigen::Vector2d closest_point_world;
00415 costmap_.mapToWorld(closest_x, closest_y, closest_point_world.x(), closest_point_world.y());
00416
00417 Eigen::Vector2d original_goal_pose(observation_pose.pose.position.x, observation_pose.pose.position.y);
00418
00419
00420 new_observation_pose.header.frame_id = "map";
00421 new_observation_pose.header.stamp = observation_pose.header.stamp;
00422
00423 Eigen::Vector2d dir_vec(original_goal_pose - closest_point_world);
00424
00425 double distance = dir_vec.norm();
00426
00427
00428 if (distance < (costmap_.getResolution() * 1.5)){
00429 new_observation_pose.pose = observation_pose.pose;
00430 new_observation_pose.pose.position.z = 0.0;
00431 ROS_INFO("Observation pose unchanged");
00432 }else{
00433
00434 if (desired_distance < distance){
00435 new_observation_pose.pose.position.x = closest_point_world.x();
00436 new_observation_pose.pose.position.y = closest_point_world.y();
00437 new_observation_pose.pose.position.z = 0.0;
00438 }else{
00439
00440 double test_distance = distance;
00441
00442 Eigen::Vector2d last_valid_pos(closest_point_world);
00443
00444 do{
00445 test_distance += 0.1;
00446
00447 double distance_factor = test_distance / distance;
00448
00449 Eigen::Vector2d new_pos(original_goal_pose - dir_vec*distance_factor);
00450
00451 unsigned int x, y;
00452 costmap_.worldToMap(new_pos[0], new_pos[1], x, y);
00453 unsigned int idx = costmap_.getIndex(x,y);
00454
00455 if(!this->isFree(idx)){
00456 break;
00457 }
00458
00459 last_valid_pos = new_pos;
00460
00461 }while (test_distance < desired_distance);
00462
00463 new_observation_pose.pose.position.x = last_valid_pos.x();
00464 new_observation_pose.pose.position.y = last_valid_pos.y();
00465 new_observation_pose.pose.position.z = 0.0;
00466 }
00467
00468 double angle = std::atan2(dir_vec.y(), dir_vec.x());
00469
00470 new_observation_pose.pose.orientation.w = cos(angle*0.5);
00471 new_observation_pose.pose.orientation.x = 0.0;
00472 new_observation_pose.pose.orientation.y = 0.0;
00473 new_observation_pose.pose.orientation.z = sin(angle*0.5);
00474 ROS_INFO("Observation pose moved away from wall");
00475 }
00476
00477 return true;
00478 }else{
00479
00480 ROS_ERROR("Couldn't find observation pose for given point.");
00481 return false;
00482 }
00483 }
00484
00485 bool HectorExplorationPlanner::doAlternativeExploration(const geometry_msgs::PoseStamped &start, std::vector<geometry_msgs::PoseStamped> &plan, std::vector<geometry_msgs::PoseStamped> &oldplan){
00486 ROS_INFO("[hector_exploration_planner] alternative exploration: starting alternative exploration");
00487
00488
00489 resetMaps();
00490 plan.clear();
00491
00492 std::vector<geometry_msgs::PoseStamped> goals;
00493
00494 std::vector<geometry_msgs::PoseStamped> old_frontier;
00495 old_frontier.push_back(oldplan.back());
00496
00497
00498 buildobstacle_trans_array_(p_use_inflated_obs_);
00499
00500
00501 if(findFrontiers(goals,old_frontier)){
00502 ROS_INFO("[hector_exploration_planner] alternative exploration: found %u frontiers!", (unsigned int) goals.size());
00503 } else {
00504 ROS_WARN("[hector_exploration_planner] alternative exploration: no frontiers have been found!");
00505 return false;
00506 }
00507
00508
00509 if(!buildexploration_trans_array_(start,goals,true)){
00510 return false;
00511 }
00512 if(!getTrajectory(start,goals,plan)){
00513 return false;
00514 }
00515
00516 const geometry_msgs::PoseStamped& this_goal = plan.back();
00517 unsigned int mx,my;
00518 costmap_.worldToMap(this_goal.pose.position.x,this_goal.pose.position.y,mx,my);
00519 previous_goal_ = costmap_.getIndex(mx,my);
00520
00521 ROS_INFO("[hector_exploration_planner] alternative exploration: plan to a frontier has been found! plansize: %u ", (unsigned int)plan.size());
00522 return true;
00523 }
00524
00525 float HectorExplorationPlanner::angleDifferenceWall(const geometry_msgs::PoseStamped &start, const geometry_msgs::PoseStamped &goal){
00526
00527 unsigned int mxs,mys;
00528 costmap_.worldToMap(start.pose.position.x,start.pose.position.y,mxs,mys);
00529
00530 unsigned int gx,gy;
00531 costmap_.worldToMap(goal.pose.position.x,goal.pose.position.y,gx,gy);
00532
00533 int goal_proj_x = gx-mxs;
00534 int goal_proj_y = gy-mys;
00535
00536 float start_angle = tf::getYaw(start.pose.orientation);
00537 float goal_angle = std::atan2(goal_proj_y,goal_proj_x);
00538
00539 float both_angle = 0;
00540 if(start_angle > goal_angle){
00541 both_angle = start_angle - goal_angle;
00542 } else {
00543 both_angle = goal_angle - start_angle;
00544 }
00545
00546 return both_angle;
00547 }
00548
00549 bool HectorExplorationPlanner::exploreWalls(const geometry_msgs::PoseStamped &start, std::vector<geometry_msgs::PoseStamped> &plan){
00550
00551
00552 int startExploreWall = 1;
00553
00554 ROS_DEBUG("[hector_exploration_planner] wall-follow: exploreWalls");
00555 unsigned int mx,my;
00556 if(!costmap_.worldToMap(start.pose.position.x, start.pose.position.y, mx, my)){
00557 ROS_WARN("[hector_exploration_planner] wall-follow: The start coordinates are outside the costmap!");
00558 return false;
00559 }
00560 int currentPoint=costmap_.getIndex(mx, my);
00561 int nextPoint;
00562 int oldDirection = -1;
00563 int k=0;
00564 int loop=0;
00565
00566 while(k<50){
00567 int adjacentPoints [8];
00568 getAdjacentPoints(currentPoint, adjacentPoints);
00569 int dirPoints [3];
00570
00571 int minDelta=INT_MAX;
00572 int maxDelta=0;
00573 int thisDelta;
00574 float minAngle=3.1415;
00575
00576 geometry_msgs::PoseStamped trajPoint;
00577 unsigned int gx,gy;
00578
00579 if(oldDirection==-1){
00580
00581 for ( int i=0; i<8; i++){
00582 costmap_.indexToCells((unsigned int)adjacentPoints[i],gx,gy);
00583 double wx,wy;
00584 costmap_.mapToWorld(gx,gy,wx,wy);
00585 std::string global_frame = costmap_ros_->getGlobalFrameID();
00586 trajPoint.header.frame_id = global_frame;
00587 trajPoint.pose.position.x = wx;
00588 trajPoint.pose.position.y = wy;
00589 trajPoint.pose.position.z = 0.0;
00590 float yaw = angleDifferenceWall(start, trajPoint);
00591 if(yaw < minAngle){
00592 minAngle=yaw;
00593 oldDirection=i;
00594 }
00595 }
00596 }
00597
00598
00599
00600 if (oldDirection == 0){
00601 dirPoints[0]=oldDirection+4;
00602 dirPoints[1]=oldDirection;
00603 dirPoints[2]=oldDirection+7;
00604 }
00605 else if (oldDirection < 3){
00606 dirPoints[0]=oldDirection+4;
00607 dirPoints[1]=oldDirection;
00608 dirPoints[2]=oldDirection+3;
00609 }
00610 else if (oldDirection == 3){
00611 dirPoints[0]=oldDirection+4;
00612 dirPoints[1]=oldDirection;
00613 dirPoints[2]=oldDirection+3;
00614 }
00615 else if (oldDirection == 4){
00616 dirPoints[0]=oldDirection-3;
00617 dirPoints[1]=oldDirection;
00618 dirPoints[2]=oldDirection-4;
00619 }
00620 else if (oldDirection < 7){
00621 dirPoints[0]=oldDirection-3;
00622 dirPoints[1]=oldDirection;
00623 dirPoints[2]=oldDirection-4;
00624 }
00625 else if (oldDirection == 7){
00626 dirPoints[0]=oldDirection-7;
00627 dirPoints[1]=oldDirection;
00628 dirPoints[2]=oldDirection-4;
00629 }
00630
00631
00632 if(startExploreWall == -1){
00633 if(obstacle_trans_array_[adjacentPoints[dirPoints[0]]] <= obstacle_trans_array_[adjacentPoints[dirPoints[2]]]){
00634 startExploreWall = 0;
00635 ROS_INFO("[hector_exploration_planner] wall-follow: RHR");
00636 }
00637 else {
00638 startExploreWall = 1;
00639 ROS_INFO("[hector_exploration_planner] wall-follow: LHR");
00640 }
00641 }
00642
00643
00644
00645
00646 if(startExploreWall == 1){
00647 int temp=dirPoints[0];
00648 dirPoints[0]=dirPoints[2];
00649 dirPoints[2]=temp;
00650 }
00651
00652
00653
00654 int t=0;
00655 for(int i=0; i<3; i++){
00656 thisDelta= obstacle_trans_array_[adjacentPoints[dirPoints[i]]];
00657
00658 if (thisDelta > 3000 || loop > 7)
00659 {
00660 int plansize = plan.size() - 4;
00661 if(plansize > 0 ){
00662 plan.resize(plansize);
00663 }
00664 ROS_DEBUG("[hector_exploration_planner] wall-follow: END: exploreWalls. Plansize %d", (int)plan.size());
00665 return !plan.empty();
00666 }
00667
00668 if(thisDelta >= p_min_obstacle_dist_){
00669 if(obstacle_trans_array_[currentPoint] >= p_min_obstacle_dist_){
00670 if(abs(thisDelta - p_min_obstacle_dist_) < minDelta){
00671 minDelta = abs(thisDelta - p_min_obstacle_dist_);
00672 nextPoint = adjacentPoints[dirPoints[i]];
00673 oldDirection = dirPoints[i];
00674 }
00675 }
00676 if(obstacle_trans_array_[currentPoint] < p_min_obstacle_dist_){
00677 if(thisDelta > maxDelta){
00678 maxDelta = thisDelta;
00679 nextPoint = adjacentPoints[dirPoints[i]];
00680 oldDirection = dirPoints[i];
00681 }
00682 }
00683 }
00684 else {
00685 if(thisDelta < obstacle_trans_array_[currentPoint]){
00686 t++;
00687 }
00688 if(thisDelta > maxDelta){
00689 maxDelta = thisDelta;
00690 nextPoint = adjacentPoints[dirPoints[i]];
00691 oldDirection = dirPoints[i];
00692
00693 }
00694 }
00695 }
00696
00697 if(t==3 && abs(obstacle_trans_array_[adjacentPoints[dirPoints[0]]] - obstacle_trans_array_[adjacentPoints[dirPoints[1]]]) < STRAIGHT_COST
00698 && abs(obstacle_trans_array_[adjacentPoints[dirPoints[0]]] - obstacle_trans_array_[adjacentPoints[dirPoints[2]]]) < STRAIGHT_COST
00699 && abs(obstacle_trans_array_[adjacentPoints[dirPoints[1]]] - obstacle_trans_array_[adjacentPoints[dirPoints[2]]]) < STRAIGHT_COST){
00700 nextPoint=adjacentPoints[dirPoints[2]];
00701 oldDirection=dirPoints[2];
00702 }
00703
00704 if(oldDirection==dirPoints[2])
00705 loop++;
00706 else
00707 loop=0;
00708
00709
00710 unsigned int sx,sy;
00711 costmap_.indexToCells((unsigned int)currentPoint,sx,sy);
00712 costmap_.indexToCells((unsigned int)nextPoint,gx,gy);
00713 double wx,wy;
00714 costmap_.mapToWorld(sx,sy,wx,wy);
00715 std::string global_frame = costmap_ros_->getGlobalFrameID();
00716 trajPoint.header.frame_id = global_frame;
00717 trajPoint.pose.position.x = wx;
00718 trajPoint.pose.position.y = wy;
00719 trajPoint.pose.position.z = 0.0;
00720
00721 int dx = gx-sx;
00722 int dy = gy-sy;
00723 double yaw_path = std::atan2(dy,dx);
00724 trajPoint.pose.orientation.x = 0.0;
00725 trajPoint.pose.orientation.y = 0.0;
00726 trajPoint.pose.orientation.z = sin(yaw_path*0.5f);
00727 trajPoint.pose.orientation.w = cos(yaw_path*0.5f);
00728 plan.push_back(trajPoint);
00729
00730 currentPoint=nextPoint;
00731 k++;
00732 }
00733 ROS_DEBUG("[hector_exploration_planner] wall-follow: END: exploreWalls. Plansize %d", (int)plan.size());
00734 return !plan.empty();
00735 }
00736
00737 void HectorExplorationPlanner::setupMapData()
00738 {
00739 costmap_ros_->getCostmapCopy(costmap_);
00740
00741 if ((this->map_width_ != costmap_ros_->getSizeInCellsX()) || (this->map_height_ != costmap_ros_->getSizeInCellsY())){
00742 this->deleteMapData();
00743
00744 map_width_ = costmap_.getSizeInCellsX();
00745 map_height_ = costmap_.getSizeInCellsY();
00746 num_map_cells_ = map_width_ * map_height_;
00747
00748
00749 exploration_trans_array_ = new unsigned int[num_map_cells_];
00750 obstacle_trans_array_ = new unsigned int[num_map_cells_];
00751 is_goal_array_ = new bool[num_map_cells_];
00752 frontier_map_array_ = new int[num_map_cells_];
00753 clearFrontiers();
00754 resetMaps();
00755 }
00756
00757
00758 occupancy_grid_array_ = costmap_.getCharMap();
00759 }
00760
00761 void HectorExplorationPlanner::deleteMapData()
00762 {
00763 if(exploration_trans_array_){
00764 delete[] exploration_trans_array_;
00765 exploration_trans_array_ = 0;
00766 }
00767 if(obstacle_trans_array_){
00768 delete[] obstacle_trans_array_;
00769 obstacle_trans_array_ = 0;
00770 }
00771 if(is_goal_array_){
00772 delete[] is_goal_array_;
00773 is_goal_array_ = 0;
00774 }
00775 if(frontier_map_array_){
00776 delete[] frontier_map_array_;
00777 frontier_map_array_=0;
00778 }
00779 }
00780
00781
00782 bool HectorExplorationPlanner::buildexploration_trans_array_(const geometry_msgs::PoseStamped &start, std::vector<geometry_msgs::PoseStamped> goals, bool useAnglePenalty){
00783
00784 ROS_DEBUG("[hector_exploration_planner] buildexploration_trans_array_");
00785
00786
00787 std::fill_n(exploration_trans_array_, num_map_cells_, INT_MAX);
00788 std::fill_n(is_goal_array_, num_map_cells_, false);
00789
00790 std::queue<int> myqueue;
00791
00792 size_t num_free_goals = 0;
00793
00794
00795 for(unsigned int i = 0; i < goals.size(); ++i){
00796
00797 unsigned int mx,my;
00798
00799 if(!costmap_.worldToMap(goals[i].pose.position.x,goals[i].pose.position.y,mx,my)){
00800
00801 continue;
00802 }
00803
00804 int goal_point = costmap_.getIndex(mx,my);
00805
00806
00807 if(!isFree(goal_point)){
00808 continue;
00809 }else{
00810 ++num_free_goals;
00811 }
00812
00813 unsigned int init_cost = 0;
00814 if(false){
00815 init_cost = angleDanger(angleDifference(start,goals[i])) * getDistanceWeight(start,goals[i]);
00816 }
00817
00818 exploration_trans_array_[goal_point] = init_cost;
00819
00820
00821 if(false && isValid(previous_goal_)){
00822 if(isSameFrontier(goal_point, previous_goal_)){
00823 ROS_DEBUG("[hector_exploration_planner] same frontier: init with 0");
00824 exploration_trans_array_[goal_point] = 0;
00825 }
00826 }
00827
00828 ROS_DEBUG("[hector_exploration_planner] Goal init cost: %d, point: %d", exploration_trans_array_[goal_point], goal_point);
00829 is_goal_array_[goal_point] = true;
00830 myqueue.push(goal_point);
00831 }
00832
00833 if (num_free_goals == 0){
00834 ROS_WARN("[hector_exploration_planner] All goal coordinates for exploration transform invalid (occupied or out of bounds), aborting.");
00835 return false;
00836 }
00837
00838
00839 while(myqueue.size()){
00840 int point = myqueue.front();
00841 myqueue.pop();
00842
00843 unsigned int minimum = exploration_trans_array_[point];
00844
00845 int straightPoints[4];
00846 getStraightPoints(point,straightPoints);
00847 int diagonalPoints[4];
00848 getDiagonalPoints(point,diagonalPoints);
00849
00850
00851
00852 if(!is_goal_array_[point]){
00853
00854 const unsigned int point_cell_danger = cellDanger(point);
00855
00856 for(int i = 0; i < 4; ++i){
00857 if(isFree(straightPoints[i]) && (exploration_trans_array_[straightPoints[i]] + STRAIGHT_COST + point_cell_danger) < minimum){
00858 minimum = exploration_trans_array_[straightPoints[i]] + STRAIGHT_COST + point_cell_danger;
00859 }
00860 if(isFree(diagonalPoints[i]) && (exploration_trans_array_[diagonalPoints[i]] + DIAGONAL_COST + point_cell_danger) < minimum){
00861 minimum = exploration_trans_array_[diagonalPoints[i]] + DIAGONAL_COST + point_cell_danger;
00862 }
00863 }
00864 }
00865
00866
00867 if(minimum < exploration_trans_array_[point] || is_goal_array_[point]){
00868 exploration_trans_array_[point] = minimum;
00869
00870 for(int i = 0; i < 4; ++i){
00871 if(isFree(straightPoints[i]) && !is_goal_array_[straightPoints[i]]){
00872 myqueue.push(straightPoints[i]);
00873 }
00874 if(isFree(diagonalPoints[i]) && !is_goal_array_[diagonalPoints[i]]){
00875 myqueue.push(diagonalPoints[i]);
00876 }
00877 }
00878 }
00879
00880 }
00881
00882 ROS_DEBUG("[hector_exploration_planner] END: buildexploration_trans_array_");
00883 return true;
00884
00885 }
00886
00887 bool HectorExplorationPlanner::buildobstacle_trans_array_(bool use_inflated_obstacles){
00888 ROS_DEBUG("[hector_exploration_planner] buildobstacle_trans_array_");
00889 std::queue<int> myqueue;
00890
00891
00892 for(unsigned int i=0; i < num_map_cells_; ++i){
00893 if(occupancy_grid_array_[i] == costmap_2d::LETHAL_OBSTACLE){
00894 myqueue.push(i);
00895 obstacle_trans_array_[i] = 0;
00896 } else if(use_inflated_obstacles){
00897 if(occupancy_grid_array_[i] == costmap_2d::INSCRIBED_INFLATED_OBSTACLE){
00898 myqueue.push(i);
00899 obstacle_trans_array_[i] = 0;
00900 }
00901 }
00902 }
00903
00904
00905 while(myqueue.size()){
00906 int point = myqueue.front();
00907 myqueue.pop();
00908
00909 unsigned int minimum = obstacle_trans_array_[point];
00910
00911 int straightPoints[4];
00912 getStraightPoints(point,straightPoints);
00913 int diagonalPoints[4];
00914 getDiagonalPoints(point,diagonalPoints);
00915
00916 if(obstacle_trans_array_[point] != 0){
00917
00918
00919 for(int i = 0; i < 4; ++i){
00920 if(isValid(straightPoints[i]) && ((obstacle_trans_array_[straightPoints[i]] + STRAIGHT_COST) < minimum)){
00921 minimum = obstacle_trans_array_[straightPoints[i]] + STRAIGHT_COST;
00922 }
00923 if(isValid(diagonalPoints[i]) && ((obstacle_trans_array_[diagonalPoints[i]] + DIAGONAL_COST) < minimum)){
00924 minimum = obstacle_trans_array_[diagonalPoints[i]] + DIAGONAL_COST;
00925 }
00926 }
00927 }
00928
00929
00930 if((minimum < obstacle_trans_array_[point]) || (obstacle_trans_array_[point] == 0)){
00931 obstacle_trans_array_[point] = minimum;
00932
00933 for(int i = 0; i < 4; ++i){
00934 if(isFree(straightPoints[i])){
00935 myqueue.push(straightPoints[i]);
00936 }
00937 if(isFree(diagonalPoints[i])){
00938 myqueue.push(diagonalPoints[i]);
00939 }
00940 }
00941 }
00942 }
00943 ROS_DEBUG("[hector_exploration_planner] END: buildobstacle_trans_array_");
00944 return true;
00945 }
00946
00947 bool HectorExplorationPlanner::getTrajectory(const geometry_msgs::PoseStamped &start, std::vector<geometry_msgs::PoseStamped> goals, std::vector<geometry_msgs::PoseStamped> &plan){
00948
00949 ROS_DEBUG("[hector_exploration_planner] getTrajectory");
00950
00951
00952 unsigned int mx,my;
00953
00954 if(!costmap_.worldToMap(start.pose.position.x,start.pose.position.y,mx,my)){
00955 ROS_WARN("[hector_exploration_planner] The start coordinates are outside the costmap!");
00956 return false;
00957 }
00958
00959 int currentPoint = costmap_.getIndex(mx,my);
00960 int nextPoint = currentPoint;
00961 int maxDelta = 0;
00962
00963
00964 geometry_msgs::PoseStamped trajPoint;
00965 std::string global_frame = costmap_ros_->getGlobalFrameID();
00966 trajPoint.header.frame_id = global_frame;
00967
00968 while(!is_goal_array_[currentPoint]){
00969 int thisDelta;
00970 int adjacentPoints[8];
00971 getAdjacentPoints(currentPoint,adjacentPoints);
00972
00973 for(int i = 0; i < 8; ++i){
00974 if(isFree(adjacentPoints[i])){
00975 thisDelta = exploration_trans_array_[currentPoint] - exploration_trans_array_[adjacentPoints[i]];
00976 if(thisDelta > maxDelta){
00977 maxDelta = thisDelta;
00978 nextPoint = adjacentPoints[i];
00979 }
00980 }
00981 }
00982
00983
00984 if(maxDelta == 0){
00985 ROS_WARN("[hector_exploration_planner] No path to the goal could be found by following gradient!");
00986 return false;
00987 }
00988
00989
00990
00991 unsigned int sx,sy,gx,gy;
00992 costmap_.indexToCells((unsigned int)currentPoint,sx,sy);
00993 costmap_.indexToCells((unsigned int)nextPoint,gx,gy);
00994 double wx,wy;
00995 costmap_.mapToWorld(sx,sy,wx,wy);
00996
00997 trajPoint.pose.position.x = wx;
00998 trajPoint.pose.position.y = wy;
00999 trajPoint.pose.position.z = 0.0;
01000
01001
01002 int dx = gx-sx;
01003 int dy = gy-sy;
01004 double yaw_path = std::atan2(dy,dx);
01005 trajPoint.pose.orientation.x = 0.0;
01006 trajPoint.pose.orientation.y = 0.0;
01007 trajPoint.pose.orientation.z = sin(yaw_path*0.5f);
01008 trajPoint.pose.orientation.w = cos(yaw_path*0.5f);
01009
01010 plan.push_back(trajPoint);
01011
01012 currentPoint = nextPoint;
01013 maxDelta = 0;
01014 }
01015
01016
01017
01018 ROS_DEBUG("[hector_exploration_planner] END: getTrajectory. Plansize %u", (unsigned int)plan.size());
01019 return !plan.empty();
01020 }
01021
01022 bool HectorExplorationPlanner::findFrontiers(std::vector<geometry_msgs::PoseStamped> &frontiers){
01023 std::vector<geometry_msgs::PoseStamped> empty_vec;
01024 return findFrontiers(frontiers,empty_vec);
01025 }
01026
01027
01028
01029
01030
01031 bool HectorExplorationPlanner::findFrontiers(std::vector<geometry_msgs::PoseStamped> &frontiers, std::vector<geometry_msgs::PoseStamped> &noFrontiers){
01032
01033
01034 clearFrontiers();
01035
01036
01037 std::vector<int> allFrontiers;
01038
01039
01040 for(unsigned int i = 0; i < num_map_cells_; ++i){
01041 if(isFrontier(i)){
01042 allFrontiers.push_back(i);
01043 }
01044 }
01045
01046 tf::Stamped<tf::Pose> robotPose;
01047 if(!costmap_ros_->getRobotPose(robotPose)){
01048 ROS_WARN("[hector_exploration_planner]: Failed to get RobotPose");
01049 }
01050
01051
01052 for(unsigned int i = 0; i < allFrontiers.size(); ++i){
01053 if(!isFrontierReached(allFrontiers[i])){
01054 geometry_msgs::PoseStamped finalFrontier;
01055 double wx,wy;
01056 unsigned int mx,my;
01057 costmap_.indexToCells(allFrontiers[i], mx, my);
01058 costmap_.mapToWorld(mx,my,wx,wy);
01059 std::string global_frame = costmap_ros_->getGlobalFrameID();
01060 finalFrontier.header.frame_id = global_frame;
01061 finalFrontier.pose.position.x = wx;
01062 finalFrontier.pose.position.y = wy;
01063 finalFrontier.pose.position.z = 0.0;
01064
01065 double yaw = getYawToUnknown(costmap_.getIndex(mx,my));
01066
01067
01068
01069 finalFrontier.pose.orientation = tf::createQuaternionMsgFromYaw(yaw);
01070
01071 frontiers.push_back(finalFrontier);
01072 }
01073
01074 }
01075
01076 return true;
01077
01078
01079 int nextBlobValue = 1;
01080 std::list<int> usedBlobs;
01081
01082 for(unsigned int i = 0; i < allFrontiers.size(); ++i){
01083
01084
01085 int currentPoint = allFrontiers[i];
01086 int adjacentPoints[8];
01087 getAdjacentPoints(currentPoint,adjacentPoints);
01088
01089 std::list<int> blobs;
01090
01091 for(int j = 0; j < 8; j++){
01092 if(isValid(adjacentPoints[j]) && (frontier_map_array_[adjacentPoints[j]] > 0)){
01093 blobs.push_back(frontier_map_array_[adjacentPoints[j]]);
01094 }
01095 }
01096 blobs.unique();
01097
01098 if(blobs.empty()){
01099
01100 frontier_map_array_[currentPoint] = nextBlobValue;
01101 usedBlobs.push_back(nextBlobValue);
01102 nextBlobValue++;
01103 } else {
01104
01105 int blobMergeVal = 0;
01106
01107 for(std::list<int>::iterator adjBlob = blobs.begin(); adjBlob != blobs.end(); ++adjBlob){
01108 if(adjBlob == blobs.begin()){
01109 blobMergeVal = *adjBlob;
01110 frontier_map_array_[currentPoint] = blobMergeVal;
01111 } else {
01112
01113 for(unsigned int k = 0; k < allFrontiers.size(); k++){
01114 if(frontier_map_array_[allFrontiers[k]] == *adjBlob){
01115 usedBlobs.remove(*adjBlob);
01116 frontier_map_array_[allFrontiers[k]] = blobMergeVal;
01117 }
01118 }
01119 }
01120 }
01121 }
01122 }
01123
01124 int id = 1;
01125
01126 bool visualization_requested = (visualization_pub_.getNumSubscribers() > 0);
01127
01128
01129 for(std::list<int>::iterator currentBlob = usedBlobs.begin(); currentBlob != usedBlobs.end(); ++currentBlob){
01130 int current_frontier_size = 0;
01131 int max_obs_idx = 0;
01132
01133 for(unsigned int i = 0; i < allFrontiers.size(); ++i){
01134 int point = allFrontiers[i];
01135
01136 if(frontier_map_array_[point] == *currentBlob){
01137 current_frontier_size++;
01138 if(obstacle_trans_array_[point] > obstacle_trans_array_[allFrontiers[max_obs_idx]]){
01139 max_obs_idx = i;
01140 }
01141 }
01142 }
01143
01144 if(current_frontier_size < p_min_frontier_size_){
01145 continue;
01146 }
01147
01148 int frontier_point = allFrontiers[max_obs_idx];
01149 unsigned int x,y;
01150 costmap_.indexToCells(frontier_point,x,y);
01151
01152
01153 bool frontier_is_valid = true;
01154
01155 if(isFrontierReached(frontier_point)){
01156 frontier_is_valid = false;
01157 }
01158
01159 for(size_t i = 0; i < noFrontiers.size(); ++i){
01160 const geometry_msgs::PoseStamped& noFrontier = noFrontiers[i];
01161 unsigned int mx,my;
01162 costmap_.worldToMap(noFrontier.pose.position.x,noFrontier.pose.position.y,mx,my);
01163 int no_frontier_point = costmap_.getIndex(x,y);
01164 if(isSameFrontier(frontier_point,no_frontier_point)){
01165 frontier_is_valid = false;
01166 }
01167 }
01168
01169 geometry_msgs::PoseStamped finalFrontier;
01170 double wx,wy;
01171 costmap_.mapToWorld(x,y,wx,wy);
01172 std::string global_frame = costmap_ros_->getGlobalFrameID();
01173 finalFrontier.header.frame_id = global_frame;
01174 finalFrontier.pose.position.x = wx;
01175 finalFrontier.pose.position.y = wy;
01176 finalFrontier.pose.position.z = 0.0;
01177
01178 double yaw = getYawToUnknown(costmap_.getIndex(x,y));
01179
01180 if(frontier_is_valid){
01181
01182 finalFrontier.pose.orientation = tf::createQuaternionMsgFromYaw(yaw);
01183 frontiers.push_back(finalFrontier);
01184 }
01185
01186
01187 if(visualization_requested){
01188 visualization_msgs::Marker marker;
01189 marker.header.frame_id = "map";
01190 marker.header.stamp = ros::Time();
01191 marker.ns = "hector_exploration_planner";
01192 marker.id = id++;
01193 marker.type = visualization_msgs::Marker::ARROW;
01194 marker.action = visualization_msgs::Marker::ADD;
01195 marker.pose.position.x = wx;
01196 marker.pose.position.y = wy;
01197 marker.pose.position.z = 0.0;
01198 marker.pose.orientation = tf::createQuaternionMsgFromYaw(yaw);
01199 marker.scale.x = 0.2;
01200 marker.scale.y = 0.2;
01201 marker.scale.z = 0.2;
01202 marker.color.a = 1.0;
01203
01204 if(frontier_is_valid){
01205 marker.color.r = 0.0;
01206 marker.color.g = 1.0;
01207 }else{
01208 marker.color.r = 1.0;
01209 marker.color.g = 0.0;
01210 }
01211
01212 marker.color.b = 0.0;
01213 marker.lifetime = ros::Duration(5,0);
01214 visualization_pub_.publish(marker);
01215 }
01216
01217 }
01218 return !frontiers.empty();
01219 }
01220
01221 bool HectorExplorationPlanner::findInnerFrontier(std::vector<geometry_msgs::PoseStamped> &innerFrontier){
01222 clearFrontiers();
01223
01224
01225 hector_nav_msgs::GetRobotTrajectory srv_path;
01226 if (path_service_client_.call(srv_path)){
01227
01228 std::vector<geometry_msgs::PoseStamped>& traj_vector (srv_path.response.trajectory.poses);
01229
01230
01231 std::vector<geometry_msgs::PoseStamped> goals;
01232
01233 size_t size = traj_vector.size();
01234 ROS_DEBUG("[hector_exploration_planner] size of trajectory vector %u", (unsigned int)size);
01235
01236 if(size > 0){
01237 geometry_msgs::PoseStamped lastPose = traj_vector[size-1];
01238 goals.push_back(lastPose);
01239
01240 if (size > 1){
01241
01242
01243 bool collision_allowed = true;
01244
01245 for(int i = static_cast<int>(size-2); i >= 0; --i){
01246 const geometry_msgs::PoseStamped& pose = traj_vector[i];
01247 unsigned int x,y;
01248 costmap_.worldToMap(pose.pose.position.x,pose.pose.position.y,x,y);
01249 unsigned int m_point = costmap_.getIndex(x,y);
01250
01251 double dx = lastPose.pose.position.x - pose.pose.position.x;
01252 double dy = lastPose.pose.position.y - pose.pose.position.y;
01253
01254 bool point_in_free_space = isFree(m_point);
01255
01256
01257 if(point_in_free_space){
01258 if((dx*dx) + (dy*dy) > (0.25*0.25)){
01259 goals.push_back(pose);
01260 lastPose = pose;
01261 collision_allowed = false;
01262 }
01263 }
01264
01265 if (!point_in_free_space && !collision_allowed){
01266 break;
01267 }
01268 }
01269 }
01270
01271
01272 ROS_DEBUG("[hector_exploration_planner] pushed %u goals (trajectory) for inner frontier-search", (unsigned int)goals.size());
01273
01274
01275 tf::Stamped<tf::Pose> robotPose;
01276 if(!costmap_ros_->getRobotPose(robotPose)){
01277 ROS_WARN("[hector_exploration_planner]: Failed to get RobotPose");
01278 }
01279 geometry_msgs::PoseStamped robotPoseMsg;
01280 tf::poseStampedTFToMsg(robotPose, robotPoseMsg);
01281
01282 if (!buildexploration_trans_array_(robotPoseMsg, goals, false)){
01283 ROS_WARN("[hector_exploration_planner]: Creating exploration transform array in find inner frontier failed, aborting.");
01284 return false;
01285 }
01286
01287 inner_vis_->publishVisOnDemand(costmap_, exploration_trans_array_);
01288
01289 unsigned int x,y;
01290 costmap_.worldToMap(robotPoseMsg.pose.position.x,robotPoseMsg.pose.position.y,x,y);
01291
01292
01293
01294
01295
01296 int max_exploration_trans_point = -1;
01297 unsigned int max_exploration_trans_val = 0;
01298
01299 for(unsigned int i = 0; i < num_map_cells_; ++i){
01300
01301 if(exploration_trans_array_[i] < INT_MAX){
01302 if(exploration_trans_array_[i] > max_exploration_trans_val){
01303 if(!isFrontierReached(i)){
01304 max_exploration_trans_point = i;
01305 max_exploration_trans_val = exploration_trans_array_[i];
01306 }
01307 }
01308 }
01309 }
01310
01311 if (max_exploration_trans_point == 0){
01312 ROS_WARN("[hector_exploration_planner]: Couldn't find max exploration transform point for inner exploration, aborting.");
01313 return false;
01314 }
01315
01316 geometry_msgs::PoseStamped finalFrontier;
01317 unsigned int fx,fy;
01318 double wfx,wfy;
01319 costmap_.indexToCells(max_exploration_trans_point,fx,fy);
01320 costmap_.mapToWorld(fx,fy,wfx,wfy);
01321 std::string global_frame = costmap_ros_->getGlobalFrameID();
01322 finalFrontier.header.frame_id = global_frame;
01323 finalFrontier.pose.position.x = wfx;
01324 finalFrontier.pose.position.y = wfy;
01325 finalFrontier.pose.position.z = 0.0;
01326
01327
01328 int dx = fx-x;
01329 int dy = fy-y;
01330 double yaw_path = std::atan2(dy,dx);
01331 finalFrontier.pose.orientation.x = 0.0;
01332 finalFrontier.pose.orientation.y = 0.0;
01333 finalFrontier.pose.orientation.z = sin(yaw_path*0.5f);
01334 finalFrontier.pose.orientation.w = cos(yaw_path*0.5f);
01335
01336 innerFrontier.push_back(finalFrontier);
01337
01338 if(visualization_pub_.getNumSubscribers() > 0){
01339 visualization_msgs::Marker marker;
01340 marker.header.frame_id = "map";
01341 marker.header.stamp = ros::Time();
01342 marker.ns = "hector_exploration_planner";
01343 marker.id = 100;
01344 marker.type = visualization_msgs::Marker::ARROW;
01345 marker.action = visualization_msgs::Marker::ADD;
01346 marker.pose.position.x = wfx;
01347 marker.pose.position.y = wfy;
01348 marker.pose.position.z = 0.0;
01349 marker.pose.orientation = tf::createQuaternionMsgFromYaw(yaw_path);
01350 marker.scale.x = 0.2;
01351 marker.scale.y = 0.2;
01352 marker.scale.z = 0.2;
01353 marker.color.a = 1.0;
01354 marker.color.r = 0.0;
01355 marker.color.g = 0.0;
01356 marker.color.b = 1.0;
01357 marker.lifetime = ros::Duration(5,0);
01358 visualization_pub_.publish(marker);
01359 }
01360 return true;
01361 }
01362 }
01363 return false;
01364 }
01365
01366
01367
01368
01369
01370
01371 bool HectorExplorationPlanner::isFrontier(int point){
01372 if(isFree(point)){
01373
01374 int adjacentPoints[8];
01375 getAdjacentPoints(point,adjacentPoints);
01376
01377 for(int i = 0; i < 8; ++i){
01378 if(isValid(adjacentPoints[i])){
01379 if(occupancy_grid_array_[adjacentPoints[i]] == costmap_2d::NO_INFORMATION){
01380
01381 int no_inf_count = 0;
01382 int noInfPoints[8];
01383 getAdjacentPoints(adjacentPoints[i],noInfPoints);
01384 for(int j = 0; j < 8; j++){
01385 if(occupancy_grid_array_[noInfPoints[j]] == costmap_2d::NO_INFORMATION){
01386 no_inf_count++;
01387 }
01388 }
01389 if(no_inf_count > 2){
01390 return true;
01391 }
01392
01393 }
01394 }
01395 }
01396 }
01397
01398 return false;
01399 }
01400
01401
01402 void HectorExplorationPlanner::resetMaps(){
01403 std::fill_n(exploration_trans_array_, num_map_cells_, INT_MAX);
01404 std::fill_n(obstacle_trans_array_, num_map_cells_, INT_MAX);
01405 std::fill_n(is_goal_array_, num_map_cells_, false);
01406 }
01407
01408 void HectorExplorationPlanner::clearFrontiers(){
01409 std::fill_n(frontier_map_array_, num_map_cells_, 0);
01410 }
01411
01412 inline bool HectorExplorationPlanner::isValid(int point){
01413 return (point>=0);
01414 }
01415
01416 bool HectorExplorationPlanner::isFree(int point){
01417
01418 if(isValid(point)){
01419
01420 if(p_use_inflated_obs_){
01421 if(occupancy_grid_array_[point] < costmap_2d::INSCRIBED_INFLATED_OBSTACLE){
01422 return true;
01423 }
01424 } else {
01425 if(occupancy_grid_array_[point] <= costmap_2d::INSCRIBED_INFLATED_OBSTACLE){
01426 return true;
01427 }
01428 }
01429
01430 if(p_plan_in_unknown_){
01431 if(occupancy_grid_array_[point] == costmap_2d::NO_INFORMATION){
01432 return true;
01433 }
01434 }
01435 }
01436 return false;
01437 }
01438
01439 bool HectorExplorationPlanner::isFrontierReached(int point){
01440
01441 tf::Stamped<tf::Pose> robotPose;
01442 if(!costmap_ros_->getRobotPose(robotPose)){
01443 ROS_WARN("[hector_exploration_planner]: Failed to get RobotPose");
01444 }
01445 geometry_msgs::PoseStamped robotPoseMsg;
01446 tf::poseStampedTFToMsg(robotPose, robotPoseMsg);
01447
01448 unsigned int fx,fy;
01449 double wfx,wfy;
01450 costmap_.indexToCells(point,fx,fy);
01451 costmap_.mapToWorld(fx,fy,wfx,wfy);
01452
01453
01454 double dx = robotPoseMsg.pose.position.x - wfx;
01455 double dy = robotPoseMsg.pose.position.y - wfy;
01456
01457 if ( (dx*dx) + (dy*dy) < (p_dist_for_goal_reached_*p_dist_for_goal_reached_)) {
01458 ROS_DEBUG("[hector_exploration_planner]: frontier is within the squared range of: %f", p_dist_for_goal_reached_);
01459 return true;
01460 }
01461 return false;
01462
01463 }
01464
01465 bool HectorExplorationPlanner::isSameFrontier(int frontier_point1, int frontier_point2){
01466 unsigned int fx1,fy1;
01467 unsigned int fx2,fy2;
01468 double wfx1,wfy1;
01469 double wfx2,wfy2;
01470 costmap_.indexToCells(frontier_point1,fx1,fy1);
01471 costmap_.indexToCells(frontier_point2,fx2,fy2);
01472 costmap_.mapToWorld(fx1,fy1,wfx1,wfy1);
01473 costmap_.mapToWorld(fx2,fy2,wfx2,wfy2);
01474
01475 double dx = wfx1 - wfx2;
01476 double dy = wfy1 - wfy2;
01477
01478 if((dx*dx) + (dy*dy) < (p_same_frontier_dist_*p_same_frontier_dist_)){
01479 return true;
01480 }
01481 return false;
01482 }
01483
01484 inline unsigned int HectorExplorationPlanner::cellDanger(int point){
01485
01486 if((int)obstacle_trans_array_[point] <= p_min_obstacle_dist_){
01487 return p_alpha_ * std::pow(p_min_obstacle_dist_ - obstacle_trans_array_[point],2);
01488 }
01489 return 0;
01490 }
01491
01492 float HectorExplorationPlanner::angleDifference(const geometry_msgs::PoseStamped &start, const geometry_msgs::PoseStamped &goal){
01493
01494 unsigned int mxs,mys;
01495 costmap_.worldToMap(start.pose.position.x,start.pose.position.y,mxs,mys);
01496
01497 unsigned int gx,gy;
01498 costmap_.worldToMap(goal.pose.position.x,goal.pose.position.y,gx,gy);
01499
01500 int goal_proj_x = gx-mxs;
01501 int goal_proj_y = gy-mys;
01502
01503 float start_angle = tf::getYaw(start.pose.orientation);
01504 float goal_angle = std::atan2(goal_proj_y,goal_proj_x);
01505
01506 float both_angle = 0;
01507 if(start_angle > goal_angle){
01508 both_angle = start_angle - goal_angle;
01509 } else {
01510 both_angle = goal_angle - start_angle;
01511 }
01512
01513 if(both_angle > M_PI){
01514 both_angle = (M_PI - std::abs(start_angle)) + (M_PI - std::abs(goal_angle));
01515 }
01516
01517 return both_angle;
01518 }
01519
01520
01521 double HectorExplorationPlanner::getYawToUnknown(int point){
01522 int adjacentPoints[8];
01523 getAdjacentPoints(point,adjacentPoints);
01524
01525 int max_obs_idx = 0;
01526
01527 for(int i = 0; i < 8; ++i){
01528 if(isValid(adjacentPoints[i])){
01529 if(occupancy_grid_array_[adjacentPoints[i]] == costmap_2d::NO_INFORMATION){
01530 if(obstacle_trans_array_[adjacentPoints[i]] > obstacle_trans_array_[adjacentPoints[max_obs_idx]]){
01531 max_obs_idx = i;
01532 }
01533 }
01534 }
01535 }
01536
01537 int orientationPoint = adjacentPoints[max_obs_idx];
01538 unsigned int sx,sy,gx,gy;
01539 costmap_.indexToCells((unsigned int)point,sx,sy);
01540 costmap_.indexToCells((unsigned int)orientationPoint,gx,gy);
01541 int x = gx-sx;
01542 int y = gy-sy;
01543 double yaw = std::atan2(y,x);
01544
01545 return yaw;
01546
01547 }
01548
01549 unsigned int HectorExplorationPlanner::angleDanger(float angle){
01550 float angle_fraction = std::pow(angle,3);
01551 unsigned int result = static_cast<unsigned int>(p_goal_angle_penalty_ * angle_fraction);
01552 return result;
01553 }
01554
01555 float HectorExplorationPlanner::getDistanceWeight(const geometry_msgs::PoseStamped &point1, const geometry_msgs::PoseStamped &point2){
01556 float distance = std::sqrt(std::pow(point1.pose.position.x - point2.pose.position.x,2) + std::pow(point1.pose.position.y - point2.pose.position.y,2));
01557 if(distance < 0.5){
01558 return 5.0;
01559 } else {
01560 return 1;
01561 }
01562 }
01563
01564
01565
01566
01567
01568 inline void HectorExplorationPlanner::getStraightPoints(int point, int points[]){
01569
01570 points[0] = left(point);
01571 points[1] = up(point);
01572 points[2] = right(point);
01573 points[3] = down(point);
01574
01575 }
01576
01577 inline void HectorExplorationPlanner::getDiagonalPoints(int point, int points[]){
01578
01579 points[0] = upleft(point);
01580 points[1] = upright(point);
01581 points[2] = downright(point);
01582 points[3] = downleft(point);
01583
01584 }
01585
01586
01587
01588
01589
01590
01591
01592
01593
01594
01595
01596
01597
01598
01599
01600
01601
01602 inline void HectorExplorationPlanner::getAdjacentPoints(int point, int points[]){
01603
01604 points[0] = left(point);
01605 points[1] = up(point);
01606 points[2] = right(point);
01607 points[3] = down(point);
01608 points[4] = upleft(point);
01609 points[5] = upright(point);
01610 points[6] = downright(point);
01611 points[7] = downleft(point);
01612
01613 }
01614
01615 inline int HectorExplorationPlanner::left(int point){
01616
01617 if((point % map_width_ != 0)){
01618 return point-1;
01619 }
01620 return -1;
01621 }
01622 inline int HectorExplorationPlanner::upleft(int point){
01623 if((point % map_width_ != 0) && (point >= (int)map_width_)){
01624 return point-map_width_-1;
01625 }
01626 return -1;
01627
01628 }
01629 inline int HectorExplorationPlanner::up(int point){
01630 if(point >= (int)map_width_){
01631 return point-map_width_;
01632 }
01633 return -1;
01634 }
01635 inline int HectorExplorationPlanner::upright(int point){
01636 if((point >= (int)map_width_) && ((point + 1) % (int)map_width_ != 0)){
01637 return point-map_width_+1;
01638 }
01639 return -1;
01640 }
01641 inline int HectorExplorationPlanner::right(int point){
01642 if((point + 1) % map_width_ != 0){
01643 return point+1;
01644 }
01645 return -1;
01646
01647 }
01648 inline int HectorExplorationPlanner::downright(int point){
01649 if(((point + 1) % map_width_ != 0) && ((point/map_width_) < (map_width_-1))){
01650 return point+map_width_+1;
01651 }
01652 return -1;
01653
01654 }
01655 inline int HectorExplorationPlanner::down(int point){
01656 if((point/map_width_) < (map_width_-1)){
01657 return point+map_width_;
01658 }
01659 return -1;
01660
01661 }
01662 inline int HectorExplorationPlanner::downleft(int point){
01663 if(((point/map_width_) < (map_width_-1)) && (point % map_width_ != 0)){
01664 return point+map_width_-1;
01665 }
01666 return -1;
01667
01668 }
01669
01670
01671
01672
01673
01674
01675
01676
01677
01678
01679
01680
01681
01682
01683
01684
01685
01686
01687
01688
01689
01690
01691
01692
01693
01694
01695
01696
01697
01698
01699
01700
01701
01702
01703
01704
01705
01706
01707
01708
01709
01710
01711
01712
01713
01714
01715
01716
01717
01718
01719
01720
01721
01722
01723
01724
01725
01726
01727
01728
01729
01730
01731
01732
01733
01734
01735
01736
01737
01738
01739
01740
01741
01742
01743
01744
01745
01746