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 <cmath>
00038 #include <moveit/pointcloud_octomap_updater/pointcloud_octomap_updater.h>
00039 #include <moveit/occupancy_map_monitor/occupancy_map_monitor.h>
00040 #include <message_filters/subscriber.h>
00041 #include <pcl_conversions/pcl_conversions.h>
00042 #include <XmlRpcException.h>
00043
00044 namespace occupancy_map_monitor
00045 {
00046
00047 PointCloudOctomapUpdater::PointCloudOctomapUpdater() : OccupancyMapUpdater("PointCloudUpdater"),
00048 private_nh_("~"),
00049 scale_(1.0),
00050 padding_(0.0),
00051 max_range_(std::numeric_limits<double>::infinity()),
00052 point_subsample_(1),
00053 point_cloud_subscriber_(NULL),
00054 point_cloud_filter_(NULL)
00055 {
00056 }
00057
00058 PointCloudOctomapUpdater::~PointCloudOctomapUpdater()
00059 {
00060 stopHelper();
00061 }
00062
00063 bool PointCloudOctomapUpdater::setParams(XmlRpc::XmlRpcValue ¶ms)
00064 {
00065 try
00066 {
00067 if (!params.hasMember("point_cloud_topic"))
00068 return false;
00069 point_cloud_topic_ = static_cast<const std::string&>(params["point_cloud_topic"]);
00070
00071 readXmlParam(params, "max_range", &max_range_);
00072 readXmlParam(params, "padding_offset", &padding_);
00073 readXmlParam(params, "padding_scale", &scale_);
00074 readXmlParam(params, "point_subsample", &point_subsample_);
00075 if (params.hasMember("filtered_cloud_topic"))
00076 filtered_cloud_topic_ = static_cast<const std::string&>(params["filtered_cloud_topic"]);
00077 }
00078 catch (XmlRpc::XmlRpcException &ex)
00079 {
00080 ROS_ERROR("XmlRpc Exception: %s", ex.getMessage().c_str());
00081 return false;
00082 }
00083
00084 return true;
00085 }
00086
00087 bool PointCloudOctomapUpdater::initialize()
00088 {
00089 tf_ = monitor_->getTFClient();
00090 shape_mask_.reset(new point_containment_filter::ShapeMask());
00091 shape_mask_->setTransformCallback(boost::bind(&PointCloudOctomapUpdater::getShapeTransform, this, _1, _2));
00092 if (!filtered_cloud_topic_.empty())
00093 filtered_cloud_publisher_ = private_nh_.advertise<sensor_msgs::PointCloud2>(filtered_cloud_topic_, 10, false);
00094 return true;
00095 }
00096
00097 void PointCloudOctomapUpdater::start()
00098 {
00099 if (point_cloud_subscriber_)
00100 return;
00101
00102 point_cloud_subscriber_ = new message_filters::Subscriber<sensor_msgs::PointCloud2>(root_nh_, point_cloud_topic_, 5);
00103 if (tf_ && !monitor_->getMapFrame().empty())
00104 {
00105 point_cloud_filter_ = new tf::MessageFilter<sensor_msgs::PointCloud2>(*point_cloud_subscriber_, *tf_, monitor_->getMapFrame(), 5);
00106 point_cloud_filter_->registerCallback(boost::bind(&PointCloudOctomapUpdater::cloudMsgCallback, this, _1));
00107 ROS_INFO("Listening to '%s' using message filter with target frame '%s'", point_cloud_topic_.c_str(), point_cloud_filter_->getTargetFramesString().c_str());
00108 }
00109 else
00110 {
00111 point_cloud_subscriber_->registerCallback(boost::bind(&PointCloudOctomapUpdater::cloudMsgCallback, this, _1));
00112 ROS_INFO("Listening to '%s'", point_cloud_topic_.c_str());
00113 }
00114 }
00115
00116 void PointCloudOctomapUpdater::stopHelper()
00117 {
00118 delete point_cloud_filter_;
00119 delete point_cloud_subscriber_;
00120 }
00121
00122 void PointCloudOctomapUpdater::stop()
00123 {
00124 stopHelper();
00125 point_cloud_filter_ = NULL;
00126 point_cloud_subscriber_ = NULL;
00127 }
00128
00129 ShapeHandle PointCloudOctomapUpdater::excludeShape(const shapes::ShapeConstPtr &shape)
00130 {
00131 ShapeHandle h = 0;
00132 if (shape_mask_)
00133 h = shape_mask_->addShape(shape, scale_, padding_);
00134 else
00135 ROS_ERROR("Shape filter not yet initialized!");
00136 return h;
00137 }
00138
00139 void PointCloudOctomapUpdater::forgetShape(ShapeHandle handle)
00140 {
00141 if (shape_mask_)
00142 shape_mask_->removeShape(handle);
00143 }
00144
00145 bool PointCloudOctomapUpdater::getShapeTransform(ShapeHandle h, Eigen::Affine3d &transform) const
00146 {
00147 ShapeTransformCache::const_iterator it = transform_cache_.find(h);
00148 if (it == transform_cache_.end())
00149 {
00150 ROS_ERROR("Internal error. Shape filter handle %u not found", h);
00151 return false;
00152 }
00153 transform = it->second;
00154 return true;
00155 }
00156
00157 void PointCloudOctomapUpdater::updateMask(const pcl::PointCloud<pcl::PointXYZ> &cloud, const Eigen::Vector3d &sensor_origin, std::vector<int> &mask)
00158 {
00159 }
00160
00161 void PointCloudOctomapUpdater::cloudMsgCallback(const sensor_msgs::PointCloud2::ConstPtr &cloud_msg)
00162 {
00163 ROS_DEBUG("Received a new point cloud message");
00164 ros::WallTime start = ros::WallTime::now();
00165
00166 if (monitor_->getMapFrame().empty())
00167 monitor_->setMapFrame(cloud_msg->header.frame_id);
00168
00169
00170 tf::StampedTransform map_H_sensor;
00171 if (monitor_->getMapFrame() == cloud_msg->header.frame_id)
00172 map_H_sensor.setIdentity();
00173 else
00174 {
00175 if (tf_)
00176 {
00177 try
00178 {
00179 tf_->lookupTransform(monitor_->getMapFrame(), cloud_msg->header.frame_id, cloud_msg->header.stamp, map_H_sensor);
00180 }
00181 catch (tf::TransformException& ex)
00182 {
00183 ROS_ERROR_STREAM("Transform error of sensor data: " << ex.what() << "; quitting callback");
00184 return;
00185 }
00186 }
00187 else
00188 return;
00189 }
00190
00191
00192 pcl::PointCloud<pcl::PointXYZ> cloud;
00193 pcl::fromROSMsg(*cloud_msg, cloud);
00194
00195
00196 const tf::Vector3 &sensor_origin_tf = map_H_sensor.getOrigin();
00197 octomap::point3d sensor_origin(sensor_origin_tf.getX(), sensor_origin_tf.getY(), sensor_origin_tf.getZ());
00198 Eigen::Vector3d sensor_origin_eigen(sensor_origin_tf.getX(), sensor_origin_tf.getY(), sensor_origin_tf.getZ());
00199
00200 if (!updateTransformCache(cloud_msg->header.frame_id, cloud_msg->header.stamp))
00201 {
00202 ROS_ERROR_THROTTLE(1, "Transform cache was not updated. Self-filtering may fail.");
00203 return;
00204 }
00205
00206
00207 shape_mask_->maskContainment(cloud, sensor_origin_eigen, 0.0, max_range_, mask_);
00208 updateMask(cloud, sensor_origin_eigen, mask_);
00209
00210 octomap::KeySet free_cells, occupied_cells, model_cells, clip_cells;
00211 boost::scoped_ptr<pcl::PointCloud<pcl::PointXYZ> > filtered_cloud;
00212 if (!filtered_cloud_topic_.empty())
00213 filtered_cloud.reset(new pcl::PointCloud<pcl::PointXYZ>());
00214
00215 tree_->lockRead();
00216
00217 try
00218 {
00219
00220
00221 for (unsigned int row = 0; row < cloud.height; row += point_subsample_)
00222 {
00223 unsigned int row_c = row * cloud.width;
00224 for (unsigned int col = 0; col < cloud.width; col += point_subsample_)
00225 {
00226
00227
00228 const pcl::PointXYZ &p = cloud(col, row);
00229
00230
00231 if (!isnan(p.x) && !isnan(p.y) && !isnan(p.z))
00232 {
00233
00234 tf::Vector3 point_tf = map_H_sensor * tf::Vector3(p.x, p.y, p.z);
00235
00236
00237
00238 if (mask_[row_c + col] == point_containment_filter::ShapeMask::INSIDE)
00239 model_cells.insert(tree_->coordToKey(point_tf.getX(), point_tf.getY(), point_tf.getZ()));
00240 else if (mask_[row_c + col] == point_containment_filter::ShapeMask::CLIP)
00241 clip_cells.insert(tree_->coordToKey(point_tf.getX(), point_tf.getY(), point_tf.getZ()));
00242 else
00243 {
00244 occupied_cells.insert(tree_->coordToKey(point_tf.getX(), point_tf.getY(), point_tf.getZ()));
00245 if (filtered_cloud)
00246 filtered_cloud->push_back(p);
00247 }
00248 }
00249 }
00250 }
00251
00252
00253 for (octomap::KeySet::iterator it = occupied_cells.begin(), end = occupied_cells.end(); it != end; ++it)
00254 if (tree_->computeRayKeys(sensor_origin, tree_->keyToCoord(*it), key_ray_))
00255 free_cells.insert(key_ray_.begin(), key_ray_.end());
00256
00257
00258 for (octomap::KeySet::iterator it = model_cells.begin(), end = model_cells.end(); it != end; ++it)
00259 if (tree_->computeRayKeys(sensor_origin, tree_->keyToCoord(*it), key_ray_))
00260 free_cells.insert(key_ray_.begin(), key_ray_.end());
00261
00262
00263 for (octomap::KeySet::iterator it = clip_cells.begin(), end = clip_cells.end(); it != end; ++it)
00264 if (tree_->computeRayKeys(sensor_origin, tree_->keyToCoord(*it), key_ray_))
00265 free_cells.insert(key_ray_.begin(), key_ray_.end());
00266 }
00267 catch (...)
00268 {
00269 tree_->unlockRead();
00270 return;
00271 }
00272
00273 tree_->unlockRead();
00274
00275
00276 for (octomap::KeySet::iterator it = model_cells.begin(), end = model_cells.end(); it != end; ++it)
00277 occupied_cells.erase(*it);
00278
00279
00280 for (octomap::KeySet::iterator it = occupied_cells.begin(), end = occupied_cells.end(); it != end; ++it)
00281 free_cells.erase(*it);
00282
00283 tree_->lockWrite();
00284
00285 try
00286 {
00287
00288 for (octomap::KeySet::iterator it = free_cells.begin(), end = free_cells.end(); it != end; ++it)
00289 tree_->updateNode(*it, false);
00290
00291
00292 for (octomap::KeySet::iterator it = occupied_cells.begin(), end = occupied_cells.end(); it != end; ++it)
00293 tree_->updateNode(*it, true);
00294
00295
00296 const float lg = tree_->getClampingThresMinLog() - tree_->getClampingThresMaxLog();
00297 for (octomap::KeySet::iterator it = model_cells.begin(), end = model_cells.end(); it != end; ++it)
00298 tree_->updateNode(*it, lg);
00299 }
00300 catch (...)
00301 {
00302 ROS_ERROR("Internal error while updating octree");
00303 }
00304 tree_->unlockWrite();
00305 ROS_DEBUG("Processed point cloud in %lf ms", (ros::WallTime::now() - start).toSec() * 1000.0);
00306 tree_->triggerUpdateCallback();
00307
00308 if (filtered_cloud)
00309 {
00310 sensor_msgs::PointCloud2 filtered_cloud_msg;
00311 pcl::toROSMsg(*filtered_cloud, filtered_cloud_msg);
00312 filtered_cloud_msg.header = cloud_msg->header;
00313 filtered_cloud_publisher_.publish(filtered_cloud_msg);
00314 }
00315 }
00316
00317 }