gpsd客户端数据缓冲区

问题描述:

我正在开发一个C++应用程序,它应该使用gpsd检索收到的类型为$ GPGGA的NMEA语句。这个想法是每秒从gpsd读取一次,并解析最后一个$ GPGGA收到的句子,提取我感兴趣的两个字段:质量指标和参考站点ID。我使用C++ libgpsmm库,定期调用gpsmm::read()gpsmm::data(),直接访问客户端数据缓冲区。首先,我使用gpsfake和伪造的GPS日志(指定gpsfake选项“-c 0.5”,以便每秒钟有两个句子)做了几次测试。当两个gpsd请求之间的时间小于或等于400ms时,结果是OK的。如果我用更多的时间尝试,结果是意想不到的,在每次阅读中都有一段NMEA句子,其中包含大量重复数据以及一些截短的句子。当我尝试使用每秒写入40个句子的真实GPS时,情况会更糟糕:在这种情况下,读取之间的时间应该为〜10ms或更少,以便获得正确的结果。gpsd客户端数据缓冲区

以下是打印收到的NMEA句子的一个更简单的程序。它运行良好,模拟甚至是真正的GPS。但是,如果我取消注释usleep()调用,这会使程序每秒检查一次缓冲区,但客户端数据缓冲区不会给出合理的结果。

#include <iostream> 

#include "libgpsmm.h" 

using namespace std; 

#define WAITING_TIME 5000000 
#define RETRY_TIME 5 
#define ONE_SECOND 1000000 

int main(void) 
{ 
    for(;;){ 
     //For version 3.7 
     gpsmm gps_rec("localhost", DEFAULT_GPSD_PORT); 

     if (gps_rec.stream(WATCH_ENABLE|WATCH_NMEA) == NULL) { 
      cout << "No GPSD running. Retry to connect in " << RETRY_TIME << " seconds." << endl; 
      usleep(RETRY_TIME * ONE_SECOND); 
      continue; // It will try to connect to gpsd again 
     } 

     const char* buffer = NULL; 

     for (;;) { 
      struct gps_data_t* newdata; 

      if (!gps_rec.waiting(WAITING_TIME)) 
       continue; 

      if ((newdata = gps_rec.read()) == NULL) { 
       cerr << "Read error.\n"; 
       break; 
      } else { 
       buffer = gps_rec.data(); 

       // We print the NMEA sentences! 
       cout << "***********" << endl; 
       cout << buffer << endl;    

       //usleep(1000000); 
      } 
     } 
    } 
} 

这里是具有usleep()函式输出呼叫评论(即连续地读取数据。):

$  ./GPSTest1 
*********** 
{"class":"VERSION","release":"3.7","rev":"3.7","proto_major":3,"proto_minor":7} 
*********** 
{"class":"WATCH","enable":true,"json":false,"nmea":true,"raw":0,"scaled":false,"timing":false} 
*********** 
$GPGGA,202010.00,3313.9555651,S,06019.3785868,W,4,09,1.0,39.384,M,16.110,M,10.0,*46<CR><LF> 
*********** 
$GPGGA,202011.00,3313.9555664,S,06019.3785876,W,4,09,1.0,39.386,M,16.110,M,11.0,*4D<CR><LF> 
*********** 
$GPGGA,202012.00,3313.9555668,S,06019.3785882,W,4,09,1.0,39.394,M,16.110,M,12.0,*49<CR><LF> 
*********** 
$GPGGA,202013.00,3313.9555673,S,06019.3785911,W,4,09,1.0,39.395,M,16.110,M,13.0,*49<CR><LF> 
*********** 
$GPGGA,202014.00,3313.9555670,S,06019.3785907,W,4,09,1.0,39.409,M,16.110,M,14.0,*4F<CR><LF> 
*********** 
$GPGGA,202015.00,3313.9555657,S,06019.3785905,W,4,09,1.0,39.395,M,16.110,M,15.0,*4A<CR><LF> 

这是当线被注释的输出(即,缓冲检查每秒一次):

$ ./GPSTest2 
*********** 
{"class":"VERSION","release":"3.7","rev":"3.7","proto_major":3,"proto_minor":7} 
*********** 
{"class":"DEVICE","path":"/dev/pts/0","activated":"2012-11-05T23:48:38.110Z","driver":"Generic NMEA","native":0,"bps":4800,"parity":"N","stopbits":1,"cycle":1.00} 
$GPGGA,202013.00,3313.9555673,S,06019.3785911,W,1,09,1.0,39.395,M,16.110,M,13.0,*49<CR><LF> 
0} 
$GPGGA,202013.00,3313.9555673,S,06019.3785911,W,1,09,1.0,39.395,M,16.110,M,13.0,*49<CR><LF> 
":"Generic NMEA","native":0,"bps":4800,"parity":"N","stopbits":1,"cycle":1.00} 
$GPGGA,202013.00,3313.9555673,S,06019.3785911,W,1,09,1.0,39.395,M,16.110,M,13.0,*49<CR><LF> 

*********** 
$GPGGA,202013.00,3313.9555673,S,06019.3785911,W,1,09,1.0,39.395,M,16.110,M,13.0,*49<CR><LF> 
*********** 
$GPGGA,202016.00,3313.9555642,S,06019.3785894,W,1,09,1.0,39.402,M,16.110,M,16.0,*4E<CR><LF> 
$GPGGA,202017.00,3313.9555643,S,06019.3785925,W,1,09,1.0,39.404,M,16.110,M,17.0,*42<CR><LF> 
$GPGGA,202017.00,3313.9555643,S,06019.3785925,W,1,09,1.0,39.404,M,16.110,M,17.0,*42<CR><LF> 
$GPGGA,202017.00,3313.9555643,S,06019.3785925,W,1,09,1.0,39.404,M,16.110,M,17.0,*42<CR><LF> 
*********** 

任何建议?起初,我试图直接分析gps_data_t结构,但在结构的所有领域中,与NMEA句子中的搜索相比,似乎很难确定质量指标和参考站ID。

我不熟悉gpsd服务,但是您描述的内容看起来很像接收缓冲区被损坏(覆盖)。 GPS接收器不断地输出NMEA信息,当你的应用程序正在休眠时,这些字符将会累积在缓冲区中,如果接收到太多字符,则缓冲区将被覆盖。

要么增加串口接收缓冲区大小(如果可能的话),要么可能在唤醒后清空缓冲区,然后等待下一个GGA消息(最坏的情况下可能会达到1秒)。

GPS接收机应该配置为以1Hz(每秒一次)输出信息,在这种情况下,该设备应该只输出每秒约8次的读数。如果你看到40个功放,那么你的接收机似乎会以5Hz左右的频率输出信息,这听起来像是为了你特别感兴趣的矫枉过正。

+0

感谢您的回答,timrorr! 一些评论: 1)我想过增加缓冲区大小之前......但我无法在libgps所做的所有定义中识别它,我认为必须有一种通常的方法来获得我想要的。 2)唤醒后清除缓冲区并不能解决我的问题,因为我的真实应用程序无法阻止等待消息,因为它必须同时处理其他消息。 3)我正在使用20Hz的GPS接收机:我每秒接收10个GGA,10个TVG和1个ZDA。 – pabloderosario

+0

当然,解决我的问题的最好方法是将GPS数据采集和消耗这些信息分为两个不同的线程。这样,缓冲区不会被破坏,而且也不需要更多的读取。 – pabloderosario