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