Program Listing for File pcl_node.hpp

Return to documentation for file (include/pcl_ros/pcl_node.hpp)

/*
 * Software License Agreement (BSD License)
 *
 *  Copyright (c) 2010, Willow Garage, Inc.
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of Willow Garage, Inc. nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 *
 * $Id: pcl_node.h 33238 2010-03-11 00:46:58Z rusu $
 *
 */

#ifndef PCL_ROS__PCL_NODE_HPP_
#define PCL_ROS__PCL_NODE_HPP_

#include <message_filters/subscriber.h>
#include <message_filters/synchronizer.h>
#include <message_filters/sync_policies/exact_time.h>
#include <message_filters/sync_policies/approximate_time.h>
#include <pcl/pcl_base.h>
#include <pcl/point_types.h>
#include <pcl_conversions/pcl_conversions.h>
#include <tf2_ros/transform_listener.h>
#include <tf2_ros/buffer.h>
// #include <nodelet_topic_tools/nodelet_lazy.h>  // TODO(daisukes): lazy subscription

#include <memory>
#include <string>
#include <vector>

#include <rclcpp/rclcpp.hpp>
#include <sensor_msgs/msg/point_cloud2.hpp>
#include <pcl_msgs/msg/point_indices.hpp>
#include <pcl_msgs/msg/model_coefficients.hpp>

// #include "pcl_ros/point_cloud.hpp"

using pcl_conversions::fromPCL;

namespace pcl_ros
{

template<typename T, typename PublisherT = rclcpp::Publisher<T>>
class PCLNode : public rclcpp::Node
{
public:
  typedef sensor_msgs::msg::PointCloud2 PointCloud2;

  typedef pcl::PointCloud<pcl::PointXYZ> PointCloud;
  typedef PointCloud::Ptr PointCloudPtr;
  typedef PointCloud::ConstPtr PointCloudConstPtr;

  typedef pcl_msgs::msg::PointIndices PointIndices;
  typedef PointIndices::SharedPtr PointIndicesPtr;
  typedef PointIndices::ConstSharedPtr PointIndicesConstPtr;

  typedef pcl_msgs::msg::ModelCoefficients ModelCoefficients;
  typedef ModelCoefficients::SharedPtr ModelCoefficientsPtr;
  typedef ModelCoefficients::ConstSharedPtr ModelCoefficientsConstPtr;

  typedef pcl::IndicesPtr IndicesPtr;
  typedef pcl::IndicesConstPtr IndicesConstPtr;

  PCLNode(std::string node_name, const rclcpp::NodeOptions & options)
  : rclcpp::Node(node_name, options),
    use_indices_(false), transient_local_indices_(false),
    max_queue_size_(3), approximate_sync_(false),
    tf_buffer_(this->get_clock()),
    tf_listener_(tf_buffer_)
  {
    {
      rcl_interfaces::msg::ParameterDescriptor desc;
      desc.name = "max_queue_size";
      desc.type = rcl_interfaces::msg::ParameterType::PARAMETER_INTEGER;
      desc.description = "QoS History depth";
      desc.read_only = true;
      max_queue_size_ = declare_parameter(desc.name, max_queue_size_, desc);
    }

    {
      rcl_interfaces::msg::ParameterDescriptor desc;
      desc.name = "use_indices";
      desc.type = rcl_interfaces::msg::ParameterType::PARAMETER_BOOL;
      desc.description = "Only process a subset of the point cloud from an indices topic";
      desc.read_only = true;
      use_indices_ = declare_parameter(desc.name, use_indices_, desc);
    }

    {
      rcl_interfaces::msg::ParameterDescriptor desc;
      desc.name = "transient_local_indices";
      desc.type = rcl_interfaces::msg::ParameterType::PARAMETER_BOOL;
      desc.description = "Does indices topic use transient local documentation";
      desc.read_only = true;
      transient_local_indices_ = declare_parameter(desc.name, transient_local_indices_, desc);
    }

    {
      rcl_interfaces::msg::ParameterDescriptor desc;
      desc.name = "approximate_sync";
      desc.type = rcl_interfaces::msg::ParameterType::PARAMETER_BOOL;
      desc.description =
        "Match indices and point cloud messages if time stamps are approximatly the same.";
      desc.read_only = true;
      approximate_sync_ = declare_parameter(desc.name, approximate_sync_, desc);
    }

    RCLCPP_DEBUG(
      this->get_logger(), "PCL Node successfully created with the following parameters:\n"
      " - approximate_sync          : %s\n"
      " - use_indices               : %s\n"
      " - transient_local_indices_  : %s\n"
      " - max_queue_size            : %d",
      (approximate_sync_) ? "true" : "false",
      (use_indices_) ? "true" : "false",
      (transient_local_indices_) ? "true" : "false",
      max_queue_size_);
  }

protected:
  bool use_indices_;
  bool transient_local_indices_;

  message_filters::Subscriber<PointCloud2> sub_input_filter_;

  message_filters::Subscriber<PointIndices> sub_indices_filter_;

  std::shared_ptr<PublisherT> pub_output_;

  int max_queue_size_;

  bool approximate_sync_;

  tf2_ros::Buffer tf_buffer_;
  tf2_ros::TransformListener tf_listener_;

  inline bool
  isValid(const PointCloud2::ConstSharedPtr & cloud, const std::string & topic_name = "input")
  {
    if (cloud->width * cloud->height * cloud->point_step != cloud->data.size()) {
      RCLCPP_WARN(
        this->get_logger(),
        "Invalid PointCloud (data = %zu, width = %d, height = %d, step = %d) "
        "with stamp %d.%09d, and frame %s on topic %s received!",
        cloud->data.size(), cloud->width, cloud->height, cloud->point_step,
        cloud->header.stamp.sec, cloud->header.stamp.nanosec,
        cloud->header.frame_id.c_str(), topic_name.c_str());

      return false;
    }
    return true;
  }

  inline bool
  isValid(const PointCloudConstPtr & cloud, const std::string & topic_name = "input")
  {
    if (cloud->width * cloud->height != cloud->points.size()) {
      RCLCPP_WARN(
        this->get_logger(),
        "Invalid PointCloud (points = %zu, width = %d, height = %d) "
        "with stamp %d.%09d, and frame %s on topic %s received!",
        cloud->points.size(), cloud->width, cloud->height,
        fromPCL(cloud->header).stamp.sec, fromPCL(cloud->header).stamp.nanosec,
        cloud->header.frame_id.c_str(), topic_name.c_str());

      return false;
    }
    return true;
  }

  inline bool
  isValid(
    const PointIndicesConstPtr & /*indices*/,
    const std::string & /*topic_name*/ = "indices")
  {
    /*if (indices->indices.empty ())
    {
      RCLCPP_WARN(
        this->get_logger(), "Empty indices (values = %zu) with stamp %d.%09d, "
        "and frame %s on topic %s received!",
        indices->indices.size(), indices->header.stamp.sec, indices->header.stamp.nanosec,
        indices->header.frame_id.c_str(), topic_name.c_str());
      //return (true);  // looks like it should be false
      return false;
    }*/
    return true;
  }

  inline bool
  isValid(
    const ModelCoefficientsConstPtr & /*model*/,
    const std::string & /*topic_name*/ = "model")
  {
    /*if (model->values.empty ())
    {
      RCLCPP_WARN(
        this->get_logger(), "Empty model (values = %zu) with stamp %d.%09d, "
        "and frame %s on topic %s received!",
        model->values.size(), model->header.stamp.sec, model->header.stamp.nanosec,
        model->header.frame_id.c_str(), topic_name.c_str());
      return (false);
    }*/
    return true;
  }

  virtual void subscribe() {}
  virtual void unsubscribe() {}

public:
  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
};
}  // namespace pcl_ros

#endif  // PCL_ROS__PCL_NODE_HPP_