2

gpsd を使用して、受信した $GPGGA タイプの NMEA センテンスを取得する C++ アプリケーションを開発しています。gpsd から約 1 秒に 1 回読み取り、最後の $GPGGA 受信文を解析して、関心のある 2 つのフィールド (品質インジケーターと参照ステーション ID) を抽出するという考え方です。C++ libgpsmm ライブラリを使用し、定期的に と を呼び出しgpsmm::read()gpsmm::data()クライアント データ バッファに直接アクセスしました。

最初に、gpsfake と偽の GPS ログ (gpsfake オプション "-c 0.5" を指定して、1 秒あたり 2 つの文を持つようにする) を使用していくつかのテストを行いました。gpsd への 2 つのリクエスト間の時間が 400 ミリ秒以下の場合、結果は OK です。より長い時間で試してみると、結果は予想外であり、多くの繰り返しデータといくつかの切り捨てられた文を含む NMEA 文を読み取るたびに発生します。毎秒最大 40 文を書き込む実際の G​​PS を試してみると、状況はさらに悪化します。この場合、正しい結果を得るには、読み取り間の時間は最大 10 ミリ秒以下にする必要があります。

以下は、受信した NMEA センテンスを出力する簡単なプログラムです。シミュレートされたGPSでも、実際のGPSでもうまく機能します。しかし、usleep() 呼び出しのコメントを外すと、プログラムは 1 秒に 1 回バッファをチェックするようになり、クライアント データ バッファは適切な結果をもたらしません。

#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>

これは、行がコメント化されたときの出力です (つまり、バッファは 1 秒に 1 回チェックされます)。

$    ./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