kvh_geo_fog_3d_node.cpp
Go to the documentation of this file.
1 /*********************************************************************
2  * Software License Agreement (Apache 2.0)
3  *
4  * Copyright (c) 2019, The MITRE Corporation.
5  * All rights reserved.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * https://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  * Sections of this project contains content developed by The MITRE Corporation.
20  * If this code is used in a deployment or embedded within another project,
21  * it is requested that you send an email to opensource@mitre.org in order to
22  * let us know where this software is being used.
23  *********************************************************************/
24 
33 // STD
34 #include "unistd.h"
35 #include <map>
36 #include <cmath>
37 
38 // KVH GEO FOG
41 #include "spatial_packets.h"
43 
44 // ROS
45 #include "ros/ros.h"
48 #include <geometry_msgs/TransformStamped.h>
50 
51 // Custom ROS msgs
52 #include <kvh_geo_fog_3d_msgs/KvhGeoFog3DSystemState.h>
53 #include <kvh_geo_fog_3d_msgs/KvhGeoFog3DSatellites.h>
54 #include <kvh_geo_fog_3d_msgs/KvhGeoFog3DDetailSatellites.h>
55 #include <kvh_geo_fog_3d_msgs/KvhGeoFog3DLocalMagneticField.h>
56 #include <kvh_geo_fog_3d_msgs/KvhGeoFog3DUTMPosition.h>
57 #include <kvh_geo_fog_3d_msgs/KvhGeoFog3DECEFPos.h>
58 #include <kvh_geo_fog_3d_msgs/KvhGeoFog3DNorthSeekingInitStatus.h>
59 #include <kvh_geo_fog_3d_msgs/KvhGeoFog3DOdometerState.h>
60 #include <kvh_geo_fog_3d_msgs/KvhGeoFog3DRawGNSS.h>
61 #include <kvh_geo_fog_3d_msgs/KvhGeoFog3DRawSensors.h>
62 
63 // Standard ROS msgs
64 #include "sensor_msgs/Imu.h"
65 #include "sensor_msgs/NavSatFix.h"
66 #include "sensor_msgs/NavSatStatus.h"
67 #include "sensor_msgs/MagneticField.h"
68 #include "nav_msgs/Odometry.h"
69 #include "geometry_msgs/Quaternion.h"
70 #include "geometry_msgs/Vector3.h"
71 #include "geometry_msgs/Vector3Stamped.h"
72 
73 // Bounds on [-pi, pi)
74 inline double BoundFromNegPiToPi(const double &_value)
75 {
76  double num = std::fmod(_value, (2*M_PI));
77  if (num > M_PI)
78  {
79  num = num - (2*M_PI);
80  }
81  return num;
82 } //end: BoundFromNegPiToPi(double* _value)
83 
84 inline double BoundFromNegPiToPi(const float &_value)
85 {
86  double num = std::fmod(_value, (2*M_PI));
87  if (num > M_PI)
88  {
89  num = num - (2*M_PI);
90  }
91  return num;
92 } //end: BoundFromNegPiToPi(const float& _value)
93 
94 // Bounds on [-pi, pi)
95 inline double BoundFromZeroTo2Pi(const double &_value)
96 {
97  return std::fmod(_value, (2 * M_PI));
98 } //end: BoundFromZeroTo2Pi(double* _value)
99 
100 inline double BoundFromZeroTo2Pi(const float &_value)
101 {
102  return std::fmod(_value, (2 * M_PI));
103 } //end: BoundFromZeroTo2Pi(const float& _value)
104 
106 {
107  _diagnostics->setHardwareID("KVH GEO FOG 3D");
108 
111  _diagnostics->add("KVH System", _diagContainer, &mitre::KVH::DiagnosticsContainer::UpdateSystemStatus);
112  _diagnostics->add("KVH Filters", _diagContainer, &mitre::KVH::DiagnosticsContainer::UpdateFilterStatus);
113 }
114 
116 {
117 
118  // Check if the port has been set on the ros param server
119  _node.getParam("port", _initOptions.port);
120  _node.getParam("baud", _initOptions.baudRate);
121  _node.getParam("debug", _initOptions.debugOn);
122 
123  int filterVehicleType;
124  if (_node.getParam("filterVehicleType", filterVehicleType))
125  {
126  // node.getParam doesn't have an overload for uint8_t
127  _initOptions.filterVehicleType = filterVehicleType;
128  }
129 
130  _node.getParam("atmosphericAltitudeEnabled", _initOptions.atmosphericAltitudeEnabled);
131  _node.getParam("velocityHeadingEnabled", _initOptions.velocityHeadingEnabled);
132  _node.getParam("reversingDetectionEnabled", _initOptions.reversingDetectionEnabled);
133  _node.getParam("motionAnalysisEnabled", _initOptions.motionAnalysisEnabled);
134  _node.getParam("odomPulseToMeters", _initOptions.odomPulseToMeters);
135 
136  ROS_INFO_STREAM("Port: " << _initOptions.port);
137  ROS_INFO_STREAM("Baud: " << _initOptions.baudRate);
138  ROS_INFO_STREAM("Debug: " << _initOptions.debugOn);
139  ROS_INFO_STREAM("Filter Vehicle Type: " << (int) _initOptions.filterVehicleType);
140  ROS_INFO_STREAM("Atmospheric Altitude Enabled: " << _initOptions.atmosphericAltitudeEnabled);
141  ROS_INFO_STREAM("Velocity Heading Enabled: " << _initOptions.velocityHeadingEnabled);
142  ROS_INFO_STREAM("Reversing Detection Enabled: " << _initOptions.reversingDetectionEnabled);
143  ROS_INFO_STREAM("Motion Analysis Enabled: " << _initOptions.motionAnalysisEnabled);
144  ROS_INFO_STREAM("Odometer Pulses to Meters: " << _initOptions.odomPulseToMeters);
145 
146  return 0;
147 }
148 
149 int main(int argc, char **argv)
150 {
151  ros::init(argc, argv, "kvh_geo_fog_3d_driver");
152 
153  ros::NodeHandle node("~");
154  ros::Rate rate(50); // 50hz by default, may eventually make settable parameter
155 
156  diagnostic_updater::Updater diagnostics;
157  mitre::KVH::DiagnosticsContainer diagContainer;
158  SetupUpdater(&diagnostics, &diagContainer);
159 
160  // Custom msg publishers
161  std::map<packet_id_e, ros::Publisher> kvhPubMap{
162  {packet_id_system_state, node.advertise<kvh_geo_fog_3d_msgs::KvhGeoFog3DSystemState>("kvh_system_state", 1)},
163  {packet_id_satellites, node.advertise<kvh_geo_fog_3d_msgs::KvhGeoFog3DSatellites>("kvh_satellites", 1)},
164  {packet_id_satellites_detailed, node.advertise<kvh_geo_fog_3d_msgs::KvhGeoFog3DDetailSatellites>("kvh_detailed_satellites", 1)},
165  {packet_id_local_magnetics, node.advertise<kvh_geo_fog_3d_msgs::KvhGeoFog3DLocalMagneticField>("kvh_local_magnetics", 1)},
166  {packet_id_utm_position, node.advertise<kvh_geo_fog_3d_msgs::KvhGeoFog3DUTMPosition>("kvh_utm_position", 1)},
167  {packet_id_ecef_position, node.advertise<kvh_geo_fog_3d_msgs::KvhGeoFog3DECEFPos>("kvh_ecef_pos", 1)},
168  {packet_id_north_seeking_status, node.advertise<kvh_geo_fog_3d_msgs::KvhGeoFog3DNorthSeekingInitStatus>("kvh_north_seeking_status", 1)},
169  {packet_id_odometer_state, node.advertise<kvh_geo_fog_3d_msgs::KvhGeoFog3DOdometerState>("kvh_odometer_state", 1)},
170  {packet_id_raw_sensors, node.advertise<kvh_geo_fog_3d_msgs::KvhGeoFog3DRawSensors>("kvh_raw_sensors", 1)},
171  {packet_id_raw_gnss, node.advertise<kvh_geo_fog_3d_msgs::KvhGeoFog3DRawGNSS>("kvh_raw_gnss", 1)}};
172 
173  // Publishers for standard ros messages
174  ros::Publisher imuDataRawPub = node.advertise<sensor_msgs::Imu>("imu/data_raw_frd", 1);
175  ros::Publisher imuDataRawFLUPub = node.advertise<sensor_msgs::Imu>("imu/data_raw_flu", 1);
176  ros::Publisher imuDataNEDPub = node.advertise<sensor_msgs::Imu>("imu/data_ned", 1);
177  ros::Publisher imuDataENUPub = node.advertise<sensor_msgs::Imu>("imu/data_enu", 1);
178  ros::Publisher imuDataRpyNEDPub = node.advertise<geometry_msgs::Vector3Stamped>("imu/rpy_ned", 1);
179  ros::Publisher imuDataRpyNEDDegPub = node.advertise<geometry_msgs::Vector3Stamped>("imu/rpy_ned_deg", 1);
180  ros::Publisher imuDataRpyENUPub = node.advertise<geometry_msgs::Vector3Stamped>("imu/rpy_enu", 1);
181  ros::Publisher imuDataRpyENUDegPub = node.advertise<geometry_msgs::Vector3Stamped>("imu/rpy_enu_deg", 1);
182  ros::Publisher navSatFixPub = node.advertise<sensor_msgs::NavSatFix>("gps/fix", 1);
183  ros::Publisher rawNavSatFixPub = node.advertise<sensor_msgs::NavSatFix>("gps/raw_fix", 1);
184  ros::Publisher magFieldPub = node.advertise<sensor_msgs::MagneticField>("mag", 1);
185  ros::Publisher odomPubNED = node.advertise<nav_msgs::Odometry>("gps/utm_ned", 1);
186  ros::Publisher odomPubENU = node.advertise<nav_msgs::Odometry>("gps/utm_enu", 1);
187  ros::Publisher odomStatePub = node.advertise<nav_msgs::Odometry>("odom/wheel_encoder", 1);
188  ros::Publisher rawSensorImuPub = node.advertise<sensor_msgs::Imu>("imu/raw_sensor_frd", 1);
189  ros::Publisher rawSensorImuFluPub = node.advertise<sensor_msgs::Imu>("imu/raw_sensor_flu", 1);
190 
192  // KVH Setup
194 
195  // To get packets from the driver, we first create a vector
196  // that holds a pair containing the packet id and the desired frequency for it to be published
197  // See documentation for all id's.
198  typedef std::pair<packet_id_e, int> freqPair;
199 
200  kvh::KvhPacketRequest packetRequest{
202  freqPair(packet_id_system_state, 50),
203  freqPair(packet_id_satellites, 10),
204  freqPair(packet_id_satellites_detailed, 1),
205  freqPair(packet_id_local_magnetics, 50),
206  freqPair(packet_id_utm_position, 50),
207  freqPair(packet_id_ecef_position, 50),
208  freqPair(packet_id_north_seeking_status, 50),
209  freqPair(packet_id_odometer_state, 50),
210  freqPair(packet_id_raw_sensors, 50),
211  freqPair(packet_id_raw_gnss, 50),
212  };
213 
214  kvh::Driver kvhDriver;
215  kvh::KvhInitOptions initOptions;
216 
217  if (GetInitOptions(node, initOptions) < 0)
218  {
219  ROS_ERROR("Unable to get init options. Exiting.");
220  exit(1);
221  }
222 
223  int errorCode;
224  if ((errorCode = kvhDriver.Init(initOptions.port, packetRequest, initOptions)) < 0)
225  {
226  ROS_ERROR("Unable to initialize driver. Error Code %d", errorCode);
227  exit(1);
228  };
229 
230  // Declare these for reuse
231  system_state_packet_t systemStatePacket;
232  satellites_packet_t satellitesPacket;
233  detailed_satellites_packet_t detailSatellitesPacket;
234  local_magnetics_packet_t localMagPacket;
235  kvh::utm_fix utmPosPacket;
236  ecef_position_packet_t ecefPosPacket;
237  north_seeking_status_packet_t northSeekingStatPacket;
239  odometer_state_packet_t odomStatePacket;
240  raw_sensors_packet_t rawSensorsPacket;
241  raw_gnss_packet_t rawGnssPacket;
242 
243  while (ros::ok())
244  {
245  // Collect packet data
246  kvhDriver.Once();
247 
248  // Create header we will use for all messages. Important to have timestamp the same
249  std_msgs::Header header;
250  header.stamp = ros::Time::now();
251 
253  // CUSTOM ROS MESSAGES
255 
256  // SYSTEM STATE PACKET
258  {
259  ROS_DEBUG("System state packet has updated. Publishing...");
260 
261  kvhDriver.GetPacket(packet_id_system_state, systemStatePacket);
262 
263  kvh_geo_fog_3d_msgs::KvhGeoFog3DSystemState sysStateMsg;
264  sysStateMsg.header = header;
265 
266  sysStateMsg.system_status = systemStatePacket.system_status.r;
267  sysStateMsg.filter_status = systemStatePacket.filter_status.r;
268 
269  sysStateMsg.unix_time_s = systemStatePacket.unix_time_seconds;
270  sysStateMsg.unix_time_us = systemStatePacket.microseconds;
271 
272  sysStateMsg.latitude_rad = systemStatePacket.latitude;
273  sysStateMsg.longitude_rad = systemStatePacket.longitude;
274  sysStateMsg.height_m = systemStatePacket.height;
275 
276  sysStateMsg.absolute_velocity_north_mps = systemStatePacket.velocity[0];
277  sysStateMsg.absolute_velocity_east_mps = systemStatePacket.velocity[1];
278  sysStateMsg.absolute_velocity_down_mps = systemStatePacket.velocity[2];
279 
280  sysStateMsg.body_acceleration_x_mps = systemStatePacket.body_acceleration[0];
281  sysStateMsg.body_acceleration_y_mps = systemStatePacket.body_acceleration[1];
282  sysStateMsg.body_acceleration_z_mps = systemStatePacket.body_acceleration[2];
283 
284  sysStateMsg.g_force_g = systemStatePacket.g_force;
285 
286  sysStateMsg.roll_rad = systemStatePacket.orientation[0];
287  sysStateMsg.pitch_rad = systemStatePacket.orientation[1];
288  sysStateMsg.heading_rad = systemStatePacket.orientation[2];
289 
290  sysStateMsg.angular_velocity_x_rad_per_s = systemStatePacket.angular_velocity[0];
291  sysStateMsg.angular_velocity_y_rad_per_s = systemStatePacket.angular_velocity[1];
292  sysStateMsg.angular_velocity_z_rad_per_s = systemStatePacket.angular_velocity[2];
293 
294  sysStateMsg.latitude_stddev_m = systemStatePacket.standard_deviation[0];
295  sysStateMsg.longitude_stddev_m = systemStatePacket.standard_deviation[1];
296  sysStateMsg.height_stddev_m = systemStatePacket.standard_deviation[2];
297 
298  //Update diagnostics container from this message
299  diagContainer.SetSystemStatus(systemStatePacket.system_status.r);
300  diagContainer.SetFilterStatus(systemStatePacket.filter_status.r);
301 
302  kvhPubMap[packet_id_system_state].publish(sysStateMsg);
303  }
304 
305  // SATELLITES PACKET
306  if (kvhDriver.PacketIsUpdated(packet_id_satellites))
307  {
308  ROS_DEBUG("Satellites packet updated. Publishing...");
309  kvhDriver.GetPacket(packet_id_satellites, satellitesPacket);
310  kvh_geo_fog_3d_msgs::KvhGeoFog3DSatellites satellitesMsg;
311 
312  satellitesMsg.header = header;
313  satellitesMsg.hdop = satellitesPacket.hdop;
314  satellitesMsg.vdop = satellitesPacket.vdop;
315  satellitesMsg.gps_satellites = satellitesPacket.gps_satellites;
316  satellitesMsg.glonass_satellites = satellitesPacket.glonass_satellites;
317  satellitesMsg.beidou_satellites = satellitesPacket.beidou_satellites;
318  satellitesMsg.galileo_satellites = satellitesPacket.sbas_satellites;
319 
320  kvhPubMap[packet_id_satellites].publish(satellitesMsg);
321  }
322 
323  // SATELLITES DETAILED
325  {
326  ROS_DEBUG("Detailed satellites packet updated. Publishing...");
327  kvhDriver.GetPacket(packet_id_satellites_detailed, detailSatellitesPacket);
328  kvh_geo_fog_3d_msgs::KvhGeoFog3DDetailSatellites detailSatellitesMsg;
329 
330  detailSatellitesMsg.header = header;
331 
332  // MAXIMUM_DETAILED_SATELLITES is defined as 32 in spatial_packets.h
333  // We must check if each field equals 0 as that denotes the end of the array
334  for (int i = 0; i < MAXIMUM_DETAILED_SATELLITES; i++)
335  {
336  satellite_t satellite = detailSatellitesPacket.satellites[i];
337 
338  // Check if all fields = 0, if so then we should end our loop
339  if (satellite.satellite_system == 0 && satellite.number == 0 &&
340  satellite.frequencies.r == 0 && satellite.elevation == 0 &&
341  satellite.azimuth == 0 && satellite.snr == 0)
342  {
343  break;
344  }
345 
346  detailSatellitesMsg.satellite_system.push_back(satellite.satellite_system);
347  detailSatellitesMsg.satellite_number.push_back(satellite.number);
348  detailSatellitesMsg.satellite_frequencies.push_back(satellite.frequencies.r);
349  detailSatellitesMsg.elevation_deg.push_back(satellite.elevation);
350  detailSatellitesMsg.azimuth_deg.push_back(satellite.azimuth);
351  detailSatellitesMsg.snr_decibal.push_back(satellite.snr);
352  }
353 
354  kvhPubMap[packet_id_satellites_detailed].publish(detailSatellitesMsg);
355  }
356 
357  // LOCAL MAGNETICS PACKET
359  {
360  ROS_DEBUG("Local magnetics packet updated. Publishing...");
361  kvhDriver.GetPacket(packet_id_local_magnetics, localMagPacket);
362  kvh_geo_fog_3d_msgs::KvhGeoFog3DLocalMagneticField localMagFieldMsg;
363 
364  localMagFieldMsg.header = header;
365  localMagFieldMsg.loc_mag_field_x_mG = localMagPacket.magnetic_field[0];
366  localMagFieldMsg.loc_mag_field_y_mG = localMagPacket.magnetic_field[1];
367  localMagFieldMsg.loc_mag_field_z_mG = localMagPacket.magnetic_field[2];
368 
369  kvhPubMap[packet_id_local_magnetics].publish(localMagFieldMsg);
370  }
371 
372  // UTM POSITION PACKET
374  {
375  ROS_DEBUG("UTM Position packet updated. Publishing...");
376  kvhDriver.GetPacket(packet_id_utm_position, utmPosPacket);
377  kvh_geo_fog_3d_msgs::KvhGeoFog3DUTMPosition utmPosMsg;
378 
379  utmPosMsg.header = header;
380  utmPosMsg.northing_m = utmPosPacket.position[0];
381  utmPosMsg.easting_m = utmPosPacket.position[1];
382  utmPosMsg.height_m = utmPosPacket.position[2];
383  utmPosMsg.zone_character = utmPosPacket.zone;
384 
385  kvhPubMap[packet_id_utm_position].publish(utmPosMsg);
386  }
387 
388  // ECEF POSITION PACKET
390  {
391  ROS_DEBUG("ECEF position packet updated. Publishing...");
392  kvhDriver.GetPacket(packet_id_ecef_position, ecefPosPacket);
393  kvh_geo_fog_3d_msgs::KvhGeoFog3DECEFPos ecefPosMsg;
394 
395  ecefPosMsg.header = header;
396  ecefPosMsg.ecef_x_m = ecefPosPacket.position[0];
397  ecefPosMsg.ecef_y_m = ecefPosPacket.position[1];
398  ecefPosMsg.ecef_z_m = ecefPosPacket.position[2];
399 
400  kvhPubMap[packet_id_ecef_position].publish(ecefPosMsg);
401  }
402 
403  // NORTH SEEKING STATUS PACKET
405  {
406  ROS_DEBUG("North seeking status packet updated. Publishing...");
407  kvhDriver.GetPacket(packet_id_north_seeking_status, northSeekingStatPacket);
408  kvh_geo_fog_3d_msgs::KvhGeoFog3DNorthSeekingInitStatus northSeekInitStatMsg;
409 
410  northSeekInitStatMsg.header = header;
411 
412  northSeekInitStatMsg.flags = northSeekingStatPacket.north_seeking_status.r;
413  northSeekInitStatMsg.quadrant_1_data_per = northSeekingStatPacket.quadrant_data_collection_progress[0];
414  northSeekInitStatMsg.quadrant_2_data_per = northSeekingStatPacket.quadrant_data_collection_progress[1];
415  northSeekInitStatMsg.quadrant_3_data_per = northSeekingStatPacket.quadrant_data_collection_progress[2];
416  northSeekInitStatMsg.quadrant_4_data_per = northSeekingStatPacket.quadrant_data_collection_progress[3];
417 
418  northSeekInitStatMsg.current_rotation_angle_rad = northSeekingStatPacket.current_rotation_angle;
419 
420  northSeekInitStatMsg.current_gyro_bias_sol_x_rad_s = northSeekingStatPacket.current_gyroscope_bias_solution[0];
421  northSeekInitStatMsg.current_gyro_bias_sol_y_rad_s = northSeekingStatPacket.current_gyroscope_bias_solution[1];
422  northSeekInitStatMsg.current_gyro_bias_sol_z_rad_s = northSeekingStatPacket.current_gyroscope_bias_solution[2];
423  northSeekInitStatMsg.current_gyro_bias_sol_error_per = northSeekingStatPacket.current_gyroscope_bias_solution_error;
424 
425  kvhPubMap[packet_id_north_seeking_status].publish(northSeekInitStatMsg);
426  }
427 
429  {
430  ROS_DEBUG("Odometer stage updated. Publishing...");
431  kvhDriver.GetPacket(packet_id_odometer_state, odomStatePacket);
432  kvh_geo_fog_3d_msgs::KvhGeoFog3DOdometerState odometerStateMsg;
433 
434  odometerStateMsg.header = header;
435  odometerStateMsg.odometer_pulse_count = odomStatePacket.pulse_count;
436  odometerStateMsg.odometer_distance_m = odomStatePacket.distance;
437  odometerStateMsg.odometer_speed_mps = odomStatePacket.speed;
438  odometerStateMsg.odometer_slip_m = odomStatePacket.slip;
439  odometerStateMsg.odometer_active = odomStatePacket.active;
440 
441  kvhPubMap[packet_id_odometer_state].publish(odometerStateMsg);
442  }
443 
444  if (kvhDriver.PacketIsUpdated(packet_id_raw_sensors))
445  {
446  ROS_DEBUG("Raw sensors packet updated. Publishing...");
447  kvhDriver.GetPacket(packet_id_raw_sensors, rawSensorsPacket);
448  kvh_geo_fog_3d_msgs::KvhGeoFog3DRawSensors rawSensorMsg;
449 
450  rawSensorMsg.header = header;
451 
452  rawSensorMsg.accelerometer_x_mpss = rawSensorsPacket.accelerometers[0];
453  rawSensorMsg.accelerometer_y_mpss = rawSensorsPacket.accelerometers[1];
454  rawSensorMsg.accelerometer_z_mpss = rawSensorsPacket.accelerometers[2];
455 
456  rawSensorMsg.gyro_x_rps = rawSensorsPacket.gyroscopes[0];
457  rawSensorMsg.gyro_y_rps = rawSensorsPacket.gyroscopes[1];
458  rawSensorMsg.gyro_z_rps = rawSensorsPacket.gyroscopes[2];
459 
460  rawSensorMsg.magnetometer_x_mG = rawSensorsPacket.magnetometers[0];
461  rawSensorMsg.magnetometer_y_mG = rawSensorsPacket.magnetometers[1];
462  rawSensorMsg.magnetometer_z_mG = rawSensorsPacket.magnetometers[2];
463 
464  rawSensorMsg.imu_temp_c = rawSensorsPacket.imu_temperature;
465  rawSensorMsg.pressure_pa = rawSensorsPacket.pressure;
466  rawSensorMsg.pressure_temp_c = rawSensorsPacket.pressure_temperature;
467 
468  kvhPubMap[packet_id_raw_sensors].publish(rawSensorMsg);
469  }
470 
477  if (kvhDriver.PacketIsUpdated(packet_id_raw_gnss))
478  {
479  ROS_DEBUG("Raw GNSS packet updated. Publishing...");
480  kvhDriver.GetPacket(packet_id_raw_gnss, rawGnssPacket);
481  kvh_geo_fog_3d_msgs::KvhGeoFog3DRawGNSS rawGnssMsg;
482 
483  rawGnssMsg.header = header;
484  rawGnssMsg.unix_time_s = rawGnssPacket.unix_time_seconds;
485  rawGnssMsg.unix_time_us = rawGnssPacket.microseconds;
486 
487  rawGnssMsg.latitude_rad = rawGnssPacket.position[0];
488  rawGnssMsg.longitude_rad = rawGnssPacket.position[1];
489  rawGnssMsg.height_m = rawGnssPacket.position[2];
490 
491  rawGnssMsg.latitude_stddev_m = rawGnssPacket.position_standard_deviation[0];
492  rawGnssMsg.longitude_stddev_m = rawGnssPacket.position_standard_deviation[1];
493  rawGnssMsg.height_stddev_m = rawGnssPacket.position_standard_deviation[2];
494 
495  rawGnssMsg.vel_north_m = rawGnssPacket.velocity[0];
496  rawGnssMsg.vel_east_m = rawGnssPacket.velocity[1];
497  rawGnssMsg.vel_down_m = rawGnssPacket.velocity[2];
498 
499  rawGnssMsg.tilt_rad = rawGnssPacket.tilt;
500  rawGnssMsg.tilt_stddev_rad = rawGnssPacket.tilt_standard_deviation;
501 
502  rawGnssMsg.heading_rad = rawGnssPacket.heading;
503  rawGnssMsg.heading_stddev_rad = rawGnssPacket.heading_standard_deviation;
504 
505  rawGnssMsg.gnss_fix = rawGnssPacket.flags.b.fix_type;
506  rawGnssMsg.doppler_velocity_valid = rawGnssPacket.flags.b.velocity_valid;
507  rawGnssMsg.time_valid = rawGnssPacket.flags.b.time_valid;
508  rawGnssMsg.external_gnss = rawGnssPacket.flags.b.external_gnss;
509  rawGnssMsg.tilt_valid = rawGnssPacket.flags.b.tilt_valid;
510  rawGnssMsg.heading_valid = rawGnssPacket.flags.b.heading_valid;
511 
512  kvhPubMap[packet_id_raw_gnss].publish(rawGnssMsg);
513  }
514 
516  // STANDARD ROS MESSAGES
518 
520  {
521  kvhDriver.GetPacket(packet_id_system_state, systemStatePacket);
523 
524  // IMU Message Structure: http://docs.ros.org/melodic/api/sensor_msgs/html/msg/Imu.html
525  // Header
526  // Quaternion orientation
527  // float64[9] orientation_covariance
528  // Vector3 angular_velocity
529  // float64[9] angular_velocity_covariance
530  // Vector3 linear_acceleration
531  // float64[9] linear_acceleration_covariance
532 
533  // [-pi,pi) bounded yaw
534  double boundedBearingPiToPi = BoundFromNegPiToPi(systemStatePacket.orientation[2]);
535  double boundedBearingZero2Pi = BoundFromZeroTo2Pi(systemStatePacket.orientation[2]);
536 
537  // ORIENTATION
538  // All orientations from this sensor are w.r.t. true north.
539  if (std::isnan(eulStdDevPack.standard_deviation[0]))
540  {
541  eulStdDevPack.standard_deviation[0] = 0;
542  ROS_INFO("NAN Found");
543  }
544 
545  if (std::isnan(eulStdDevPack.standard_deviation[1]))
546  {
547  eulStdDevPack.standard_deviation[1] = 0;
548  ROS_INFO("NAN Found");
549  }
550 
551  if (std::isnan(eulStdDevPack.standard_deviation[2]))
552  {
553  eulStdDevPack.standard_deviation[2] = 0;
554  ROS_INFO("NAN Found");
555  }
556 
557  tf2::Quaternion orientQuatNED;
558  orientQuatNED.setRPY(
559  systemStatePacket.orientation[0],
560  systemStatePacket.orientation[1],
561  boundedBearingZero2Pi);
562  double orientCovNED[3] = {
563  pow(eulStdDevPack.standard_deviation[0], 2),
564  pow(eulStdDevPack.standard_deviation[1], 2),
565  pow(eulStdDevPack.standard_deviation[2], 2)};
566 
567  tf2::Quaternion orientQuatENU;
568  //For NED -> ENU transformation:
569  //(X -> Y, Y -> -X, Z -> -Z, Yaw = -Yaw + 90 deg, Pitch -> Roll, and Roll -> Pitch)
570  double unfixedEnuBearing = (-1 * boundedBearingZero2Pi) + (M_PI / 2.0);
571  double enuBearing = BoundFromZeroTo2Pi(unfixedEnuBearing);
572  orientQuatENU.setRPY(
573  systemStatePacket.orientation[1], // ENU roll = NED pitch
574  systemStatePacket.orientation[0], // ENU pitch = NED roll
575  enuBearing // ENU bearing = -(NED bearing) + 90 degrees
576  );
577  double orientCovENU[3] = {
578  pow(eulStdDevPack.standard_deviation[1], 2),
579  pow(eulStdDevPack.standard_deviation[0], 2),
580  pow(eulStdDevPack.standard_deviation[2], 2),
581  };
582 
583  // DATA_RAW Topic
584  sensor_msgs::Imu imuDataRaw;
585  imuDataRaw.header = header;
586  imuDataRaw.header.frame_id = "imu_link_frd";
587 
588  // ANGULAR VELOCITY
589  imuDataRaw.angular_velocity.x = systemStatePacket.angular_velocity[0];
590  imuDataRaw.angular_velocity.y = systemStatePacket.angular_velocity[1];
591  imuDataRaw.angular_velocity.z = systemStatePacket.angular_velocity[2];
592  // Leave covariance at 0 since we don't have it
593  // imuDataRaw.angular_velocity_covariance[0]
594  // imuDataRaw.angular_velocity_covariance[4]
595  // imuDataRaw.angular_velocity_covariance[8]
596 
597  // LINEAR ACCELERATION
598  imuDataRaw.linear_acceleration.x = systemStatePacket.body_acceleration[0];
599  imuDataRaw.linear_acceleration.y = systemStatePacket.body_acceleration[1];
600  imuDataRaw.linear_acceleration.z = systemStatePacket.body_acceleration[2];
601  // Leave covariance at 0 since we don't have it
602  // imuDataRaw.linear_acceleration_covariance[0]
603  // imuDataRaw.linear_acceleration_covariance[4]
604  // imuDataRaw.linear_acceleration_covariance[8]
605 
606  imuDataRawPub.publish(imuDataRaw);
607 
608  // DATA_RAW_FLU
609  sensor_msgs::Imu imuDataRawFLU;
610  imuDataRawFLU.header = header;
611  imuDataRawFLU.header.frame_id = "imu_link_flu";
612 
613  // ANGULAR VELOCITY
614  imuDataRawFLU.angular_velocity.x = systemStatePacket.angular_velocity[0];
615  imuDataRawFLU.angular_velocity.y = -1 * systemStatePacket.angular_velocity[1];
616  imuDataRawFLU.angular_velocity.z = -1 * systemStatePacket.angular_velocity[2]; // To account for east north up system
617  // Leave covariance at 0 since we don't have it
618  // imuDataRawFLU.angular_velocity_covariance[0]
619  // imuDataRawFLU.angular_velocity_covariance[4]
620  // imuDataRawFLU.angular_velocity_covariance[8]
621 
622  // LINEAR ACCELERATION
623  imuDataRawFLU.linear_acceleration.x = systemStatePacket.body_acceleration[0];
624  imuDataRawFLU.linear_acceleration.y = -1 * systemStatePacket.body_acceleration[1];
625  imuDataRawFLU.linear_acceleration.z = -1 * systemStatePacket.body_acceleration[2];
626  // Leave covariance at 0 since we don't have it
627  // imuDataRawFLU.linear_acceleration_covariance[0]
628  // imuDataRawFLU.linear_acceleration_covariance[4]
629  // imuDataRawFLU.linear_acceleration_covariance[8]
630 
631  imuDataRawFLUPub.publish(imuDataRawFLU);
632 
634  // DATA_NED topic
636 
637  sensor_msgs::Imu imuDataNED;
638  geometry_msgs::Vector3Stamped imuDataRpyNED;
639  geometry_msgs::Vector3Stamped imuDataRpyNEDDeg;
640  imuDataNED.header = header;
641  imuDataNED.header.frame_id = "imu_link_frd";
642 
643  imuDataNED.orientation.x = orientQuatNED.x();
644  imuDataNED.orientation.y = orientQuatNED.y();
645  imuDataNED.orientation.z = orientQuatNED.z();
646  imuDataNED.orientation.w = orientQuatNED.w();
647 
648  imuDataNED.orientation_covariance[0] = orientCovNED[0];
649  imuDataNED.orientation_covariance[4] = orientCovNED[1];
650  imuDataNED.orientation_covariance[8] = orientCovNED[2];
651 
652  imuDataRpyNED.header = header;
653  imuDataRpyNED.header.frame_id = "imu_link_frd";
654  imuDataRpyNED.vector.x = systemStatePacket.orientation[0];
655  imuDataRpyNED.vector.y = systemStatePacket.orientation[1];
656  imuDataRpyNED.vector.z = boundedBearingZero2Pi;
657 
658  imuDataRpyNEDDeg.header = header;
659  imuDataRpyNEDDeg.header.frame_id = "imu_link_frd";
660  imuDataRpyNEDDeg.vector.x = ((imuDataRpyNED.vector.x * 180.0) / M_PI);
661  imuDataRpyNEDDeg.vector.y = ((imuDataRpyNED.vector.y * 180.0) / M_PI);
662  imuDataRpyNEDDeg.vector.z = ((imuDataRpyNED.vector.z * 180.0) / M_PI);
663 
664  // ANGULAR VELOCITY
665  imuDataNED.angular_velocity.x = systemStatePacket.angular_velocity[0];
666  imuDataNED.angular_velocity.y = systemStatePacket.angular_velocity[1];
667  imuDataNED.angular_velocity.z = systemStatePacket.angular_velocity[2];
668 
669  // LINEAR ACCELERATION
670  imuDataNED.linear_acceleration.x = systemStatePacket.body_acceleration[0];
671  imuDataNED.linear_acceleration.y = systemStatePacket.body_acceleration[1];
672  imuDataNED.linear_acceleration.z = systemStatePacket.body_acceleration[2];
673 
674  imuDataNEDPub.publish(imuDataNED);
675  imuDataRpyNEDPub.publish(imuDataRpyNED);
676  imuDataRpyNEDDegPub.publish(imuDataRpyNEDDeg);
677 
679  // DATA_ENU topic
681 
682  sensor_msgs::Imu imuDataENU;
683  geometry_msgs::Vector3Stamped imuDataRpyENU;
684  geometry_msgs::Vector3Stamped imuDataRpyENUDeg;
685 
686  imuDataENU.header = header;
687  imuDataENU.header.frame_id = "imu_link_flu";
688 
689  imuDataRpyENU.header = header;
690  imuDataRpyENU.header.frame_id = "imu_link_flu";
691 
692  imuDataRpyENUDeg.header = header;
693  imuDataRpyENUDeg.header.frame_id = "imu_link_flu";
694 
695  // ORIENTATION
696  //Keep in mind that these are w.r.t. frame_id
697  imuDataENU.orientation.x = orientQuatENU.x();
698  imuDataENU.orientation.y = orientQuatENU.y();
699  imuDataENU.orientation.z = orientQuatENU.z();
700  imuDataENU.orientation.w = orientQuatENU.w();
701 
702  imuDataENU.orientation_covariance[0] = orientCovENU[1];
703  imuDataENU.orientation_covariance[4] = orientCovENU[0];
704  imuDataENU.orientation_covariance[8] = orientCovENU[2];
705 
706  imuDataRpyENU.vector.x = systemStatePacket.orientation[1];
707  imuDataRpyENU.vector.y = systemStatePacket.orientation[0];
708  imuDataRpyENU.vector.z = enuBearing;
709 
710  imuDataRpyENUDeg.vector.x = ((imuDataRpyENU.vector.x * 180.0) / M_PI);
711  imuDataRpyENUDeg.vector.y = ((imuDataRpyENU.vector.y * 180.0) / M_PI);
712  imuDataRpyENUDeg.vector.z = ((imuDataRpyENU.vector.z * 180.0) / M_PI);
713 
714  // ANGULAR VELOCITY
715  // Keep in mind that for the sensor_msgs/Imu message, accelerations are
716  // w.r.t the frame_id, which in this case is imu_link_flu.
717  imuDataENU.angular_velocity.x = systemStatePacket.angular_velocity[0];
718  imuDataENU.angular_velocity.y = -1 * systemStatePacket.angular_velocity[1];
719  imuDataENU.angular_velocity.z = -1 * systemStatePacket.angular_velocity[2];
720 
721  // LINEAR ACCELERATION
722  // Keep in mind that for the sensor_msgs/Imu message, accelerations are
723  // w.r.t the frame_id, which in this case is imu_link_flu.
724  imuDataENU.linear_acceleration.x = systemStatePacket.body_acceleration[0];
725  imuDataENU.linear_acceleration.y = -1 * systemStatePacket.body_acceleration[1];
726  imuDataENU.linear_acceleration.z = -1 * systemStatePacket.body_acceleration[2];
727 
728  // Publish
729  imuDataENUPub.publish(imuDataENU);
730  imuDataRpyENUPub.publish(imuDataRpyENU);
731  imuDataRpyENUDegPub.publish(imuDataRpyENUDeg);
732 
733  // NAVSATFIX Message Structure: http://docs.ros.org/melodic/api/sensor_msgs/html/msg/NavSatFix.html
734  // NavSatStatus status
735  // float64 latitude
736  // float64 longitude
737  // float64 altitude
738  // float64[9] position_covariance // Uses East North Up (ENU) in row major order
739  // uint8 position_covariance type
740  sensor_msgs::NavSatFix navSatFixMsg;
741  navSatFixMsg.header = header;
742  navSatFixMsg.header.frame_id = "gps";
743 
744  // Set nav sat status
745  int status = systemStatePacket.filter_status.b.gnss_fix_type;
746  switch (status)
747  {
748  case 0:
749  navSatFixMsg.status.status = navSatFixMsg.status.STATUS_NO_FIX;
750  break;
751  case 1:
752  case 2:
753  navSatFixMsg.status.status = navSatFixMsg.status.STATUS_FIX;
754  break;
755  case 3:
756  navSatFixMsg.status.status = navSatFixMsg.status.STATUS_SBAS_FIX;
757  break;
758  default:
759  navSatFixMsg.status.status = navSatFixMsg.status.STATUS_GBAS_FIX;
760  }
761 
762  //NavSatFix specifies degrees as lat/lon, but KVH publishes in radians
763  double latitude_deg = (systemStatePacket.latitude * 180.0) / M_PI;
764  double longitude_deg = (systemStatePacket.longitude * 180.0) / M_PI;
765  navSatFixMsg.latitude = latitude_deg;
766  navSatFixMsg.longitude = longitude_deg;
767  navSatFixMsg.altitude = systemStatePacket.height;
768  navSatFixMsg.position_covariance_type = navSatFixMsg.COVARIANCE_TYPE_DIAGONAL_KNOWN;
769  // They use ENU for mat for this matrix. To me it makes sense that we should use
770  // the longitude standard deviation for east.
771  navSatFixMsg.position_covariance[0] = pow(systemStatePacket.standard_deviation[1], 2);
772  navSatFixMsg.position_covariance[4] = pow(systemStatePacket.standard_deviation[0], 2);
773  navSatFixMsg.position_covariance[8] = pow(systemStatePacket.standard_deviation[2], 2);
774 
775  navSatFixPub.publish(navSatFixMsg);
776 
777  // If we have system state and utm position we can publish odometry
779  {
780  // Odometry Message Structure: http://docs.ros.org/melodic/api/nav_msgs/html/msg/Odometry.html
781  // Header
782  // String child_frame_id \todo Fill out child frame id
783  // PoseWithCovariance pose
784  // --> Pose
785  // -->-->Point position
786  // -->-->Quaternion orientation
787  // -->float6[36] covariance // 6x6 order is [x, y, z, X axis rot, y axis rot, z axis rot]
788  // TwistWithCovariance twist
789  // --> Twist // Velocity in free space
790  // -->-->Vector3 linear
791  // -->-->Vector3 angular
792  // -->float64[36] covariance // 6x6 order is [x, y, z, x axis rot, y axis rot, z axis rot]
793 
794  // Since UTM is by default NED, we will publish a message like that and a message using
795  // the ros ENU standard
796  nav_msgs::Odometry odomMsgENU;
797  nav_msgs::Odometry odomMsgNED;
798  int error = kvhDriver.GetPacket(packet_id_utm_position, utmPosPacket);
799  if (error < 0)
800  {
801  printf("Error Code: %d\n", error);
802  printf("UTM PACKET: %f, %f, %f\n", utmPosPacket.position[0], utmPosPacket.position[1], utmPosPacket.position[2]);
803  }
804 
805  odomMsgENU.header = header;
806  odomMsgENU.header.frame_id = "utm_enu"; //The nav_msgs/Odometry "Pose" section should be in this frame
807  odomMsgENU.child_frame_id = "imu_link_flu"; //The nav_msgs/Odometry "Twist" section should be in this frame
808 
809  odomMsgNED.header = header;
810  odomMsgNED.header.frame_id = "utm_ned"; //The nav_msgs/Odometry "Pose" section should be in this frame
811  odomMsgNED.child_frame_id = "imu_link_frd"; //The nav_msgs/Odometry "Twist" section should be in this frame
812 
813  // POSE
814  // Position ENU
815  odomMsgENU.pose.pose.position.x = utmPosPacket.position[1];
816  odomMsgENU.pose.pose.position.y = utmPosPacket.position[0];
817  odomMsgENU.pose.pose.position.z = -1 * utmPosPacket.position[2];
818  // odomMsg.pose.covariance[0] =
819  // odomMsg.pose.covariance[7] =
820  // odomMsg.pose.covariance[14] =
821 
822  // Position NED
823  odomMsgNED.pose.pose.position.x = utmPosPacket.position[0];
824  odomMsgNED.pose.pose.position.y = utmPosPacket.position[1];
825  odomMsgNED.pose.pose.position.z = utmPosPacket.position[2];
826  // odomMsg.pose.covariance[0] =
827  // odomMsg.pose.covariance[7] =
828  // odomMsg.pose.covariance[14] =
829 
830  // Orientation ENU
831  // Use orientation quaternion we created earlier
832  odomMsgENU.pose.pose.orientation.x = orientQuatENU.x();
833  odomMsgENU.pose.pose.orientation.y = orientQuatENU.y();
834  odomMsgENU.pose.pose.orientation.z = orientQuatENU.z();
835  odomMsgENU.pose.pose.orientation.w = orientQuatENU.w();
836  // Use covariance array created earlier to fill out orientation covariance
837  odomMsgENU.pose.covariance[21] = orientCovENU[0];
838  odomMsgENU.pose.covariance[28] = orientCovENU[1];
839  odomMsgENU.pose.covariance[35] = orientCovENU[2];
840 
841  // Orientation NED
842  odomMsgNED.pose.pose.orientation.x = orientQuatNED.x();
843  odomMsgNED.pose.pose.orientation.y = orientQuatNED.y();
844  odomMsgNED.pose.pose.orientation.z = orientQuatNED.z();
845  odomMsgNED.pose.pose.orientation.w = orientQuatNED.w();
846  // Use covariance array created earlier to fill out orientation covariance
847  odomMsgNED.pose.covariance[21] = orientCovNED[0];
848  odomMsgNED.pose.covariance[28] = orientCovNED[1];
849  odomMsgNED.pose.covariance[35] = orientCovNED[2];
850 
851  // TWIST
852  // ENU uses FLU rates/accels
853  odomMsgENU.twist.twist.linear.x = systemStatePacket.velocity[0];
854  odomMsgENU.twist.twist.linear.y = (-1 * systemStatePacket.velocity[1]);
855  odomMsgENU.twist.twist.linear.z = (-1 * systemStatePacket.velocity[2]);
856 
857  odomMsgENU.twist.twist.angular.x = systemStatePacket.angular_velocity[0];
858  odomMsgENU.twist.twist.angular.y = (-1 * systemStatePacket.angular_velocity[1]);
859  odomMsgENU.twist.twist.angular.z = (-1 * systemStatePacket.angular_velocity[2]);
860 
861  // NED uses FRD rates/accels
862  odomMsgNED.twist.twist.linear.x = systemStatePacket.velocity[0];
863  odomMsgNED.twist.twist.linear.y = systemStatePacket.velocity[1];
864  odomMsgNED.twist.twist.linear.z = systemStatePacket.velocity[2];
865 
866  odomMsgNED.twist.twist.angular.x = systemStatePacket.angular_velocity[0];
867  odomMsgNED.twist.twist.angular.y = systemStatePacket.angular_velocity[1];
868  odomMsgNED.twist.twist.angular.z = systemStatePacket.angular_velocity[2];
869 
870  odomPubENU.publish(odomMsgENU);
871  odomPubNED.publish(odomMsgNED);
872  }
873  }
874 
876  {
877  kvhDriver.GetPacket(packet_id_odometer_state, odomStatePacket);
878  nav_msgs::Odometry kvhOdomStateMsg;
879 
880  kvhOdomStateMsg.header = header;
881  //Technically this should be w.r.t the fixed frame locked to your wheel
882  //with the encoder mounted. But, since I don't know what you're going to
883  //call it, we'll stick with base_link.
884  kvhOdomStateMsg.header.frame_id = "base_link";
885 
886  kvhOdomStateMsg.pose.pose.position.x = (odomStatePacket.pulse_count * initOptions.odomPulseToMeters);
887  kvhOdomStateMsg.pose.pose.position.y = 0;
888  kvhOdomStateMsg.pose.pose.position.z = 0;
889  kvhOdomStateMsg.twist.twist.linear.x = odomStatePacket.speed;
890  kvhOdomStateMsg.twist.twist.linear.y = 0;
891  kvhOdomStateMsg.twist.twist.linear.z = 0;
892 
893  odomStatePub.publish(kvhOdomStateMsg);
894  }
895 
896  if (kvhDriver.PacketIsUpdated(packet_id_raw_gnss))
897  {
898  kvhDriver.GetPacket(packet_id_raw_gnss, rawGnssPacket);
899  sensor_msgs::NavSatFix rawNavSatFixMsg;
900 
901  rawNavSatFixMsg.header = header;
902  rawNavSatFixMsg.header.frame_id = "gps";
903 
904  //NavSatFix specifies degrees as lat/lon, but KVH publishes in radians
905  double rawGnssLatitude_deg = (rawGnssPacket.position[0] * 180.0) / M_PI;
906  double rawGnssLongitude_deg = (rawGnssPacket.position[1] * 180.0) / M_PI;
907  rawNavSatFixMsg.latitude = rawGnssLatitude_deg;
908  rawNavSatFixMsg.longitude = rawGnssLongitude_deg;
909  rawNavSatFixMsg.altitude = rawGnssPacket.position[2];
910 
911  int status = systemStatePacket.filter_status.b.gnss_fix_type;
912  switch (status)
913  {
914  case 0:
915  rawNavSatFixMsg.status.status = rawNavSatFixMsg.status.STATUS_NO_FIX;
916  break;
917  case 1:
918  case 2:
919  rawNavSatFixMsg.status.status = rawNavSatFixMsg.status.STATUS_FIX;
920  break;
921  case 3:
922  rawNavSatFixMsg.status.status = rawNavSatFixMsg.status.STATUS_SBAS_FIX;
923  break;
924  default:
925  rawNavSatFixMsg.status.status = rawNavSatFixMsg.status.STATUS_GBAS_FIX;
926  }
927 
928  rawNavSatFixMsg.position_covariance_type = rawNavSatFixMsg.COVARIANCE_TYPE_DIAGONAL_KNOWN;
929  // They use ENU for mat for this matrix. To me it makes sense that we should use
930  // the longitude standard deviation for east.
931  rawNavSatFixMsg.position_covariance[0] = pow(rawGnssPacket.position_standard_deviation[1], 2);
932  rawNavSatFixMsg.position_covariance[4] = pow(rawGnssPacket.position_standard_deviation[0], 2);
933  rawNavSatFixMsg.position_covariance[8] = pow(rawGnssPacket.position_standard_deviation[2], 2);
934 
935  rawNavSatFixPub.publish(rawNavSatFixMsg);
936 
937  }
938 
939  if (kvhDriver.PacketIsUpdated(packet_id_raw_sensors))
940  {
941  kvhDriver.GetPacket(packet_id_raw_sensors, rawSensorsPacket);
942 
943  // DATA_RAW Topic
944  sensor_msgs::Imu imuDataRaw;
945  imuDataRaw.header = header;
946  imuDataRaw.header.frame_id = "imu_link_frd";
947 
948  // ANGULAR VELOCITY
949  imuDataRaw.angular_velocity.x = rawSensorsPacket.gyroscopes[0];
950  imuDataRaw.angular_velocity.y = rawSensorsPacket.gyroscopes[1];
951  imuDataRaw.angular_velocity.z = rawSensorsPacket.gyroscopes[2];
952 
953  // LINEAR ACCELERATION
954  imuDataRaw.linear_acceleration.x = rawSensorsPacket.accelerometers[0];
955  imuDataRaw.linear_acceleration.y = rawSensorsPacket.accelerometers[1];
956  imuDataRaw.linear_acceleration.z = rawSensorsPacket.accelerometers[2];
957 
958  rawSensorImuPub.publish(imuDataRaw);
959 
960  // DATA_RAW_FLU
961  sensor_msgs::Imu imuDataRawFLU;
962  imuDataRawFLU.header = header;
963  imuDataRawFLU.header.frame_id = "imu_link_flu";
964 
965  // ANGULAR VELOCITY
966  imuDataRawFLU.angular_velocity.x = rawSensorsPacket.gyroscopes[0];
967  imuDataRawFLU.angular_velocity.y = -1 * rawSensorsPacket.gyroscopes[1];
968  imuDataRawFLU.angular_velocity.z = -1 * rawSensorsPacket.gyroscopes[2]; // To account for east north up system
969 
970  // LINEAR ACCELERATION
971  imuDataRawFLU.linear_acceleration.x = rawSensorsPacket.accelerometers[0];
972  imuDataRawFLU.linear_acceleration.y = -1 * rawSensorsPacket.accelerometers[1];
973  imuDataRawFLU.linear_acceleration.z = -1 * rawSensorsPacket.accelerometers[2];
974 
975  rawSensorImuFluPub.publish(imuDataRawFLU);
976 
977  sensor_msgs::MagneticField magFieldMsg;
978 
979  magFieldMsg.header = header;
980  magFieldMsg.header.frame_id = "imu_link_frd";
981  magFieldMsg.magnetic_field.x = rawSensorsPacket.magnetometers[0];
982  magFieldMsg.magnetic_field.y = rawSensorsPacket.magnetometers[1];
983  magFieldMsg.magnetic_field.z = rawSensorsPacket.magnetometers[2];
984 
985  magFieldPub.publish(magFieldMsg);
986 
987  }
988 
989  // Set that we have read the latest versions of all packets. There is a small possibility we miss one packet
990  // between using it above and setting it here.
991  kvhDriver.SetPacketUpdated(packet_id_system_state, false);
992  kvhDriver.SetPacketUpdated(packet_id_satellites, false);
994  kvhDriver.SetPacketUpdated(packet_id_utm_position, false);
995  kvhDriver.SetPacketUpdated(packet_id_ecef_position, false);
999  kvhDriver.SetPacketUpdated(packet_id_odometer_state, false);
1000  kvhDriver.SetPacketUpdated(packet_id_raw_gnss, false);
1001  kvhDriver.SetPacketUpdated(packet_id_raw_sensors, false);
1002 
1003  diagnostics.update();
1004 
1005  ros::spinOnce();
1006  rate.sleep();
1007  ROS_DEBUG("----------------------------------------");
1008  }
1009 
1010  diagnostics.broadcast(diagnostic_msgs::DiagnosticStatus::WARN, "Shutting down the KVH driver");
1011  kvhDriver.Cleanup();
1012 }
struct raw_gnss_packet_t::@8::@9 b
void UpdateSystemStatus(diagnostic_updater::DiagnosticStatusWrapper &stat)
KVH Geo Fog 3D driver class header.
void setRPY(const tf2Scalar &roll, const tf2Scalar &pitch, const tf2Scalar &yaw)
union system_state_packet_t::@1 filter_status
Driver worker class for the KVH Geo Fog 3D.
union satellite_t::@10 frequencies
global variables used to store packet information.
void setHardwareID(const std::string &hwid)
ROSCPP_DECL void init(int &argc, char **argv, const std::string &name, uint32_t options=0)
double BoundFromZeroTo2Pi(const double &_value)
union north_seeking_status_packet_t::@20 north_seeking_status
void add(const std::string &name, TaskFunction f)
int Once()
Do a single data read from the device.
double BoundFromNegPiToPi(const double &_value)
void SetupUpdater(diagnostic_updater::Updater *_diagnostics, mitre::KVH::DiagnosticsContainer *_diagContainer)
float heading_standard_deviation
uint32_t unix_time_seconds
int GetPacket(packet_id_e _packetId, T &packet)
#define MAXIMUM_DETAILED_SATELLITES
uint8_t satellite_system
struct system_state_packet_t::@0::@2 b
#define ROS_INFO(...)
satellite_t satellites[MAXIMUM_DETAILED_SATELLITES]
ROSCPP_DECL bool ok()
float position_standard_deviation[3]
std::vector< std::pair< packet_id_e, uint16_t > > KvhPacketRequest
Contains diagnostic information published out the ROS diagnostics topic.
int Init(const std::string &_port, KvhPacketRequest &_packetsRequested)
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
uint16_t azimuth
bool PacketIsUpdated(packet_id_e)
Use this function to determine if new packet data has arrived since the last time you checked...
bool sleep()
int SetPacketUpdated(packet_id_e, bool)
Use this function to set that the packet has been updated (though the driver will usually do that its...
union raw_gnss_packet_t::@8 flags
#define ROS_INFO_STREAM(args)
bool getParam(const std::string &key, std::string &s) const
uint8_t elevation
static Time now()
void UpdateFilterStatus(diagnostic_updater::DiagnosticStatusWrapper &stat)
void broadcast(int lvl, const std::string msg)
int main(int argc, char **argv)
ROSCPP_DECL void spinOnce()
int Cleanup()
Cleanup and close our connections.
int GetInitOptions(ros::NodeHandle &_node, kvh::KvhInitOptions &_initOptions)
#define ROS_ERROR(...)
union system_state_packet_t::@0 system_status
#define ROS_DEBUG(...)


kvh_geo_fog_3d_driver
Author(s): Trevor Bostic , Zach LaCelle
autogenerated on Fri Jan 24 2020 03:18:17