32 #include <pcl/point_cloud.h> 33 #include <pcl/point_types.h> 35 #include <pcl/io/pcd_io.h> 36 #include <pcl/filters/voxel_grid.h> 37 #include <pcl/filters/radius_outlier_removal.h> 43 #include <nav_msgs/Odometry.h> 44 #include <sensor_msgs/PointCloud2.h> 51 #include <rtabmap_ros/OdomInfo.h> 54 #include <rtabmap/core/Version.h> 113 bool subscribeOdomInfo =
false;
115 pnh.
param(
"queue_size", queueSize, queueSize);
131 pnh.
param(
"subscribe_odom_info", subscribeOdomInfo, subscribeOdomInfo);
149 ROS_INFO(
"%s: remove_z=%s",
getName().c_str(),
removeZ_?
"true":
"false");
153 ROS_ERROR(
"point_cloud_assembler: max_cloud or assembling_time parameters should be set!");
159 std::string subscribedTopicsMsg;
163 subscribedTopicsMsg =
uFormat(
"\n%s subscribed to %s",
167 else if(subscribeOdomInfo)
174 subscribedTopicsMsg =
uFormat(
"\n%s subscribed to (exact sync):\n %s,\n %s",
176 syncCloudSub_.getTopic().c_str(),
177 syncOdomSub_.getTopic().c_str(),
188 subscribedTopicsMsg =
uFormat(
"\n%s subscribed to (exact sync):\n %s,\n %s",
190 syncCloudSub_.getTopic().c_str(),
202 const sensor_msgs::PointCloud2ConstPtr & cloudMsg,
203 const nav_msgs::OdometryConstPtr & odomMsg)
214 NODELET_WARN(
"Reseting point cloud assembler as null odometry has been received.");
220 const sensor_msgs::PointCloud2ConstPtr & cloudMsg,
221 const nav_msgs::OdometryConstPtr & odomMsg,
222 const rtabmap_ros::OdomInfoConstPtr & odomInfoMsg)
228 if(odomInfoMsg->keyFrameAdded)
240 NODELET_WARN(
"Reseting point cloud assembler as null odometry has been received.");
245 sensor_msgs::PointCloud2
removeField(
const sensor_msgs::PointCloud2 & input,
const std::string & field)
247 sensor_msgs::PointCloud2 output;
249 std::vector<int> inputFieldIndex;
250 for(
size_t i=0; i<input.fields.size(); ++i)
252 if(input.fields[i].name.compare(field) == 0)
258 sensor_msgs::PointField outputField = input.fields[i];
259 outputField.offset =
offset;
260 offset += outputField.count * sizeOfPointField(outputField.datatype);
261 output.fields.push_back(outputField);
262 inputFieldIndex.push_back(i);
265 output.header = input.header;
266 output.height = input.height;
267 output.width = input.width;
268 output.is_bigendian = input.is_bigendian;
269 output.is_dense = input.is_dense;
270 output.point_step =
offset;
271 output.row_step = output.width * output.point_step;
272 output.data.resize(output.height*output.row_step);
273 int total = output.height*output.width;
274 for(
int i=0; i<total; ++i)
277 int oi = i*output.point_step;
278 int pi = i*input.point_step;
279 for(
size_t j=0;j<output.fields.size(); ++j)
281 memcpy(&output.data[oi + output.fields[j].offset],
282 &input.data[pi + input.fields[inputFieldIndex[j]].offset],
283 output.fields[j].count * sizeOfPointField(output.fields[j].datatype));
293 UASSERT_MSG(cloudMsg->data.size() == cloudMsg->row_step*cloudMsg->height,
294 uFormat(
"data=%d row_step=%d height=%d", cloudMsg->data.size(), cloudMsg->row_step, cloudMsg->height).c_str());
296 if(skipClouds_<=0 || cloudsSkipped_ >=
skipClouds_)
302 cloudMsg->header.frame_id,
303 cloudMsg->header.stamp,
309 ROS_ERROR(
"Cloud not transform all clouds! Resetting...");
314 bool isMoving =
true;
329 pcl::PCLPointCloud2::Ptr newCloud(
new pcl::PCLPointCloud2);
335 #if PCL_VERSION_COMPARE(>=, 1, 10, 0) 341 newCloud->header.stamp =
stamp;
345 sensor_msgs::PointCloud2 output;
350 if(!newCloud->is_dense)
358 #if PCL_VERSION_COMPARE(>=, 1, 10, 0) 359 bool reachedMaxSize =
364 bool reachedMaxSize =
372 pcl::PCLPointCloud2Ptr assembled(
new pcl::PCLPointCloud2);
373 for(std::list<pcl::PCLPointCloud2::Ptr>::iterator iter=
clouds_.begin(); iter!=
clouds_.end(); ++iter)
375 if(assembled->data.empty())
377 *assembled = *(*iter);
381 pcl::PCLPointCloud2Ptr assembledTmp(
new pcl::PCLPointCloud2);
382 #if PCL_VERSION_COMPARE(>=, 1, 10, 0) 383 pcl::concatenate(*assembled, *(*iter), *assembledTmp);
388 assembledTmp->row_step = assembled->row_step + (*iter)->row_step;
389 assembled = assembledTmp;
393 sensor_msgs::PointCloud2 rosCloud;
397 int x_idx=-1, y_idx=-1, z_idx=-1;
398 for (std::size_t
d = 0;
d < assembled->fields.size (); ++
d)
400 if (assembled->fields[
d].name.compare(
"x")==0)
402 if (assembled->fields[
d].name.compare(
"y")==0)
404 if (assembled->fields[
d].name.compare(
"z")==0)
407 bool overflow =
false;
408 if(x_idx>=0 && y_idx>=0 && z_idx>=0) {
409 Eigen::Vector4f min_p, max_p;
410 pcl::getMinMax3D(assembled, x_idx, y_idx, z_idx, min_p, max_p);
425 #if PCL_VERSION_COMPARE(>=, 1, 10, 0) 431 assembled->header.stamp =
stamp;
435 pcl::VoxelGrid<pcl::PCLPointCloud2> filter;
437 filter.setInputCloud(assembled);
438 pcl::PCLPointCloud2Ptr output(
new pcl::PCLPointCloud2);
439 filter.filter(*output);
445 pcl::RadiusOutlierRemoval<pcl::PCLPointCloud2> filter;
448 filter.setInputCloud(assembled);
449 pcl::PCLPointCloud2Ptr output(
new pcl::PCLPointCloud2);
450 filter.filter(*output);
462 cloudMsg->header.stamp,
467 ROS_ERROR(
"Cloud not transform back assembled clouds in target frame \"%s\"! Resetting...",
frameId_.c_str());
479 rosCloud.header = cloudMsg->header;
482 rosCloud.header.frame_id =
frameId_;
530 ROS_WARN(
"%s: Did not receive data since 5 seconds! Make sure the input topics are " 531 "published (\"$ rostopic hz my_topic\") and the timestamps in their " 532 "header are set. %s",
534 subscribedTopicsMsg.c_str());
message_filters::Synchronizer< syncInfoPolicy > * exactInfoSync_
GLM_FUNC_DECL T roll(detail::tquat< T, P > const &x)
tf::TransformListener tfListener_
std::string uFormat(const char *fmt,...)
std::string getTopic() const
sensor_msgs::PointCloud2 removeField(const sensor_msgs::PointCloud2 &input, const std::string &field)
#define NODELET_WARN(...)
std::string getTopic() const
Subscriber subscribe(const std::string &topic, uint32_t queue_size, void(T::*fp)(M), T *obj, const TransportHints &transport_hints=TransportHints())
message_filters::Subscriber< nav_msgs::Odometry > syncOdomSub_
void callbackCloud(const sensor_msgs::PointCloud2ConstPtr &cloudMsg)
ros::NodeHandle & getNodeHandle() const
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())
double waitForTransformDuration_
rtabmap::Transform transformFromPoseMsg(const geometry_msgs::Pose &msg, bool ignoreRotationIfNotSet=false)
ros::NodeHandle & getPrivateNodeHandle() const
GLM_FUNC_DECL T pitch(detail::tquat< T, P > const &x)
boost::thread * warningThread_
geometry_msgs::TransformStamped t
rtabmap::Transform getTransform(const std::string &fromFrameId, const std::string &toFrameId, const ros::Time &stamp, tf::TransformListener &listener, double waitForTransform)
std::list< pcl::PCLPointCloud2::Ptr > clouds_
const std::string & getName() const
void callbackCloudOdom(const sensor_msgs::PointCloud2ConstPtr &cloudMsg, const nav_msgs::OdometryConstPtr &odomMsg)
LaserScan RTABMAP_EXP commonFiltering(const LaserScan &scan, int downsamplingStep, float rangeMin=0.0f, float rangeMax=0.0f, float voxelSize=0.0f, int normalK=0, float normalRadius=0.0f, float groundNormalsUp=0.0f)
bool param(const std::string ¶m_name, T ¶m_val, const T &default_val) const
void publish(const boost::shared_ptr< M > &message) const
void warningLoop(const std::string &subscribedTopicsMsg)
#define UASSERT_MSG(condition, msg_str)
GLM_FUNC_DECL genType pi()
message_filters::Subscriber< sensor_msgs::PointCloud2 > syncCloudSub_
LaserScan laserScanFromPointCloud(const PointCloud2T &cloud, bool filterNaNs, bool is2D, const Transform &transform)
void toPCL(const ros::Time &stamp, std::uint64_t &pcl_stamp)
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
message_filters::sync_policies::ExactTime< sensor_msgs::PointCloud2, nav_msgs::Odometry, rtabmap_ros::OdomInfo > syncInfoPolicy
virtual ~PointCloudAssembler()
message_filters::sync_policies::ExactTime< sensor_msgs::PointCloud2, nav_msgs::Odometry > syncPolicy
bool concatenatePointCloud(const sensor_msgs::PointCloud2 &cloud1, const sensor_msgs::PointCloud2 &cloud2, sensor_msgs::PointCloud2 &cloud_out)
message_filters::Subscriber< rtabmap_ros::OdomInfo > syncOdomInfoSub_
#define NODELET_INFO(...)
GLM_FUNC_DECL genType max(genType const &x, genType const &y)
void subscribe(ros::NodeHandle &nh, const std::string &topic, uint32_t queue_size, const ros::TransportHints &transport_hints=ros::TransportHints(), ros::CallbackQueueInterface *callback_queue=0)
void transformPointCloud(const pcl::PointCloud< PointT > &cloud_in, pcl::PointCloud< PointT > &cloud_out, const tf::Transform &transform)
ros::Subscriber cloudSub_
void callbackCloudOdomInfo(const sensor_msgs::PointCloud2ConstPtr &cloudMsg, const nav_msgs::OdometryConstPtr &odomMsg, const rtabmap_ros::OdomInfoConstPtr &odomInfoMsg)
GLM_FUNC_DECL T yaw(detail::tquat< T, P > const &x)
rtabmap::Transform previousPose_
message_filters::Synchronizer< syncPolicy > * exactSync_
PLUGINLIB_EXPORT_CLASS(rtabmap_ros::CoreWrapper, nodelet::Nodelet)
void moveFromPCL(pcl::PCLImage &pcl_image, sensor_msgs::Image &image)
uint32_t getNumSubscribers() const
std::string fixedFrameId_