ts_pointcloud_ros.cpp
Go to the documentation of this file.
2 
3 namespace toposens_pointcloud
4 {
6 {
7  const auto buffer_size = int{100};
8 
9  // Read parameters
10  int pcd_save_interval{0};
11  private_nh.param<std::string>("scans_topic", scans_topic_, "ts_scans");
12  private_nh.param<std::string>("target_frame", target_frame_, "toposens");
13  private_nh.param<float>("lifetime_normals_vis", lifetime_normals_vis_, 0.0);
14  private_nh.param<int>("pcd_save_interval", pcd_save_interval, 0);
15  ROS_INFO("Reading scans from \"%s\"", scans_topic_.c_str()); // NOLINT
16  ROS_INFO("target_frame: \"%s\"", target_frame_.c_str()); // NOLINT
17  ROS_INFO("lifetime_normals_vis: %f", lifetime_normals_vis_); // NOLINT
18  ROS_INFO("pcd_save_interval: %f", pcd_save_interval); // NOLINT
19 
20  // Subscribers
21  scans_sub_ = nh.subscribe(scans_topic_, buffer_size, &TSPointCloudROS::cloudCallback, this);
23 
24  // Publishers
25  cloud_pub_ = nh.advertise<XYZINCloud>(kPointCloudTopic, buffer_size);
26  if (lifetime_normals_vis_ != 0.0)
27  {
28  marker_pub_ =
29  nh.advertise<visualization_msgs::Marker>(kPointCloudTopic + "_normals", buffer_size);
30  }
31 
32  // Processing entities
33  pointTransform_ = std::make_unique<Mapping>();
34  if (pcd_save_interval > 0)
35  {
36  log_thread_ = new boost::thread(&Logging::logPointcloud);
37  }
38 }
39 
41 {
42  delete tf2_listener_;
43 
44  if (log_thread_ != nullptr)
45  {
46  log_thread_->interrupt();
47  log_thread_->join();
48  delete log_thread_;
49  }
50 }
51 
52 void TSPointCloudROS::cloudCallback(const toposens_msgs::TsScan::ConstPtr &msg)
53 {
55  XYZINCloud::Ptr transformed_cloud(new XYZINCloud);
56  pcl_conversions::toPCL(msg->header.stamp, transformed_cloud->header.stamp);
57  transformed_cloud->header.frame_id = target_frame_;
58  transformed_cloud->height = 1;
59 
60  geometry_msgs::TransformStamped transform;
62  try
63  {
64  transform = tf2_buffer_.lookupTransform(target_frame_, msg->header.frame_id, msg->header.stamp,
65  ros::Duration(0.5));
66 
67  for (auto it = msg->points.begin(); it != msg->points.end(); ++it)
68  {
69  if (it->intensity <= 0)
70  {
71  continue;
72  }
73 
74  toposens_msgs::TsPoint msg_point = *it;
75  pcl::PointXYZINormal pcl_point = pointTransform_->convertToXYZINormal(msg_point);
76  TSPointCloudROS::doTransform(transform, pcl_point, msg->header);
77  transformed_cloud->points.push_back(pcl_point);
78  }
79  }
80  catch (tf2::TransformException ex)
81  {
82  ROS_INFO_STREAM(ex.what()); // NOLINT
83  }
84 
86  transformed_cloud->width = transformed_cloud->points.size();
87  cloud_pub_.publish(transformed_cloud);
88 
89  if (lifetime_normals_vis_ != 0.0)
90  {
91  TSPointCloudROS::publishNormals(transformed_cloud);
92  }
93 }
94 
95 void TSPointCloudROS::doTransform(geometry_msgs::TransformStamped transform,
96  pcl::PointXYZINormal &pcl_point, std_msgs::Header header)
97 {
98  // Skip if current and target frames are the same
99  if (header.frame_id == target_frame_)
100  {
101  return;
102  }
103 
104  // Intermediate translation variable
105  Vector3f translation;
106  translation[0] = transform.transform.translation.x;
107  translation[1] = transform.transform.translation.y;
108  translation[2] = transform.transform.translation.z;
109  // Intermediate quaternion variable
110  Vector4f quaternion;
111  quaternion[0] = transform.transform.rotation.x;
112  quaternion[1] = transform.transform.rotation.y;
113  quaternion[2] = transform.transform.rotation.z;
114  quaternion[3] = transform.transform.rotation.w;
115 
116  // Perform the transformations to target frames
117  try
118  {
119  pointTransform_->doTransform(pcl_point, translation, quaternion);
120  }
121  catch (tf2::TransformException ex)
122  {
123  ROS_ERROR("Point or normal transformation failed: %s", ex.what());
124  }
125 }
126 
127 void TSPointCloudROS::publishNormals(XYZINCloud::ConstPtr transformed_cloud)
128 {
129  // Initialize the marker
130  marker.type = visualization_msgs::Marker::ARROW;
131  marker.header = pcl_conversions::fromPCL(transformed_cloud->header);
132  marker.ns = "normals"; // Namespace the normal marker will be posted to
133  marker.action = visualization_msgs::Marker::ADD;
135  marker.pose.orientation.x = 0.0;
136  marker.pose.orientation.y = 0.0;
137  marker.pose.orientation.z = 0.0;
138  marker.pose.orientation.w = 1.0;
139  marker.scale.x = 0.005f;
140  marker.scale.y = 0.01f;
141  marker.color.r = 1.f;
142  marker.color.g = 0.f;
143  marker.color.b = 0.f;
144  marker.color.a = 1.f;
145 
146  // Publish normal markers individually
147  for (const auto &cloud_point : transformed_cloud->points)
148  {
149  marker.id = marker_id_++;
150 
151  marker.points.clear();
152  geometry_msgs::Point point_msg;
153 
154  point_msg.x = cloud_point.x;
155  point_msg.y = cloud_point.y;
156  point_msg.z = cloud_point.z;
157 
158  marker.points.push_back(point_msg);
159 
160  point_msg.x += cloud_point.normal_x * .1f;
161  point_msg.y += cloud_point.normal_y * .1f;
162  point_msg.z += cloud_point.normal_z * .1f;
163 
164  marker.points.push_back(point_msg);
166  }
167 }
168 
169 } // namespace toposens_pointcloud
visualization_msgs::Marker marker
void doTransform(geometry_msgs::TransformStamped transform, pcl::PointXYZINormal &pt, std_msgs::Header h)
Subscriber subscribe(const std::string &topic, uint32_t queue_size, void(T::*fp)(M), T *obj, const TransportHints &transport_hints=TransportHints())
bool param(const std::string &param_name, T &param_val, const T &default_val) const
virtual geometry_msgs::TransformStamped lookupTransform(const std::string &target_frame, const std::string &source_frame, const ros::Time &time, const ros::Duration timeout) const
void publish(const boost::shared_ptr< M > &message) const
#define ROS_INFO(...)
tf2_ros::TransformListener * tf2_listener_
void publishNormals(XYZINCloud::ConstPtr tc)
pcl::PointCloud< pcl::PointXYZINormal > XYZINCloud
Definition: mapping.h:26
void toPCL(const ros::Time &stamp, std::uint64_t &pcl_stamp)
static void logPointcloud()
Definition: logging.h:63
std::unique_ptr< Mapping > pointTransform_
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
static const std::string kPointCloudTopic
void cloudCallback(const toposens_msgs::TsScan::ConstPtr &msg)
#define ROS_INFO_STREAM(args)
TSPointCloudROS(ros::NodeHandle nh, ros::NodeHandle private_nh)
void fromPCL(const std::uint64_t &pcl_stamp, ros::Time &stamp)
#define ROS_ERROR(...)


toposens_pointcloud
Author(s): Adi Singh, Sebastian Dengler, Christopher Lang, Inshal Uddin
autogenerated on Mon Feb 28 2022 23:57:49