Wio LTEでGrove GPS出力を解析

#Wio LTEでGPSを使う
日本版の[Wio LTE](https://soracom.jp/products/wio_lte/)にはGPS機能は付いていませんが、Groveのモジュールに[Grove - GPS](http://wiki.seeed.cc/Grove-GPS/)があります。これを使えばGPSを使って、位置や時刻を取得できるようになります。[Grove - GPS](http://wiki.seeed.cc/Grove-GPS/)は国内では[スイッチサイエンス](https://www.switch-science.com/catalog/1179/)で購入することができます。
また、SORACOMの[Grove IoT スターターキット](https://soracom.jp/products/)にも[Grove - GPS](http://wiki.seeed.cc/Grove-GPS/)が付属しています。(実はWio LTEとGrove - GPSだけでGrove IoT スターターキットの販売価格ぐらいになるのでWio LTEでGPSを使いたい方はめちゃお得です。)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/109992/a6059bbf-aa25-8bc2-9400-47c9b1a6914e.png)


[Wio LTEのライブラリ](https://github.com/SeeedJP/WioLTEforArduino)にはそれを扱うライブラリもありますが単純に受信したデータを表示するだけのものなので、中身まで解析する方法を紹介します。

#NMEA
GPSから受信するデータは一般的に[NMEA](https://ja.wikipedia.org/wiki/NMEA_0183)というフォーマットになっています。
一般的なフォーマットなので、それを扱うライブラリもたくさんあります。
その中で使ってみたものがあるので紹介します。

#MicroNMEA
Arduino用のライブラリなので、APIはほぼそのまま使えます。その上、マイコン用に小さいサイズで作られているのでWio LTEでも使いやすいと思います。

https://github.com/stevemarple/MicroNMEA

ZIP形式でダウンロードして、ArduinoIDEにインポートします。

#スケッチ
ライブラリの中にはスケッチ例も含んでいますが、Wio LTEではそのまま使えないのでWio LTE向けにカスタムしました。

```Arduino
#include <WioLTEforArduino.h>
#include <MicroNMEA.h>

HardwareSerial& gps = Serial;
char nmeaBuffer[100];
MicroNMEA nmea(nmeaBuffer, sizeof(nmeaBuffer));
bool ledState = LOW;

WioLTE Wio;

void led(bool state)
{
  if(state)  Wio.LedSetRGB(0, 255, 0);
  else       Wio.LedSetRGB(255, 0, 0);
}

void gpsHardwareReset()
{
  while (gps.available())
    gps.read();
  
  Wio.PowerSupplyGrove(false);
  delay(500);
  Wio.PowerSupplyGrove(true);

  while (1) {
    while (gps.available()) {
      char c = gps.read();
      if (nmea.process(c))  return;
      
    }
  }
}

void setup()
{
  gps.begin(9600);
  
  Wio.Init();
  Wio.PowerSupplyGrove(true);

  led(ledState);
  
  SerialUSB.println("Resetting GPS module ...");
  gpsHardwareReset();
  SerialUSB.println("... done");
  
  MicroNMEA::sendSentence(gps, "$PORZB");
  MicroNMEA::sendSentence(gps, "$PORZB,RMC,1,GGA,1");
  MicroNMEA::sendSentence(gps, "$PNVGNME,2,9,1");
  
}

void loop()
{  
  if(nmea.isValid()) {
    ledState = true;
    SerialUSB.println();
    SerialUSB.println("-----------------------");  
  
    SerialUSB.print("Valid fix: ");
    SerialUSB.println(nmea.isValid() ? "yes" : "no");
  
    SerialUSB.print("Nav. system: ");
    if (nmea.getNavSystem())
      SerialUSB.println(nmea.getNavSystem());
    else
      SerialUSB.println("none");
  
    SerialUSB.print("Num. satellites: ");
    SerialUSB.println(nmea.getNumSatellites());
  
    SerialUSB.print("HDOP: ");
    SerialUSB.println(nmea.getHDOP()/10., 1);
    
    SerialUSB.print("Date/time: ");
    SerialUSB.print(nmea.getYear());
    SerialUSB.print('-');
    SerialUSB.print(int(nmea.getMonth()));
    SerialUSB.print('-');
    SerialUSB.print(int(nmea.getDay()));
    SerialUSB.print('T');
    SerialUSB.print(int(nmea.getHour()));
    SerialUSB.print(':');
    SerialUSB.print(int(nmea.getMinute()));
    SerialUSB.print(':');
    SerialUSB.println(int(nmea.getSecond()));
  
    long latitude_mdeg = nmea.getLatitude();
    long longitude_mdeg = nmea.getLongitude();
    SerialUSB.print("Latitude (deg): ");
    SerialUSB.println(latitude_mdeg / 1000000., 6);
  
    SerialUSB.print("Longitude (deg): ");
    SerialUSB.println(longitude_mdeg / 1000000., 6);
  
    long alt;
    SerialUSB.print("Altitude (m): ");
    if (nmea.getAltitude(alt))
      SerialUSB.println(alt / 1000., 3);
    else
      SerialUSB.println("not available");
  
    SerialUSB.print("Speed: ");
    SerialUSB.println(nmea.getSpeed() / 1000., 3);
    SerialUSB.print("Course: ");
    SerialUSB.println(nmea.getCourse() / 1000., 3);
  
    SerialUSB.println("-----------------------");    
    nmea.clear();
  }
  else
  {
    ledState = false;
  }
  
  led(ledState);

  while (gps.available()) {
    char c = gps.read();
    if(!ledState) SerialUSB.print(c);
    nmea.process(c);
  }
  delay(1000);
}
```

#動作
[Grove - GPS](http://wiki.seeed.cc/Grove-GPS/)を[Wio LTE](https://soracom.jp/products/wio_lte/)の[UARTのGroveコネクタ](https://github.com/SeeedJP/WioLTEforArduino/wiki/Hardware-ja)に接続して、動作をさせます。
受信したGPSの情報が妥当でない場合はLEDを赤く点灯し、GPSから受信したNMEAをそのまま表示します。GPSの情報が妥当な場合はNMEAを解析した結果を表示します。

GPS情報が妥当でない場合
![image.png](https://qiita-image-store.s3.amazonaws.com/0/109992/2b155f3c-bb88-0125-754e-60f33f35d784.png)

GPS情報が妥当な場合（自宅がバレそうなので、位置情報の細かい値は伏せてます）
![image.png](https://qiita-image-store.s3.amazonaws.com/0/109992/027400a4-2454-1a64-b271-3f863ce2e5fb.png)

GPS情報の各値はMicroNMEAクラスの各関数で取得できるようになっていますので、
ちなみに緯度経度はWGS84（世界測地系）です。こちらはGoogleMapなどのほとんどの地図ソフトがWGS84なので気にする必要はありませんが、時刻はUTC（協定世界時）なのでJST（日本時間）にしたい場合は9時間分足してください。（時刻の足し算はそのままやるとめんどくさいので、わからない場合ははコメント下さい。）

#執筆しているWio LTEのkindle書籍について
だいぶ出版が遅れてしまっているのですが、執筆しているWio LTEの本がようやくゴールが見えてきました。いろいろ掲載許可の確認が遅くなってしまったのと、次々載せたいネタが増えたので遅れてしまいました。
すでに出版している[ファーストステップ編](http://amzn.to/2EkuCpr)では、Arduino環境とEspruino（JavaScript）環境のセットアップ方法を解析しましたが、近日出版予定のGroveリファレンス編はこの記事で書いている様にさまざまなGroveのモジュールの扱い方を解説しています。実はこの記事もGroveリファレンス編に掲載しているネタの一つです。（この記事よりもうちょっと細かく書いています）
ファーストステップ編ではArduino環境で扱う場合とEspruino（JavaScript）環境で扱う場合の両方を書きましたが、ボリュームの都合上、それぞれの書籍を分けることにしました。近日出版するのはArduino環境向けの書籍です。

以下、書籍の情報です。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/109992/4c1b51fd-f6e8-cbaf-407e-889a9a48a9bc.png)

出版形式：kindle(電子書籍)
価格：1,250円（予定）
その他：書籍の中で、扱っているライブラリやスケッチ例はGitHubからダウンロードできるようにします。
〇目次
  Groveとは
  Groveの種類
  　電圧の違い
  　インターフェースの違い
  Groveリファレンス
   　Grove IoT Starter kit
    　　Grove - ボタン(P) (入力装置)
    　　Grove - ブザー(出力装置)
    　　Grove - 磁気スイッチ
    　　Grove - 温湿度センサー
    　　Grove - 超音波距離センサー
    　　Grove - GPS
    　　Grove - 3軸デジタル加速度センサー(±16g) 
   　さまざまなGroveモジュール
    　　Grove - 水センサ
    　　Grove - 水分センサ
    　　Grove - シリアルカメラモジュールキット
    　　Grove - I2C タッチセンサ
   　そのまま繋げられないGroveモジュール
    　　Grove - ダストセンサー
    　　Grove - CO2センサー 
    　　GROVE - 火炎センサ
   　自作Groveモジュール
    　　e-DISP4
    　　BME680 温湿度・気圧・ガスセンサモジュール
    　　VEML6070 UV紫外線センサ・モジュール

（リクエストあれば、出版後扱うモジュールを追加していく予定です。）