MOOS 0.2375
|
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