gpsd客户端数据缓冲区
gpsd client data buffer
我正在开发一个C++应用程序,该应用程序应该使用gpsd检索收到的$GPGGA类型的NMEA语句。这个想法是大约每秒从gpsd读取一次,并解析最后一个$GPGGA接收到的句子,提取我感兴趣的两个字段:质量指标和参考站ID。我使用C++libgpsmm库,定期调用gpsmm::read()
和gpsmm::data()
,直接访问客户端数据缓冲区。
起初,我使用gpsfake和一个假的GPS日志进行了几次测试(指定gpsfake选项"-c 0.5",以便每秒有两句话)。当两个对gpsd的请求之间的时间小于或等于400ms时,结果是可以的。如果我试着花更多的时间,结果是出乎意料的,每次阅读一段NMEA句子时都会有很多重复的数据和一些截断的句子。当我尝试使用一个每秒能写大约40句话的真正GPS时,情况真的更糟:在这种情况下,为了得到正确的结果,两次阅读之间的时间应该是大约10ms甚至更短。
下面是一个更简单的程序,用于打印收到的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消息(在最坏的情况下,可能长达一秒钟)。
GPS接收器应配置为以1Hz(每秒一次)输出信息,在这种情况下,设备应每秒仅输出约8个哨兵。如果你看到40个岗哨,那么你的接收器似乎在5Hz左右输出信息,这对你的特定兴趣来说听起来有些过头了。
- 多线程和共享资源:使用C++定期将数据从缓冲区(数据结构)复制到文件
- OpenGL:使用指向静态数据的指针数组传递缓冲区数据
- 提取肮脏的RGB像素缓冲区数据Directx
- 如何使用模板函数从缓冲区(T* 数据数组)创建 cv::Mat
- 将缓冲区数据解析为结构
- glReadPixels更改缓冲区数据
- OpenGL + 无法使用缓冲区子数据更新缓冲区数据
- 与缓冲区数据匹配的 C++ 字符串模式
- 如何在使用FFmpeg写入mp4文件时将缓冲区数据刷新到磁盘
- 为什么boost::asio::读取缓冲区数据大小小于读取大小
- 使用C++AMP读取缓冲区数据
- DX11正在丢失实例缓冲区数据
- 是否可以在没有完全定义着色器的情况下测试缓冲区数据是否成功加载到GPU上?(C++、OpenGL 4.4、GLFW)
- opengl =中缓冲区数据的问题仅在我缓冲比需要更多的字节时绘制
- 谷歌协议缓冲区-对编码解码base64 char * c字符串协议缓冲区数据感到困惑
- 通过套接字发送协议缓冲区数据并确定类
- 通过原始缓冲区数据缩放和旋转纹理到另一个纹理上
- 仅修改VBO缓冲区数据的特定元素类型
- 在read()之前检查boost::asio缓冲区数据是否存在
- 从原始缓冲区数据创建Mat图像