SPRESENSEで高精度GPSロガーをつくる

# はじめに

みちびきの[サブメータ級測位補強サービス(L1S)に対応した製品](https://qzss.go.jp/usage/products/list.html#clas-slas)を眺めていたら
ソニーの[SPRESENSE](https://developer.sony.com/ja/develop/spresense/)があるではないですか。

これでGPSロガーを作れば高精度測位の ~~実力とやらを見せてもらおうか~~ 実験ができる！
というわけで[買って](https://item.rakuten.co.jp/tsukumorobo/0405995975010/)しまいました

さて、GPSロガーに仕立てていきます

結果だけ知りたい、という人は[結果](#結果)へどうぞ

# 開発環境の構築 ～ Lチカ

[公式のスタートガイド](https://developer.sony.com/develop/spresense/docs/arduino_set_up_ja.html)に従えば、ハマリどころはないのですが
手順を簡単に書いておきます。

**環境**

- PC w/ Windows7 Pro SP1 (公式には8.1 or 10とありますが、7でもいけました)
- SPRESENSE本体 (拡張ボードなし)
- USB-microケーブル

**ダウンロードしたもの**

- [Arduino IDE](https://www.arduino.cc/en/Main/Donate) (JUST DOWNLOAD... ごめん、いつか貢献する)
- [CP210x USB to serial driver for Windows 7/8/8.1](https://www.silabs.com/documents/public/software/CP210x_Windows_Drivers.zip)

**手順**

1. [Arduino IDEをインストール](https://developer.sony.com/develop/spresense/docs/arduino_set_up_ja.html#_arduino_ide_%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB) → インストーラーを起動しインストールするだけ
2. [CP210xをインストール](https://developer.sony.com/develop/spresense/docs/arduino_set_up_ja.html#_usb_%E3%83%89%E3%83%A9%E3%82%A4%E3%83%90%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB) → これも...
3. [Spresense Arduino board package のインストール](https://developer.sony.com/develop/spresense/docs/arduino_set_up_ja.html#_spresense_arduino_board_package_%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB) → Arduino IDEでの操作だけ
4. SPRESENSEをPCに接続 → USBケーブルでつなげるだけ
5. [ブートローダのインストール](https://developer.sony.com/develop/spresense/docs/arduino_set_up_ja.html#_spresense_%E3%83%96%E3%83%BC%E3%83%88%E3%83%AD%E3%83%BC%E3%83%80%E3%83%BC%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB) → Arduino IDEでの操作だけ
6. [サンプルスケッチでLチカ](https://developer.sony.com/develop/spresense/docs/arduino_set_up_ja.html#_led_%E3%81%AE%E3%82%B9%E3%82%B1%E3%83%83%E3%83%81%E3%82%92%E5%8B%95%E3%81%8B%E3%81%97%E3%81%A6%E3%81%BF%E3%82%8B) → コードをコピペしてボタン押すだけ

**あれっ、ボードコンピューターってこんなに簡単に動かせるんだ！**
と思うくらい簡単です。いい世の中になりました。

# GPSロガーに仕立てる

開発環境には豊富にサンプルがついています。
Arduino IDEで ファイル > スケッチ例 と開くとサンプルが見られます。
**GNSS**がGPSを使ったサンプル群です。
で、**gnss_tracker** が非常によくできておりまして、
これをベースに以下の点を変更してロガーとして仕立てました。

1. 利用する衛星に GPS + L1C/A(みちびき) + **L1S**(みちびき 測位補強) を指定
2. ログデータの書き込み先を SDカード から 内蔵Flash に変更 (拡張ボード未購入のため...)
3. カスタマイズ性はいらないので、config file周りのコードをがっさり削除
4. LEDの利用方法の変更 (L1S信号受信状況を表示)

コードはGitHubに置きました
[こちら](https://github.com/Tomonobu3110/spresense-arduino-compatible/tree/track_without_extend_board/Arduino15/packages/SPRESENSE/hardware/spresense/1.0.0/libraries/GNSS/examples/gnss_logger)からどうぞ。

## (追記) Qiita記事らしくコードを引用してポイント解説

### インスタンス生成

```
SpGnss Gnss;                            /**< SpGnss object */
```

### GPS受信の準備

```c
  if (Gnss.begin(Serial) != 0)
  {
    /* Error case. */
    APP_PRINT_E("Gnss begin error!!\n");
    error_flag = 1;
  }
  else
  {
    APP_PRINT_I("Gnss begin OK.\n");

    // GPS + QZSS(L1C/A) + QZAA(L1S)
    Gnss.select(GPS);
    Gnss.select(QZ_L1CA);
    Gnss.select(QZ_L1S);
    Gnss.setInterval(POSITIONING_INTERVAL);

    if (Gnss.start(HOT_START) != OK)
    {
      /* Error case. */
      APP_PRINT_E("Gnss start error!!\n");
      error_flag = 1;
    }
  }
```
`Gnss.begin()`で初期化、`Gnss.select()`で衛星を指定、`Gnss.setInterval()`で受信間隔を指定、`Gnss.start()`で受信開始

### 位置データの受信

```c
void loop() {
  // static
  static bool PosFixflag = false;
  static char *pNmeaBuff = NULL;
  static int WriteCounter = NUMBER_OF_CACHE;

  /* Check update. */
  if (Gnss.waitUpdate(POSITIONING_INTERVAL * 1000))
  {
    /* Get NavData. */
    SpNavData NavData;
    Gnss.getNavData(&NavData);

    /* Position Fixed?? */
    bool LedSet = ((NavData.posDataExist) && (NavData.posFixMode != 0));
    if (PosFixflag != LedSet)
    {
      Led_isPosfix(LedSet);
      PosFixflag = LedSet;
    }
    if (PosFixflag) {
        //unsigned short sat = NavData.posSatelliteType;
        unsigned short sat = NavData.satelliteType;
        // GPS, QZ_L1CA --> LED1
        if (0 != (sat & (GPS | QZ_L1CA))) {
          ledOn(PIN_LED1);
        } else {
          ledOff(PIN_LED1);  
        }
        // QZ_L1S --> LED2
        if (0 != (sat & QZ_L1S)) {
          ledOn(PIN_LED2);
        } else {
          ledOff(PIN_LED2);  
        }
    }
```
`Gnss.waitUpdate()`で位置情報の取得をまち、1が戻れば位置情報が取れています。
`Gnss.getNavData()`で様々な情報が詰まった`SpNavData`が取り出せます。
例えば`SpNavData::satelliteType`には捕捉している衛星の種類が入っています。

### NMEAデータに変換

```
    /* Convert Nav-Data to Nmea-String. */
    String NmeaString = getNmeaGga(&NavData);
```
もとのサンプル(gnss_tracker)のコードをそのまま使わせてもらっています。
あとはこれをファイルに書けばOKです。
Flashなのであまり高頻度に書き込みしないように気を付けましょう。
このコードでは受信データ12回分をバッファして、書き込み頻度を1回/分にしています。

# Flash上のファイルの取り出し方

GPSログをFlashから読みだす必要があります。
そのために、YModem転送機能をそなえた簡易ファイラーを作りました。
コードは以下から取得できます。

* [X/YModelライブラリ](https://github.com/Tomonobu3110/arduino-xmodem)
* [簡易ファイラー](https://github.com/Tomonobu3110/spresense-arduino-compatible/tree/tiny_filer_with_xmodem/Arduino15/packages/SPRESENSE/hardware/spresense/1.0.0/libraries/Flash/examples/tiny_filer)

ターミナルソフトはArduino IDEのものではなく[Tera Term](https://ttssh2.osdn.jp/)を利用してください。
Y + 番号でダウンロードしたいファイルを指定した後、
Tera Termのメニューから ファイル > 転送 > Y-Modem > 受信
を選択します。
あらかじめ「ディレクトリを変更」でダウンロード先を指定するとよいと思います。

ログは[NMEAフォーマット](https://jh8xvh.hdlc.jp/gps/nmea.html)です。
あとは煮るなり焼くなりお好きに...

# 結果

自転車で120kmほど走ってログを取得しました。

Google Map
https://drive.google.com/open?id=15Q-2rhg1ZXhqd4IbaEpAJG99x_awx3eZ&usp=sharing

ログを取った日は、スタート直後からL1S信号を安定して受信できていました。
往路の環７、江戸川、手賀沼、復路の江戸川、荒川では
ほぼ100%の時間L1S信号を捕捉していたようです。

**ログの精度は素晴らしく、**
特に三郷駅付近、みさとの風ひろばでの休憩中のログの
ブレの少なさには驚きました。

ビルの多い街中ではL1S信号をなかなかつかめないこともありますが、
ひらけた場所を走ることが多い自転車用のロガーとしては
かなり優秀なんじゃないでしょうか。
ケースとバッテリーを工夫してロングライドのお供にしようと思います。

# おまけ

ステム部分にモバイルバッテリーとSPRESENSEをつけています
![IMG_20200109.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/102797/8bfb0692-099f-5b3f-1635-28a5de2b25f9.jpeg)