protobuf2ros_stream.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2017 Roboception GmbH
3  * All rights reserved
4  *
5  * Author: Christian Emmerich
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright notice,
11  * this list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright notice,
14  * this list of conditions and the following disclaimer in the documentation
15  * and/or other materials provided with the distribution.
16  *
17  * 3. Neither the name of the copyright holder nor the names of its contributors
18  * may be used to endorse or promote products derived from this software without
19  * specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
25  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31  * POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include "protobuf2ros_stream.h"
35 
38 
39 #include <ros/ros.h>
41 #include <visualization_msgs/Marker.h>
42 #include <nav_msgs/Odometry.h>
43 
45 
46 using namespace std;
47 
48 namespace rc
49 {
50 namespace rcd = dynamics;
51 
52 bool Protobuf2RosStream::startReceivingAndPublishingAsRos()
53 {
54  unsigned int timeoutMillis = 500;
55  string pbMsgType = _rcdyn->getPbMsgTypeOfStream(_stream);
56 
57  Protobuf2RosPublisher rosPublisher(_nh, _stream, pbMsgType, _tfPrefix);
58 
59  unsigned int cntNoListener = 0;
60  bool failed = false;
61 
62  while (!_stop && !failed)
63  {
64  // start streaming only if someone is listening
65 
66  if (!rosPublisher.used())
67  {
68  // ros getNumSubscribers usually takes a while to register the subscribers
69  if (++cntNoListener > 200)
70  {
71  _requested = false;
72  }
73  usleep(1000 * 10);
74  continue;
75  }
76  cntNoListener = 0;
77  _requested = true;
78  _success = false;
79  ROS_INFO_STREAM("rc_visard_driver: Enabled rc-dynamics stream: " << _stream);
80 
81  // initialize data stream to this host
82 
83  rcd::DataReceiver::Ptr receiver;
84  try
85  {
86  receiver = _rcdyn->createReceiverForStream(_stream);
87  }
89  {
90  stringstream msg;
91  msg << "Could not initialize rc-dynamics stream: " << _stream << ":" << endl << e.what();
92  ROS_WARN_STREAM_THROTTLE(5, msg.str());
93  continue;
94  }
95  catch (exception& e)
96  {
97  ROS_ERROR_STREAM(std::string("Could not initialize rc-dynamics stream: ") + _stream + ": " + e.what());
98  failed = true;
99  break;
100  }
101  receiver->setTimeout(timeoutMillis);
102  ROS_INFO_STREAM("rc_visard_driver: rc-dynamics stream ready: " << _stream);
103 
104  // main loop for listening, receiving and republishing data to ROS
105 
106  shared_ptr<::google::protobuf::Message> pbMsg;
107  while (!_stop && rosPublisher.used())
108  {
109  // try receive msg; blocking call (timeout)
110  try
111  {
112  pbMsg = receiver->receive(pbMsgType);
113  _success = true;
114  }
115  catch (std::exception& e)
116  {
117  ROS_ERROR_STREAM("Caught exception during receiving " << _stream << ": " << e.what());
118  failed = true;
119  break; // stop receiving loop
120  }
121 
122  // timeout happened
123  if (!pbMsg)
124  {
125  ROS_WARN_STREAM("Did not receive any " << _stream << " message within the last " << timeoutMillis << " ms. "
126  << "Either rc_visard stopped streaming or is turned off, "
127  << "or you seem to have serious network/connection problems!");
128  continue; // wait for next packet
129  }
130 
131  ROS_DEBUG_STREAM_THROTTLE(1, "Received protobuf message: " << pbMsg->DebugString());
132 
133  // convert to ROS message and publish
134  rosPublisher.publish(pbMsg);
135  }
136 
137  ROS_INFO_STREAM("rc_visard_driver: Disabled rc-dynamics stream: " << _stream);
138  }
139 
140  // return info about stream being stopped externally or failed internally
141  return !failed;
142 }
143 
144 bool PoseStream::startReceivingAndPublishingAsRos()
145 {
146  unsigned int timeoutMillis = 500;
147 
148  ros::Publisher pub = _nh.advertise<geometry_msgs::PoseStamped>(_stream, 1000);
150 
151  unsigned int cntNoListener = 0;
152  bool failed = false;
153 
154  while (!_stop && !failed)
155  {
156  bool someoneListens = _tfEnabled || pub.getNumSubscribers() > 0;
157 
158  // start streaming only if someone is listening
159 
160  if (!someoneListens)
161  {
162  // ros getNumSubscribers usually takes a while to register the subscribers
163  if (++cntNoListener > 200)
164  {
165  _requested = false;
166  }
167  usleep(1000 * 10);
168  continue;
169  }
170  cntNoListener = 0;
171  _requested = true;
172  _success = false;
173  ROS_INFO_STREAM("rc_visard_driver: Enabled rc-dynamics stream: " << _stream);
174 
175  // initialize data stream to this host
176 
177  rcd::DataReceiver::Ptr receiver;
178  try
179  {
180  receiver = _rcdyn->createReceiverForStream(_stream);
181  }
183  {
184  stringstream msg;
185  msg << "Could not initialize rc-dynamics stream: " << _stream << ":" << endl << e.what();
186  ROS_WARN_STREAM_THROTTLE(5, msg.str());
187  continue;
188  }
189  catch (exception& e)
190  {
191  ROS_ERROR_STREAM(std::string("Could not initialize rc-dynamics stream: ") + _stream + ": " + e.what());
192  failed = true;
193  break;
194  }
195  receiver->setTimeout(timeoutMillis);
196  ROS_INFO_STREAM("rc_visard_driver: rc-dynamics stream ready: " << _stream);
197 
198  // main loop for listening, receiving and republishing data to ROS
199 
200  shared_ptr<roboception::msgs::Frame> protoFrame;
201  while (!_stop && someoneListens)
202  {
203  // try receive msg; blocking call (timeout)
204  try
205  {
206  protoFrame = receiver->receive<roboception::msgs::Frame>();
207  _success = true;
208  }
209  catch (std::exception& e)
210  {
211  ROS_ERROR_STREAM("Caught exception during receiving " << _stream << ": " << e.what());
212  failed = true;
213  break; // stop receiving loop
214  }
215 
216  // timeout happened
217  if (!protoFrame)
218  {
219  ROS_WARN_STREAM("Did not receive any " << _stream << " message within the last " << timeoutMillis << " ms. "
220  << "Either rc_visard stopped streaming or is turned off, "
221  << "or you seem to have serious network/connection problems!");
222  continue; // wait for next packet
223  }
224 
225  ROS_DEBUG_STREAM_THROTTLE(1, "Received protoFrame: " << protoFrame->DebugString());
226 
227  // overwrite frame name/ids
228  protoFrame->set_parent(_tfPrefix + protoFrame->parent());
229  protoFrame->set_name(_tfPrefix + protoFrame->name());
230 
231  auto rosPose = toRosPoseStamped(*protoFrame);
232  pub.publish(rosPose);
233 
234  // convert to tf and publish
235  if (_tfEnabled)
236  {
237  tf::StampedTransform transform = toRosTfStampedTransform(*protoFrame);
238  tf_pub.sendTransform(transform);
239  }
240 
241  // check if still someone is listening
242  someoneListens = _tfEnabled || pub.getNumSubscribers() > 0;
243  }
244 
245  ROS_INFO_STREAM("rc_visard_driver: Disabled rc-dynamics stream: " << _stream);
246  }
247 
248  // return info about stream being stopped externally or failed internally
249  return !failed;
250 }
251 
252 bool DynamicsStream::startReceivingAndPublishingAsRos()
253 {
254  unsigned int timeoutMillis = 500;
255 
256  // publish visualization markers only if enabled by ros param and only for 'dynamics', not for 'dynamics_ins'
257 
258  bool publishVisualizationMarkers = false;
259  ros::NodeHandle("~").param("enable_visualization_markers", publishVisualizationMarkers, publishVisualizationMarkers);
260  publishVisualizationMarkers = publishVisualizationMarkers && (_stream == "dynamics");
261 
262  // create publishers
263 
264  ros::Publisher pub_odom = _nh.advertise<nav_msgs::Odometry>(_stream, 1000);
265  ros::Publisher pub_markers;
267  if (publishVisualizationMarkers)
268  {
269  pub_markers = _nh.advertise<visualization_msgs::Marker>("dynamics_visualization_markers", 1000);
270  }
271 
272  unsigned int cntNoListener = 0;
273  bool failed = false;
274 
275  while (!_stop && !failed)
276  {
277  bool someoneListens =
278  pub_odom.getNumSubscribers() > 0 || (publishVisualizationMarkers && pub_markers.getNumSubscribers() > 0);
279 
280  // start streaming only if someone is listening
281 
282  if (!someoneListens)
283  {
284  // ros getNumSubscribers usually takes a while to register the subscribers
285  if (++cntNoListener > 200)
286  {
287  _requested = false;
288  }
289  usleep(1000 * 10);
290  continue;
291  }
292  cntNoListener = 0;
293  _requested = true;
294  _success = false;
295  ROS_INFO_STREAM("rc_visard_driver: Enabled rc-dynamics stream: " << _stream);
296 
297  // initialize data stream to this host
298 
299  rcd::DataReceiver::Ptr receiver;
300  try
301  {
302  receiver = _rcdyn->createReceiverForStream(_stream);
303  }
305  {
306  stringstream msg;
307  msg << "Could not initialize rc-dynamics stream: " << _stream << ":" << endl << e.what();
308  ROS_WARN_STREAM_THROTTLE(5, msg.str());
309  continue;
310  }
311  catch (exception& e)
312  {
313  ROS_ERROR_STREAM(std::string("Could not initialize rc-dynamics stream: ") + _stream + ": " + e.what());
314  failed = true;
315  break;
316  }
317  receiver->setTimeout(timeoutMillis);
318  ROS_INFO_STREAM("rc_visard_driver: rc-dynamics stream ready: " << _stream);
319 
320  // main loop for listening, receiving and republishing data to ROS
321 
322  shared_ptr<roboception::msgs::Dynamics> protoMsg;
323  while (!_stop && someoneListens)
324  {
325  // try receive msg; blocking call (timeout)
326  try
327  {
328  protoMsg = receiver->receive<roboception::msgs::Dynamics>();
329  _success = true;
330  }
331  catch (std::exception& e)
332  {
333  ROS_ERROR_STREAM("Caught exception during receiving " << _stream << ": " << e.what());
334  failed = true;
335  break; // stop receiving loop
336  }
337 
338  // timeout happened
339  if (!protoMsg)
340  {
341  ROS_WARN_STREAM("Did not receive any " << _stream << " message within the last " << timeoutMillis << " ms. "
342  << "Either rc_visard stopped streaming or is turned off, "
343  << "or you seem to have serious network/connection problems!");
344  continue; // wait for next packet
345  }
346 
347  ROS_DEBUG_STREAM_THROTTLE(1, "Received protoMsg: " << protoMsg->DebugString());
348 
349  // prefix all frame ids before
350  protoMsg->set_pose_frame(_tfPrefix + protoMsg->pose_frame());
351  protoMsg->set_linear_velocity_frame(_tfPrefix + protoMsg->linear_velocity_frame());
352  protoMsg->set_angular_velocity_frame(_tfPrefix + protoMsg->angular_velocity_frame());
353  protoMsg->set_linear_acceleration_frame(_tfPrefix + protoMsg->linear_acceleration_frame());
354  protoMsg->mutable_cam2imu_transform()->set_name(_tfPrefix + protoMsg->cam2imu_transform().name());
355  protoMsg->mutable_cam2imu_transform()->set_parent(_tfPrefix + protoMsg->cam2imu_transform().parent());
356 
357  // time stamp of this message
358  ros::Time msgStamp = toRosTime(protoMsg->timestamp());
359 
360  // convert cam2imu_transform to tf and publish it - TODO: Do we need it?
361  auto cam2imu = toRosTfStampedTransform(protoMsg->cam2imu_transform());
362  // from dynamics-module we get cam2imu (i.e. camera-pose in imu-frame), but we
363  // want to have imu2cam (i.e. imu-pose in camera frame) - TODO: WHY ???
364  // overwriting cam2imu timestamp as this would be too old for normal use with tf
365  auto imu2cam = tf::StampedTransform(cam2imu.inverse(), msgStamp, cam2imu.child_frame_id_, cam2imu.frame_id_);
366  tf_pub.sendTransform(imu2cam);
367 
368  // convert pose to transform to use it for transformations
369  auto imu2world_rot_only = toRosTfTransform(protoMsg->pose());
370  imu2world_rot_only.setOrigin(tf::Vector3(0.0, 0.0, 0.0));
371 
372  // publish rc dynamics message as ros odometry
373  auto odom = boost::make_shared<nav_msgs::Odometry>();
374  odom->header.frame_id = protoMsg->pose_frame(); // "world"
375  odom->header.stamp = msgStamp;
376  odom->child_frame_id = protoMsg->linear_acceleration_frame(); //"imu"
377  odom->pose.pose = *toRosPose(protoMsg->pose());
378  // for odom twist, we need to transform lin_velocity from world to imu
379  auto lin_vel = protoMsg->linear_velocity();
380  auto lin_vel_transformed = imu2world_rot_only.inverse() * tf::Vector3(lin_vel.x(), lin_vel.y(), lin_vel.z());
381  odom->twist.twist.linear.x = lin_vel_transformed.x();
382  odom->twist.twist.linear.y = lin_vel_transformed.y();
383  odom->twist.twist.linear.z = lin_vel_transformed.z();
384  auto ang_vel = protoMsg->angular_velocity(); // ang_velocity already is in imu
385  odom->twist.twist.angular.x = ang_vel.x();
386  odom->twist.twist.angular.y = ang_vel.y();
387  odom->twist.twist.angular.z = ang_vel.z();
388  pub_odom.publish(odom);
389 
390  // convert velocities and accelerations to visualization Markers
391  if (publishVisualizationMarkers)
392  {
393  geometry_msgs::Point start, end;
394  auto protoPosePosition = protoMsg->pose().position();
395  start.x = protoPosePosition.x();
396  start.y = protoPosePosition.y();
397  start.z = protoPosePosition.z();
398 
399  visualization_msgs::Marker lin_vel_marker; // single marker for linear velocity
400  lin_vel_marker.header.stamp = msgStamp;
401  lin_vel_marker.header.frame_id = protoMsg->linear_velocity_frame();
402  lin_vel_marker.ns = _tfPrefix;
403  lin_vel_marker.id = 0;
404  lin_vel_marker.type = visualization_msgs::Marker::ARROW;
405  lin_vel_marker.action = visualization_msgs::Marker::MODIFY;
406  lin_vel_marker.frame_locked = true;
407  end.x = start.x + lin_vel.x();
408  end.y = start.y + lin_vel.y();
409  end.z = start.z + lin_vel.z();
410  lin_vel_marker.points.push_back(start);
411  lin_vel_marker.points.push_back(end);
412  lin_vel_marker.scale.x = 0.005;
413  lin_vel_marker.scale.y = 0.01;
414  lin_vel_marker.color.a = 1;
415  lin_vel_marker.color.g = lin_vel_marker.color.b = 1.0; // cyan
416  pub_markers.publish(lin_vel_marker);
417 
418  visualization_msgs::Marker ang_vel_marker; // single marker for angular velocity
419  ang_vel_marker.header.stamp = msgStamp;
420  ang_vel_marker.header.frame_id = protoMsg->pose_frame(); // "world"
421  ang_vel_marker.ns = _tfPrefix;
422  ang_vel_marker.id = 1;
423  ang_vel_marker.type = visualization_msgs::Marker::ARROW;
424  ang_vel_marker.action = visualization_msgs::Marker::MODIFY;
425  ang_vel_marker.frame_locked = true;
426  auto ang_vel_transformed = imu2world_rot_only * tf::Vector3(ang_vel.x(), ang_vel.y(), ang_vel.z());
427  end.x = start.x + ang_vel_transformed.x();
428  end.y = start.y + ang_vel_transformed.y();
429  end.z = start.z + ang_vel_transformed.z();
430  ang_vel_marker.points.push_back(start);
431  ang_vel_marker.points.push_back(end);
432  ang_vel_marker.scale.x = 0.005;
433  ang_vel_marker.scale.y = 0.01;
434  ang_vel_marker.color.a = 1;
435  ang_vel_marker.color.r = ang_vel_marker.color.b = 1.0; // mangenta
436  pub_markers.publish(ang_vel_marker);
437 
438  visualization_msgs::Marker lin_accel_marker; // single marker for linear acceleration
439  lin_accel_marker.header.stamp = msgStamp;
440  lin_accel_marker.header.frame_id = protoMsg->pose_frame(); // "world"
441  lin_accel_marker.ns = _tfPrefix;
442  lin_accel_marker.id = 2;
443  lin_accel_marker.type = visualization_msgs::Marker::ARROW;
444  lin_accel_marker.action = visualization_msgs::Marker::MODIFY;
445  lin_accel_marker.frame_locked = true;
446  auto lin_accel = protoMsg->linear_acceleration();
447  auto lin_accel_transformed = imu2world_rot_only * tf::Vector3(lin_accel.x(), lin_accel.y(), lin_accel.z());
448  end.x = start.x + lin_accel_transformed.x();
449  end.y = start.y + lin_accel_transformed.y();
450  end.z = start.z + lin_accel_transformed.z();
451  lin_accel_marker.points.push_back(start);
452  lin_accel_marker.points.push_back(end);
453  lin_accel_marker.scale.x = 0.005;
454  lin_accel_marker.scale.y = 0.01;
455  lin_accel_marker.color.a = 1;
456  lin_accel_marker.color.r = lin_accel_marker.color.g = 1.0; // yellow
457  pub_markers.publish(lin_accel_marker);
458  }
459 
460  // check if still someone is listening
461  someoneListens =
462  pub_odom.getNumSubscribers() > 0 || (publishVisualizationMarkers && pub_markers.getNumSubscribers() > 0);
463  }
464 
465  ROS_INFO_STREAM("rc_visard_driver: Disabled rc-dynamics stream: " << _stream);
466  }
467 
468  // return info about stream being stopped externally or failed internally
469  return !failed;
470 }
471 }
msg
geometry_msgs::PoseStampedPtr toRosPoseStamped(const roboception::msgs::Frame &frame)
#define ROS_WARN_STREAM_THROTTLE(period, args)
void publish(const boost::shared_ptr< M > &message) const
tf::Transform toRosTfTransform(const roboception::msgs::Pose &pose)
Generic implementation for publishing protobuf messages to ros.
#define ROS_DEBUG_STREAM_THROTTLE(period, args)
virtual void publish(std::shared_ptr<::google::protobuf::Message > pbMsg)
Publish the generic protobuf message as a corresponding Ros Message.
TFSIMD_FORCE_INLINE const tfScalar & x() const
void sendTransform(const StampedTransform &transform)
#define ROS_WARN_STREAM(args)
uint32_t getNumSubscribers() const
#define ROS_INFO_STREAM(args)
#define ROS_ERROR_STREAM(args)
geometry_msgs::PosePtr toRosPose(const roboception::msgs::Pose &pose)
ros::Time toRosTime(const roboception::msgs::Time &time)
virtual bool used()
Returns true if there are subscribers to the topic.
TFSIMD_FORCE_INLINE void setOrigin(const Vector3 &origin)
tf::StampedTransform toRosTfStampedTransform(const roboception::msgs::Frame &frame)


rc_visard_driver
Author(s): Heiko Hirschmueller , Christian Emmerich , Felix Ruess
autogenerated on Wed Mar 20 2019 07:55:49