00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038 #include <costmap_2d/obstacle_layer.h>
00039 #include <costmap_2d/costmap_math.h>
00040 #include <pluginlib/class_list_macros.h>
00041
00042 PLUGINLIB_EXPORT_CLASS(costmap_2d::ObstacleLayer, costmap_2d::Layer)
00043
00044 using costmap_2d::NO_INFORMATION;
00045 using costmap_2d::LETHAL_OBSTACLE;
00046 using costmap_2d::FREE_SPACE;
00047
00048 using costmap_2d::ObservationBuffer;
00049 using costmap_2d::Observation;
00050
00051 namespace costmap_2d
00052 {
00053
00054 void ObstacleLayer::onInitialize()
00055 {
00056 ros::NodeHandle nh("~/" + name_), g_nh;
00057 rolling_window_ = layered_costmap_->isRolling();
00058
00059 bool track_unknown_space;
00060 nh.param("track_unknown_space", track_unknown_space, layered_costmap_->isTrackingUnknown());
00061 if (track_unknown_space)
00062 default_value_ = NO_INFORMATION;
00063 else
00064 default_value_ = FREE_SPACE;
00065
00066 ObstacleLayer::matchSize();
00067 current_ = true;
00068
00069 global_frame_ = layered_costmap_->getGlobalFrameID();
00070 double transform_tolerance;
00071 nh.param("transform_tolerance", transform_tolerance, 0.2);
00072
00073 std::string topics_string;
00074
00075 nh.param("observation_sources", topics_string, std::string(""));
00076 ROS_INFO(" Subscribed to Topics: %s", topics_string.c_str());
00077
00078
00079 ros::NodeHandle prefix_nh;
00080 const std::string tf_prefix = tf::getPrefixParam(prefix_nh);
00081
00082
00083 std::stringstream ss(topics_string);
00084
00085 std::string source;
00086 while (ss >> source)
00087 {
00088 ros::NodeHandle source_node(nh, source);
00089
00090
00091 double observation_keep_time, expected_update_rate, min_obstacle_height, max_obstacle_height;
00092 std::string topic, sensor_frame, data_type;
00093 bool inf_is_valid, clearing, marking;
00094
00095 source_node.param("topic", topic, source);
00096 source_node.param("sensor_frame", sensor_frame, std::string(""));
00097 source_node.param("observation_persistence", observation_keep_time, 0.0);
00098 source_node.param("expected_update_rate", expected_update_rate, 0.0);
00099 source_node.param("data_type", data_type, std::string("PointCloud"));
00100 source_node.param("min_obstacle_height", min_obstacle_height, 0.0);
00101 source_node.param("max_obstacle_height", max_obstacle_height, 2.0);
00102 source_node.param("inf_is_valid", inf_is_valid, false);
00103 source_node.param("clearing", clearing, false);
00104 source_node.param("marking", marking, true);
00105
00106 if (!sensor_frame.empty())
00107 {
00108 sensor_frame = tf::resolve(tf_prefix, sensor_frame);
00109 }
00110
00111 if (!(data_type == "PointCloud2" || data_type == "PointCloud" || data_type == "LaserScan"))
00112 {
00113 ROS_FATAL("Only topics that use point clouds or laser scans are currently supported");
00114 throw std::runtime_error("Only topics that use point clouds or laser scans are currently supported");
00115 }
00116
00117 std::string raytrace_range_param_name, obstacle_range_param_name;
00118
00119
00120 double obstacle_range = 2.5;
00121 if (source_node.searchParam("obstacle_range", obstacle_range_param_name))
00122 {
00123 source_node.getParam(obstacle_range_param_name, obstacle_range);
00124 }
00125
00126
00127 double raytrace_range = 3.0;
00128 if (source_node.searchParam("raytrace_range", raytrace_range_param_name))
00129 {
00130 source_node.getParam(raytrace_range_param_name, raytrace_range);
00131 }
00132
00133 ROS_DEBUG("Creating an observation buffer for source %s, topic %s, frame %s", source.c_str(), topic.c_str(),
00134 sensor_frame.c_str());
00135
00136
00137 observation_buffers_.push_back(
00138 boost::shared_ptr < ObservationBuffer
00139 > (new ObservationBuffer(topic, observation_keep_time, expected_update_rate, min_obstacle_height,
00140 max_obstacle_height, obstacle_range, raytrace_range, *tf_, global_frame_,
00141 sensor_frame, transform_tolerance)));
00142
00143
00144 if (marking)
00145 marking_buffers_.push_back(observation_buffers_.back());
00146
00147
00148 if (clearing)
00149 clearing_buffers_.push_back(observation_buffers_.back());
00150
00151 ROS_DEBUG(
00152 "Created an observation buffer for source %s, topic %s, global frame: %s, "
00153 "expected update rate: %.2f, observation persistence: %.2f",
00154 source.c_str(), topic.c_str(), global_frame_.c_str(), expected_update_rate, observation_keep_time);
00155
00156
00157 if (data_type == "LaserScan")
00158 {
00159 boost::shared_ptr < message_filters::Subscriber<sensor_msgs::LaserScan>
00160 > sub(new message_filters::Subscriber<sensor_msgs::LaserScan>(g_nh, topic, 50));
00161
00162 boost::shared_ptr < tf::MessageFilter<sensor_msgs::LaserScan>
00163 > filter(new tf::MessageFilter<sensor_msgs::LaserScan>(*sub, *tf_, global_frame_, 50));
00164
00165 if (inf_is_valid)
00166 {
00167 filter->registerCallback(
00168 boost::bind(&ObstacleLayer::laserScanValidInfCallback, this, _1, observation_buffers_.back()));
00169 }
00170 else
00171 {
00172 filter->registerCallback(
00173 boost::bind(&ObstacleLayer::laserScanCallback, this, _1, observation_buffers_.back()));
00174 }
00175
00176 observation_subscribers_.push_back(sub);
00177 observation_notifiers_.push_back(filter);
00178
00179 observation_notifiers_.back()->setTolerance(ros::Duration(0.05));
00180 }
00181 else if (data_type == "PointCloud")
00182 {
00183 boost::shared_ptr < message_filters::Subscriber<sensor_msgs::PointCloud>
00184 > sub(new message_filters::Subscriber<sensor_msgs::PointCloud>(g_nh, topic, 50));
00185
00186 if (inf_is_valid)
00187 {
00188 ROS_WARN("obstacle_layer: inf_is_valid option is not applicable to PointCloud observations.");
00189 }
00190
00191 boost::shared_ptr < tf::MessageFilter<sensor_msgs::PointCloud>
00192 > filter(new tf::MessageFilter<sensor_msgs::PointCloud>(*sub, *tf_, global_frame_, 50));
00193 filter->registerCallback(
00194 boost::bind(&ObstacleLayer::pointCloudCallback, this, _1, observation_buffers_.back()));
00195
00196 observation_subscribers_.push_back(sub);
00197 observation_notifiers_.push_back(filter);
00198 }
00199 else
00200 {
00201 boost::shared_ptr < message_filters::Subscriber<sensor_msgs::PointCloud2>
00202 > sub(new message_filters::Subscriber<sensor_msgs::PointCloud2>(g_nh, topic, 50));
00203
00204 if (inf_is_valid)
00205 {
00206 ROS_WARN("obstacle_layer: inf_is_valid option is not applicable to PointCloud observations.");
00207 }
00208
00209 boost::shared_ptr < tf::MessageFilter<sensor_msgs::PointCloud2>
00210 > filter(new tf::MessageFilter<sensor_msgs::PointCloud2>(*sub, *tf_, global_frame_, 50));
00211 filter->registerCallback(
00212 boost::bind(&ObstacleLayer::pointCloud2Callback, this, _1, observation_buffers_.back()));
00213
00214 observation_subscribers_.push_back(sub);
00215 observation_notifiers_.push_back(filter);
00216 }
00217
00218 if (sensor_frame != "")
00219 {
00220 std::vector < std::string > target_frames;
00221 target_frames.push_back(global_frame_);
00222 target_frames.push_back(sensor_frame);
00223 observation_notifiers_.back()->setTargetFrames(target_frames);
00224 }
00225 }
00226
00227 dsrv_ = NULL;
00228 setupDynamicReconfigure(nh);
00229 }
00230
00231 void ObstacleLayer::setupDynamicReconfigure(ros::NodeHandle& nh)
00232 {
00233 dsrv_ = new dynamic_reconfigure::Server<costmap_2d::ObstaclePluginConfig>(nh);
00234 dynamic_reconfigure::Server<costmap_2d::ObstaclePluginConfig>::CallbackType cb = boost::bind(
00235 &ObstacleLayer::reconfigureCB, this, _1, _2);
00236 dsrv_->setCallback(cb);
00237 }
00238
00239 ObstacleLayer::~ObstacleLayer()
00240 {
00241 if (dsrv_)
00242 delete dsrv_;
00243 }
00244 void ObstacleLayer::reconfigureCB(costmap_2d::ObstaclePluginConfig &config, uint32_t level)
00245 {
00246 enabled_ = config.enabled;
00247 footprint_clearing_enabled_ = config.footprint_clearing_enabled;
00248 max_obstacle_height_ = config.max_obstacle_height;
00249 combination_method_ = config.combination_method;
00250 }
00251
00252 void ObstacleLayer::laserScanCallback(const sensor_msgs::LaserScanConstPtr& message,
00253 const boost::shared_ptr<ObservationBuffer>& buffer)
00254 {
00255
00256 sensor_msgs::PointCloud2 cloud;
00257 cloud.header = message->header;
00258
00259
00260 try
00261 {
00262 projector_.transformLaserScanToPointCloud(message->header.frame_id, *message, cloud, *tf_);
00263 }
00264 catch (tf::TransformException &ex)
00265 {
00266 ROS_WARN("High fidelity enabled, but TF returned a transform exception to frame %s: %s", global_frame_.c_str(),
00267 ex.what());
00268 projector_.projectLaser(*message, cloud);
00269 }
00270
00271
00272 buffer->lock();
00273 buffer->bufferCloud(cloud);
00274 buffer->unlock();
00275 }
00276
00277 void ObstacleLayer::laserScanValidInfCallback(const sensor_msgs::LaserScanConstPtr& raw_message,
00278 const boost::shared_ptr<ObservationBuffer>& buffer)
00279 {
00280
00281 float epsilon = 0.0001;
00282 sensor_msgs::LaserScan message = *raw_message;
00283 for (size_t i = 0; i < message.ranges.size(); i++)
00284 {
00285 float range = message.ranges[ i ];
00286 if (!std::isfinite(range) && range > 0)
00287 {
00288 message.ranges[ i ] = message.range_max - epsilon;
00289 }
00290 }
00291
00292
00293 sensor_msgs::PointCloud2 cloud;
00294 cloud.header = message.header;
00295
00296
00297 try
00298 {
00299 projector_.transformLaserScanToPointCloud(message.header.frame_id, message, cloud, *tf_);
00300 }
00301 catch (tf::TransformException &ex)
00302 {
00303 ROS_WARN("High fidelity enabled, but TF returned a transform exception to frame %s: %s",
00304 global_frame_.c_str(), ex.what());
00305 projector_.projectLaser(message, cloud);
00306 }
00307
00308
00309 buffer->lock();
00310 buffer->bufferCloud(cloud);
00311 buffer->unlock();
00312 }
00313
00314 void ObstacleLayer::pointCloudCallback(const sensor_msgs::PointCloudConstPtr& message,
00315 const boost::shared_ptr<ObservationBuffer>& buffer)
00316 {
00317 sensor_msgs::PointCloud2 cloud2;
00318
00319 if (!sensor_msgs::convertPointCloudToPointCloud2(*message, cloud2))
00320 {
00321 ROS_ERROR("Failed to convert a PointCloud to a PointCloud2, dropping message");
00322 return;
00323 }
00324
00325
00326 buffer->lock();
00327 buffer->bufferCloud(cloud2);
00328 buffer->unlock();
00329 }
00330
00331 void ObstacleLayer::pointCloud2Callback(const sensor_msgs::PointCloud2ConstPtr& message,
00332 const boost::shared_ptr<ObservationBuffer>& buffer)
00333 {
00334
00335 buffer->lock();
00336 buffer->bufferCloud(*message);
00337 buffer->unlock();
00338 }
00339
00340 void ObstacleLayer::updateBounds(double robot_x, double robot_y, double robot_yaw, double* min_x,
00341 double* min_y, double* max_x, double* max_y)
00342 {
00343 if (rolling_window_)
00344 updateOrigin(robot_x - getSizeInMetersX() / 2, robot_y - getSizeInMetersY() / 2);
00345 if (!enabled_)
00346 return;
00347 useExtraBounds(min_x, min_y, max_x, max_y);
00348
00349 bool current = true;
00350 std::vector<Observation> observations, clearing_observations;
00351
00352
00353 current = current && getMarkingObservations(observations);
00354
00355
00356 current = current && getClearingObservations(clearing_observations);
00357
00358
00359 current_ = current;
00360
00361
00362 for (unsigned int i = 0; i < clearing_observations.size(); ++i)
00363 {
00364 raytraceFreespace(clearing_observations[i], min_x, min_y, max_x, max_y);
00365 }
00366
00367
00368 for (std::vector<Observation>::const_iterator it = observations.begin(); it != observations.end(); ++it)
00369 {
00370 const Observation& obs = *it;
00371
00372 const pcl::PointCloud<pcl::PointXYZ>& cloud = *(obs.cloud_);
00373
00374 double sq_obstacle_range = obs.obstacle_range_ * obs.obstacle_range_;
00375
00376 for (unsigned int i = 0; i < cloud.points.size(); ++i)
00377 {
00378 double px = cloud.points[i].x, py = cloud.points[i].y, pz = cloud.points[i].z;
00379
00380
00381 if (pz > max_obstacle_height_)
00382 {
00383 ROS_DEBUG("The point is too high");
00384 continue;
00385 }
00386
00387
00388 double sq_dist = (px - obs.origin_.x) * (px - obs.origin_.x) + (py - obs.origin_.y) * (py - obs.origin_.y)
00389 + (pz - obs.origin_.z) * (pz - obs.origin_.z);
00390
00391
00392 if (sq_dist >= sq_obstacle_range)
00393 {
00394 ROS_DEBUG("The point is too far away");
00395 continue;
00396 }
00397
00398
00399 unsigned int mx, my;
00400 if (!worldToMap(px, py, mx, my))
00401 {
00402 ROS_DEBUG("Computing map coords failed");
00403 continue;
00404 }
00405
00406 unsigned int index = getIndex(mx, my);
00407 costmap_[index] = LETHAL_OBSTACLE;
00408 touch(px, py, min_x, min_y, max_x, max_y);
00409 }
00410 }
00411
00412 updateFootprint(robot_x, robot_y, robot_yaw, min_x, min_y, max_x, max_y);
00413 }
00414
00415 void ObstacleLayer::updateFootprint(double robot_x, double robot_y, double robot_yaw, double* min_x, double* min_y,
00416 double* max_x, double* max_y)
00417 {
00418 if (!footprint_clearing_enabled_) return;
00419 transformFootprint(robot_x, robot_y, robot_yaw, getFootprint(), transformed_footprint_);
00420
00421 for (unsigned int i = 0; i < transformed_footprint_.size(); i++)
00422 {
00423 touch(transformed_footprint_[i].x, transformed_footprint_[i].y, min_x, min_y, max_x, max_y);
00424 }
00425 }
00426
00427 void ObstacleLayer::updateCosts(costmap_2d::Costmap2D& master_grid, int min_i, int min_j, int max_i, int max_j)
00428 {
00429 if (!enabled_)
00430 return;
00431
00432 if (footprint_clearing_enabled_)
00433 {
00434 setConvexPolygonCost(transformed_footprint_, costmap_2d::FREE_SPACE);
00435 }
00436
00437 switch (combination_method_)
00438 {
00439 case 0:
00440 updateWithOverwrite(master_grid, min_i, min_j, max_i, max_j);
00441 break;
00442 case 1:
00443 updateWithMax(master_grid, min_i, min_j, max_i, max_j);
00444 break;
00445 default:
00446 break;
00447 }
00448 }
00449
00450 void ObstacleLayer::addStaticObservation(costmap_2d::Observation& obs, bool marking, bool clearing)
00451 {
00452 if (marking)
00453 static_marking_observations_.push_back(obs);
00454 if (clearing)
00455 static_clearing_observations_.push_back(obs);
00456 }
00457
00458 void ObstacleLayer::clearStaticObservations(bool marking, bool clearing)
00459 {
00460 if (marking)
00461 static_marking_observations_.clear();
00462 if (clearing)
00463 static_clearing_observations_.clear();
00464 }
00465
00466 bool ObstacleLayer::getMarkingObservations(std::vector<Observation>& marking_observations) const
00467 {
00468 bool current = true;
00469
00470 for (unsigned int i = 0; i < marking_buffers_.size(); ++i)
00471 {
00472 marking_buffers_[i]->lock();
00473 marking_buffers_[i]->getObservations(marking_observations);
00474 current = marking_buffers_[i]->isCurrent() && current;
00475 marking_buffers_[i]->unlock();
00476 }
00477 marking_observations.insert(marking_observations.end(),
00478 static_marking_observations_.begin(), static_marking_observations_.end());
00479 return current;
00480 }
00481
00482 bool ObstacleLayer::getClearingObservations(std::vector<Observation>& clearing_observations) const
00483 {
00484 bool current = true;
00485
00486 for (unsigned int i = 0; i < clearing_buffers_.size(); ++i)
00487 {
00488 clearing_buffers_[i]->lock();
00489 clearing_buffers_[i]->getObservations(clearing_observations);
00490 current = clearing_buffers_[i]->isCurrent() && current;
00491 clearing_buffers_[i]->unlock();
00492 }
00493 clearing_observations.insert(clearing_observations.end(),
00494 static_clearing_observations_.begin(), static_clearing_observations_.end());
00495 return current;
00496 }
00497
00498 void ObstacleLayer::raytraceFreespace(const Observation& clearing_observation, double* min_x, double* min_y,
00499 double* max_x, double* max_y)
00500 {
00501 double ox = clearing_observation.origin_.x;
00502 double oy = clearing_observation.origin_.y;
00503 pcl::PointCloud < pcl::PointXYZ > cloud = *(clearing_observation.cloud_);
00504
00505
00506 unsigned int x0, y0;
00507 if (!worldToMap(ox, oy, x0, y0))
00508 {
00509 ROS_WARN_THROTTLE(
00510 1.0, "The origin for the sensor at (%.2f, %.2f) is out of map bounds. So, the costmap cannot raytrace for it.",
00511 ox, oy);
00512 return;
00513 }
00514
00515
00516 double origin_x = origin_x_, origin_y = origin_y_;
00517 double map_end_x = origin_x + size_x_ * resolution_;
00518 double map_end_y = origin_y + size_y_ * resolution_;
00519
00520
00521 touch(ox, oy, min_x, min_y, max_x, max_y);
00522
00523
00524 for (unsigned int i = 0; i < cloud.points.size(); ++i)
00525 {
00526 double wx = cloud.points[i].x;
00527 double wy = cloud.points[i].y;
00528
00529
00530
00531 double a = wx - ox;
00532 double b = wy - oy;
00533
00534
00535 if (wx < origin_x)
00536 {
00537 double t = (origin_x - ox) / a;
00538 wx = origin_x;
00539 wy = oy + b * t;
00540 }
00541 if (wy < origin_y)
00542 {
00543 double t = (origin_y - oy) / b;
00544 wx = ox + a * t;
00545 wy = origin_y;
00546 }
00547
00548
00549 if (wx > map_end_x)
00550 {
00551 double t = (map_end_x - ox) / a;
00552 wx = map_end_x - .001;
00553 wy = oy + b * t;
00554 }
00555 if (wy > map_end_y)
00556 {
00557 double t = (map_end_y - oy) / b;
00558 wx = ox + a * t;
00559 wy = map_end_y - .001;
00560 }
00561
00562
00563 unsigned int x1, y1;
00564
00565
00566 if (!worldToMap(wx, wy, x1, y1))
00567 continue;
00568
00569 unsigned int cell_raytrace_range = cellDistance(clearing_observation.raytrace_range_);
00570 MarkCell marker(costmap_, FREE_SPACE);
00571
00572 raytraceLine(marker, x0, y0, x1, y1, cell_raytrace_range);
00573
00574 updateRaytraceBounds(ox, oy, wx, wy, clearing_observation.raytrace_range_, min_x, min_y, max_x, max_y);
00575 }
00576 }
00577
00578 void ObstacleLayer::activate()
00579 {
00580
00581 for (unsigned int i = 0; i < observation_subscribers_.size(); ++i)
00582 {
00583 if (observation_subscribers_[i] != NULL)
00584 observation_subscribers_[i]->subscribe();
00585 }
00586
00587 for (unsigned int i = 0; i < observation_buffers_.size(); ++i)
00588 {
00589 if (observation_buffers_[i])
00590 observation_buffers_[i]->resetLastUpdated();
00591 }
00592 }
00593 void ObstacleLayer::deactivate()
00594 {
00595 for (unsigned int i = 0; i < observation_subscribers_.size(); ++i)
00596 {
00597 if (observation_subscribers_[i] != NULL)
00598 observation_subscribers_[i]->unsubscribe();
00599 }
00600 }
00601
00602 void ObstacleLayer::updateRaytraceBounds(double ox, double oy, double wx, double wy, double range,
00603 double* min_x, double* min_y, double* max_x, double* max_y)
00604 {
00605 double dx = wx-ox, dy = wy-oy;
00606 double full_distance = hypot(dx, dy);
00607 double scale = std::min(1.0, range / full_distance);
00608 double ex = ox + dx * scale, ey = oy + dy * scale;
00609 touch(ex, ey, min_x, min_y, max_x, max_y);
00610 }
00611
00612 void ObstacleLayer::reset()
00613 {
00614 deactivate();
00615 resetMaps();
00616 current_ = true;
00617 activate();
00618 }
00619
00620 }