node.cpp
Go to the documentation of this file.
1 /*********************************************************************
2  * Software License Agreement (BSD License)
3  *
4  * Copyright (c) 2015-2020, Dataspeed Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  * notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above
14  * copyright notice, this list of conditions and the following
15  * disclaimer in the documentation and/or other materials provided
16  * with the distribution.
17  * * Neither the name of Dataspeed Inc. nor the names of its
18  * contributors may be used to endorse or promote products derived
19  * from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *********************************************************************/
34 
35 // ROS
36 #include <ros/ros.h>
37 
38 // ROS messages
39 #include <sensor_msgs/NavSatFix.h>
40 #include <sensor_msgs/Imu.h>
41 #include <sensor_msgs/TimeReference.h>
42 #include <geometry_msgs/TwistWithCovarianceStamped.h>
43 #include <nav_msgs/Odometry.h>
44 #include <std_msgs/String.h>
45 
46 // Tf
48 #include <tf/transform_datatypes.h>
49 
50 // Packet structure
51 #include "dispatch.h"
52 
53 // UTM conversion
54 #include <gps_common/conversions.h>
55 
56 // Ethernet
57 #include <arpa/inet.h>
58 
59 // UINT16_MAX is not defined by default in Ubuntu Saucy
60 #ifndef UINT16_MAX
61 #define UINT16_MAX (65535)
62 #endif
63 
64 // GPS time to UTC time
66 #define GPS_LEAP_SECONDS 18 // Offset to account for UTC leap seconds (need to increment when UTC changes)
67 #define GPS_EPOCH_OFFSET 315964800 // Offset to account for GPS / UTC epoch difference
68 
69 
70 static inline bool openSocket(const std::string &interface, const std::string &ip_addr, uint16_t port, int *fd_ptr, sockaddr_in *sock_ptr)
71 {
72  // Create UDP socket
73  int fd;
74  fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
75  if (fd != -1) {
76  if (interface.length()) {
77  if (!setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, interface.c_str(), interface.length()) == 0) {
78  close(fd);
79  return false;
80  }
81  }
82  memset(sock_ptr, 0, sizeof(sockaddr_in));
83  sock_ptr->sin_family = AF_INET;
84  sock_ptr->sin_port = htons(port);
85  if (!inet_aton(ip_addr.c_str(), &sock_ptr->sin_addr)) {
86  sock_ptr->sin_addr.s_addr = INADDR_ANY; // Invalid address, use ANY
87  }
88  if (bind(fd, (sockaddr*)sock_ptr, sizeof(sockaddr)) == 0) {
89  *fd_ptr = fd;
90  return true;
91  }
92  }
93  return false;
94 }
95 
96 static inline int readSocket(int fd, unsigned int timeout, void *data, size_t size, sockaddr *source_ptr = NULL)
97 {
98  if (fd >= 0) {
99  fd_set fds;
100  FD_ZERO(&fds);
101  FD_SET(fd, &fds);
102 
103  // Set up timeout
104  struct timeval tv;
105  tv.tv_sec = timeout / 1000;
106  tv.tv_usec = (timeout * 1000) % 1000000;
107 
108  if (select(fd + 1, &fds, NULL, NULL, &tv) > 0) {
109  socklen_t socklen = source_ptr ? sizeof(*source_ptr) : 0;
110  socklen_t *socklen_ptr = source_ptr ? &socklen : NULL;
111  return recvfrom(fd, data, size, 0, source_ptr, socklen_ptr);
112  }
113 
114  // Timeout
115  return 0;
116  }
117  return -1;
118 }
119 
120 static inline double SQUARE(double x) { return x * x; }
121 
122 #ifndef OXFORD_DISPLAY_INFO
123 #define OXFORD_DISPLAY_INFO 0
124 #endif
125 #if OXFORD_DISPLAY_INFO
126 #define OXTS_INFO(...) ROS_INFO(__VA_ARGS__)
127 #define OXTS_WARN(...) ROS_WARN(__VA_ARGS__)
128 #else
129 #define OXTS_INFO(...) ROS_DEBUG(__VA_ARGS__)
130 #define OXTS_WARN(...) ROS_DEBUG(__VA_ARGS__)
131 #endif
132 
133 static const std::map<uint8_t, std::string> POS_MODE_MAP = {
134  {MODE_NONE, "NONE"},
135  {MODE_NO_DATA, "NONE"},
136  {MODE_BLANKED, "NONE"},
137  {MODE_SEARCH, "SEARCHING"},
138  {MODE_NOT_RECOGNISED, "NONE"},
139  {MODE_UNKNOWN, "NONE"},
140  {MODE_DOPPLER, "DOPPLER"},
141  {MODE_DOPPLER_PP, "DOPPLER"},
142  {MODE_DOPPLER_GX, "DOPPLER"},
143  {MODE_DOPPLER_IX, "DOPPLER"},
144  {MODE_SPS, "POINT_POSITION"},
145  {MODE_SPS_PP, "POINT_POSITION"},
146  {MODE_SPS_GX, "POINT_POSITION"},
147  {MODE_SPS_IX, "POINT_POSITION"},
148  {MODE_DIFFERENTIAL, "DIFF_PSEUDORANGE"},
149  {MODE_DIFFERENTIAL_PP, "DIFF_PSEUDORANGE"},
150  {MODE_DIFFERENTIAL_GX, "DIFF_PSEUDORANGE"},
151  {MODE_DIFFERENTIAL_IX, "DIFF_PSEUDORANGE"},
152  {MODE_RTK_FLOAT, "RTK_FLOAT"},
153  {MODE_RTK_FLOAT_PP, "RTK_FLOAT"},
154  {MODE_RTK_FLOAT_GX, "RTK_FLOAT"},
155  {MODE_RTK_FLOAT_IX, "RTK_FLOAT"},
156  {MODE_RTK_INTEGER, "RTK_INTEGER"},
157  {MODE_RTK_INTEGER_PP, "RTK_INTEGER"},
158  {MODE_RTK_INTEGER_GX, "RTK_INTEGER"},
159  {MODE_RTK_INTEGER_IX, "RTK_INTEGER"},
160  {MODE_WAAS, "WAAS"},
161  {MODE_OMNISTAR_VBS, "OMNISTAR_VBS"},
162  {MODE_OMNISTAR_HP, "OMNISTAR_HP"},
163  {MODE_OMNISTAR_XP, "OMNISTAR_XP"},
164  {MODE_CDGPS, "CANADA_DGPS"},
165  {MODE_PPP_CONVERGING, "PPP_CONVERGING"},
166  {MODE_PPP, "PPP"}
167 };
168 
169 static const std::map<uint8_t, std::string> NAV_STATUS_MAP = {
170  {0, "INVALID"},
171  {1, "IMU_ONLY"},
172  {2, "INITIALIZING"},
173  {3, "LOCKING"},
174  {4, "READY"},
175 };
176 
177 static inline void mapLookup(const std::map<uint8_t, std::string>& map, uint8_t key, std::string& val) {
178  std::map<uint8_t, std::string>::const_iterator it = map.find(key);
179  if (it != map.end()) {
180  val = map.at(key);
181  } else {
182  val = "UNKNOWN";
183  }
184 }
185 
186 static inline double getZoneMeridian(const std::string& utm_zone)
187 {
188  int zone_number = std::atoi(utm_zone.substr(0,2).c_str());
189  return (zone_number == 0) ? 0.0 : (zone_number - 1) * 6.0 - 177.0;
190 }
191 
192 static inline double toUtcTime(uint32_t gps_minutes, uint16_t gps_ms)
193 {
194  return GPS_EPOCH_OFFSET - GPS_LEAP_SECONDS + 60.0 * (double)gps_minutes + 0.001 * (double)gps_ms;
195 }
196 
197 static inline void generateGGAString(double latitude, double longitude, double altitude, const ros::Time& utc_time, std::string& gga_msg)
198 {
199  std::stringstream msg;
200  std::stringstream gga_payload;
201 
202  int lat_deg = (int)fabs(latitude);
203  float lat_min = 60.0 * fmod(fabs(latitude), 1.0);
204  int lon_deg = (int)fabs(longitude);
205  float lon_min = 60.0 * fmod(fabs(longitude), 1.0);
206 
207  double utc_timestamp = utc_time.toSec();
208  uint8_t utc_hours = (uint8_t)(fmod(utc_timestamp / 3600.0, 24.0));
209  uint8_t utc_minutes = (uint8_t)(60.0 * fmod(utc_timestamp / 3600.0, 1.0));
210  uint8_t utc_secs = (uint8_t)(3600.0 * fmod(utc_timestamp / 3600.0, 24.0) - 3600.0 * utc_hours - 60.0 * utc_minutes);
211 
212  gga_payload.precision(3);
213  gga_payload << std::setfill('0');
214  gga_payload << "GPGGA," << std::setw(2) << (int)utc_hours << std::setw(2) << (int)utc_minutes << std::setw(2) << (int)utc_secs << ",";
215  gga_payload << std::setw(2) << lat_deg << std::fixed << std::setw(6) << lat_min;
216 
217  if (latitude > 0) {
218  gga_payload << ",N,";
219  } else {
220  gga_payload << ",S,";
221  }
222 
223  gga_payload << std::setw(3) << lon_deg << std::fixed << std::setw(6) << lon_min;
224  if (longitude > 0) {
225  gga_payload << ",E,";
226  } else {
227  gga_payload << ",W,";
228  }
229 
230  gga_payload.precision(1);
231  gga_payload << "1,4,1.5,";
232  gga_payload << std::setfill('0');
233  gga_payload << std::fixed << std::setw(4) << altitude;
234  gga_payload << ",M,0,M,,";
235 
236  uint8_t checksum = 0;
237  for (size_t i = 0; i < gga_payload.str().size(); i++) {
238  checksum ^= gga_payload.str()[i];
239  }
240 
241  msg << "$" << gga_payload.str() << "*" << std::hex << std::setfill('0') << std::setw(2) << std::uppercase << (int)checksum << "\r\n";
242  gga_msg = msg.str();
243 }
244 
245 static inline void handlePacket(const Packet *packet, ros::Publisher &pub_fix, ros::Publisher &pub_vel,
246  ros::Publisher &pub_imu, ros::Publisher &pub_odom, ros::Publisher &pub_pos_type,
247  ros::Publisher &pub_nav_status, ros::Publisher &pub_gps_time_ref, ros::Publisher& pub_gga,
248  const std::string & frame_id_gps, const std::string &frame_id_vel, const std::string &frame_id_odom)
249 {
250  static uint8_t fix_status = sensor_msgs::NavSatStatus::STATUS_FIX;
251  static uint8_t position_covariance_type = sensor_msgs::NavSatFix::COVARIANCE_TYPE_UNKNOWN;
252  static double position_stddev[3];
253  static uint8_t velocity_covariance_type = sensor_msgs::NavSatFix::COVARIANCE_TYPE_UNKNOWN;
254  static double velocity_stddev[3];
255  static uint8_t orientation_covariance_type = sensor_msgs::NavSatFix::COVARIANCE_TYPE_UNKNOWN;
256  static double orientation_stddev[3];
257  static uint8_t pos_mode = 0;
258  static int none_type_count = 0;
259 
260  ros::Time stamp = ros::Time::now();
261 
262  switch (packet->channel) {
263  case 0:
264  if (packet->chan.chan0.position_mode != MODE_NONE) {
265  pos_mode = packet->chan.chan0.position_mode;
266  none_type_count = 0;
267  } else {
268  if (none_type_count > 2) {
269  none_type_count = 0;
270  pos_mode = MODE_NONE;
271  } else {
272  none_type_count++;
273  }
274  }
275 
276  if (packet->chan.chan0.gps_minutes > 1000) { // Documentation says invalid if < 1000
277  sensor_msgs::TimeReference gps_time_ref_msg;
278  gps_time_ref_msg.source = "gps";
279  gps_time_ref_msg.header.stamp = stamp;
280  g_gps_utc_time = ros::Time(toUtcTime(packet->chan.chan0.gps_minutes, packet->time));
281  gps_time_ref_msg.time_ref = g_gps_utc_time;
282  pub_gps_time_ref.publish(gps_time_ref_msg);
283  }
284 
285  switch (pos_mode) {
286  case MODE_DIFFERENTIAL:
290  case MODE_RTK_FLOAT:
291  case MODE_RTK_FLOAT_PP:
292  case MODE_RTK_FLOAT_GX:
293  case MODE_RTK_FLOAT_IX:
294  case MODE_RTK_INTEGER:
295  case MODE_RTK_INTEGER_PP:
296  case MODE_RTK_INTEGER_GX:
297  case MODE_RTK_INTEGER_IX:
298  fix_status = sensor_msgs::NavSatStatus::STATUS_GBAS_FIX;
299  break;
300  case MODE_OMNISTAR_VBS:
301  case MODE_OMNISTAR_HP:
302  case MODE_OMNISTAR_XP:
303  case MODE_WAAS:
304  case MODE_CDGPS:
305  fix_status = sensor_msgs::NavSatStatus::STATUS_SBAS_FIX;
306  break;
307  case MODE_SPS:
308  case MODE_SPS_PP:
309  case MODE_SPS_GX:
310  case MODE_SPS_IX:
311  fix_status = sensor_msgs::NavSatStatus::STATUS_FIX;
312  break;
313  case MODE_NONE:
314  case MODE_SEARCH:
315  case MODE_DOPPLER:
316  case MODE_NO_DATA:
317  case MODE_BLANKED:
318  case MODE_NOT_RECOGNISED:
319  case MODE_UNKNOWN:
320  default:
321  fix_status = sensor_msgs::NavSatStatus::STATUS_NO_FIX;
322  break;
323  }
324  OXTS_INFO("Num Sats: %u, Position mode: %u, Velocity mode: %u, Orientation mode: %u",
325  packet->chan.chan0.num_sats,
326  packet->chan.chan0.position_mode,
327  packet->chan.chan0.velocity_mode,
328  packet->chan.chan0.orientation_mode);
329  break;
330  case 3:
331  if (packet->chan.chan3.age < 150) {
332  position_stddev[0] = (double)packet->chan.chan3.acc_position_east * 1e-3;
333  position_stddev[1] = (double)packet->chan.chan3.acc_position_north * 1e-3;
334  position_stddev[2] = (double)packet->chan.chan3.acc_position_down * 1e-3;
335  position_covariance_type = sensor_msgs::NavSatFix::COVARIANCE_TYPE_DIAGONAL_KNOWN;
336  OXTS_INFO("Position accuracy: North: %umm, East: %umm, Down: %umm",
337  packet->chan.chan3.acc_position_north,
338  packet->chan.chan3.acc_position_east,
339  packet->chan.chan3.acc_position_down);
340  } else {
341  position_covariance_type = sensor_msgs::NavSatFix::COVARIANCE_TYPE_UNKNOWN;
342  }
343  break;
344  case 4:
345  if (packet->chan.chan4.age < 150) {
346  velocity_stddev[0] = (double)packet->chan.chan4.acc_velocity_east * 1e-3;
347  velocity_stddev[1] = (double)packet->chan.chan4.acc_velocity_north * 1e-3;
348  velocity_stddev[2] = (double)packet->chan.chan4.acc_velocity_down * 1e-3;
349  velocity_covariance_type = sensor_msgs::NavSatFix::COVARIANCE_TYPE_DIAGONAL_KNOWN;
350  OXTS_INFO("Velocity accuracy: North: %umm/s, East: %umm/s, Down: %umm/s",
351  packet->chan.chan4.acc_velocity_north,
352  packet->chan.chan4.acc_velocity_east,
353  packet->chan.chan4.acc_velocity_down);
354  } else {
355  velocity_covariance_type = sensor_msgs::NavSatFix::COVARIANCE_TYPE_UNKNOWN;
356  }
357  break;
358 
359  case 5:
360  if (packet->chan.chan5.age < 150) {
361  orientation_stddev[0] = (double)packet->chan.chan5.acc_roll * 1e-5;
362  orientation_stddev[1] = (double)packet->chan.chan5.acc_pitch * 1e-5;
363  orientation_stddev[2] = (double)packet->chan.chan5.acc_heading * 1e-5;
364  orientation_covariance_type = sensor_msgs::NavSatFix::COVARIANCE_TYPE_DIAGONAL_KNOWN;
365  OXTS_INFO("Velocity accuracy: Heading: %frad, Pitch: %frad, Roll: %frad",
366  (double)packet->chan.chan5.acc_heading * 1e-5,
367  (double)packet->chan.chan5.acc_pitch * 1e-5,
368  (double)packet->chan.chan5.acc_roll * 1e-5);
369  } else {
370  orientation_covariance_type = sensor_msgs::NavSatFix::COVARIANCE_TYPE_UNKNOWN;
371  }
372  break;
373  case 23:
374  OXTS_INFO("Delay: %ums", packet->chan.chan23.delay_ms);
375  break;
376  case 27:
377  OXTS_INFO("Heading quality: %u", packet->chan.chan27.heading_quality);
378  break;
379  case 37:
380  if (packet->chan.chan37.valid) {
381  OXTS_INFO("Heading Misalignment: Angle: %frad, Accuracy: %frad",
382  (double)packet->chan.chan37.heading_misalignment_angle * 1e-4,
383  (double)packet->chan.chan37.heading_misalignment_accuracy * 1e-4);
384  }
385  break;
386  case 48:
387  OXTS_INFO("HDOP: %0.1f, PDOP: %0.1f",
388  (double)packet->chan.chan48.HDOP * 1e-1,
389  (double)packet->chan.chan48.PDOP * 1e-1);
390  break;
391  }
392  std_msgs::String str_msg;
393  mapLookup(POS_MODE_MAP, pos_mode, str_msg.data);
394  pub_pos_type.publish(str_msg);
395  mapLookup(NAV_STATUS_MAP, packet->nav_status, str_msg.data);
396  pub_nav_status.publish(str_msg);
397 
398  if (packet->nav_status == 4) {
399  // Convert lat/lon into UTM x, y, and zone
400  double utm_x;
401  double utm_y;
402  std::string utm_zone;
403  gps_common::LLtoUTM(180.0 / M_PI * packet->latitude, 180.0 / M_PI * packet->longitude, utm_y, utm_x, utm_zone);
404 
405  // Generate GPGGA message to send to NTRIP casters that require it to maintain a connection
406  std_msgs::String gga_msg;
407  generateGGAString(180.0 / M_PI * packet->latitude, 180.0 / M_PI * packet->longitude, packet->altitude, g_gps_utc_time, gga_msg.data);
408  pub_gga.publish(gga_msg);
409 
410  // Compute convergence angle and heading in ENU and UTM grid
411  double central_meridian = M_PI / 180.0 * getZoneMeridian(utm_zone);
412  double convergence_angle = atan(tan(packet->longitude - central_meridian) * sin(packet->latitude));
413  double enu_heading = M_PI_2 - (double)packet->heading * 1e-6;
414  double grid_heading = enu_heading + convergence_angle;
415 
416  // Compute local frame velocity for odometry message
417  double east_vel = (double)packet->vel_east * 1e-4;
418  double north_vel = (double)packet->vel_north * 1e-4;
419  double local_x_vel = east_vel * cos(enu_heading) + north_vel * sin(enu_heading);
420  double local_y_vel = -east_vel * sin(enu_heading) + north_vel * cos(enu_heading);
421 
422  sensor_msgs::NavSatFix msg_fix;
423  msg_fix.header.stamp = stamp;
424  msg_fix.header.frame_id = frame_id_gps;
425  msg_fix.latitude = packet->latitude * (180 / M_PI);
426  msg_fix.longitude = packet->longitude * (180 / M_PI);
427  msg_fix.altitude = packet->altitude;
428  msg_fix.status.status = fix_status;
429  msg_fix.status.service = sensor_msgs::NavSatStatus::SERVICE_GPS;
430  msg_fix.position_covariance_type = position_covariance_type;
431  if (position_covariance_type > sensor_msgs::NavSatFix::COVARIANCE_TYPE_UNKNOWN) {
432  msg_fix.position_covariance[0] = SQUARE(position_stddev[0]); // x
433  msg_fix.position_covariance[4] = SQUARE(position_stddev[1]); // y
434  msg_fix.position_covariance[8] = SQUARE(position_stddev[2]); // z
435  }
436  pub_fix.publish(msg_fix);
437 
438  geometry_msgs::TwistWithCovarianceStamped msg_vel;
439  msg_vel.header.stamp = stamp;
440  msg_vel.header.frame_id = frame_id_vel;
441  msg_vel.twist.twist.linear.x = east_vel;
442  msg_vel.twist.twist.linear.y = north_vel;
443  msg_vel.twist.twist.linear.z = (double)packet->vel_down * -1e-4;
444  if (velocity_covariance_type > sensor_msgs::NavSatFix::COVARIANCE_TYPE_UNKNOWN) {
445  msg_vel.twist.covariance[0] = SQUARE(velocity_stddev[0]); // x
446  msg_vel.twist.covariance[7] = SQUARE(velocity_stddev[1]); // y
447  msg_vel.twist.covariance[14] = SQUARE(velocity_stddev[2]); // z
448  }
449  pub_vel.publish(msg_vel);
450 
451  tf::Quaternion q;
452  q.setRPY((double)packet->roll * 1e-6, (double)packet->pitch * 1e-6, enu_heading);
453  sensor_msgs::Imu msg_imu;
454  msg_imu.header.stamp = stamp;
455  msg_imu.header.frame_id = frame_id_gps;
456  msg_imu.linear_acceleration.x = (double)packet->accel_x * 1e-4;
457  msg_imu.linear_acceleration.y = (double)packet->accel_y * 1e-4;
458  msg_imu.linear_acceleration.z = (double)packet->accel_z * -1e-4;
459  msg_imu.angular_velocity.x = (double)packet->gyro_x * 1e-5;
460  msg_imu.angular_velocity.y = (double)packet->gyro_y * 1e-5;
461  msg_imu.angular_velocity.z = (double)packet->gyro_z * -1e-5;
462  msg_imu.orientation.w = q.w();
463  msg_imu.orientation.x = q.x();
464  msg_imu.orientation.y = q.y();
465  msg_imu.orientation.z = q.z();
466  if (orientation_covariance_type > sensor_msgs::NavSatFix::COVARIANCE_TYPE_UNKNOWN) {
467  msg_imu.orientation_covariance[0] = SQUARE(orientation_stddev[0]); // x
468  msg_imu.orientation_covariance[4] = SQUARE(orientation_stddev[1]); // y
469  msg_imu.orientation_covariance[8] = SQUARE(orientation_stddev[2]); // z
470  }
471  pub_imu.publish(msg_imu);
472 
473  // Project position standard deviations into UTM frame, accounting for convergence angle
474  double std_east = position_stddev[0];
475  double std_north = position_stddev[1];
476  double std_x = std_east * cos(convergence_angle) - std_north * sin(convergence_angle);
477  double std_y = std_north * sin(convergence_angle) + std_east * cos(convergence_angle);
478 
479  // Project velocity standard deviations into local frame
480  double std_east_vel = velocity_stddev[0];
481  double std_north_vel = velocity_stddev[1];
482  double std_x_vel = std_east_vel * cos(enu_heading) + std_north_vel * sin(enu_heading);
483  double std_y_vel = -std_east_vel * cos(enu_heading) + std_north_vel * sin(enu_heading);
484 
485  nav_msgs::Odometry msg_odom;
486  msg_odom.header.stamp = stamp;
487  msg_odom.header.frame_id = "utm";
488  msg_odom.child_frame_id = frame_id_odom;
489  msg_odom.pose.pose.position.x = utm_x;
490  msg_odom.pose.pose.position.y = utm_y;
491  msg_odom.pose.pose.orientation = tf::createQuaternionMsgFromYaw(grid_heading);
492  if (position_covariance_type > sensor_msgs::NavSatFix::COVARIANCE_TYPE_UNKNOWN) {
493  msg_odom.pose.covariance[0*6 + 0] = SQUARE(std_x);
494  msg_odom.pose.covariance[1*6 + 1] = SQUARE(std_y);
495  msg_odom.pose.covariance[5*6 + 5] = SQUARE(orientation_stddev[2]);
496  }
497  msg_odom.twist.twist.linear.x = local_x_vel;
498  msg_odom.twist.twist.linear.y = local_y_vel;
499  msg_odom.twist.twist.angular.z = msg_imu.angular_velocity.z;
500  if (velocity_covariance_type > sensor_msgs::NavSatFix::COVARIANCE_TYPE_UNKNOWN) {
501  msg_odom.twist.covariance[0*6 + 0] = SQUARE(std_x_vel);
502  msg_odom.twist.covariance[1*6 + 1] = SQUARE(std_y_vel);
503  }
504  pub_odom.publish(msg_odom);
505 
506  } else {
507  OXTS_WARN("Nav Status: %u", packet->nav_status);
508  }
509 }
510 
511 int main(int argc, char **argv)
512 {
513  ros::init(argc, argv, "oxford_gps");
514  ros::NodeHandle node;
515  ros::NodeHandle priv_nh("~");
516 
517  std::string interface = "";
518  priv_nh.getParam("interface", interface);
519 
520  std::string ip_addr = "";
521  priv_nh.getParam("ip_address", ip_addr);
522 
523  int port = 3000;
524  priv_nh.getParam("port", port);
525 
526  std::string frame_id_gps = "gps";
527  priv_nh.getParam("frame_id_gps", frame_id_gps);
528 
529  std::string frame_id_vel = "enu";
530  priv_nh.getParam("frame_id_vel", frame_id_vel);
531 
532  std::string frame_id_odom = "base_footprint";
533  priv_nh.getParam("frame_id_odom", frame_id_odom);
534 
535  if (port > UINT16_MAX) {
536  ROS_ERROR("Port %u greater than maximum value of %u", port, UINT16_MAX);
537  }
538 
539  if (interface.length() && ip_addr.length()) {
540  ROS_INFO("Preparing to listen on interface %s port %u and IP %s", interface.c_str(), port, ip_addr.c_str());
541  } else if (interface.length()) {
542  ROS_INFO("Preparing to listen on interface %s port %u", interface.c_str(), port);
543  } else if (ip_addr.length()) {
544  ROS_INFO("Preparing to listen on %s:%u", ip_addr.c_str(), port);
545  } else {
546  ROS_INFO("Preparing to listen on port %u", port);
547  }
548 
549  int fd;
550  sockaddr_in sock;
551  if (openSocket(interface, ip_addr, port, &fd, &sock)) {
552  // Setup Publishers
553  ros::Publisher pub_fix = node.advertise<sensor_msgs::NavSatFix>("gps/fix", 2);
554  ros::Publisher pub_vel = node.advertise<geometry_msgs::TwistWithCovarianceStamped>("gps/vel", 2);
555  ros::Publisher pub_imu = node.advertise<sensor_msgs::Imu>("imu/data", 2);
556  ros::Publisher pub_odom = node.advertise<nav_msgs::Odometry>("gps/odom", 2);
557  ros::Publisher pub_pos_type = node.advertise<std_msgs::String>("gps/pos_type", 2);
558  ros::Publisher pub_nav_status = node.advertise<std_msgs::String>("gps/nav_status", 2);
559  ros::Publisher pub_gps_time_ref = node.advertise<sensor_msgs::TimeReference>("gps/time_ref", 2);
560  ros::Publisher pub_gga = node.advertise<std_msgs::String>("gps/gga", 2);
561 
562  // Variables
563  Packet packet;
564  sockaddr source;
565  bool first = true;
566 
567  // Loop until shutdown
568  while (ros::ok()) {
569  if (readSocket(fd, 10, &packet, sizeof(packet), &source) >= sizeof(packet)) {
570  if (validatePacket(&packet)) {
571  if (first) {
572  first = false;
573  ROS_INFO("Connected to Oxford GPS at %s:%u", inet_ntoa(((sockaddr_in*)&source)->sin_addr), htons(((sockaddr_in*)&source)->sin_port));
574  }
575  handlePacket(&packet, pub_fix, pub_vel, pub_imu, pub_odom, pub_pos_type, pub_nav_status, pub_gps_time_ref, pub_gga, frame_id_gps, frame_id_vel, frame_id_odom);
576  }
577  }
578 
579  // Handle callbacks
580  ros::spinOnce();
581  }
582 
583  // Close socket
584  close(fd);
585  } else {
586  ROS_FATAL("Failed to open socket");
587  ros::WallDuration(1.0).sleep();
588  }
589 
590  return 0;
591 }
uint16_t acc_roll
Definition: dispatch.h:64
int32_t accel_x
Definition: dispatch.h:92
uint16_t acc_position_down
Definition: dispatch.h:52
#define UINT16_MAX
Definition: node.cpp:61
#define ROS_FATAL(...)
#define GPS_LEAP_SECONDS
Definition: node.cpp:66
uint16_t delay_ms
Definition: dispatch.h:72
uint8_t heading_quality
Definition: dispatch.h:75
void publish(const boost::shared_ptr< M > &message) const
uint16_t acc_position_north
Definition: dispatch.h:50
static void generateGGAString(double latitude, double longitude, double altitude, const ros::Time &utc_time, std::string &gga_msg)
Definition: node.cpp:197
static double toUtcTime(uint32_t gps_minutes, uint16_t gps_ms)
Definition: node.cpp:192
struct Channel::@9 chan48
int32_t vel_down
Definition: dispatch.h:105
static const std::map< uint8_t, std::string > POS_MODE_MAP
Definition: node.cpp:133
uint8_t age
Definition: dispatch.h:53
ROSCPP_DECL void init(int &argc, char **argv, const std::string &name, uint32_t options=0)
static double getZoneMeridian(const std::string &utm_zone)
Definition: node.cpp:186
uint32_t gps_minutes
Definition: dispatch.h:43
struct Channel::@4 chan5
static void handlePacket(const Packet *packet, ros::Publisher &pub_fix, ros::Publisher &pub_vel, ros::Publisher &pub_imu, ros::Publisher &pub_odom, ros::Publisher &pub_pos_type, ros::Publisher &pub_nav_status, ros::Publisher &pub_gps_time_ref, ros::Publisher &pub_gga, const std::string &frame_id_gps, const std::string &frame_id_vel, const std::string &frame_id_odom)
Definition: node.cpp:245
uint8_t channel
Definition: dispatch.h:110
#define OXTS_INFO(...)
Definition: node.cpp:129
uint16_t acc_velocity_east
Definition: dispatch.h:57
ros::Time g_gps_utc_time
Definition: node.cpp:65
int32_t gyro_y
Definition: dispatch.h:96
uint8_t velocity_mode
Definition: dispatch.h:46
int32_t vel_east
Definition: dispatch.h:104
struct Channel::@6 chan23
double latitude
Definition: dispatch.h:100
#define OXTS_WARN(...)
Definition: node.cpp:130
struct Channel::@3 chan4
static double SQUARE(double x)
Definition: node.cpp:120
static void LLtoUTM(const double Lat, const double Long, double &UTMNorthing, double &UTMEasting, char *UTMZone)
static bool validatePacket(const Packet *packet)
Definition: dispatch.h:151
uint8_t nav_status
Definition: dispatch.h:98
uint16_t acc_position_east
Definition: dispatch.h:51
uint8_t HDOP
Definition: dispatch.h:85
bool sleep() const
struct Channel::@8 chan37
static const std::map< uint8_t, std::string > NAV_STATUS_MAP
Definition: node.cpp:169
void setRPY(const tfScalar &roll, const tfScalar &pitch, const tfScalar &yaw)
#define ROS_INFO(...)
double longitude
Definition: dispatch.h:101
int16_t heading_misalignment_angle
Definition: dispatch.h:78
#define GPS_EPOCH_OFFSET
Definition: node.cpp:67
ROSCPP_DECL bool ok()
uint16_t acc_heading
Definition: dispatch.h:62
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
uint8_t PDOP
Definition: dispatch.h:86
uint16_t acc_velocity_down
Definition: dispatch.h:58
uint16_t acc_velocity_north
Definition: dispatch.h:56
struct Channel::@7 chan27
int32_t heading
Definition: dispatch.h:106
static void mapLookup(const std::map< uint8_t, std::string > &map, uint8_t key, std::string &val)
Definition: node.cpp:177
uint16_t heading_misalignment_accuracy
Definition: dispatch.h:79
struct Channel::@1 chan0
static geometry_msgs::Quaternion createQuaternionMsgFromYaw(double yaw)
uint8_t position_mode
Definition: dispatch.h:45
uint16_t acc_pitch
Definition: dispatch.h:63
uint8_t num_sats
Definition: dispatch.h:44
bool getParam(const std::string &key, std::string &s) const
int32_t accel_y
Definition: dispatch.h:93
int32_t accel_z
Definition: dispatch.h:94
int32_t gyro_z
Definition: dispatch.h:97
struct Channel::@2 chan3
int main(int argc, char **argv)
Definition: node.cpp:511
static Time now()
static bool openSocket(const std::string &interface, const std::string &ip_addr, uint16_t port, int *fd_ptr, sockaddr_in *sock_ptr)
Definition: node.cpp:70
int32_t pitch
Definition: dispatch.h:107
uint8_t valid
Definition: dispatch.h:81
static int readSocket(int fd, unsigned int timeout, void *data, size_t size, sockaddr *source_ptr=NULL)
Definition: node.cpp:96
int32_t roll
Definition: dispatch.h:108
int32_t vel_north
Definition: dispatch.h:103
ROSCPP_DECL void spinOnce()
int32_t gyro_x
Definition: dispatch.h:95
#define ROS_ERROR(...)
uint16_t time
Definition: dispatch.h:91
float altitude
Definition: dispatch.h:102
Channel chan
Definition: dispatch.h:111
uint8_t orientation_mode
Definition: dispatch.h:47


oxford_gps_eth
Author(s): Kevin Hallenbeck
autogenerated on Sun Aug 9 2020 04:05:34