Я разрабатываю приложение на C ++, которое должно получать полученные предложения NMEA типа $ GPGGA, используя gpsd. Идея заключается в том, чтобы читать из GPSD примерно один раз в секунду, и разобрать последний $ GPGGA получил предложение, извлекая два поля моего интереса: индикатор качества и идентификатор базовой станции. Я использовал библиотеку C ++ libgpsmm, периодически вызывая gpsmm::read()
и к gpsmm::data()
, обращаясь непосредственно к клиентскому буферу данных.
Сначала я сделал несколько тестов, используя gpsfake и поддельный журнал GPS (указав опцию gpsfake «-c 0.5», чтобы иметь два предложения в секунду). Результаты в порядке, когда время между двумя запросами к gpsd меньше или равно 400 мс. Если я попробую с большим временем, результаты будут неожиданными, в каждом чтении будет фрагмент NMEA-предложений с большим количеством повторяющихся данных, а также несколько усеченных предложений. Ситуация действительно хуже, когда я пытаюсь использовать настоящий GPS, который пишет ~ 40 предложений в секунду: в этом случае промежуток времени между чтением должен составлять ~ 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 предложения.
Я не знаком со службой gpsd, но то, что вы описываете, похоже на то, что буфер приема поврежден (перезаписан). Приемник GPS непрерывно выводит информацию NMEA, и когда ваше приложение находится в спящем режиме, эти символы будут накапливаться в буфере. Если получено слишком много символов, буфер будет перезаписан.
Либо увеличьте размер буфера приемника последовательного порта (если это возможно), либо, возможно, очистите буфер после пробуждения, а затем дождитесь следующего сообщения GGA (которое может быть на расстоянии до одной секунды в худшем случае).
Приемник GPS должен быть настроен на вывод информации с частотой 1 Гц (один раз в секунду), в этом случае устройство должно выводить только около 8 сигналов в секунду. Если вы видите 40 отправлений, то ваш приемник, похоже, будет выводить информацию на частоте около 5 Гц, что звучит как излишнее для вашего особого интереса.
Других решений пока нет …