ESP8266 ArduinoとGPSモジュールでGPSロガーを作る


ESP8266 ArduinoとGPSモジュールで位置情報付きのデーターを取得し、[IoTデーター可視化サービスAmbient](https://ambidata.io)に送信して地図上にプロットしました。

![MacとGPSロガー](https://ambidata.io/wp/wp-content/uploads/2017/08/20170804gps02-1024x768.jpg)

# GPSモジュール

GPSモジュールは秋月電子さんの「[GPS受信機キット 1PPS出力付き 『みちびき』対応](http://akizukidenshi.com/catalog/g/gK-09991/)」を使いました。このGPSモジュールは、受信したGPSデーターをシリアルで送出します。

マイコンはESP8266を搭載したスイッチサイエンスさんの[ESPr Developer](https://www.switch-science.com/catalog/2500/)を使いました。ESPr DeveloperとGPSモジュールとは次のように接続します。

|ESPr Developer|GPSモジュール|
|:------------:|:----------|
|Vout | 5V|
|GND | GND|
|IO4 | TXD|
|IO5 | RXD|

GPSの1PPSピンは使わないので何もつなぎません。

# ESPr Developerでソフトシリアル通信

ESPr Developerのシリアル通信ポートは開発環境との通信に使われているので、GPSモジュールと通信するにはGPIOピン(今回はIO4とIO5)を使い、ソフトシリアルで通信します。

ソフトシリアルのライブラリーは[EspSoftwareSerial](https://github.com/plerup/espsoftwareserial)を使いました。インストールは簡単で、[Githubのページ](https://github.com/plerup/espsoftwareserial)右上の「Clone or download」から「Download ZIP」を選んでZIPファイルをダウンロードし、Arduino IDEを立ち上げて、「スケッチ」メニューの「ライブラリをインクルード」→「.ZIP形式のライブラリをインストール...」でダウンロードしたZIPファイルを選択すれば完了です。

# ArduinoでGPSデーターを扱うライブラリー

GPSモジュールはGPS衛星からの信号を受信し、時刻、緯度、経度、海抜高度、測位に利用した衛星の数やID、それぞれの衛星の位置(方位角と仰角)などの情報を[NMEA-0183フォーマット](https://ja.wikipedia.org/wiki/NMEA_0183)というフォーマットの文字列として送出します。この文字列データーをプログラムで扱いやすいデーターに変換するArduinoライブラリーがあります。

「[Raspberry Pi3のPythonでGPSを扱う](https://ambidata.io/blog/2017/08/02/gps/)」というブログではPythonでGPSデーターを扱うｍicropyGPSというライブラリーを紹介しました。このmicropyGPSがモデルにしているArduinoのライブラリーがTinyGPSで、今回はその後継にあたる[TinyGPS++](http://arduiniana.org/libraries/tinygpsplus/)というライブラリーを使いました。

インストールはソフトシリアルと同様で[TinyGPS++のサイト](http://arduiniana.org/libraries/tinygpsplus/)のダウンロードアイコンの先の最新のZIPファイルをダウンロードし、
Arduino IDEで「.ZIP形式のライブラリをインストール...」でZIPファイルをインストールします。

シリアルから読んだGPSデーターを1文字づつライブラリーに渡すとそれを解析し、GPSオブジェクトに追加、更新します。解析中はfalseが返り、1行処理して解析が成功するとtrueが返されます。シリアルからGPSデーターを読んでGPSオブジェクトにする部分は次のようなプログラムになります。

```cpp
    while (ss.available() > 0) {
        if (gps.encode(ss.read())) {
            break;
        }
    }
```

# プログラム

Arduinoプログラムを示します。

ESPr DeveloperのIO16にスイッチを付けて、スイッチが押されていたら、その時の緯度経度と標高をAmbientに送信しています。while文でスイッチが押されている時間を見ているのはチャタリング(スイッチの機械的なバタつき)防止です。

Ambientには位置情報付きのデーターを受信し、地図上に表示する機能があります。通常のd1からd8のデーターに加えて、緯度をデーター9、経度をデーター10として送ると位置情報付きデーターになります。

```cpp
#include <ESP8266WiFi.h>
#include <SoftwareSerial.h>
#include <TinyGPS++.h>
#include "Ambient.h"

extern "C" {
#include "user_interface.h"
}

unsigned int channelId = 100;
const char* writeKey = "ライトキー";

const char* ssid = "...ssid...";
const char* password = "...password...";

static const int RXPin = 4, TXPin = 5;
SoftwareSerial ss(RXPin, TXPin, false, 256);
TinyGPSPlus gps;
void sendInfo2Ambient();
static const int sw = 16;
static const unsigned long PUSH_SHORT = 100;

WiFiClient client;
Ambient ambient;

void setup()
{
    Serial.begin(115200);
    delay(20);
    Serial.println(F("Start"));

    wifi_set_sleep_type(LIGHT_SLEEP_T);

    WiFi.begin(ssid, password);  //  Wi-Fi APに接続
    while (WiFi.status() != WL_CONNECTED) {  //  Wi-Fi AP接続待ち
        delay(100);
    }

    Serial.print("WiFi connected\r\nIP address: ");
    Serial.println(WiFi.localIP());

    ss.begin(9600);
    pinMode(sw, INPUT);

    ambient.begin(channelId, writeKey, &client);
}

void loop()
{
    unsigned long gauge = 0;

    while (digitalRead(sw) == 0) {
        gauge++;
        delay(0);
    }
    if (gauge > PUSH_SHORT) {
        if (gps.location.isValid()) {
            sendInfo2Ambient();
        }
    }
    while (ss.available() > 0) {
        if (gps.encode(ss.read())) {
            break;
        }
    }
}

void sendInfo2Ambient()
{
    char buf[16];

    if (gps.location.isValid()) {
        dtostrf(gps.altitude.meters(), 4, 2, buf);
        Serial.println(buf);
        ambient.set(1, buf);
        dtostrf(gps.location.lat(), 12, 8, buf);
        Serial.println(buf);
        ambient.set(9, buf);
        dtostrf(gps.location.lng(), 12, 8, buf);
        Serial.println(buf);
        ambient.set(10, buf);

        ambient.send();
    }
}
```

# Ambientでデーターを確認する

作ったGPSロガーを持ち、歩きながら所々でスイッチを押してデーターを取得し、スマホでテザリングしてAmbientにデーターを送信しました。

Ambientで位置情報付きのデーターを地図上に表示するには、チャート設定でグラフ種類として「地図」を選択します。

![地図表示の設定](https://ambidata.io/wp/wp-content/uploads/2017/08/20170804gps03-768x551.jpg)

データーはこんな感じで地図上に表示されます。データーはGPSから取得した海抜高度です。緯度経度は非常に正確な値が取得できていますが、海抜高度は非常にばらつきが大きいようです。

![地図表示](https://ambidata.io/wp/wp-content/uploads/2017/08/20170804gps04.jpg)

位置情報付きデーターは車両の運行管理など実務的な応用もありますし、サイクルコンピューターのデーターなどを蓄積、可視化できたら面白いと思います。