client.cpp
Go to the documentation of this file.
1 #include <ros/ros.h>
2 #include <gps_common/GPSFix.h>
3 #include <gps_common/GPSStatus.h>
4 #include <sensor_msgs/NavSatFix.h>
5 #include <sensor_msgs/NavSatStatus.h>
6 #include <libgpsmm.h>
7 
8 #include <cmath>
9 
10 using namespace gps_common;
11 using namespace sensor_msgs;
12 
13 class GPSDClient {
14  public:
15  GPSDClient() : privnode("~"), gps(NULL), use_gps_time(true), check_fix_by_variance(true), frame_id("gps") {}
16 
17  bool start() {
18  gps_fix_pub = node.advertise<GPSFix>("extended_fix", 1);
19  navsat_fix_pub = node.advertise<NavSatFix>("fix", 1);
20 
21  privnode.getParam("use_gps_time", use_gps_time);
22  privnode.getParam("check_fix_by_variance", check_fix_by_variance);
23  privnode.param("frame_id", frame_id, frame_id);
24 
25  std::string host = "localhost";
26  int port = 2947;
27  privnode.getParam("host", host);
28  privnode.getParam("port", port);
29 
30  char port_s[12];
31  snprintf(port_s, 12, "%d", port);
32 
33  gps_data_t *resp = NULL;
34 
35 #if GPSD_API_MAJOR_VERSION >= 5
36  gps = new gpsmm(host.c_str(), port_s);
37  resp = gps->stream(WATCH_ENABLE);
38 #elif GPSD_API_MAJOR_VERSION == 4
39  gps = new gpsmm();
40  gps->open(host.c_str(), port_s);
41  resp = gps->stream(WATCH_ENABLE);
42 #else
43  gps = new gpsmm();
44  resp = gps->open(host.c_str(), port_s);
45  gps->query("w\n");
46 #endif
47 
48  if (resp == NULL) {
49  ROS_ERROR("Failed to open GPSd");
50  return false;
51  }
52 
53  ROS_INFO("GPSd opened");
54  return true;
55  }
56 
57  void step() {
58 #if GPSD_API_MAJOR_VERSION >= 5
59  if (!gps->waiting(1e6))
60  return;
61 
62  gps_data_t *p = gps->read();
63 #else
64  gps_data_t *p = gps->poll();
65 #endif
66  process_data(p);
67  }
68 
69  void stop() {
70  // gpsmm doesn't have a close method? OK ...
71  }
72 
73  private:
78  gpsmm *gps;
79 
82  std::string frame_id;
83 
84  void process_data(struct gps_data_t* p) {
85  if (p == NULL)
86  return;
87 
88 #if GPSD_API_MAJOR_VERSION >= 9
89  if (!p->online.tv_sec && !p->online.tv_nsec) {
90 #else
91  if (!p->online) {
92 #endif
93  return;
94  }
95 
96  process_data_gps(p);
97  process_data_navsat(p);
98  }
99 
100 
101 #if GPSD_API_MAJOR_VERSION >= 4
102 #define SATS_VISIBLE p->satellites_visible
103 #elif GPSD_API_MAJOR_VERSION == 3
104 #define SATS_VISIBLE p->satellites
105 #else
106 #error "gpsd_client only supports gpsd API versions 3+"
107 #endif
108 
109  void process_data_gps(struct gps_data_t* p) {
110  ros::Time time = ros::Time::now();
111 
112  GPSFix fix;
113  GPSStatus status;
114 
115  status.header.stamp = time;
116  fix.header.stamp = time;
117  fix.header.frame_id = frame_id;
118 
119  status.satellites_used = p->satellites_used;
120 
121  status.satellite_used_prn.resize(status.satellites_used);
122  for (int i = 0; i < status.satellites_used; ++i) {
123 #if GPSD_API_MAJOR_VERSION > 5
124  status.satellite_used_prn[i] = p->skyview[i].used;
125 #else
126  status.satellite_used_prn[i] = p->used[i];
127 #endif
128  }
129 
130  status.satellites_visible = SATS_VISIBLE;
131 
132  status.satellite_visible_prn.resize(status.satellites_visible);
133  status.satellite_visible_z.resize(status.satellites_visible);
134  status.satellite_visible_azimuth.resize(status.satellites_visible);
135  status.satellite_visible_snr.resize(status.satellites_visible);
136 
137  for (int i = 0; i < SATS_VISIBLE; ++i) {
138 #if GPSD_API_MAJOR_VERSION > 5
139  status.satellite_visible_prn[i] = p->skyview[i].PRN;
140  status.satellite_visible_z[i] = p->skyview[i].elevation;
141  status.satellite_visible_azimuth[i] = p->skyview[i].azimuth;
142  status.satellite_visible_snr[i] = p->skyview[i].ss;
143 #else
144  status.satellite_visible_prn[i] = p->PRN[i];
145  status.satellite_visible_z[i] = p->elevation[i];
146  status.satellite_visible_azimuth[i] = p->azimuth[i];
147  status.satellite_visible_snr[i] = p->ss[i];
148 #endif
149  }
150 
151 #if GPSD_API_MAJOR_VERSION >= 12
152  if ((p->fix.status & STATUS_GPS) && !(check_fix_by_variance && std::isnan(p->fix.epx))) {
153 #elif GPSD_API_MAJOR_VERSION >= 10
154  if ((p->fix.status & STATUS_FIX) && !(check_fix_by_variance && std::isnan(p->fix.epx))) {
155 #else
156  if ((p->status & STATUS_FIX) && !(check_fix_by_variance && std::isnan(p->fix.epx))) {
157 #endif
158 
159  status.status = 0; // FIXME: gpsmm puts its constants in the global
160  // namespace, so `GPSStatus::STATUS_FIX' is illegal.
161 
162 // STATUS_DGPS_FIX was removed in API version 6 but re-added afterward and next renamed since the version 12
163 #if GPSD_API_MAJOR_VERSION != 6
164 #if GPSD_API_MAJOR_VERSION >= 12
165  if (p->fix.status & STATUS_DGPS)
166 #elif GPSD_API_MAJOR_VERSION >= 10
167  if (p->fix.status & STATUS_DGPS_FIX)
168 #else
169  if (p->status & STATUS_DGPS_FIX)
170 #endif
171  status.status |= 18; // same here
172 #endif
173 
174 #if GPSD_API_MAJOR_VERSION >= 9
175  fix.time = (double)(p->fix.time.tv_sec) + (double)(p->fix.time.tv_nsec) / 1000000.;
176 #else
177  fix.time = p->fix.time;
178 #endif
179  fix.latitude = p->fix.latitude;
180  fix.longitude = p->fix.longitude;
181  fix.altitude = p->fix.altitude;
182  fix.track = p->fix.track;
183  fix.speed = p->fix.speed;
184  fix.climb = p->fix.climb;
185 
186 #if GPSD_API_MAJOR_VERSION > 3
187  fix.pdop = p->dop.pdop;
188  fix.hdop = p->dop.hdop;
189  fix.vdop = p->dop.vdop;
190  fix.tdop = p->dop.tdop;
191  fix.gdop = p->dop.gdop;
192 #else
193  fix.pdop = p->pdop;
194  fix.hdop = p->hdop;
195  fix.vdop = p->vdop;
196  fix.tdop = p->tdop;
197  fix.gdop = p->gdop;
198 #endif
199 
200 #if GPSD_API_MAJOR_VERSION < 8
201  fix.err = p->epe;
202 #else
203  fix.err = p->fix.eph;
204 #endif
205  fix.err_vert = p->fix.epv;
206  fix.err_track = p->fix.epd;
207  fix.err_speed = p->fix.eps;
208  fix.err_climb = p->fix.epc;
209  fix.err_time = p->fix.ept;
210 
211  /* TODO: attitude */
212  } else {
213  status.status = -1; // STATUS_NO_FIX or STATUS_UNK
214  }
215 
216  fix.status = status;
217 
218  gps_fix_pub.publish(fix);
219  }
220 
221  void process_data_navsat(struct gps_data_t* p) {
222  NavSatFixPtr fix(new NavSatFix);
223 
224  /* TODO: Support SBAS and other GBAS. */
225 
226 #if GPSD_API_MAJOR_VERSION >= 9
227  if (use_gps_time && (p->online.tv_sec || p->online.tv_nsec)) {
228  fix->header.stamp = ros::Time(p->fix.time.tv_sec, p->fix.time.tv_nsec);
229 #else
230  if (use_gps_time && !std::isnan(p->fix.time)) {
231  fix->header.stamp = ros::Time(p->fix.time);
232 #endif
233  }
234  else {
235  fix->header.stamp = ros::Time::now();
236  }
237 
238  fix->header.frame_id = frame_id;
239 
240  /* gpsmm pollutes the global namespace with STATUS_,
241  * so we need to use the ROS message's integer values
242  * for status.status
243  */
244 #if GPSD_API_MAJOR_VERSION >= 10
245  switch (p->fix.status) {
246 #else
247  switch (p->status) {
248 #endif
249 #if GPSD_API_MAJOR_VERSION >= 12
250  case STATUS_GPS:
251 #else
252  case STATUS_NO_FIX:
253 #endif
254  fix->status.status = 0; // NavSatStatus::STATUS_FIX or NavSatStatus::STATUS_GPS;
255  break;
256 // STATUS_DGPS_FIX was removed in API version 6 but re-added afterward and next renamed since the version 12
257 #if GPSD_API_MAJOR_VERSION != 6
258 #if GPSD_API_MAJOR_VERSION >= 12
259  case STATUS_DGPS:
260 #else
261  case STATUS_DGPS_FIX:
262 #endif
263  fix->status.status = 2; // NavSatStatus::STATUS_GBAS_FIX;
264  break;
265 #endif
266  }
267 
268  fix->status.service = NavSatStatus::SERVICE_GPS;
269 
270  fix->latitude = p->fix.latitude;
271  fix->longitude = p->fix.longitude;
272  fix->altitude = p->fix.altitude;
273 
274  /* gpsd reports status=OK even when there is no current fix,
275  * as long as there has been a fix previously. Throw out these
276  * fake results, which have NaN variance
277  */
278  if (std::isnan(p->fix.epx) && check_fix_by_variance) {
280  "GPS status was reported as OK, but variance was invalid");
281  return;
282  }
283 
284  fix->position_covariance[0] = p->fix.epx;
285  fix->position_covariance[4] = p->fix.epy;
286  fix->position_covariance[8] = p->fix.epv;
287 
288  fix->position_covariance_type = NavSatFix::COVARIANCE_TYPE_DIAGONAL_KNOWN;
289 
290  navsat_fix_pub.publish(fix);
291  }
292 };
293 
294 int main(int argc, char ** argv) {
295  ros::init(argc, argv, "gpsd_client");
296 
297  GPSDClient client;
298 
299  if (!client.start())
300  return -1;
301 
302 
303  while(ros::ok()) {
304  ros::spinOnce();
305  client.step();
306  }
307 
308  client.stop();
309 }
void process_data_navsat(struct gps_data_t *p)
Definition: client.cpp:221
ros::Publisher gps_fix_pub
Definition: client.cpp:76
void step()
Definition: client.cpp:57
void stop()
Definition: client.cpp:69
ROSCPP_DECL void init(int &argc, char **argv, const std::string &name, uint32_t options=0)
std::string frame_id
Definition: client.cpp:82
bool check_fix_by_variance
Definition: client.cpp:81
void process_data_gps(struct gps_data_t *p)
Definition: client.cpp:109
int main(int argc, char **argv)
Definition: client.cpp:294
bool use_gps_time
Definition: client.cpp:80
void publish(const boost::shared_ptr< M > &message) const
bool start()
Definition: client.cpp:17
#define ROS_INFO(...)
ROSCPP_DECL bool ok()
GPSDClient()
Definition: client.cpp:15
std::string frame_id
gpsmm * gps
Definition: client.cpp:78
ros::NodeHandle privnode
Definition: client.cpp:75
ros::NodeHandle node
Definition: client.cpp:74
static Time now()
ROSCPP_DECL void spinOnce()
#define ROS_ERROR(...)
#define ROS_DEBUG_THROTTLE(period,...)
ros::Publisher navsat_fix_pub
Definition: client.cpp:77
void process_data(struct gps_data_t *p)
Definition: client.cpp:84


gpsd_client
Author(s): Ken Tossell , Rob Thomson
autogenerated on Sat Jun 17 2023 02:44:31