client.cpp
Go to the documentation of this file.
00001 #include <ros/ros.h>
00002 #include <gps_common/GPSFix.h>
00003 #include <gps_common/GPSStatus.h>
00004 #include <sensor_msgs/NavSatFix.h>
00005 #include <sensor_msgs/NavSatStatus.h>
00006 #include <libgpsmm.h>
00007 
00008 using namespace gps_common;
00009 using namespace sensor_msgs;
00010 
00011 class GPSDClient {
00012   public:
00013     GPSDClient() : privnode("~"), gps(NULL), use_gps_time(true), check_fix_by_variance(true) {}
00014 
00015     bool start() {
00016       gps_fix_pub = node.advertise<GPSFix>("extended_fix", 1);
00017       navsat_fix_pub = node.advertise<NavSatFix>("fix", 1);
00018 
00019       privnode.getParam("use_gps_time", use_gps_time);
00020       privnode.getParam("check_fix_by_variance", check_fix_by_variance);
00021 
00022       std::string host = "localhost";
00023       int port = 2947;
00024       privnode.getParam("host", host);
00025       privnode.getParam("port", port);
00026 
00027       char port_s[12];
00028       snprintf(port_s, 12, "%d", port);
00029 
00030       gps_data_t *resp = NULL;
00031 
00032 #if GPSD_API_MAJOR_VERSION >= 5
00033       gps = new gpsmm(host.c_str(), port_s);
00034       resp = gps->stream(WATCH_ENABLE);
00035 #elif GPSD_API_MAJOR_VERSION == 4
00036       gps = new gpsmm();
00037       gps->open(host.c_str(), port_s);
00038       resp = gps->stream(WATCH_ENABLE);
00039 #else
00040       gps = new gpsmm();
00041       resp = gps->open(host.c_str(), port_s);
00042       gps->query("w\n");
00043 #endif
00044 
00045       if (resp == NULL) {
00046         ROS_ERROR("Failed to open GPSd");
00047         return false;
00048       }
00049 
00050       ROS_INFO("GPSd opened");
00051       return true;
00052     }
00053 
00054     void step() {
00055 #if GPSD_API_MAJOR_VERSION >= 5
00056       if (!gps->waiting(1e6))
00057         return;
00058 
00059       gps_data_t *p = gps->read();
00060 #else
00061       gps_data_t *p = gps->poll();
00062 #endif
00063       process_data(p);
00064     }
00065 
00066     void stop() {
00067       // gpsmm doesn't have a close method? OK ...
00068     }
00069 
00070   private:
00071     ros::NodeHandle node;
00072     ros::NodeHandle privnode;
00073     ros::Publisher gps_fix_pub;
00074     ros::Publisher navsat_fix_pub;
00075     gpsmm *gps;
00076 
00077     bool use_gps_time;
00078     bool check_fix_by_variance;
00079 
00080     void process_data(struct gps_data_t* p) {
00081       if (p == NULL)
00082         return;
00083 
00084       if (!p->online)
00085         return;
00086 
00087       process_data_gps(p);
00088       process_data_navsat(p);
00089     }
00090 
00091 
00092 #if GPSD_API_MAJOR_VERSION >= 4
00093 #define SATS_VISIBLE p->satellites_visible
00094 #elif GPSD_API_MAJOR_VERSION == 3
00095 #define SATS_VISIBLE p->satellites
00096 #else
00097 #error "gpsd_client only supports gpsd API versions 3+"
00098 #endif
00099 
00100     void process_data_gps(struct gps_data_t* p) {
00101       ros::Time time = ros::Time::now();
00102 
00103       GPSFix fix;
00104       GPSStatus status;
00105 
00106       status.header.stamp = time;
00107       fix.header.stamp = time;
00108 
00109       status.satellites_used = p->satellites_used;
00110 
00111       status.satellite_used_prn.resize(status.satellites_used);
00112       for (int i = 0; i < status.satellites_used; ++i) {
00113 #if GPSD_API_MAJOR_VERSION > 5
00114         status.satellite_used_prn[i] = p->skyview[i].used;
00115 #else
00116         status.satellite_used_prn[i] = p->used[i];
00117 #endif
00118       }
00119 
00120       status.satellites_visible = SATS_VISIBLE;
00121 
00122       status.satellite_visible_prn.resize(status.satellites_visible);
00123       status.satellite_visible_z.resize(status.satellites_visible);
00124       status.satellite_visible_azimuth.resize(status.satellites_visible);
00125       status.satellite_visible_snr.resize(status.satellites_visible);
00126 
00127       for (int i = 0; i < SATS_VISIBLE; ++i) {
00128 #if GPSD_API_MAJOR_VERSION > 5
00129         status.satellite_visible_prn[i] = p->skyview[i].PRN;
00130         status.satellite_visible_z[i] = p->skyview[i].elevation;
00131         status.satellite_visible_azimuth[i] = p->skyview[i].azimuth;
00132         status.satellite_visible_snr[i] = p->skyview[i].ss;
00133 #else
00134         status.satellite_visible_prn[i] = p->PRN[i];
00135         status.satellite_visible_z[i] = p->elevation[i];
00136         status.satellite_visible_azimuth[i] = p->azimuth[i];
00137         status.satellite_visible_snr[i] = p->ss[i];
00138 #endif
00139       }
00140 
00141       if ((p->status & STATUS_FIX) && !(check_fix_by_variance && isnan(p->fix.epx))) {
00142         status.status = 0; // FIXME: gpsmm puts its constants in the global
00143                            // namespace, so `GPSStatus::STATUS_FIX' is illegal.
00144 
00145 // STATUS_DGPS_FIX was removed in API version 6 but re-added afterward
00146 #if GPSD_API_MAJOR_VERSION != 6
00147         if (p->status & STATUS_DGPS_FIX)
00148           status.status |= 18; // same here
00149 #endif
00150 
00151         fix.time = p->fix.time;
00152         fix.latitude = p->fix.latitude;
00153         fix.longitude = p->fix.longitude;
00154         fix.altitude = p->fix.altitude;
00155         fix.track = p->fix.track;
00156         fix.speed = p->fix.speed;
00157         fix.climb = p->fix.climb;
00158 
00159 #if GPSD_API_MAJOR_VERSION > 3
00160         fix.pdop = p->dop.pdop;
00161         fix.hdop = p->dop.hdop;
00162         fix.vdop = p->dop.vdop;
00163         fix.tdop = p->dop.tdop;
00164         fix.gdop = p->dop.gdop;
00165 #else
00166         fix.pdop = p->pdop;
00167         fix.hdop = p->hdop;
00168         fix.vdop = p->vdop;
00169         fix.tdop = p->tdop;
00170         fix.gdop = p->gdop;
00171 #endif
00172 
00173         fix.err = p->epe;
00174         fix.err_vert = p->fix.epv;
00175         fix.err_track = p->fix.epd;
00176         fix.err_speed = p->fix.eps;
00177         fix.err_climb = p->fix.epc;
00178         fix.err_time = p->fix.ept;
00179 
00180         /* TODO: attitude */
00181       } else {
00182         status.status = -1; // STATUS_NO_FIX
00183       }
00184 
00185       fix.status = status;
00186 
00187       gps_fix_pub.publish(fix);
00188     }
00189 
00190     void process_data_navsat(struct gps_data_t* p) {
00191       NavSatFixPtr fix(new NavSatFix);
00192 
00193       /* TODO: Support SBAS and other GBAS. */
00194 
00195       if (use_gps_time && !isnan(p->fix.time))
00196         fix->header.stamp = ros::Time(p->fix.time);
00197       else
00198         fix->header.stamp = ros::Time::now();
00199 
00200       /* gpsmm pollutes the global namespace with STATUS_,
00201        * so we need to use the ROS message's integer values
00202        * for status.status
00203        */
00204       switch (p->status) {
00205         case STATUS_NO_FIX:
00206           fix->status.status = -1; // NavSatStatus::STATUS_NO_FIX;
00207           break;
00208         case STATUS_FIX:
00209           fix->status.status = 0; // NavSatStatus::STATUS_FIX;
00210           break;
00211 // STATUS_DGPS_FIX was removed in API version 6 but re-added afterward
00212 #if GPSD_API_MAJOR_VERSION != 6 
00213         case STATUS_DGPS_FIX:
00214           fix->status.status = 2; // NavSatStatus::STATUS_GBAS_FIX;
00215           break;
00216 #endif
00217       }
00218 
00219       fix->status.service = NavSatStatus::SERVICE_GPS;
00220 
00221       fix->latitude = p->fix.latitude;
00222       fix->longitude = p->fix.longitude;
00223       fix->altitude = p->fix.altitude;
00224 
00225       /* gpsd reports status=OK even when there is no current fix,
00226        * as long as there has been a fix previously. Throw out these
00227        * fake results, which have NaN variance
00228        */
00229       if (isnan(p->fix.epx) && check_fix_by_variance) {
00230         return;
00231       }
00232 
00233       fix->position_covariance[0] = p->fix.epx;
00234       fix->position_covariance[4] = p->fix.epy;
00235       fix->position_covariance[8] = p->fix.epv;
00236 
00237       fix->position_covariance_type = NavSatFix::COVARIANCE_TYPE_DIAGONAL_KNOWN;
00238 
00239       navsat_fix_pub.publish(fix);
00240     }
00241 };
00242 
00243 int main(int argc, char ** argv) {
00244   ros::init(argc, argv, "gpsd_client");
00245 
00246   GPSDClient client;
00247 
00248   if (!client.start())
00249     return -1;
00250 
00251 
00252   while(ros::ok()) {
00253     ros::spinOnce();
00254     client.step();
00255   }
00256 
00257   client.stop();
00258 }


gpsd_client
Author(s): Ken Tossell , Rob Thomson
autogenerated on Fri Jul 14 2017 02:37:03