2

我正在开发一个 C++ 应用程序,它应该使用 gpsd 检索收到的 $GPGGA 类型的 NMEA 语句。这个想法是大约每秒从 gpsd 读取一次并解析最后收到的 $GPGGA 句子,提取我感兴趣的两个字段:质量指标和参考站 ID。我使用了 C++ libgpsmm 库,定期调用 togpsmm::read()和 to gpsmm::data(),直接访问客户端数据缓冲区。

起初,我使用 gpsfake 和伪造的 GPS 日志进行了几次测试(指定 gpsfake 选项“-c 0.5”,以便每秒有两个句子)。当两次请求 gpsd 之间的时间小于或等于 400ms 时,结果正常。如果我尝试更长的时间,结果是出乎意料的,每次阅读一段 NMEA 句子,其中包含大量重复数据以及一些截断的句子。当我尝试使用每秒写入约 40 个句子的真正 GPS 时,情况变得更糟:在这种情况下,读取之间的时间应该是 10 毫秒或更短,以便获得正确的结果。

以下是打印接收到的 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 似乎更难。

4

1 回答 1

1

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

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

The GPS receiver should be configured to output information at a 1Hz (once per second), in this case the the device should only output about 8 sentances per second. If you're seeing 40 sentances then your receiver would seem to be outputting information at around 5Hz which sounds like overkill for your particular interest.

于 2012-11-29T01:26:49.060 回答