MOOS 0.2375
/home/toby/moos-ivp/MOOS-2375-Oct0611/Instruments/Common/iGPS/GPSInstrument.cpp
Go to the documentation of this file.
00001 
00002 //
00003 //   MOOS - Mission Oriented Operating Suite
00004 //
00005 //   A suit of Applications and Libraries for Mobile Robotics Research
00006 //   Copyright (C) 2001-2005 Massachusetts Institute of Technology and
00007 //   Oxford University.
00008 //
00009 //   This software was written by Paul Newman and others
00010 //   at MIT 2001-2002 and Oxford University 2003-2005.
00011 //   email: pnewman@robots.ox.ac.uk.
00012 //
00013 //   This file is part of a  MOOS Instrument.
00014 //
00015 //   This program is free software; you can redistribute it and/or
00016 //   modify it under the terms of the GNU General Public License as
00017 //   published by the Free Software Foundation; either version 2 of the
00018 //   License, or (at your option) any later version.
00019 //
00020 //   This program is distributed in the hope that it will be useful,
00021 //   but WITHOUT ANY WARRANTY; without even the implied warranty of
00022 //   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00023 //   General Public License for more details.
00024 //
00025 //   You should have received a copy of the GNU General Public License
00026 //   along with this program; if not, write to the Free Software
00027 //   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
00028 //   02111-1307, USA.
00029 //
00031 // GPSInstrument.cpp: implementation of the CGPSInstrument class.
00032 //
00034 #include <MOOSLIB/MOOSLib.h>
00035 #include <MOOSGenLib/MOOSGenLib.h>
00036 #include "GPSInstrument.h"
00037 
00038 #include <iostream>
00039 #include <sstream>
00040 #include <iomanip>
00041 #include <cstring>
00042 #include <assert.h>
00043 using namespace std;
00044 
00045 
00047 // Construction/Destruction
00049 
00050 CGPSInstrument::CGPSInstrument()
00051 {
00052     m_sType = "VANILLA";
00053     m_bCombineMessages = false;
00054 }
00055 
00056 CGPSInstrument::~CGPSInstrument()
00057 {
00058 
00059 }
00060 
00061 
00064 bool CGPSInstrument::Iterate()
00065 {
00066     if(GetData())
00067     {
00068         PublishData();
00069     }
00070 
00071     return true;
00072 }
00073 
00074 
00075 bool CGPSInstrument::OnStartUp()
00076 {
00077     
00078     CMOOSInstrument::OnStartUp();
00079 
00080     //set up Geodetic conversions
00081     double dfLatOrigin;
00082     double dfLongOrigin;
00083 
00084 
00085     m_MissionReader.GetConfigurationParam("TYPE",m_sType);
00086 
00087     // If FALSE then outputs old-style messages, where each piece
00088     // of info (N,E,X,Y,#Sats) comes in a separate message.
00089     // If TRUE then outputs all data in a single message, with a proper timestamp.
00090     m_MissionReader.GetConfigurationParam("CombineMessages", m_bCombineMessages);
00091 
00092     string sVal;
00093     if(m_MissionReader.GetValue("LatOrigin",sVal))
00094     {
00095         dfLatOrigin = atof(sVal.c_str());
00096     }
00097     else
00098     {
00099         MOOSTrace("LatOrigin not set - FAIL\n");
00100 
00101         return false;
00102 
00103     }
00104 
00105     if(m_MissionReader.GetValue("LongOrigin",sVal))
00106     {
00107         dfLongOrigin = atof(sVal.c_str());
00108     }
00109     else
00110     {
00111         MOOSTrace("LongOrigin not set - FAIL\n");
00112 
00113         return false;
00114     }
00115 
00116     if(!m_Geodesy.Initialise(dfLatOrigin,dfLongOrigin))
00117     {
00118         MOOSTrace("Geodesy Init failed - FAIL\n");
00119 
00120         return false;
00121     }
00122 
00123 
00124     //here we make the variables that we are managing
00125     double dfGPSPeriod = 1.0;
00126 
00127     //GPS update @ 2Hz
00128     if (m_bCombineMessages)
00129     {
00130         AddMOOSVariable("GPS","SIM_GPS", "GPS", 0);
00131     }
00132     else
00133     {
00134         AddMOOSVariable("X","SIM_X","GPS_X",dfGPSPeriod);
00135         AddMOOSVariable("Y","SIM_Y","GPS_Y",dfGPSPeriod);
00136         AddMOOSVariable("N","","GPS_N",dfGPSPeriod);
00137         AddMOOSVariable("E","","GPS_E",dfGPSPeriod);
00138         AddMOOSVariable("Satellites","","GPS_SAT",dfGPSPeriod);
00139     }
00140 
00141     AddMOOSVariable("Raw","","GPS_RAW",dfGPSPeriod);
00142 
00143 
00144 
00145 
00146     if(IsSimulateMode())
00147     {
00148         //not much to do...
00149         RegisterMOOSVariables();
00150     }
00151     else
00152     {
00153         //try to open
00154         if(!SetupPort())
00155         {
00156             return false;
00157         }
00158 
00159         //try 10 times to initialise sensor
00160         if(!InitialiseSensorN(10,"GPS"))
00161         {
00162             return false;
00163         }
00164     }
00165 
00166 
00167     return true;
00168 }
00169 
00170 
00171 
00172 bool CGPSInstrument::OnNewMail(MOOSMSG_LIST &NewMail)
00173 {
00174     return UpdateMOOSVariables(NewMail);
00175 }
00176 
00177 
00178 
00179 bool CGPSInstrument::PublishData()
00180 {
00181     return PublishFreshMOOSVariables();
00182 }
00183 
00184 
00185 
00186 bool CGPSInstrument::OnConnectToServer()
00187 {
00188     if(IsSimulateMode())
00189     {
00190         //not much to do...
00191         RegisterMOOSVariables();
00192     }
00193     else
00194     {
00195 
00196 
00197     }
00198     return true;
00199 }
00200 
00201 
00202 
00203 bool CGPSInstrument::InitialiseSensor()
00204 {
00205     if (MOOSStrCmp(m_sType, "ASHTECH"))
00206     {
00207         const char * sInit = "$PASHS,NME,GGA,A,ON\r\n";
00208         MOOSTrace("Sending %s\n", sInit);
00209         m_Port.Write(sInit, strlen(sInit));
00210 
00211         MOOSPause(2000);
00212         string sReply;
00213         double dfTime;
00214 
00215         if (m_Port.GetLatest(sReply, dfTime)) {
00216             MOOSTrace("Rx %s", sReply.c_str());
00217         } else {
00218             MOOSTrace("No reply\n");
00219         }
00220 
00221     }
00222     else if (MOOSStrCmp(m_sType, "GARMIN"))
00223     {
00224 
00225         const char *sInitA = "$PGRMO,,2\r\n";
00226         MOOSTrace("Sending %s\n", sInitA);
00227         MOOSPause(2000);
00228         m_Port.Write(sInitA, strlen(sInitA));
00229 
00230         const char *sInitB = "$PGRMO,GPGGA,1\r\n";
00231         MOOSTrace("Sending %s\n", sInitB);
00232         MOOSPause(2000);
00233         m_Port.Write(sInitB, strlen(sInitB));
00234 
00235         const char *sInitC = "$PGRMO,GPRMC,1\r\n";
00236         MOOSTrace("Sending %s\n", sInitC);
00237         MOOSPause(2000);
00238         m_Port.Write(sInitC, strlen(sInitC));
00239 
00240 
00241         string sReply;
00242         double dfTime;
00243 
00244         if (m_Port.GetLatest(sReply, dfTime))
00245         {
00246             MOOSTrace("Rx %s\n", sReply.c_str());
00247         }
00248         else
00249         {
00250             MOOSTrace("No reply\n");
00251         }
00252 
00253         const char *sInit = "$PGRMC,,,,,,,,,,,,2,1,\r\n";
00254         MOOSTrace("Sending %s\n", sInit);
00255         m_Port.Write(sInit, strlen(sInit));
00256 
00257 
00258         if(m_Port.GetLatest(sReply, dfTime))
00259         {
00260             MOOSTrace("Rx %s\n", sReply.c_str());
00261         }
00262         else
00263         {
00264             MOOSTrace("No reply\n");
00265         }
00266     }
00267     else if (MOOSStrCmp(m_sType, "SERES"))
00268     {
00269         //Some information about the Seres unit:
00270         //Default baud is 9600.
00271         //If the unit is sending binary messgaes, try sending a $JRESET message
00272         //This can happen after poking it with a diagnostic program like SLXMon.
00273 
00274         const char * sInit = "$JASC,GPGGA,5\r\n";
00275         MOOSTrace("Sending %s\n", sInit);
00276         m_Port.Write(sInit, strlen(sInit));
00277 
00278         MOOSPause(2000);
00279         string sReply;
00280         double dfTime;
00281 
00282         if (m_Port.GetLatest(sReply, dfTime)) {
00283             MOOSTrace("Rx %s", sReply.c_str());
00284         } else {
00285             MOOSTrace("No reply\n");
00286         }
00287 
00288     }
00289     return true;
00290 }
00291 
00292 
00293 
00294 
00299 bool CGPSInstrument::GetData()
00300 {
00301     if(!IsSimulateMode())
00302     {
00303         //here we actually access serial ports etc
00304 
00305         string sWhat;
00306 
00307         double dfWhen;
00308 
00309         if(m_Port.IsStreaming())
00310         {
00311             if(!m_Port.GetLatest(sWhat,dfWhen))
00312             {
00313                 return false;
00314             }
00315         }
00316         else
00317         {
00318             if(!m_Port.GetTelegram(sWhat,0.5))
00319             {
00320                 return false;
00321             }
00322         }
00323 
00324         double dfTimeNow = MOOSTime();
00325 
00326         //MOOSTrace("Rx:  %s",sWhat.c_str());
00327         if(PublishRaw())
00328         {
00329             SetMOOSVar("Raw",sWhat,dfTimeNow);
00330         }
00331 
00332         // Try to make sense of the string
00333         CGPSData data;
00334         if (!ParseNMEAString(sWhat, data))
00335         {
00336             return false;
00337         }
00338 
00339 
00340         // Publish all the bits that we can.  Each component is published separately
00341         // (as they were originally), but at the same time a large string is built up
00342         // containing all the info in one place
00343         stringstream buf;
00344         buf << "time=";
00345         buf.setf(ios::fixed);
00346         buf << setprecision(3) << dfTimeNow;
00347 
00348         if (data.bGood)
00349         {
00350             double dfNLocal, dfELocal;
00351             if(m_Geodesy.LatLong2LocalUTM(data.dfLat_deg,data.dfLong_deg,dfNLocal,dfELocal))
00352             {
00353                 if (!m_bCombineMessages)
00354                 {
00355                     SetMOOSVar("N", dfNLocal, dfTimeNow);
00356                     SetMOOSVar("E", dfELocal, dfTimeNow);
00357                 }
00358                 buf << ",N=" << dfNLocal << ",E=" << dfELocal;
00359             }
00360 
00361             double dfXLocal, dfYLocal;
00362             if(m_Geodesy.LatLong2LocalGrid(data.dfLat_deg,data.dfLong_deg,dfYLocal,dfXLocal))
00363             {
00364                 if (!m_bCombineMessages)
00365                 {
00366                     SetMOOSVar("X", dfXLocal, dfTimeNow);
00367                     SetMOOSVar("Y", dfYLocal, dfTimeNow);
00368                 }
00369                 buf << ",X=" << dfXLocal << ",Y=" << dfYLocal;
00370             }
00371 
00372         }
00373 
00374         // Always say how many satellites we have
00375         SetMOOSVar("Satellites", data.nSatellites, dfTimeNow);
00376         buf << ",Sats=" << setprecision(0) << data.nSatellites;
00377 
00378         if (m_bCombineMessages)
00379             SetMOOSVar("GPS", buf.str(), dfTimeNow);
00380     }
00381     else
00382     {
00383         //in simulated mode there is nothing to do..all data
00384         //arrives via comms.
00385     }
00386 
00387     return true;
00388 }
00389 
00390 
00391 bool CGPSInstrument::ParseNMEAString(const std::string &sNMEAString, CGPSData & out_data)
00392 {
00393     CGPSData data;
00394 
00395     // Keep a copy for later..
00396     string sNMEAChomp = sNMEAString;
00397 
00398     string sWhat = MOOSChomp(sNMEAChomp, ",");
00399 
00400     bool bGood = true;
00401 
00402     // GGA and GLL headers format the NMEA string differently
00403     // We only pick up GGA records
00404     if(sWhat == "$GPGGA")
00405     {
00406 
00407         // First of all, is this a good NMEA string?
00408         if(!DoNMEACheckSum(sNMEAString))
00409         {
00410             MOOSDebugWrite("GPS Failed NMEA check sum");
00411             return false;
00412         }
00413 
00414         // Begin to extract data
00415         string sTok;
00416 
00417         // We're not currently doing anything with the GPS time
00418         // Time is in format hhmmss[.s]
00419         sTok = MOOSChomp(sNMEAChomp,",");
00420 
00421         // Latitude
00422         sTok = MOOSChomp(sNMEAChomp,",");
00423         bGood = (bGood && sTok.size());
00424         data.dfLat_deg = m_Geodesy.DMS2DecDeg(atof(sTok.c_str()));
00425 
00426         // North/South
00427         sTok = MOOSChomp(sNMEAChomp,",");
00428         if(sTok == "S")
00429         {
00430             data.dfLat_deg *= -1.0;
00431         }
00432 
00433         // Longitude
00434         sTok = MOOSChomp(sNMEAChomp,",");
00435         bGood = (bGood && sTok.size());
00436         data.dfLong_deg = m_Geodesy.DMS2DecDeg(atof(sTok.c_str()));
00437 
00438         // East/West
00439         sTok = MOOSChomp(sNMEAChomp,",");
00440         if(sTok=="W")
00441         {
00442             data.dfLong_deg *= -1.0;
00443         }
00444 
00445         // Quality measures
00446         //MJC says: I think this is wrong. GGA Message spec says this field should be Quality Indicator
00447         //0 = no position, 1 = undifferentially corrected position, 2 =
00448         //differentially corrected position, 9= position computed using almanac
00449         //HDOP field comes after Number of Sattelites
00450         //However, the value read into the HDOP variable is never actually used, so it's not currently having any effect.
00451         sTok = MOOSChomp(sNMEAChomp,",");
00452         data.dfHDOP    = atof(sTok.c_str());
00453 
00454         sTok = MOOSChomp(sNMEAChomp,",");
00455         data.nSatellites = atoi(sTok.c_str());
00456         bGood = (bGood && data.nSatellites > 3);
00457 
00458         data.bGood = bGood;
00459 
00460         // Copy result to output variable
00461         out_data = data;
00462 
00463         return true;
00464     }
00465 
00466     return false;
00467 }
00468 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines