GPS NMEAセンテンスをgpsdで解析する

# はじめに

**GPS service daemon (通称gpsd)** をPC上で動かして、NMEAを解析する方法に関するメモ書きです。GPSの性能を手っ取り早く確認するのに便利です。

gpsdの詳細については本家ホームページを参考にしてください。

https://gpsd.gitlab.io/gpsd/

NMEA出力についてはSPRESENSEボードを使用しました。

https://developer.sony.com/ja/develop/spresense/

アンテナ含めてGNSS機能を内蔵しているので便利です。

# SPRESENSEボードでNMEAを出力する

Spresense Arduino環境でNMEAセンテンスを出力する方法は、公式チュートリアルに載っていました。公式サイトから少しだけ変更しています。

https://developer.sony.com/develop/spresense/docs/arduino_tutorials_ja.html#_nmea_センテンスを出力する

```cpp:gnss_nmea.ino
#include <GNSS.h>
#include <GNSSPositionData.h>
#include <gpsutils/cxd56_gnss_nmea.h>

SpGnss Gnss;
char   PositionData[sizeof(GnssPositionData)];

/* output NMEA */
static char nmea_buf[NMEA_SENTENCE_MAX_LEN];

static char *reqbuf(uint16_t size)
{
  if (size > sizeof(nmea_buf)) {
    return NULL;
  }
  return nmea_buf;
}

static void freebuf(char *buf)
{
  return;
}

static int outbin(char *buf, uint32_t len)
{
  return len;
}

static int outnmea(char *buf)
{
  return printf("%s", buf);
}

void setup()
{
  /* Initialize Serial */
  Serial.begin(115200);

  /* Initialize GNSS */
  if (Gnss.begin()) {
    Serial.println("begin error!");
  }

  /* select satellite system */
  Gnss.select(GPS);
  Gnss.select(QZ_L1CA);
  //GLONASS/BEIDOU/GALILEOのどれか一つを有効にする
  Gnss.select(GLONASS);
  //Gnss.select(BEIDOU);
  //Gnss.select(GALILEO);

  /* set interval */
  Gnss.setInterval(1);

  if (Gnss.start(COLD_START)) {
    Serial.println("start error!");
  }

  /* use NMEA library */
  NMEA_InitMask();
  NMEA_OUTPUT_CB  funcs;
  funcs.bufReq  = reqbuf;
  funcs.out     = outnmea;
  funcs.outBin  = outbin;
  funcs.bufFree = freebuf;
  NMEA_RegistOutputFunc(&funcs);
}

void loop()
{
  /* Check update. */
  if (Gnss.waitUpdate(1000)) {
    /* Output NMEA */
    Gnss.getPositionData(PositionData);
    NMEA_Output(&(((GnssPositionData*)PositionData)->Data));
  }
}
```

# macOS環境でgpsdを使用する

macOS向けにhomebrewでgpsdが提供されているのですが、gpsmon, cgpsなど一部の機能しか使用できないようです。

## インストール

Homebrew で gpsd をインストールします

https://formulae.brew.sh/formula/gpsd

```
$ brew install gpsd
```
## 起動方法
```
$ GPSD_SOCKET="$(brew --prefix)/var/gpsd.sock" $(brew --prefix)/Cellar/gpsd/3.24/sbin/gpsdctl add /dev/tty.SLAB_USBtoUART
$ brew services restart
```
### gpsmonコマンド
```
$ gpsmon
```
#### 結果
GPSとBeiDouを有効にした例です。家の中で動かしているので信号レベル(SN)がいまいちです。
![mac-gpsmon.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/432852/b1292d29-a50b-8216-0b8a-9af454757ed4.png)

### cgpsコマンド
```
$ cgps
```
#### 結果
GPSとBeiDouを有効にした例です。DOP値など精度情報が出力されます。
![mac-cgps.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/432852/0442057e-f043-3356-4a45-b06adf2e0c2d.png)


# Ubuntu環境でgpsdを使用する

Linux向けのgpsdはフル機能が使用できます。
私はWindows10のWSL2 + VcXsrvを使って動作確認しています。

WSL2 kernelを変更して直接USBポートにアクセスすることもできるようにしています。
詳しくは、[WSL2環境からUSBシリアルデバイスを使う](https://qiita.com/baggio/items/28c13ed8ac09fc7ebdf1)を参照してください。

## インストール

apt-get で gpsd, gpsd-clients をインストールします

```
$ sudo apt-get install gpsd gpsd-clients
```
## 起動方法
```
$ gpsd /dev/ttyUSB0
```
### gpsmonコマンド
```
$ gpsmon
```
#### 結果
GPSとGLONASSを有効にした例です。
![ubuntu-gpsmon.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/432852/a6d0f17c-fc53-f9d9-59b0-9a78bac5eac9.png)

### cgpsコマンド
```
$ cgps
```
#### 結果
GPSとGLONASSを有効にした例です。
![ubuntu-cgps.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/432852/ab3dc2dc-98c2-126a-a9bd-cbeafb5ee8bc.png)

### xgpsコマンド
```
$ xgps
```
#### 結果
GPSとGLONASSを有効にした例です。衛星配置を確認できます。
![ubuntu-xgps.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/432852/ccf2e0f3-7ddd-00c2-10d3-32f8a899eac7.png)

### gpsplotコマンド
```
$ gpsplot
```
#### 結果
GPSとGLONASSを有効にした例です。測位結果のばらつきを確認できます。
![ubuntu-gpsplot.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/432852/1ce1184b-50c3-6ba6-1446-cac364f1a042.png)

### gpsprofコマンド
```
$ gpsprof -T png | gnuplot > image.png
```
#### 結果
画像に落として表示した結果。デフォルト100サンプル分の統計誤差情報。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/432852/ba8db31d-33fc-8a55-da35-58f5fa0df2a6.png)