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 "PPExplorer.h"
00038
00039 #include <cstdlib>
00040 #include <math.h>
00041
00042 particle_plume::PPExplorer::PPExplorer() : n_(), pn_("~")
00043 {
00044
00045 pn_.param<std::string>("global_frame_id", global_frame_id_, "map");
00046
00047 pn_.param("max_visited_cells_coef", max_visited_cells_coef_, 0.35);
00048 if(max_visited_cells_coef_ < 0.0)
00049 {
00050 ROS_WARN("PPExplorer -- You set max_visited_cells_coef to %lf, yet the minimum value is 0, setting max_visited_cells_coef to 0...", max_visited_cells_coef_);
00051 max_visited_cells_coef_ = 0.0;
00052 }
00053 if(max_visited_cells_coef_ > 1.0)
00054 {
00055 ROS_WARN("PPExplorer -- You set max_visited_cells_coef to %lf, yet the maximum value is 1, setting max_visited_cells_coef to 1...", max_visited_cells_coef_);
00056 max_visited_cells_coef_ = 1;
00057 }
00058
00059 pn_.param("max_odor_visited_cells_coef", max_odor_visited_cells_coef_, 0.50);
00060 if(max_odor_visited_cells_coef_ < 0.0)
00061 {
00062 ROS_WARN("PPExplorer -- You set max_odor_visited_cells_coef to %lf, yet the minimum value is 0, setting max_odor_visited_cells_coef to 0...", max_odor_visited_cells_coef_);
00063 max_odor_visited_cells_coef_ = 0.0;
00064 }
00065 if(max_odor_visited_cells_coef_ > 1.0)
00066 {
00067 ROS_WARN("PPExplorer -- You set max_odor_visited_cells_coef to %lf, yet the maximum value is 1, setting max_odor_visited_cells_coef to 1...", max_odor_visited_cells_coef_);
00068 max_odor_visited_cells_coef_ = 1;
00069 }
00070
00071 pn_.param("pie_radius", pie_radius_, 0.60);
00072 if(pie_radius_ < 0) pie_radius_ = 0.0;
00073
00074 pn_.param("pie_slices", pie_slices_, 16);
00075 if(pie_slices_ < 4)
00076 {
00077 ROS_WARN("PPExplorer -- You set pie_slices to %d, yet the minimum value is 4, setting pie_slices to 4...", pie_slices_);
00078 pie_slices_ = 4;
00079 }
00080 if(pie_slices_ > 36)
00081 {
00082 ROS_WARN("PPExplorer -- You set pie_slices to %d, yet the maximum value is 36, setting pie_slices to 36...", pie_slices_);
00083 pie_slices_ = 36;
00084 }
00085
00086 pn_.param("find_clearing_sim_steps", find_clearing_sim_steps_, 3);
00087 if(find_clearing_sim_steps_ < 1)
00088 {
00089 ROS_WARN("PPExplorer -- You set find_clearing_sim_steps to %d, yet the minimum value is 1, setting find_clearing_sim_steps to 1...", find_clearing_sim_steps_);
00090 find_clearing_sim_steps_ = 1;
00091 }
00092
00093 pn_.param("visited_cells_weight", visited_cells_weight_, 1.00);
00094 pn_.param("current_heading_weight", current_heading_weight_, 0.01);
00095 pn_.param("odor_weight", odor_weight_, 0.10);
00096 pn_.param("other_robots_weight", other_robots_weight_, 1.00);
00097
00098 pn_.param("bubble_radius", bubble_radius_, 0.10);
00099 pn_.param("min_particle_count_difference", min_particle_count_difference_, 5);
00100 if(min_particle_count_difference_ < 1)
00101 {
00102 ROS_WARN("PPExplorer -- You set min_particle_count_difference to %d, yet the minimum value is 1, setting min_particle_count_difference to 1...", min_particle_count_difference_);
00103 min_particle_count_difference_ = 1;
00104 }
00105
00106 multi_robot_ = pn_.getParam("unique_id", unique_id_);
00107
00108 pn_.param("debug_slices", debug_slices_, false);
00109
00110 n_.param("move_base/local_costmap/inflation_radius", inflation_radius_, 0.20);
00111
00112
00113 odom_sub_.subscribe(n_, "odom", 10);
00114 tf_filter_ = new tf::MessageFilter<nav_msgs::Odometry>(odom_sub_, tf_, global_frame_id_, 10);
00115 tf_filter_->registerCallback( boost::bind(&PPExplorer::odomCallback, this, _1) );
00116
00117 map_sub_ = n_.subscribe("/map", 1, &PPExplorer::mapCallback, this);
00118 map_meta_sub_ = n_.subscribe("/map_metadata", 1, &PPExplorer::mapMetaCallback, this);
00119 cells_sub_ = n_.subscribe("/visited_cells", 1, &PPExplorer::cellsCallback, this);
00120 plume_sub_ = n_.subscribe("/plume", 1, &PPExplorer::ppCallback, this);
00121
00122 obstacles_sub_ = n_.subscribe("move_base/local_costmap/obstacles", 1, &PPExplorer::obstaclesCallback, this);
00123 inflated_sub_ = n_.subscribe("move_base/local_costmap/inflated_obstacles", 1, &PPExplorer::inflatedCallback, this);
00124
00125
00126 if(multi_robot_)
00127 {
00128 ROS_INFO("PPExplorer -- Going multi-robot, my unique id is %s", unique_id_.c_str());
00129
00130 finish_on_next_recovery_ = false;
00131
00132 recovery_sub_ = n_.subscribe("/pp_explorer/recovery_cells", 100, &PPExplorer::recoveryCellsCallback, this);
00133 recovery_pub_ = n_.advertise<pp_explorer::GridCellsIdentified>("/pp_explorer/recovery_cells", 10, true);
00134
00135 chatter_sub_ = n_.subscribe("/pp_explorer/chatter", 100, &PPExplorer::chatterCallback, this);
00136 chatter_pub_ = n_.advertise<pp_explorer::StringIdentified>("/pp_explorer/chatter", 10, true);
00137
00138 poses_sub_ = n_.subscribe("/pp_explorer/poses", 100, &PPExplorer::posesCallback, this);
00139 poses_pub_ = n_.advertise<pp_explorer::PoseStampedIdentified>("/pp_explorer/poses", 10, true);
00140 }
00141
00142 debug_pub_ = n_.advertise<nav_msgs::GridCells>("debug_cells", 1, true);
00143 debug_goal_pub_ = n_.advertise<visualization_msgs::Marker>("pp_goal", 1);
00144
00145 got_map_ = false;
00146 got_odom_ = false;
00147 }
00148
00149 particle_plume::PPExplorer::~PPExplorer()
00150 {
00151
00152 }
00153
00154 bool particle_plume::PPExplorer::isReady()
00155 {
00156 return (got_map_ && got_odom_);
00157 }
00158
00159
00160 void particle_plume::PPExplorer::ppCallback(const sensor_msgs::PointCloud2::ConstPtr& msg)
00161 {
00162 ROS_DEBUG("PPExplorer - %s - Got a plume msg!", __FUNCTION__);
00163 fromROSMsg(*msg, plume_);
00164 }
00165
00166 void particle_plume::PPExplorer::cellsCallback(const nav_msgs::GridCells::ConstPtr& msg)
00167 {
00168 ROS_DEBUG("PPExplorer - %s - Got a visited cells msg!", __FUNCTION__);
00169 cells_ = *msg;
00170 }
00171
00172 void particle_plume::PPExplorer::mapCallback(const nav_msgs::OccupancyGrid::ConstPtr& msg)
00173 {
00174 ROS_DEBUG("PPExplorer - %s - Got the map!", __FUNCTION__);
00175 map_ = *msg;
00176 got_map_ = true;
00177 }
00178
00179 void particle_plume::PPExplorer::mapMetaCallback(const nav_msgs::MapMetaData::ConstPtr& msg)
00180 {
00181 ROS_DEBUG("PPExplorer - %s - Got a map metadata msg!", __FUNCTION__);
00182 map_metadata_ = *msg;
00183 }
00184
00185 void particle_plume::PPExplorer::odomCallback(const boost::shared_ptr<const nav_msgs::Odometry>& msg)
00186 {
00187 ROS_DEBUG("PPExplorer - %s - Got an odom msg!", __FUNCTION__);
00188
00189 geometry_msgs::PoseStamped odom;
00190 odom.header.frame_id = msg->header.frame_id;
00191 odom.header.stamp = msg->header.stamp;
00192 odom.pose.position.x = msg->pose.pose.position.x;
00193 odom.pose.position.y = msg->pose.pose.position.y;
00194 odom.pose.orientation = msg->pose.pose.orientation;
00195
00196 try
00197 {
00198
00199 tf_.transformPose(global_frame_id_, odom, robot_pose_);
00200 }
00201 catch(tf::TransformException &ex)
00202 {
00203 ROS_ERROR("PPExplorer - %s - Error: %s", __FUNCTION__, ex.what());
00204 return;
00205 }
00206
00207
00208
00209
00210
00211
00212 got_odom_ = true;
00213 }
00214
00215 void particle_plume::PPExplorer::obstaclesCallback(const nav_msgs::GridCells::ConstPtr& msg)
00216 {
00217 ROS_DEBUG("PPExplorer - %s - Got an obstacles msg!", __FUNCTION__);
00218 obstacles_ = *msg;
00219 }
00220
00221 void particle_plume::PPExplorer::inflatedCallback(const nav_msgs::GridCells::ConstPtr& msg)
00222 {
00223 ROS_DEBUG("PPExplorer - %s - Got an inflated obstacles msg!", __FUNCTION__);
00224 inflated_ = *msg;
00225 }
00226
00227 void particle_plume::PPExplorer::recoveryCellsCallback(const pp_explorer::GridCellsIdentified::ConstPtr& msg)
00228 {
00229 if(msg->sender.compare(unique_id_) == 0) return;
00230
00231 ROS_DEBUG("PPExplorer - %s - Got a recovery cells msg from %s with %d cells.", __FUNCTION__, msg->sender.c_str(), msg->cells.cells.size());
00232
00233 if(recovery_cells_.size() == 0)
00234 {
00235 recovery_cells_.push_back(*msg);
00236 }
00237 else
00238 {
00239 std::vector<pp_explorer::GridCellsIdentified>::iterator cell;
00240 for(cell = recovery_cells_.begin() ; cell != recovery_cells_.end() ; cell++)
00241 {
00242 if(msg->sender.compare(cell->sender) == 0)
00243 {
00244 if(msg->cells.cells.size() > 0)
00245 {
00246 cell->cells = msg->cells;
00247 }
00248 else
00249 {
00250 recovery_cells_.erase(cell);
00251 }
00252 break;
00253 }
00254 else if(cell == recovery_cells_.end() && msg->cells.cells.size() > 0)
00255 {
00256 recovery_cells_.push_back(*msg);
00257 }
00258 }
00259 }
00260 }
00261
00262 void particle_plume::PPExplorer::chatterCallback(const pp_explorer::StringIdentified::ConstPtr& msg)
00263 {
00264 if(msg->sender.compare(unique_id_) == 0) return;
00265
00266 ROS_INFO("PPExplorer - %s - Got a chatter msg from %s with the following: \"%s\"", __FUNCTION__, msg->sender.c_str(), msg->string.data.c_str());
00267
00268 if(msg->string.data.compare("Exploration complete")==0) finish_on_next_recovery_ = true;
00269 }
00270
00271 void particle_plume::PPExplorer::posesCallback(const pp_explorer::PoseStampedIdentified::ConstPtr& msg)
00272 {
00273 if(msg->sender.compare(unique_id_) == 0) return;
00274
00275 ROS_DEBUG("PPExplorer - %s - Got a pose msg from %s.", __FUNCTION__, msg->sender.c_str());
00276
00277 if(other_robots_poses_.size() == 0)
00278 {
00279 other_robots_poses_.push_back(*msg);
00280 }
00281 else
00282 {
00283 std::vector<pp_explorer::PoseStampedIdentified>::iterator pose;
00284 for(pose = other_robots_poses_.begin() ; pose != other_robots_poses_.end() ; pose++)
00285 {
00286 if(msg->sender.compare(pose->sender) == 0)
00287 {
00288 pose->pose = msg->pose;
00289 break;
00290 }
00291 else if(pose == other_robots_poses_.end())
00292 {
00293 other_robots_poses_.push_back(*msg);
00294 }
00295 }
00296 }
00297 }
00298
00299 bool particle_plume::PPExplorer::findYumiestSlice(geometry_msgs::PoseStamped * goal)
00300 {
00301 return yumiestSlice(goal, &robot_pose_);
00302 }
00303
00304 bool particle_plume::PPExplorer::yumiestSlice(geometry_msgs::PoseStamped * goal, geometry_msgs::PoseStamped * robot_pose)
00305 {
00306 ROS_DEBUG("PPExplorer - %s - Yum yum!", __FUNCTION__);
00307
00308 nav_msgs::GridCells debug_cells;
00309
00310 if(debug_slices_)
00311 {
00312 debug_cells.header.frame_id = global_frame_id_;
00313 debug_cells.cell_width = map_.info.resolution;
00314 debug_cells.cell_height = map_.info.resolution;
00315 }
00316
00317 int robot_cell_x = (int)( robot_pose->pose.position.x / map_.info.resolution );
00318 int robot_cell_y = (int)( robot_pose->pose.position.y / map_.info.resolution );
00319
00320 ROS_DEBUG("PPExplorer - %s - Map %dx%d @%lf Robot is at %d %d", __FUNCTION__, map_.info.width, map_.info.height, map_.info.resolution, robot_cell_x, robot_cell_y);
00321
00322
00323 if(!isInsideTheMap(robot_cell_x, robot_cell_y))
00324 {
00325 ROS_ERROR("PPExplorer - %s - Robot is out of bounds!", __FUNCTION__);
00326 return false;
00327 }
00328
00329
00330 best_slices_.clear();
00331
00332
00333 double slice_area = (M_PI*pie_radius_*pie_radius_)/pie_slices_;
00334
00335 double half_slice = 2*M_PI/(2*pie_slices_);
00336
00337 ROS_DEBUG("PPExplorer - %s - Half slice is %lf", __FUNCTION__, half_slice);
00338
00339 int slice_cells;
00340 int visited_cells_count;
00341 bool skip_slice;
00342 int cell_x, cell_y;
00343 double pos_x, pos_y;
00344 float slice_goal_x, slice_goal_y;
00345 double sigma;
00346
00347 double odor_yaw = 0.0;
00348 double odor_weight = 0.0;
00349
00350 geometry_msgs::PointStamped max_odor;
00351 max_odor.header.frame_id = global_frame_id_;
00352 geometry_msgs::PointStamped min_odor;
00353 min_odor.header.frame_id = global_frame_id_;
00354
00355 int max_particle_count = 0;
00356 int min_particle_count = plume_.points.size();
00357
00358
00359 bool odor_found = false;
00360 if(max_visited_cells_coef_ > 0.0)
00361 {
00362 BOOST_FOREACH(const pcl::PointXYZI& pt, plume_.points)
00363 {
00364 if(isInsidePieRadius(pt.x, pt.y, robot_pose))
00365 {
00366 int particle_count = 0;
00367 BOOST_FOREACH(const pcl::PointXYZI& pti, plume_.points)
00368 {
00369 if(sqrt((pt.x-pti.x)*(pt.x-pti.x) + (pt.y-pti.y)*(pt.y-pti.y) + (pt.z-pti.z)*(pt.z-pti.z)) <= bubble_radius_)
00370 {
00371 particle_count++;
00372 }
00373 }
00374 if(particle_count > max_particle_count)
00375 {
00376 max_particle_count = particle_count;
00377 max_odor.point.x = pt.x;
00378 max_odor.point.y = pt.y;
00379 max_odor.point.z = pt.z;
00380 }
00381 if(particle_count < min_particle_count)
00382 {
00383 min_particle_count = particle_count;
00384 min_odor.point.x = pt.x;
00385 min_odor.point.y = pt.y;
00386 min_odor.point.z = pt.z;
00387 }
00388 odor_found = true;
00389 }
00390 }
00391 }
00392 double max_visited_cells;
00393
00394
00395 if(odor_found)
00396 {
00397 max_visited_cells = max_odor_visited_cells_coef_;
00398
00399 if(!(max_particle_count == 0 || min_particle_count == plume_.points.size()) && max_particle_count-min_particle_count > min_particle_count_difference_)
00400 {
00401 odor_weight = odor_weight_;
00402
00403 odor_yaw = atan2(max_odor.point.x-min_odor.point.x, max_odor.point.y-min_odor.point.y);
00404 }
00405 else
00406 {
00407 odor_weight = 0.0;
00408 }
00409 }
00410 else
00411 {
00412 max_visited_cells = max_visited_cells_coef_;
00413 odor_weight = 0.0;
00414 }
00415
00416
00417 for(int slice=0 ; slice<pie_slices_ ; slice++)
00418 {
00419 skip_slice = false;
00420
00421
00422 int upper_bound_x = robot_cell_x;
00423 int upper_bound_y = robot_cell_y;
00424 int lower_bound_x = robot_cell_x;
00425 int lower_bound_y = robot_cell_y;
00426
00427 double start_angle = angles::normalize_angle(tf::getYaw(robot_pose->pose.orientation) + slice*2*half_slice - half_slice);
00428
00429 slice_goal_x = robot_pose->pose.position.x + pie_radius_*cos(start_angle+half_slice);
00430 slice_goal_y = robot_pose->pose.position.y + pie_radius_*sin(start_angle+half_slice);
00431
00432 ROS_DEBUG("PPExplorer - %s - Slice %d with angle of %lf", __FUNCTION__, slice+1, start_angle);
00433
00434 for(int i=0 ; i<3 ; i++)
00435 {
00436
00437 cell_x = (int)((robot_pose->pose.position.x + pie_radius_*cos(start_angle + i*half_slice)) / map_.info.resolution );
00438 cell_y = (int)((robot_pose->pose.position.y + pie_radius_*sin(start_angle + i*half_slice)) / map_.info.resolution );
00439
00440 if(cell_x > upper_bound_x) upper_bound_x = cell_x;
00441 else if(cell_x < lower_bound_x) lower_bound_x = cell_x;
00442
00443 if(cell_y > upper_bound_y) upper_bound_y = cell_y;
00444 else if(cell_y < lower_bound_y) lower_bound_y = cell_y;
00445 }
00446
00447
00448 if(upper_bound_x > map_.info.width-1 || lower_bound_x < 0 || upper_bound_y > map_.info.height-1 || lower_bound_y < 0)
00449 {
00450 skip_slice = true;
00451 }
00452
00453
00454 if(!skip_slice)
00455 {
00456 if(!isViableLocalMapGoal(slice_goal_x, slice_goal_y)) skip_slice = true;
00457 }
00458
00459
00460 if(!skip_slice)
00461 {
00462 slice_cells = 0;
00463 for(int i=lower_bound_x ; i<upper_bound_x ; i++)
00464 {
00465 for(int j=lower_bound_y ; j<upper_bound_y ; j++)
00466 {
00467
00468 pos_x = i * map_.info.resolution + map_.info.resolution/2;
00469 pos_y = j * map_.info.resolution + map_.info.resolution/2;
00470
00471 sigma = atan2(pos_y - robot_pose->pose.position.y, pos_x - robot_pose->pose.position.x);
00472 if(sigma < 0.0) sigma += 2*M_PI;
00473 sigma = angles::normalize_angle(sigma - (start_angle < 0.0 ? start_angle+2*M_PI : start_angle));
00474
00475 if(isInsidePieRadius(pos_x, pos_y, robot_pose) && sigma >= 0.0 && sigma <= half_slice*2)
00476 {
00477 geometry_msgs::Point point;
00478 point.x = i * map_.info.resolution;
00479 point.y = j * map_.info.resolution;
00480
00481
00482 if(!isViableGlobalMapCell(i,j))
00483 {
00484 skip_slice = true;
00485 }
00486
00487 if(debug_slices_)
00488 {
00489 debug_cells.cells.push_back(point);
00490 debug_cells.header.stamp = ros::Time::now();
00491 debug_pub_.publish(debug_cells);
00492
00493 visualization_msgs::Marker marker;
00494 marker.header.frame_id = "/map";
00495 marker.header.stamp = ros::Time::now();
00496 marker.ns = "pp_goal";
00497 marker.id = 0;
00498 marker.type = visualization_msgs::Marker::ARROW;
00499 marker.action = visualization_msgs::Marker::ADD;
00500 marker.pose.position.x = slice_goal_x;
00501 marker.pose.position.y = slice_goal_y;
00502 marker.pose.position.z = 0.25;
00503 marker.pose.orientation = tf::createQuaternionMsgFromRollPitchYaw(0.0, M_PI/2, 0.0);
00504 marker.scale.x = 0.20;
00505 marker.scale.y = 0.5;
00506 marker.scale.z = 0.5;
00507 marker.color.a = 1.0;
00508 marker.color.r = 1.0;
00509 marker.color.g = 0.0;
00510 marker.color.b = 0.0;
00511 debug_goal_pub_.publish(marker);
00512 }
00513 slice_cells++;
00514 }
00515 if(skip_slice) break;
00516 }
00517 if(skip_slice) break;
00518 }
00519 }
00520
00521 if(!skip_slice)
00522 {
00523
00524 visited_cells_count = 0;
00525 std::vector<geometry_msgs::Point>::iterator cell;
00526 for(cell = cells_.cells.begin() ; cell != cells_.cells.end() ; cell++)
00527 {
00528 sigma = atan2(cell->y+cells_.cell_height/2 - robot_pose->pose.position.y, cell->x+cells_.cell_width/2 - robot_pose->pose.position.x);
00529 if(sigma < 0.0) sigma += 2*M_PI;
00530 sigma = angles::normalize_angle(sigma - (start_angle < 0.0 ? start_angle+2*M_PI : start_angle));
00531
00532 if(isInsidePieRadius(cell->x, cell->y, robot_pose) && sigma >= 0.0 && sigma <= half_slice*2)
00533 {
00534 visited_cells_count++;
00535 }
00536 }
00537
00538 double slice_yaw = atan2(slice_goal_y-robot_pose->pose.position.y, slice_goal_x-robot_pose->pose.position.x);
00539
00540 SliceOfPie new_slice;
00541 new_slice.goal.position.x = slice_goal_x;
00542 new_slice.goal.position.y = slice_goal_y;
00543 new_slice.goal.orientation = tf::createQuaternionMsgFromYaw(slice_yaw);
00544
00545 double visited_cells_coef = cells_.cell_width*cells_.cell_height*visited_cells_count/slice_area;
00546
00547 if(visited_cells_coef <= max_visited_cells)
00548 {
00549
00550 new_slice.yuminess = visited_cells_weight_ * (visited_cells_coef) + current_heading_weight_ * (fabs(angles::shortest_angular_distance(slice_yaw, tf::getYaw(robot_pose->pose.orientation)))) + odor_weight * (fabs(angles::shortest_angular_distance(slice_yaw, odor_yaw)));
00551
00552
00553 if(multi_robot_)
00554 {
00555 std::vector<pp_explorer::PoseStampedIdentified>::iterator pose_it;
00556 for(pose_it = other_robots_poses_.begin() ; pose_it != other_robots_poses_.end() ; pose_it++)
00557 {
00558 if(pose_it->pose.header.stamp - ros::Time::now() > ros::Duration(0.1))
00559 {
00560 ROS_WARN("PPExplorer - %s - Discarding %s pose for being too old...", __FUNCTION__, pose_it->sender.c_str());
00561 }
00562 else
00563 {
00564
00565 double robots_delta_x = pose_it->pose.pose.position.x - robot_pose->pose.position.x;
00566 double robots_delta_y = pose_it->pose.pose.position.y - robot_pose->pose.position.y;
00567 double other_robot_yaw = atan2(robots_delta_y, robots_delta_x);
00568 double distance_between_robots = sqrt(robots_delta_x*robots_delta_x + robots_delta_y*robots_delta_y);
00569
00570 new_slice.yuminess += other_robots_weight_*exp(-1*distance_between_robots)*(fabs(angles::shortest_angular_distance(slice_yaw, other_robot_yaw)));
00571 }
00572 }
00573 }
00574
00575 best_slices_.push_back(new_slice);
00576 }
00577 else
00578 {
00579 ROS_DEBUG("PPExplorer - %s - Discarding this slice %lf %lf due to high percentage of visited cells.", __FUNCTION__, robot_pose->pose.position.x + (pie_radius_ - 0.20)*cos(start_angle+half_slice), robot_pose->pose.position.y + (pie_radius_ - 0.20)*sin(start_angle+half_slice));
00580 }
00581
00582 ROS_DEBUG("PPExplorer - %s - Found %d visited cells", __FUNCTION__, visited_cells_count);
00583 }
00584 else
00585 {
00586 ROS_DEBUG("PPExplorer - %s - Discarding this slice %lf %lf due to presence of obstacles.", __FUNCTION__, robot_pose->pose.position.x + (pie_radius_ - 0.20)*cos(start_angle+half_slice), robot_pose->pose.position.y + (pie_radius_ - 0.20)*sin(start_angle+half_slice));
00587 }
00588
00589 if(debug_slices_)
00590 {
00591 ros::Duration(0.1).sleep();
00592
00593 }
00594 }
00595
00596
00597 if(best_slices_.size() == 0)
00598 {
00599 ROS_DEBUG("PPExplorer - %s - All the slices were discarded!", __FUNCTION__);
00600 return false;
00601 }
00602
00603
00604 CompareSlices cmp;
00605 best_slices_.sort(cmp);
00606
00607
00608 this->setGoal(goal);
00609
00610 ROS_DEBUG("PPExplorer - %s - Setting goal to %lf %lf", __FUNCTION__, goal->pose.position.x, goal->pose.position.y);
00611
00612 if(debug_slices_)
00613 {
00614 ros::Duration(1.0).sleep();
00615 debug_cells.cells.clear();
00616 debug_pub_.publish(debug_cells);
00617 }
00618
00619 return true;
00620 }
00621
00622 bool particle_plume::PPExplorer::nextYumiestSlice(geometry_msgs::PoseStamped * goal)
00623 {
00624 best_slices_.pop_front();
00625
00626 if(best_slices_.size() == 0) return false;
00627
00628 this->setGoal(goal);
00629
00630 return true;
00631 }
00632
00633 bool particle_plume::PPExplorer::findClearing(geometry_msgs::PoseStamped * goal)
00634 {
00635 if(multi_robot_ && finish_on_next_recovery_)
00636 {
00637 explorationComplete();
00638 return false;
00639 }
00640
00641 ROS_DEBUG("PPExplorer - %s - Looking for a clearing to go to...", __FUNCTION__);
00642
00643 pp_explorer::GridCellsIdentified recovery_cells;
00644 recovery_cells.sender = unique_id_;
00645 recovery_cells.cells.header.frame_id = global_frame_id_;
00646
00647 nav_msgs::GridCells debug_cells;
00648
00649 if(debug_slices_)
00650 {
00651 debug_cells.header.frame_id = global_frame_id_;
00652 debug_cells.cell_width = map_.info.resolution;
00653 debug_cells.cell_height = map_.info.resolution;
00654 }
00655
00656 int robot_cell_x = (int)( robot_pose_.pose.position.x / map_.info.resolution );
00657 int robot_cell_y = (int)( robot_pose_.pose.position.y / map_.info.resolution );
00658
00659
00660 if(!isInsideTheMap(robot_cell_x, robot_cell_y))
00661 {
00662 ROS_ERROR("PPExplorer - %s - Robot is out of bounds!", __FUNCTION__);
00663 return false;
00664 }
00665
00666 std::vector<geometry_msgs::Point> last_cells;
00667 std::vector<geometry_msgs::Point> current_cells;
00668 std::vector<geometry_msgs::Point> next_cells;
00669
00670 geometry_msgs::Point cell;
00671 cell.x = robot_cell_x * map_.info.resolution + map_.info.resolution/2;
00672 cell.y = robot_cell_y * map_.info.resolution + map_.info.resolution/2;
00673 current_cells.push_back(cell);
00674
00675 while(true)
00676 {
00677 ros::spinOnce();
00678
00679 next_cells.clear();
00680
00681 std::vector<geometry_msgs::Point>::iterator cell_it;
00682 for(cell_it = current_cells.begin() ; cell_it != current_cells.end() ; cell_it++)
00683 {
00684 for(int i=(int)(cell_it->x/map_.info.resolution)-1 ; i<(int)(cell_it->x/map_.info.resolution)+2 ; i++)
00685 {
00686 for(int j=(int)(cell_it->y/map_.info.resolution)-1 ; j<(int)(cell_it->y/map_.info.resolution)+2 ; j++)
00687 {
00688 geometry_msgs::Point new_cell;
00689 new_cell.x = i * map_.info.resolution;
00690 new_cell.y = j * map_.info.resolution;
00691
00692
00693 if(new_cell.x==cell_it->x && new_cell.y==cell_it->y) continue;
00694
00695
00696 if(!isViableGlobalMapCell(i,j)) continue;
00697
00698
00699 if(testCell(&new_cell, &next_cells)) continue;
00700
00701
00702 if(testCell(&new_cell, ¤t_cells)) continue;
00703
00704
00705 if(testCell(&new_cell, &last_cells)) continue;
00706
00707
00708 if(multi_robot_)
00709 {
00710 bool is_recovery_cell = false;
00711 std::vector<pp_explorer::GridCellsIdentified>::iterator recovery_it;
00712 for(recovery_it = recovery_cells_.begin() ; recovery_it != recovery_cells_.end() ; recovery_it++)
00713 {
00714 if(testCell(&new_cell, &recovery_it->cells.cells))
00715 {
00716 is_recovery_cell = true;
00717 break;
00718 }
00719 }
00720 if(is_recovery_cell) continue;
00721 }
00722
00723
00724 if(!isInsidePieRadius(new_cell.x, new_cell.y, &robot_pose_))
00725 {
00726 geometry_msgs::PoseStamped dummy_goal;
00727 dummy_goal.pose.position.x = new_cell.x + map_.info.resolution/2;
00728 dummy_goal.pose.position.y = new_cell.y + map_.info.resolution/2;
00729 dummy_goal.pose.orientation = tf::createQuaternionMsgFromYaw(atan2(dummy_goal.pose.position.y - robot_pose_.pose.position.y, dummy_goal.pose.position.x - robot_pose_.pose.position.x));
00730
00731
00732 bool turn_debug_back_on = false;
00733 if(debug_slices_)
00734 {
00735 debug_slices_ = false;
00736 turn_debug_back_on = true;
00737 }
00738
00739
00740 double temp_visited_cells_coef = max_visited_cells_coef_;
00741 max_visited_cells_coef_ = 0.0;
00742
00743 nav_msgs::Path dummy_path;
00744 bool found_clearing = true;
00745 for(int t=0 ; t<find_clearing_sim_steps_ ; t++)
00746 {
00747 if(!yumiestSlice(&dummy_goal, &dummy_goal))
00748 {
00749 found_clearing = false;
00750 break;
00751 }
00752 if(dummy_path.poses.size()==0) dummy_path.poses.push_back(dummy_goal);
00753 else
00754 {
00755
00756 bool nearby_pose = false;
00757 std::vector<geometry_msgs::PoseStamped>::iterator pose_it;
00758 for(pose_it=dummy_path.poses.begin() ; pose_it!=dummy_path.poses.end() ; pose_it++)
00759 {
00760 double dx = pose_it->pose.position.x - dummy_goal.pose.position.x;
00761 double dy = pose_it->pose.position.y - dummy_goal.pose.position.y;
00762 if(sqrt((dx*dx+dy*dy)) < pie_radius_*0.5)
00763 {
00764 nearby_pose = true;
00765 break;
00766 }
00767 }
00768 if(nearby_pose)
00769 {
00770 found_clearing = false;
00771 break;
00772 }
00773 else
00774 {
00775 dummy_path.poses.push_back(dummy_goal);
00776 }
00777 }
00778 }
00779 dummy_path.poses.clear();
00780
00781
00782 max_visited_cells_coef_ = temp_visited_cells_coef;
00783
00784
00785 if(turn_debug_back_on) debug_slices_ = true;
00786
00787
00788 if(found_clearing)
00789 {
00790 goal->header.stamp = ros::Time::now();
00791 goal->header.frame_id = global_frame_id_;
00792 goal->pose.position.x = new_cell.x + map_.info.resolution/2;
00793 goal->pose.position.y = new_cell.y + map_.info.resolution/2;
00794 goal->pose.orientation = tf::createQuaternionMsgFromYaw(atan2(goal->pose.position.y - robot_pose_.pose.position.y, goal->pose.position.x - robot_pose_.pose.position.x));
00795
00796 if(debug_slices_)
00797 {
00798 visualization_msgs::Marker marker;
00799 marker.header.frame_id = "/map";
00800 marker.header.stamp = ros::Time::now();
00801 marker.ns = "pp_goal";
00802 marker.id = 0;
00803 marker.type = visualization_msgs::Marker::ARROW;
00804 marker.action = visualization_msgs::Marker::ADD;
00805 marker.pose.position.x = goal->pose.position.x;
00806 marker.pose.position.y = goal->pose.position.y;
00807 marker.pose.position.z = 0.2;
00808 marker.pose.orientation = tf::createQuaternionMsgFromRollPitchYaw(0.0, M_PI/2, 0.0);
00809 marker.scale.x = 0.19;
00810 marker.scale.y = 0.5;
00811 marker.scale.z = 0.5;
00812 marker.color.a = 1.0;
00813 marker.color.r = 1.0;
00814 marker.color.g = 1.0;
00815 marker.color.b = 0.0;
00816 debug_goal_pub_.publish(marker);
00817 }
00818
00819 if(multi_robot_)
00820 {
00821 recovery_cells.cells.cells.empty();
00822 recovery_pub_.publish(recovery_cells);
00823 }
00824 return true;
00825 }
00826 }
00827
00828
00829 next_cells.push_back(new_cell);
00830 }
00831 }
00832 }
00833
00834 if(next_cells.size()==0)
00835 {
00836 if(multi_robot_)
00837 {
00838 recovery_cells.cells.cells.empty();
00839 recovery_pub_.publish(recovery_cells);
00840
00841 explorationComplete();
00842 }
00843 return false;
00844 }
00845
00846 if(multi_robot_)
00847 {
00848 std::vector<geometry_msgs::Point>::iterator recovery_cell_it;
00849 for(recovery_cell_it = current_cells.begin() ; recovery_cell_it != current_cells.end() ; recovery_cell_it++) recovery_cells.cells.cells.push_back(*recovery_cell_it);
00850
00851 recovery_cells.cells.header.stamp = ros::Time::now();
00852
00853 recovery_pub_.publish(recovery_cells);
00854 }
00855
00856 if(debug_slices_)
00857 {
00858 std::vector<geometry_msgs::Point>::iterator debug_cell_it;
00859 for(debug_cell_it = current_cells.begin() ; debug_cell_it != current_cells.end() ; debug_cell_it++) debug_cells.cells.push_back(*debug_cell_it);
00860
00861 debug_pub_.publish(debug_cells);
00862 ros::Duration(0.1).sleep();
00863 }
00864
00865 last_cells = current_cells;
00866 current_cells = next_cells;
00867 }
00868 }
00869
00870
00871
00872
00873 bool particle_plume::PPExplorer::testCell(geometry_msgs::Point * cell, std::vector<geometry_msgs::Point> * cells)
00874 {
00875 std::vector<geometry_msgs::Point>::iterator cell_it;
00876
00877 for(cell_it = cells->begin() ; cell_it != cells->end() ; cell_it++)
00878 {
00879 if(cell->x == cell_it->x && cell->y == cell_it->y) return true;
00880 }
00881 return false;
00882 }
00883
00884 void particle_plume::PPExplorer::setGoal(geometry_msgs::PoseStamped * goal)
00885 {
00886 goal->header.stamp = ros::Time::now();
00887 goal->header.frame_id = global_frame_id_;
00888 goal->pose = best_slices_.front().goal;
00889
00890 if(debug_slices_)
00891 {
00892 visualization_msgs::Marker marker;
00893 marker.header.frame_id = "/map";
00894 marker.header.stamp = ros::Time::now();
00895 marker.ns = "pp_goal";
00896 marker.id = 0;
00897 marker.type = visualization_msgs::Marker::ARROW;
00898 marker.action = visualization_msgs::Marker::ADD;
00899 marker.pose.position.x = goal->pose.position.x;
00900 marker.pose.position.y = goal->pose.position.y;
00901 marker.pose.position.z = 0.2;
00902 marker.pose.orientation = tf::createQuaternionMsgFromRollPitchYaw(0.0, M_PI/2, 0.0);
00903 marker.scale.x = 0.19;
00904 marker.scale.y = 0.5;
00905 marker.scale.z = 0.5;
00906 marker.color.a = 1.0;
00907 marker.color.r = 1.0;
00908 marker.color.g = 1.0;
00909 marker.color.b = 0.0;
00910 debug_goal_pub_.publish(marker);
00911 }
00912 }
00913
00914 bool particle_plume::PPExplorer::isInsidePieRadius(double x, double y, geometry_msgs::PoseStamped * robot)
00915 {
00916 return sqrt((x - robot->pose.position.x)*(x - robot->pose.position.x) + (y - robot->pose.position.y)*(y - robot->pose.position.y)) <= pie_radius_;
00917 }
00918
00919 bool particle_plume::PPExplorer::isInsideTheMap(int x, int y)
00920 {
00921 return (x<=map_.info.width-1 && x>=0 && y<=map_.info.height-1 && y>=0);
00922 }
00923
00924 bool particle_plume::PPExplorer::isViableGlobalMapCell(int x, int y)
00925 {
00926 if(!isInsideTheMap(x,y)) return false;
00927
00928 if(map_.data[y*map_.info.width+x] != 0) return false;
00929
00930 int cir = ceil(inflation_radius_/map_.info.resolution)+1;
00931 for(int i=(x-cir<0 ? 0 : x-cir) ; i<(x+cir>map_.info.width ? map_.info.width : x+cir) ; i++)
00932 {
00933 for(int j=(y-cir<0 ? 0 : y-cir) ; j<(y+cir>map_.info.height ? map_.info.height : y+cir) ; j++)
00934 {
00935 if(map_.data[j*map_.info.width+i] != 0 && sqrt((x-i)*(x-i)+(y-j)*(y-j)) <= (float)cir-1.0)
00936 {
00937 return false;
00938 }
00939 }
00940 }
00941 return true;
00942 }
00943
00944 bool particle_plume::PPExplorer::isViableLocalMapGoal(double x, double y)
00945 {
00946 std::vector<geometry_msgs::Point>::iterator obstacle;
00947
00948 for(obstacle = obstacles_.cells.begin() ; obstacle != obstacles_.cells.end() ; obstacle++)
00949 {
00950 if(x >= obstacle->x && x <= obstacle->x+obstacles_.cell_width && y >= obstacle->y && y <= obstacle->y+obstacles_.cell_height)
00951 return false;
00952 }
00953
00954 for(obstacle = inflated_.cells.begin() ; obstacle != inflated_.cells.end() ; obstacle++)
00955 {
00956 if(x >= obstacle->x && x <= obstacle->x+obstacles_.cell_width && y >= obstacle->y && y <= obstacle->y+obstacles_.cell_height)
00957 return false;
00958 }
00959 return true;
00960 }
00961
00962 double particle_plume::PPExplorer::getExploredArea()
00963 {
00964 int map_cell_count = 0;
00965
00966 for(int i=0 ; i<map_.info.width ; i++)
00967 {
00968 for(int j=0 ; j<map_.info.height ; j++)
00969 {
00970 if(map_.data[j*map_.info.width+i] == 0) map_cell_count++;
00971 }
00972 }
00973
00974 return (cells_.cell_height*cells_.cell_width*cells_.cells.size())/(map_.info.resolution*map_.info.resolution*map_cell_count);
00975 }
00976
00977 void particle_plume::PPExplorer::explorationComplete()
00978 {
00979 pp_explorer::StringIdentified finished_msg;
00980 finished_msg.sender = unique_id_;
00981 finished_msg.string.data = "Exploration complete";
00982 chatter_pub_.publish(finished_msg);
00983 }
00984
00985
00986