【问题标题】:gpsd client data buffergpsd客户端数据缓冲区
【发布时间】:2023-03-14 05:42:01
【问题描述】:

我正在开发一个 C++ 应用程序,它应该使用 gpsd 检索收到的 $GPGGA 类型的 NMEA 语句。这个想法是大约每秒从 gpsd 读取一次并解析最后收到的 $GPGGA 句子,提取我感兴趣的两个字段:质量指标和参考站 ID。我使用了 C++ libgpsmm 库,定期调用gpsmm::read()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 .

【问题讨论】:

    标签: c++ gps buffer nmea gpsd


    【解决方案1】:

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

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

    GPS 接收器应配置为以 1Hz(每秒一次)输出信息,在这种情况下,设备每秒应仅输出约 8 个句子。如果您看到 40 句句子,那么您的接收器似乎会以 5Hz 左右的频率输出信息,这对于您的特殊兴趣来说听起来有点过头了。

    【讨论】:

    • 感谢您的回答,蒂姆罗尔!一些cmets:1)我之前考虑过增加缓冲区大小......但我无法在libgps所做的所有定义中识别它,我认为必须有一种常用的方法来获得我想要的东西。 2)唤醒后清除缓冲区并不能解决我的问题,因为我的真实应用程序无法被阻止等待消息,因为它必须同时处理其他内容。 3) 我正在使用 20Hz 的 GPS 接收器:我每秒接收 10 GGA、10 TVG 和 1 ZDA。
    • 毫无疑问,解决我的问题的最佳方法是将 GPS 数据采集和该信息的消费分为两个不同的线程。这样,缓冲区就不会损坏,而且也不需要更频繁地读取。
    猜你喜欢
    • 2020-08-09
    • 2011-03-18
    • 1970-01-01
    • 2013-10-27
    • 1970-01-01
    • 2016-08-05
    • 1970-01-01
    • 1970-01-01
    • 2019-07-08
    相关资源
    最近更新 更多