ros_publisher.cpp
Go to the documentation of this file.
1 #include <bitset>
2 #include <cmath>
3 
4 #include <boost/date_time/gregorian/gregorian.hpp>
5 #include <boost/date_time/posix_time/posix_time.hpp>
6 
7 #include "ros_publisher.h"
8 #include <ros/node_handle.h>
9 
10 ROSPublisher::ROSPublisher() : nh("~"), diagPub(nh)
11 {
12  nh.param("frame_id", frame_id, std::string("imu_link_ned"));
13  nh.param("time_source", time_source, std::string("ins"));
14  nh.param("time_origin", time_origin, std::string("unix"));
15  nh.param("use_compensated_acceleration", use_compensated_acceleration, false);
16 
17  if(time_source == std::string("ros"))
18  {
19  useInsAsTimeReference = false;
20  }
21  else if(time_source != std::string("ins"))
22  {
23  ROS_WARN("This timestamp source is not available. You can use ins or ros. By "
24  "default we replace your value by ins.");
25  time_source = std::string("ins");
26  }
27 
28  if(time_origin == std::string("sensor_default"))
29  {
30  useUnixAsTimeOrigin = false;
31  }
32  else if(time_origin != std::string("unix"))
33  {
34  ROS_WARN("This timestamp origin is not available. You can use unix or "
35  "sensor_default. By default we replace your value by unix.");
36  time_origin = std::string("unix");
37  }
38 
39  // Check parameters' value
40  ROS_INFO("Frame ID : %s", frame_id.c_str());
41  ROS_INFO("Timestamp register in the header will come from : %s", time_source.c_str());
42  ROS_INFO("Timestamp register in the header will be in the base time of : %s",
43  time_origin.c_str());
44  ROS_INFO("Use compensated acceleration : %s",
45  use_compensated_acceleration ? "true" : "false");
46 
47  // Diagnostics
48  const std::string hardwareName = std::string{"iXblue INS "} + frame_id;
49  diagPub.setHardwareID(hardwareName);
50 
51  // Publishers
52  stdImuPublisher = nh.advertise<sensor_msgs::Imu>("standard/imu", 1);
53  stdNavSatFixPublisher = nh.advertise<sensor_msgs::NavSatFix>("standard/navsatfix", 1);
55  nh.advertise<sensor_msgs::TimeReference>("standard/timereference", 1);
56  stdInsPublisher = nh.advertise<ixblue_ins_msgs::Ins>("ix/ins", 1);
57 }
58 
62 {
63  // Update status for diagnostics
65 
66  auto headerMsg = getHeader(headerData, navData);
67 
68  // If system is waiting for position, do not publish because data have no meaning
69  if(navData.insSystemStatus.is_initialized())
70  {
71  const std::bitset<32> systemStatus2{navData.insSystemStatus->status2};
72  if(systemStatus2.test(
73  ixblue_stdbin_decoder::Data::INSSystemStatus::Status2::WAIT_FOR_POSITION))
74  {
75  return;
76  }
77  }
78 
79  auto imuMsg = toImuMsg(navData, use_compensated_acceleration);
80  auto navsatfixMsg = toNavSatFixMsg(navData);
81  auto iXinsMsg = toiXInsMsg(navData);
82 
84  {
85  auto timeReferenceMsg = toTimeReference(headerData);
86 
87  if(timeReferenceMsg)
88  {
89  timeReferenceMsg->header = headerMsg;
90  stdTimeReferencePublisher.publish(timeReferenceMsg);
91  }
92  }
93 
94  if(imuMsg)
95  {
96  imuMsg->header = headerMsg;
97  stdImuPublisher.publish(imuMsg);
98  diagPub.stdImuTick(imuMsg->header.stamp);
99  }
100  if(navsatfixMsg)
101  {
102  navsatfixMsg->header = headerMsg;
103  stdNavSatFixPublisher.publish(navsatfixMsg);
104  }
105  if(iXinsMsg)
106  {
107  iXinsMsg->header = headerMsg;
108  stdInsPublisher.publish(iXinsMsg);
109  }
110 }
111 
112 std_msgs::Header
115 {
116  // --- Initialisation
117  std_msgs::Header res;
118 
119  // --- Frame ID
120  res.frame_id = frame_id;
121 
122  // --- Timestamp
124  {
125 
126  uint32_t sec = (uint32_t)((headerData.navigationDataValidityTime_100us) / 10000);
127  uint32_t nsec =
128  (uint32_t)(((headerData.navigationDataValidityTime_100us) % 10000) * 100000);
129 
130  // --- Stamp origin = unix i.e. since 1st of january 1970
132  {
133  // Step 1 : to gregorian date
134  boost::gregorian::date survey_day(navData.systemDate.get().year,
135  navData.systemDate.get().month,
136  navData.systemDate.get().day);
137 
138  // Step 2 : to unix date
139  boost::gregorian::date unix_origin(1970, 1, 1);
140  boost::posix_time::ptime survey_day_p = boost::posix_time::ptime(survey_day);
141  boost::posix_time::ptime unix_origin_p =
142  boost::posix_time::ptime(unix_origin);
143  uint32_t stamp_since_origin_sec =
144  (uint32_t)(survey_day_p - unix_origin_p).total_seconds();
145 
146  // Step 3 : to ROS format
147  res.stamp = ros::Time(stamp_since_origin_sec + sec, nsec);
148  }
149  else
150  {
151  res.stamp = ros::Time(sec, nsec);
152  }
153  }
154  else
155  {
156  res.stamp = ros::Time::now();
157  }
158 
159  return res;
160 }
161 
162 sensor_msgs::ImuPtr
165 {
166 
167  // --- Check if there are enough data to send the message
168  if(!navData.rotationRateVesselFrame.is_initialized() ||
169  !navData.attitudeQuaternion.is_initialized() ||
170  (use_compensated_acceleration &&
171  !navData.accelerationVesselFrame.is_initialized()) ||
172  (!use_compensated_acceleration &&
173  !navData.rawAccelerationVesselFrame.is_initialized()))
174  {
175  return nullptr;
176  }
177 
178  // --- Initialisation
179  sensor_msgs::ImuPtr res = boost::make_shared<sensor_msgs::Imu>();
180 
181  // --- Orientation
182  res->orientation.x = navData.attitudeQuaternion.get().q1;
183  res->orientation.y = navData.attitudeQuaternion.get().q2;
184  res->orientation.z = navData.attitudeQuaternion.get().q3;
185  // Must negate w to get a correct quaternion and match attitudeHeading output
186  res->orientation.w = -navData.attitudeQuaternion.get().q0;
187 
188  // --- Orientation SD
189  if(navData.attitudeQuaternionDeviation.is_initialized() == false)
190  {
191  // We don't have the velocity covariance in data, so according to the ROS standard
192  // described in msg file we set the whole matrix to 0.
193  res->orientation_covariance.assign(0);
194  }
195  else
196  {
197  // According to ros documentation, if the covariance is not available we only put
198  // the variance in the diagonal
199  res->orientation_covariance[0] =
200  navData.attitudeQuaternionDeviation.get().quat_stddev_xi1 *
201  navData.attitudeQuaternionDeviation.get().quat_stddev_xi1;
202  res->orientation_covariance[4] =
203  navData.attitudeQuaternionDeviation.get().quat_stddev_xi2 *
204  navData.attitudeQuaternionDeviation.get().quat_stddev_xi2;
205  res->orientation_covariance[8] =
206  navData.attitudeQuaternionDeviation.get().quat_stddev_xi3 *
207  navData.attitudeQuaternionDeviation.get().quat_stddev_xi3;
208  }
209 
210  // --- Angular Velocity
211  // According to the ros standard, the angular velocity must be in rad/sec
212  res->angular_velocity.x =
213  navData.rotationRateVesselFrame.get().xv1_degsec * M_PI / 180.;
214  res->angular_velocity.y =
215  navData.rotationRateVesselFrame.get().xv2_degsec * M_PI / 180.;
216  res->angular_velocity.z =
217  navData.rotationRateVesselFrame.get().xv3_degsec * M_PI / 180.;
218 
219  // --- Angular Velocity SD
220  if(navData.rotationRateVesselFrameDeviation.is_initialized() == false)
221  {
222  // We don't have the velocity covariance in data, so according to the ROS standard
223  // described in msg file we set the whole matrix to 0.
224  res->angular_velocity_covariance.assign(0);
225  }
226  else
227  {
228  // According to ros documentation, if the covariance is not available we only put
229  // the variance in the diagonal
230  res->angular_velocity_covariance[0] =
231  (navData.rotationRateVesselFrameDeviation.get().xv1_stddev_degsec * M_PI /
232  180) *
233  (navData.rotationRateVesselFrameDeviation.get().xv1_stddev_degsec * M_PI /
234  180);
235  res->angular_velocity_covariance[4] =
236  (navData.rotationRateVesselFrameDeviation.get().xv2_stddev_degsec * M_PI /
237  180) *
238  (navData.rotationRateVesselFrameDeviation.get().xv2_stddev_degsec * M_PI /
239  180);
240  res->angular_velocity_covariance[8] =
241  (navData.rotationRateVesselFrameDeviation.get().xv3_stddev_degsec * M_PI /
242  180) *
243  (navData.rotationRateVesselFrameDeviation.get().xv3_stddev_degsec * M_PI /
244  180);
245  }
246 
247  // --- Linear Acceleration
248  if(use_compensated_acceleration)
249  {
250  res->linear_acceleration.x = navData.accelerationVesselFrame.get().xv1_msec2;
251  res->linear_acceleration.y = navData.accelerationVesselFrame.get().xv2_msec2;
252  res->linear_acceleration.z = navData.accelerationVesselFrame.get().xv3_msec2;
253  }
254  else
255  {
256  res->linear_acceleration.x = navData.rawAccelerationVesselFrame.get().xv1_msec2;
257  res->linear_acceleration.y = navData.rawAccelerationVesselFrame.get().xv2_msec2;
258  res->linear_acceleration.z = navData.rawAccelerationVesselFrame.get().xv3_msec2;
259  }
260 
261  // --- Linear Acceleration SD
262  if(navData.accelerationVesselFrameDeviation.is_initialized() == false)
263  {
264  // We don't have the velocity covariance in data, so according to the ROS standard
265  // described in msg file we set the whole matrix to 0.
266  res->linear_acceleration_covariance.assign(0);
267  }
268  else
269  {
270  // According to ros documentation, if the covariance is not available we only put
271  // the variance in the diagonal
272  res->linear_acceleration_covariance[0] =
273  navData.accelerationVesselFrameDeviation.get().xv1_stddev_msec2 *
274  navData.accelerationVesselFrameDeviation.get().xv1_stddev_msec2;
275  res->linear_acceleration_covariance[4] =
276  navData.accelerationVesselFrameDeviation.get().xv2_stddev_msec2 *
277  navData.accelerationVesselFrameDeviation.get().xv2_stddev_msec2;
278  res->linear_acceleration_covariance[8] =
279  navData.accelerationVesselFrameDeviation.get().xv3_stddev_msec2 *
280  navData.accelerationVesselFrameDeviation.get().xv3_stddev_msec2;
281  }
282 
283  return res;
284 }
285 
286 sensor_msgs::NavSatFixPtr
288 {
289 
290  // --- Check if there are enough data to send the message
291  if(navData.position.is_initialized() == false)
292  {
293  return nullptr;
294  }
295 
296  // --- Initialisation
297  sensor_msgs::NavSatFixPtr res = boost::make_shared<sensor_msgs::NavSatFix>();
298 
299  // --- Position
300  res->latitude = navData.position.get().latitude_deg;
301  res->longitude = navData.position.get().longitude_deg;
302  // stdbin output in [0; 360[ but NavSatFix must be in [-180; +180]
303  if(res->longitude > 180.0)
304  {
305  res->longitude -= 360.0;
306  }
307  res->altitude = navData.position.get().altitude_m;
308 
309  // --- Position SD
310  if(navData.positionDeviation.is_initialized() == false)
311  {
312  // We don't have the velocity covariance in data, so according to the ROS standard
313  // described in msg file we set the whole matrix to 0.
314  res->position_covariance.assign(0);
315  res->position_covariance_type = 0;
316  }
317  else
318  {
319  // According to ros documentation, if the covariance is not available we only put
320  // the variance in the diagonal. ENU order.
321  res->position_covariance[0] = navData.positionDeviation.get().east_stddev_m *
322  navData.positionDeviation.get().east_stddev_m;
323  res->position_covariance[1] = navData.positionDeviation.get().north_east_corr *
324  navData.positionDeviation.get().east_stddev_m *
325  navData.positionDeviation.get().north_stddev_m;
326  res->position_covariance[3] = navData.positionDeviation.get().north_east_corr *
327  navData.positionDeviation.get().east_stddev_m *
328  navData.positionDeviation.get().north_stddev_m;
329  res->position_covariance[4] = navData.positionDeviation.get().north_stddev_m *
330  navData.positionDeviation.get().north_stddev_m;
331  res->position_covariance[8] = navData.positionDeviation.get().altitude_stddev_m *
332  navData.positionDeviation.get().altitude_stddev_m;
333  res->position_covariance_type = 2;
334  }
335 
336  return res;
337 }
338 
339 sensor_msgs::TimeReferencePtr
341 {
342  // --- Initialisation
343  sensor_msgs::TimeReferencePtr res = boost::make_shared<sensor_msgs::TimeReference>();
344 
345  // --- System time
346  res->header.stamp = ros::Time::now();
347 
348  // --- INS Timestamp
349  uint32_t sec = (uint32_t)((headerData.navigationDataValidityTime_100us) / 10000);
350  uint32_t nsec =
351  (uint32_t)(((headerData.navigationDataValidityTime_100us) % 10000) * 100000);
352 
353  res->time_ref = ros::Time(sec, nsec);
354 
355  // --- Frame
356  res->source = std::string("ins");
357 
358  return res;
359 }
360 
361 ixblue_ins_msgs::InsPtr
363 {
364 
365  // --- Check if there are enough data to send the message
366  if(navData.position.is_initialized() == false ||
367  navData.attitudeHeading.is_initialized() == false ||
368  navData.speedVesselFrame.is_initialized() == false ||
369  navData.insUserStatus.is_initialized() == false)
370  {
371  return nullptr;
372  }
373 
374  // --- Initialisation
375  ixblue_ins_msgs::InsPtr res = boost::make_shared<ixblue_ins_msgs::Ins>();
376 
377  // --- Position
378  res->latitude = navData.position.get().latitude_deg;
379  res->longitude = navData.position.get().longitude_deg;
380  res->altitude_ref = navData.position.get().altitude_ref;
381  res->altitude = navData.position.get().altitude_m;
382 
383  // --- Position SD
384  if(navData.positionDeviation.is_initialized() == false)
385  {
386  // We don't have the velocity covariance in data, so according to the ROS standard
387  // described in msg file we set the whole matrix to 0.
388  res->position_covariance.assign(0);
389  }
390  else
391  {
392  // According to ros documentation, if the covariance is not available we only put
393  // the variance in the diagonal. ENU order.
394  res->position_covariance[0] = navData.positionDeviation.get().east_stddev_m *
395  navData.positionDeviation.get().east_stddev_m;
396  res->position_covariance[1] = navData.positionDeviation.get().north_east_corr *
397  navData.positionDeviation.get().east_stddev_m *
398  navData.positionDeviation.get().north_stddev_m;
399  res->position_covariance[3] = navData.positionDeviation.get().north_east_corr *
400  navData.positionDeviation.get().east_stddev_m *
401  navData.positionDeviation.get().north_stddev_m;
402  res->position_covariance[4] = navData.positionDeviation.get().north_stddev_m *
403  navData.positionDeviation.get().north_stddev_m;
404  res->position_covariance[8] = navData.positionDeviation.get().altitude_stddev_m *
405  navData.positionDeviation.get().altitude_stddev_m;
406  }
407 
408  // --- Attitude
409  res->heading = navData.attitudeHeading.get().heading_deg;
410  res->roll = navData.attitudeHeading.get().roll_deg;
411  res->pitch = navData.attitudeHeading.get().pitch_deg;
412 
413  // --- Attitude SD
414  if(navData.attitudeHeadingDeviation.is_initialized() == false)
415  {
416  // We don't have the velocity covariance in data, so according to the ROS standard
417  // described in msg file we set the whole matrix to 0.
418  res->attitude_covariance.assign(0);
419  }
420  else
421  {
422  // According to ros documentation, if the covariance is not available we only put
423  // the variance in the diagonal. ENU order.
424  res->attitude_covariance[0] =
425  navData.attitudeHeadingDeviation.get().heading_stdDev_deg *
426  navData.attitudeHeadingDeviation.get().heading_stdDev_deg;
427  res->attitude_covariance[4] =
428  navData.attitudeHeadingDeviation.get().roll_stdDev_deg *
429  navData.attitudeHeadingDeviation.get().roll_stdDev_deg;
430  res->attitude_covariance[8] =
431  navData.attitudeHeadingDeviation.get().pitch_stdDev_deg *
432  navData.attitudeHeadingDeviation.get().pitch_stdDev_deg;
433  }
434 
435  // --- Speed Vessel Frame
436  res->speed_vessel_frame.x = navData.speedVesselFrame.get().xv1_msec;
437  res->speed_vessel_frame.y = navData.speedVesselFrame.get().xv2_msec;
438  res->speed_vessel_frame.z = navData.speedVesselFrame.get().xv3_msec;
439 
440  // --- Speed ENU SD
441  if(navData.speedGeographicFrameDeviation.is_initialized() == false)
442  {
443  // We don't have the velocity covariance in data, so according to the ROS standard
444  // described in msg file we set the whole matrix to 0.
445  res->speed_vessel_frame_covariance.assign(0);
446  }
447  else
448  {
449  // According to ros documentation, if the covariance is not available we only put
450  // the variance in the diagonal. ENU order.
451  res->speed_vessel_frame_covariance[0] =
452  navData.speedGeographicFrameDeviation.get().east_stddev_msec *
453  navData.speedGeographicFrameDeviation.get().east_stddev_msec;
454  res->speed_vessel_frame_covariance[4] =
455  navData.speedGeographicFrameDeviation.get().north_stddev_msec *
456  navData.speedGeographicFrameDeviation.get().north_stddev_msec;
457  res->speed_vessel_frame_covariance[8] =
458  navData.speedGeographicFrameDeviation.get().up_stddev_msec *
459  navData.speedGeographicFrameDeviation.get().up_stddev_msec;
460  }
461 
462  return res;
463 }
std::string time_source
Definition: ros_publisher.h:42
boost::optional< SpeedVesselFrame > speedVesselFrame
void onNewStdBinData(const ixblue_stdbin_decoder::Data::BinaryNav &navData, const ixblue_stdbin_decoder::Data::NavHeader &headerData)
boost::optional< AccelerationVesselFrameDeviation > accelerationVesselFrameDeviation
boost::optional< SystemDate > systemDate
boost::optional< INSSystemStatus > insSystemStatus
ros::Publisher stdInsPublisher
Definition: ros_publisher.h:52
boost::optional< AccelerationVesselFrame > accelerationVesselFrame
boost::optional< INSAlgorithmStatus > insAlgorithmStatus
boost::optional< RotationRateVesselFrame > rotationRateVesselFrame
void publish(const boost::shared_ptr< M > &message) const
boost::optional< RawAccelerationVesselFrame > rawAccelerationVesselFrame
boost::optional< Position > position
std::string frame_id
Definition: ros_publisher.h:41
static sensor_msgs::NavSatFixPtr toNavSatFixMsg(const ixblue_stdbin_decoder::Data::BinaryNav &navData)
ros::Publisher stdNavSatFixPublisher
Definition: ros_publisher.h:50
boost::optional< PositionDeviation > positionDeviation
boost::optional< AttitudeQuaternion > attitudeQuaternion
DiagnosticsPublisher diagPub
Definition: ros_publisher.h:53
#define ROS_WARN(...)
boost::optional< INSUserStatus > insUserStatus
static sensor_msgs::ImuPtr toImuMsg(const ixblue_stdbin_decoder::Data::BinaryNav &navData, bool use_compensated_acceleration)
std::string time_origin
Definition: ros_publisher.h:43
void setHardwareID(const std::string &hwId)
boost::optional< AttitudeQuaternionDeviation > attitudeQuaternionDeviation
std_msgs::Header getHeader(const ixblue_stdbin_decoder::Data::NavHeader &headerData, const ixblue_stdbin_decoder::Data::BinaryNav &navData)
bool useInsAsTimeReference
Definition: ros_publisher.h:56
#define ROS_INFO(...)
bool param(const std::string &param_name, T &param_val, const T &default_val) const
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
ros::Publisher stdTimeReferencePublisher
Definition: ros_publisher.h:51
void stdImuTick(const ros::Time &stamp)
boost::optional< AttitudeHeading > attitudeHeading
ros::Publisher stdImuPublisher
Definition: ros_publisher.h:49
static sensor_msgs::TimeReferencePtr toTimeReference(const ixblue_stdbin_decoder::Data::NavHeader &headerData)
bool useUnixAsTimeOrigin
Definition: ros_publisher.h:57
boost::optional< AttitudeHeadingDeviation > attitudeHeadingDeviation
void updateStatus(const boost::optional< ixblue_stdbin_decoder::Data::INSSystemStatus > &systemStatus, const boost::optional< ixblue_stdbin_decoder::Data::INSAlgorithmStatus > &algorithmStatus)
boost::optional< SpeedGeographicFrameDeviation > speedGeographicFrameDeviation
static Time now()
static ixblue_ins_msgs::InsPtr toiXInsMsg(const ixblue_stdbin_decoder::Data::BinaryNav &navData)
boost::optional< RotationRateVesselFrameDeviation > rotationRateVesselFrameDeviation
bool use_compensated_acceleration
Definition: ros_publisher.h:44
ros::NodeHandle nh
Definition: ros_publisher.h:46


ixblue_ins_driver
Author(s): Adrien BARRAL , Laure LE BRETON
autogenerated on Wed Jan 27 2021 03:37:01