37 #include <sensor_msgs/LaserScan.h>    38 #include <sensor_msgs/PointCloud2.h>    64                 scanCloudMaxPoints_(0),
    65                 scanCloudIs2d_(
false),
    66                 scanDownsamplingStep_(1),
    71                 scanNormalRadius_(0.0),
    72                 scanNormalGroundUp_(0.0),
    74                 deskewingSlerp_(
false),
    75                 plugin_loader_(
"rtabmap_ros", 
"rtabmap_ros::PluginInterface"),
    94                 pnh.
param(
"queue_size",  queueSize, queueSize);
    95                 pnh.
param(
"scan_cloud_max_points",  scanCloudMaxPoints_, scanCloudMaxPoints_);
    96                 pnh.
param(
"scan_cloud_is_2d",  scanCloudIs2d_, scanCloudIs2d_);
    97                 pnh.
param(
"scan_downsampling_step", scanDownsamplingStep_, scanDownsamplingStep_);
    98                 pnh.
param(
"scan_range_min",  scanRangeMin_, scanRangeMin_);
    99                 pnh.
param(
"scan_range_max",  scanRangeMax_, scanRangeMax_);
   100                 pnh.
param(
"scan_voxel_size", scanVoxelSize_, scanVoxelSize_);
   101                 pnh.
param(
"scan_normal_k",   scanNormalK_, scanNormalK_);
   102                 pnh.
param(
"scan_normal_radius", scanNormalRadius_, scanNormalRadius_);
   103                 pnh.
param(
"scan_normal_ground_up", scanNormalGroundUp_, scanNormalGroundUp_);
   104                 pnh.
param(
"deskewing",  deskewing_, deskewing_);
   105                 pnh.
param(
"deskewing_slerp",  deskewingSlerp_, deskewingSlerp_);
   110                         pnh.
getParam(
"plugins", pluginsList);
   114                                 std::string pluginName = 
static_cast<std::string
>(pluginsList[i][
"name"]);
   115                                 std::string type = 
static_cast<std::string
>(pluginsList[i][
"type"]);
   116                                 NODELET_INFO(
"IcpOdometry: Using plugin %s of type \"%s\"", pluginName.c_str(), type.c_str());
   119                                         plugins_.push_back(plugin);
   120                                         plugin->initialize(pluginName, pnh);
   121                                         if(!plugin->isEnabled())
   123                                                 NODELET_WARN(
"Plugin: %s is not enabled, filtering will not occur. \"enabled_\" member "   124                                                                          "should be managed in subclasses. This can be ignored if the "   125                                                                          "plugin should really be initialized as disabled.",
   126                                                                          plugin->getName().c_str());
   130                                         ROS_ERROR(
"Failed to load plugin %s. Error: %s", pluginName.c_str(), ex.what());
   138                         ROS_WARN(
"rtabmap: Parameter \"scan_cloud_normal_k\" has been renamed to \"scan_normal_k\". "   139                                         "The value is still used. Use \"scan_normal_k\" to avoid this warning.");
   140                         pnh.
param(
"scan_cloud_normal_k", scanNormalK_, scanNormalK_);
   143                 NODELET_INFO(
"IcpOdometry: queue_size             = %d", queueSize);
   144                 NODELET_INFO(
"IcpOdometry: scan_cloud_max_points  = %d", scanCloudMaxPoints_);
   145                 NODELET_INFO(
"IcpOdometry: scan_cloud_is_2d       = %s", scanCloudIs2d_?
"true":
"false");
   146                 NODELET_INFO(
"IcpOdometry: scan_downsampling_step = %d", scanDownsamplingStep_);
   147                 NODELET_INFO(
"IcpOdometry: scan_range_min         = %f m", scanRangeMin_);
   148                 NODELET_INFO(
"IcpOdometry: scan_range_max         = %f m", scanRangeMax_);
   149                 NODELET_INFO(
"IcpOdometry: scan_voxel_size        = %f m", scanVoxelSize_);
   150                 NODELET_INFO(
"IcpOdometry: scan_normal_k          = %d", scanNormalK_);
   151                 NODELET_INFO(
"IcpOdometry: scan_normal_radius     = %f m", scanNormalRadius_);
   152                 NODELET_INFO(
"IcpOdometry: scan_normal_ground_up  = %f", scanNormalGroundUp_);
   153                 NODELET_INFO(
"IcpOdometry: deskewing              = %s", deskewing_?
"true":
"false");
   154                 NODELET_INFO(
"IcpOdometry: deskewing_slerp        = %s", deskewingSlerp_?
"true":
"false");
   156                 scan_sub_ = nh.
subscribe(
"scan", queueSize, &ICPOdometry::callbackScan, 
this);
   157                 cloud_sub_ = nh.
subscribe(
"scan_cloud", queueSize, &ICPOdometry::callbackCloud, 
this);
   159                 filtered_scan_pub_ = nh.
advertise<sensor_msgs::PointCloud2>(
"odom_filtered_input_scan", 1);
   165                 ParametersMap::iterator iter = parameters.find(Parameters::kRegStrategy());
   166                 if(iter != parameters.end() && iter->second.compare(
"1") != 0)
   168                         ROS_WARN(
"ICP odometry works only with \"Reg/Strategy\"=1. Ignoring value %s.", iter->second.c_str());
   173                 iter = parameters.find(Parameters::kIcpDownsamplingStep());
   174                 if(iter != parameters.end())
   179                                 if(!pnh.
hasParam(
"scan_downsampling_step"))
   181                                         ROS_WARN(
"IcpOdometry: Transferring value %s of \"%s\" to ros parameter \"scan_downsampling_step\" for convenience. \"%s\" is set to 1.", iter->second.c_str(), iter->first.c_str(), iter->first.c_str());
   182                                         scanDownsamplingStep_ = value;
   187                                         ROS_WARN(
"IcpOdometry: Both parameter \"%s\" and ros parameter \"scan_downsampling_step\" are set.", iter->first.c_str());
   191                 iter = parameters.find(Parameters::kIcpRangeMin());
   192                 if(iter != parameters.end())
   199                                         ROS_WARN(
"IcpOdometry: Transferring value %s of \"%s\" to ros parameter \"scan_range_min\" for convenience. \"%s\" is set to 0.", iter->second.c_str(), iter->first.c_str(), iter->first.c_str());
   200                                         scanRangeMin_ = value;
   205                                         ROS_WARN(
"IcpOdometry: Both parameter \"%s\" and ros parameter \"scan_range_min\" are set.", iter->first.c_str());
   209                 iter = parameters.find(Parameters::kIcpRangeMax());
   210                 if(iter != parameters.end())
   217                                         ROS_WARN(
"IcpOdometry: Transferring value %s of \"%s\" to ros parameter \"scan_range_max\" for convenience. \"%s\" is set to 0.", iter->second.c_str(), iter->first.c_str(), iter->first.c_str());
   218                                         scanRangeMax_ = value;
   223                                         ROS_WARN(
"IcpOdometry: Both parameter \"%s\" and ros parameter \"scan_range_max\" are set.", iter->first.c_str());
   227                 iter = parameters.find(Parameters::kIcpVoxelSize());
   228                 if(iter != parameters.end())
   233                                 if(!pnh.
hasParam(
"scan_voxel_size"))
   235                                         ROS_WARN(
"IcpOdometry: Transferring value %s of \"%s\" to ros parameter \"scan_voxel_size\" for convenience. \"%s\" is set to 0.", iter->second.c_str(), iter->first.c_str(), iter->first.c_str());
   236                                         scanVoxelSize_ = value;
   241                                         ROS_WARN(
"IcpOdometry: Both parameter \"%s\" and ros parameter \"scan_voxel_size\" are set.", iter->first.c_str());
   245                 else if(pnh.
hasParam(
"scan_voxel_size"))
   247                         NODELET_INFO(
"IcpOdometry: scan_voxel_size is set (%f), setting %s to 0", scanVoxelSize_, Parameters::kIcpVoxelSize().c_str());
   248                         parameters.insert(
ParametersPair(Parameters::kIcpVoxelSize(), 
"0"));
   250                 iter = parameters.find(Parameters::kIcpPointToPlaneK());
   251                 if(iter != parameters.end())
   258                                         ROS_WARN(
"IcpOdometry: Transferring value %s of \"%s\" to ros parameter \"scan_normal_k\" for convenience.", iter->second.c_str(), iter->first.c_str());
   259                                         scanNormalK_ = value;
   263                                         NODELET_INFO(
"IcpOdometry: scan_normal_k is set (%d), setting %s to same value.", scanNormalK_, Parameters::kIcpPointToPlaneK().c_str());
   268                 else if(pnh.
hasParam(
"scan_normal_k"))
   270                         NODELET_INFO(
"IcpOdometry: scan_normal_k is set (%d), setting %s to same value.", scanNormalK_, Parameters::kIcpPointToPlaneK().c_str());
   273                 iter = parameters.find(Parameters::kIcpPointToPlaneRadius());
   274                 if(iter != parameters.end())
   279                                 if(!pnh.
hasParam(
"scan_normal_radius"))
   281                                         ROS_WARN(
"IcpOdometry: Transferring value %s of \"%s\" to ros parameter \"scan_normal_radius\" for convenience.", iter->second.c_str(), iter->first.c_str());
   282                                         scanNormalRadius_ = value;
   286                                         NODELET_INFO(
"IcpOdometry: scan_normal_radius is set (%f), setting %s to same value.", scanNormalRadius_, Parameters::kIcpPointToPlaneRadius().c_str());
   291                 else if(pnh.
hasParam(
"scan_normal_radius"))
   293                         NODELET_INFO(
"IcpOdometry: scan_normal_radius is set (%f), setting %s to same value.", scanNormalRadius_, Parameters::kIcpPointToPlaneRadius().c_str());
   296                 iter = parameters.find(Parameters::kIcpPointToPlaneGroundNormalsUp());
   297                 if(iter != parameters.end())
   302                                 if(!pnh.
hasParam(
"scan_normal_ground_up"))
   304                                         ROS_WARN(
"IcpOdometry: Transferring value %s of \"%s\" to ros parameter \"scan_normal_ground_up\" for convenience.", iter->second.c_str(), iter->first.c_str());
   305                                         scanNormalGroundUp_ = value;
   309                                         NODELET_INFO(
"IcpOdometry: scan_normal_ground_up is set (%f), setting %s to same value.", scanNormalGroundUp_, Parameters::kIcpPointToPlaneGroundNormalsUp().c_str());
   314                 else if(pnh.
hasParam(
"scan_normal_ground_up"))
   316                         NODELET_INFO(
"IcpOdometry: scan_normal_ground_up is set (%f), setting %s to same value.", scanNormalGroundUp_, Parameters::kIcpPointToPlaneGroundNormalsUp().c_str());
   325                         ROS_ERROR(
"%s is already receiving clouds on \"%s\", but also "   326                                         "just received a scan on \"%s\". Both subscribers cannot be "   327                                         "used at the same time! Disabling scan subscriber.",
   328                                         this->
getName().c_str(), cloud_sub_.getTopic().c_str(), scan_sub_.getTopic().c_str());
   329                         scan_sub_.shutdown();
   332                 scanReceived_ = 
true;
   340                                 scanMsg->header.frame_id,
   341                                 scanMsg->header.stamp,
   343                                 this->waitForTransformDuration());
   344                 if(localScanTransform.
isNull())
   346                         ROS_ERROR(
"TF of received laser scan topic at time %fs is not set, aborting odometry update.", scanMsg->header.stamp.toSec());
   351                 sensor_msgs::PointCloud2 scanOut;
   354                 if(deskewing_ && (!guessFrameId().empty() || (
frameId().compare(scanMsg->header.frame_id) != 0)))
   358                                         scanMsg->header.frame_id,
   359                                         guessFrameId().empty()?
frameId():guessFrameId(),
   360                                         scanMsg->header.stamp,
   361                                         scanMsg->header.stamp + 
ros::Duration().
fromSec(scanMsg->ranges.size()*scanMsg->time_increment),
   363                                         this->waitForTransformDuration());
   370                                         guessFrameId().empty()?
frameId():guessFrameId(),
   376                         if(guessFrameId().empty() && previousStamp() > 0 && !velocityGuess().
isNull())
   379                                 sensor_msgs::PointCloud2 scanOutDeskewed;
   380                                 if(!
deskew(scanOut, scanOutDeskewed, previousStamp(), velocityGuess()))
   382                                         ROS_ERROR(
"Failed to deskew input cloud, aborting odometry update!");
   385                                 scanOut = scanOutDeskewed;
   388                         sensor_msgs::PointCloud2 scanOutDeskewed;
   391                                 ROS_ERROR(
"Cannot transform back projected scan from \"%s\" frame to \"%s\" frame at time %fs.",
   392                                                 (guessFrameId().empty()?
frameId():guessFrameId()).c_str(), scanMsg->header.frame_id.c_str(), scanMsg->header.stamp.toSec());
   395                         scanOut = scanOutDeskewed;
   401                         if(deskewing_ && previousStamp() > 0 && !velocityGuess().
isNull())
   404                                 sensor_msgs::PointCloud2 scanOutDeskewed;
   405                                 if(!
deskew(scanOut, scanOutDeskewed, previousStamp(), velocityGuess()))
   407                                         ROS_ERROR(
"Failed to deskew input cloud, aborting odometry update!");
   410                                 scanOut = scanOutDeskewed;
   414                 bool hasIntensity = 
false;
   415                 for(
unsigned int i=0; i<scanOut.fields.size(); ++i)
   417                         if(scanOut.fields[i].name.compare(
"intensity") == 0)
   419                                 if(scanOut.fields[i].datatype == sensor_msgs::PointField::FLOAT32)
   425                                         static bool warningShown = 
false;
   428                                                 ROS_WARN(
"The input scan cloud has an \"intensity\" field "   429                                                                 "but the datatype (%d) is not supported. Intensity will be ignored. "   430                                                                 "This message is only shown once.", scanOut.fields[i].datatype);
   437                 pcl::PointCloud<pcl::PointXYZI>::Ptr pclScanI(
new pcl::PointCloud<pcl::PointXYZI>);
   438                 pcl::PointCloud<pcl::PointXYZ>::Ptr pclScan(
new pcl::PointCloud<pcl::PointXYZ>);
   443                         pclScanI->is_dense = 
true;
   448                         pclScan->is_dense = 
true;
   452                 int maxLaserScans = (int)scanMsg->ranges.
size();
   453                 if(!pclScan->empty() || !pclScanI->empty())
   455                         if(scanDownsamplingStep_ > 1)
   465                                 maxLaserScans /= scanDownsamplingStep_;
   467                         if(scanVoxelSize_ > 0.0
f)
   469                                 float pointsBeforeFiltering;
   470                                 float pointsAfterFiltering;
   473                                         pointsBeforeFiltering = (float)pclScanI->size();
   475                                         pointsAfterFiltering = (float)pclScanI->size();
   479                                         pointsBeforeFiltering = (float)pclScan->size();
   481                                         pointsAfterFiltering = (float)pclScan->size();
   483                                 float ratio = pointsAfterFiltering / pointsBeforeFiltering;
   484                                 maxLaserScans = int(
float(maxLaserScans) * ratio);
   486                         if(scanNormalK_ > 0 || scanNormalRadius_>0.0
f)
   489                                 pcl::PointCloud<pcl::Normal>::Ptr normals;
   490                                 if(scanVoxelSize_ > 0.0
f)
   512                                 pcl::PointCloud<pcl::PointXYZINormal>::Ptr pclScanINormal;
   513                                 pcl::PointCloud<pcl::PointNormal>::Ptr pclScanNormal;
   516                                         pclScanINormal.reset(
new pcl::PointCloud<pcl::PointXYZINormal>);
   517                                         pcl::concatenateFields(*pclScanI, *normals, *pclScanINormal);
   522                                         pclScanNormal.reset(
new pcl::PointCloud<pcl::PointNormal>);
   523                                         pcl::concatenateFields(*pclScan, *normals, *pclScanNormal);
   540                 if(scanRangeMin_ > 0 || scanRangeMax_ > 0)
   548                                                 scanRangeMax_>0&&scanRangeMax_<scanMsg->range_max?scanRangeMax_:scanMsg->range_max,
   556                 this->processData(data, scanMsg->header);
   561                 UASSERT_MSG(pointCloudMsg->data.size() == pointCloudMsg->row_step*pointCloudMsg->height,
   562                                 uFormat(
"data=%d row_step=%d height=%d", pointCloudMsg->data.size(), pointCloudMsg->row_step, pointCloudMsg->height).c_str());
   566                         ROS_ERROR(
"%s is already receiving scans on \"%s\", but also "   567                                         "just received a cloud on \"%s\". Both subscribers cannot be "   568                                         "used at the same time! Disabling cloud subscriber.",
   569                                         this->
getName().c_str(), scan_sub_.getTopic().c_str(), cloud_sub_.getTopic().c_str());
   570                         cloud_sub_.shutdown();
   573                 cloudReceived_ = 
true;
   579                 sensor_msgs::PointCloud2::Ptr cloudMsg(
new sensor_msgs::PointCloud2);
   580                 if (!plugins_.empty())
   582                         if (plugins_[0]->isEnabled())
   584                                 *cloudMsg = plugins_[0]->filterPointCloud(*pointCloudMsg);
   588                                 *cloudMsg = *pointCloudMsg;
   591                         if (plugins_.size() > 1)
   593                                 for (
int i = 1; i < plugins_.size(); i++) {
   594                                         if (plugins_[i]->isEnabled()) {
   595                                                 *cloudMsg = plugins_[i]->filterPointCloud(*cloudMsg);
   602                         *cloudMsg = *pointCloudMsg;
   605                 Transform localScanTransform = 
getTransform(this->
frameId(), cloudMsg->header.frame_id, cloudMsg->header.stamp, this->tfListener(), this->waitForTransformDuration());
   606                 if(localScanTransform.
isNull())
   608                         ROS_ERROR(
"TF of received scan cloud at time %fs is not set, aborting rtabmap update.", cloudMsg->header.stamp.toSec());
   614                         if(!guessFrameId().empty())
   617                                 if(!
deskew(*pointCloudMsg, *cloudMsg, guessFrameId(), tfListener(), waitForTransformDuration(), deskewingSlerp_))
   619                                         ROS_ERROR(
"Failed to deskew input cloud, aborting odometry update!");
   623                         else if(previousStamp() > 0 && !velocityGuess().
isNull())
   626                                 bool alreadyInBaseFrame = 
frameId().compare(pointCloudMsg->header.frame_id) == 0;
   627                                 sensor_msgs::PointCloud2Ptr cloudInBaseFrame;
   628                                 sensor_msgs::PointCloud2Ptr cloudPtr = cloudMsg;
   629                                 if(!alreadyInBaseFrame)
   632                                         cloudInBaseFrame.reset(
new sensor_msgs::PointCloud2);
   635                                                 ROS_ERROR(
"Cannot transform back projected scan from \"%s\" frame to \"%s\" frame at time %fs.",
   636                                                                 pointCloudMsg->header.frame_id.c_str(), 
frameId().c_str(), pointCloudMsg->header.stamp.toSec());
   639                                         cloudPtr = cloudInBaseFrame;
   642                                 sensor_msgs::PointCloud2::Ptr cloudDeskewed(
new sensor_msgs::PointCloud2);
   643                                 if(!
deskew(*cloudPtr, *cloudDeskewed, previousStamp(), velocityGuess()))
   645                                         ROS_ERROR(
"Failed to deskew input cloud, aborting odometry update!");
   649                                 if(!alreadyInBaseFrame)
   654                                                 ROS_ERROR(
"Cannot transform back projected scan from \"%s\" frame to \"%s\" frame at time %fs.",
   655                                                                 frameId().c_str(), pointCloudMsg->header.frame_id.c_str(), pointCloudMsg->header.stamp.toSec());
   661                                         cloudMsg = cloudDeskewed;
   667                 bool hasNormals = 
false;
   668                 bool hasIntensity = 
false;
   670                 for(
unsigned int i=0; i<cloudMsg->fields.size(); ++i)
   672                         if(scanVoxelSize_ == 0.0
f && cloudMsg->fields[i].name.compare(
"normal_x") == 0)
   676                         if(cloudMsg->fields[i].name.compare(
"z") == 0 && !scanCloudIs2d_)
   680                         if(cloudMsg->fields[i].name.compare(
"intensity") == 0)
   682                                 if(cloudMsg->fields[i].datatype == sensor_msgs::PointField::FLOAT32)
   688                                         static bool warningShown = 
false;
   691                                                 ROS_WARN(
"The input scan cloud has an \"intensity\" field "   692                                                                 "but the datatype (%d) is not supported. Intensity will be ignored. "   693                                                                 "This message is only shown once.", cloudMsg->fields[i].datatype);
   700                 if(scanCloudMaxPoints_ == 0 && cloudMsg->height > 1)
   702                         scanCloudMaxPoints_ = cloudMsg->height * cloudMsg->width;
   703                         NODELET_WARN(
"IcpOdometry: \"scan_cloud_max_points\" is not set but input "   704                                         "cloud is not dense, for convenience it will be set to %d (%dx%d)",
   705                                         scanCloudMaxPoints_, cloudMsg->width, cloudMsg->height);
   707                 else if(cloudMsg->height > 1 && scanCloudMaxPoints_ < cloudMsg->height * cloudMsg->width)
   709                         NODELET_WARN(
"IcpOdometry: \"scan_cloud_max_points\" is set to %d but input "   710                                         "cloud is not dense and has a size of %d (%dx%d), setting to this later size.",
   711                                         scanCloudMaxPoints_, cloudMsg->width *cloudMsg->height, cloudMsg->width, cloudMsg->height);
   712                         scanCloudMaxPoints_ = cloudMsg->width *cloudMsg->height;
   714                 int maxLaserScans = scanCloudMaxPoints_;
   716                 if(hasNormals && hasIntensity)
   718                         pcl::PointCloud<pcl::PointXYZINormal>::Ptr pclScan(
new pcl::PointCloud<pcl::PointXYZINormal>);
   720                         if(pclScan->size() && scanDownsamplingStep_ > 1)
   723                                 if(pclScan->height>1)
   725                                         maxLaserScans = pclScan->height * pclScan->width;
   729                                         maxLaserScans /= scanDownsamplingStep_;
   736                         pcl::PointCloud<pcl::PointNormal>::Ptr pclScan(
new pcl::PointCloud<pcl::PointNormal>);
   738                         if(pclScan->size() && scanDownsamplingStep_ > 1)
   741                                 if(pclScan->height>1)
   743                                         maxLaserScans = pclScan->height * pclScan->width;
   747                                         maxLaserScans /= scanDownsamplingStep_;
   752                 else if(hasIntensity)
   754                         pcl::PointCloud<pcl::PointXYZI>::Ptr pclScan(
new pcl::PointCloud<pcl::PointXYZI>);
   756                         if(pclScan->size() && scanDownsamplingStep_ > 1)
   759                                 if(pclScan->height>1)
   761                                         maxLaserScans = pclScan->height * pclScan->width;
   765                                         maxLaserScans /= scanDownsamplingStep_;
   768                         if(!pclScan->is_dense)
   775                                 if(scanVoxelSize_ > 0.0
f)
   777                                         float pointsBeforeFiltering = (float)pclScan->size();
   779                                         float ratio = float(pclScan->size()) / pointsBeforeFiltering;
   780                                         maxLaserScans = int(
float(maxLaserScans) * ratio);
   782                                 if(scanNormalK_ > 0 || scanNormalRadius_>0.0
f)
   785                                         pcl::PointCloud<pcl::Normal>::Ptr normals = is3D?
   788                                         pcl::PointCloud<pcl::PointXYZINormal>::Ptr pclScanNormal(
new pcl::PointCloud<pcl::PointXYZINormal>);
   789                                         pcl::concatenateFields(*pclScan, *normals, *pclScanNormal);
   800                         pcl::PointCloud<pcl::PointXYZ>::Ptr pclScan(
new pcl::PointCloud<pcl::PointXYZ>);
   802                         if(pclScan->size() && scanDownsamplingStep_ > 1)
   805                                 if(pclScan->height>1)
   807                                         maxLaserScans = pclScan->height * pclScan->width;
   811                                         maxLaserScans /= scanDownsamplingStep_;
   814                         if(!pclScan->is_dense)
   821                                 if(scanVoxelSize_ > 0.0
f)
   823                                         float pointsBeforeFiltering = (float)pclScan->size();
   825                                         float ratio = float(pclScan->size()) / pointsBeforeFiltering;
   826                                         maxLaserScans = int(
float(maxLaserScans) * ratio);
   828                                 if(scanNormalK_ > 0 || scanNormalRadius_>0.0
f)
   831                                         pcl::PointCloud<pcl::Normal>::Ptr normals = is3D?
   834                                         pcl::PointCloud<pcl::PointNormal>::Ptr pclScanNormal(
new pcl::PointCloud<pcl::PointNormal>);
   835                                         pcl::concatenateFields(*pclScan, *normals, *pclScanNormal);
   849                 if(scanRangeMin_ > 0 || scanRangeMax_ > 0)
   866                 this->processData(data, cloudMsg->header);
   877                 if(filtered_scan_pub_.getNumSubscribers())
   879                         sensor_msgs::PointCloud2 msg;
   882                         filtered_scan_pub_.publish(msg);
   901         std::vector<boost::shared_ptr<rtabmap_ros::PluginInterface> > 
plugins_;
   903         bool scanReceived_ = 
false;
   904         bool cloudReceived_ = 
false;
 
void projectLaser(const sensor_msgs::LaserScan &scan_in, sensor_msgs::PointCloud &cloud_out, double range_cutoff=-1.0, int channel_options=channel_option::Default)
std::string uFormat(const char *fmt,...)
virtual void flushCallbacks()
pcl::PointCloud< pcl::Normal >::Ptr RTABMAP_EXP computeNormals2D(const pcl::PointCloud< pcl::PointXYZ >::Ptr &cloud, int searchK=5, float searchRadius=0.0f, const Eigen::Vector3f &viewPoint=Eigen::Vector3f(0, 0, 0))
#define NODELET_WARN(...)
int scanDownsamplingStep_
Subscriber subscribe(const std::string &topic, uint32_t queue_size, void(T::*fp)(M), T *obj, const TransportHints &transport_hints=TransportHints())
std::pair< std::string, std::string > ParametersPair
double scanNormalGroundUp_
ros::Publisher filtered_scan_pub_
pcl::PointCloud< pcl::PointXYZ >::Ptr RTABMAP_EXP removeNaNFromPointCloud(const pcl::PointCloud< pcl::PointXYZ >::Ptr &cloud)
pcl::PCLPointCloud2::Ptr RTABMAP_EXP laserScanToPointCloud2(const LaserScan &laserScan, const Transform &transform=Transform())
ros::Subscriber scan_sub_
ROSCONSOLE_CONSOLE_IMPL_DECL std::string getName(void *handle)
void callbackCloud(const sensor_msgs::PointCloud2ConstPtr &pointCloudMsg)
void fromROSMsg(const sensor_msgs::PointCloud2 &cloud, pcl::PointCloud< T > &pcl_cloud)
bool deskew(const sensor_msgs::PointCloud2 &input, sensor_msgs::PointCloud2 &output, const std::string &fixedFrameId, tf::TransformListener &listener, double waitForTransform, bool slerp=false)
rtabmap::Transform getTransform(const std::string &fromFrameId, const std::string &toFrameId, const ros::Time &stamp, tf::TransformListener &listener, double waitForTransform)
ros::Subscriber cloud_sub_
pcl::PointCloud< pcl::Normal >::Ptr RTABMAP_EXP computeFastOrganizedNormals2D(const pcl::PointCloud< pcl::PointXYZ >::Ptr &cloud, int searchK=5, float searchRadius=0.0f, const Eigen::Vector3f &viewPoint=Eigen::Vector3f(0, 0, 0))
pluginlib::ClassLoader< rtabmap_ros::PluginInterface > plugin_loader_
void callbackScan(const sensor_msgs::LaserScanConstPtr &scanMsg)
GLM_FUNC_DECL bool isNull(detail::tmat2x2< T, P > const &m, T const &epsilon)
LaserScan RTABMAP_EXP downsample(const LaserScan &cloud, int step)
int uStr2Int(const std::string &str)
std::string uNumber2Str(unsigned int number)
bool param(const std::string ¶m_name, T ¶m_val, const T &default_val) const
#define UASSERT_MSG(condition, msg_str)
Duration & fromSec(double t)
bool getParam(const std::string &key, std::string &s) const
cv::Mat RTABMAP_EXP computeNormals(const cv::Mat &laserScan, int searchK, float searchRadius)
LaserScan laserScanFromPointCloud(const PointCloud2T &cloud, bool filterNaNs, bool is2D, const Transform &transform)
QMap< QString, QVariant > ParametersMap
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
bool hasParam(const std::string &key) const
virtual void onOdomInit()
#define NODELET_INFO(...)
const LaserScan & laserScanRaw() const
void transformPointCloud(const pcl::PointCloud< PointT > &cloud_in, pcl::PointCloud< PointT > &cloud_out, const tf::Transform &transform)
virtual void updateParameters(ParametersMap ¶meters)
LaserScan RTABMAP_EXP rangeFiltering(const LaserScan &scan, float rangeMin, float rangeMax)
double timestampFromROS(const ros::Time &stamp)
float uStr2Float(const std::string &str)
void transformLaserScanToPointCloud(const std::string &target_frame, const sensor_msgs::LaserScan &scan_in, sensor_msgs::PointCloud &cloud_out, tf::Transformer &tf, double range_cutoff, int channel_options=channel_option::Default)
void fromPCL(const std::uint64_t &pcl_stamp, ros::Time &stamp)
std::vector< boost::shared_ptr< rtabmap_ros::PluginInterface > > plugins_
pcl::PointCloud< pcl::PointXYZ >::Ptr RTABMAP_EXP voxelize(const pcl::PointCloud< pcl::PointXYZ >::Ptr &cloud, const pcl::IndicesPtr &indices, float voxelSize)
PLUGINLIB_EXPORT_CLASS(apriltag_ros::ContinuousDetector, nodelet::Nodelet)
LaserScan RTABMAP_EXP laserScan2dFromPointCloud(const pcl::PointCloud< pcl::PointXYZ > &cloud, const Transform &transform=Transform(), bool filterNaNs=true)
void uInsert(std::map< K, V > &map, const std::pair< K, V > &pair)
LaserScan RTABMAP_EXP adjustNormalsToViewPoint(const LaserScan &scan, const Eigen::Vector3f &viewpoint=Eigen::Vector3f(0, 0, 0), float groundNormalsUp=0.0f)
void postProcessData(const SensorData &data, const std_msgs::Header &header) const