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


corobot_gps
Author(s): Morgan Cormier/mcormier@coroware.com
autogenerated on Tue Jan 7 2014 11:39:30