ESP32 - MicroPythonにて、GPS受信キットを制御する

# はじめに

ESP32 - MicroPythonを使い、GPS受信キットから受信方法について記載します。<br>


![000.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/559938/292ac3bb-d94f-db6b-36e0-34e84f35077b.jpeg)


# GPS受信機キット - 1PPS出力付き「みちびき」3機受信対応

今回、秋月電子さんで購入できるGPS受信機キット - 1PPS出力付き「みちびき」3機受信対応を使用します。<br>
以下が主な仕様です。

- GPSモジュール：GYSFDMAXB(太陽誘電)
- 搭載GPS受信チップ：MT3339(MediaTek)
- 受信周波数：1575.42MHz(L1,C/Aコード)
- 受信チャネル数：66(アクイジション)、22(トラッキング)
- 対応測位衛星システム：GPS(米国)、QZSS(日本)
- 受信(トラッキング)感度：-164dBm(typ.)
- 測位確度：2m(typ.緯経度の水平位置)@-135dBm
- 出力データ形式：NMEA0183V3.01準拠
- 測地系：WGS1984(デフォルト)
- 電源電圧：DC5V(3.8V~12V)/・電源電流：40mA
- 入出力信号レベル：C-MOSロジック(3.3V)レベル、非同期シリアル信号
- UART通信速度：9600bps(デフォルト)、4800~115200bps
- 出力データ更新レート：毎秒1回(デフォルト)、毎秒1~10回出力可
- 1PPS出力：C-MOSロジック(3.3V)レベル、パルス幅：100mS(アクティブLow)
- インジケータ：赤色LEDによる通電表示、衛星追尾中(1PPS)表示
- 基板サイズ：30×30×13.5mm(電池ボックス実装時)
- 重量：約11g(バックアップ電池装着時)


[商品ページへのリンク](http://akizukidenshi.com/catalog/g/gK-09991/)

!!!本商品は、はんだ付けが必要です。!!!



# 開発環境

以下が確認した環境となります。

- ホストPC
  - windows10 64bit Home
  - VSCode - 1.41.1
     - Pymakr 1.1.5
  - NodeJS - 12.14.1 LTS
- ターゲット
    - MicroPython v1.12 on 2019-12-20; ESP32 module with ESP32

# 機材

※型名が購入先のリンクになっています。

|項目  |型名|備考  |
|---|---|---|
| ESP32-WROOM-32 開発ボード  |[NodeMCU-32S ESP32-WROOM-32](https://www.amazon.co.jp/gp/product/B07R87Z178/ref=ppx_yo_dt_b_asin_title_o06_s00?ie=UTF8&psc=1)   | -   |
| GPS受信機キット             |[秋月電子](http://akizukidenshi.com/catalog/g/gK-09991/)   | -   |
| ダイオード(1N4148)          |[秋月電子](http://akizukidenshi.com/catalog/g/gI-00941/)   | GPS取説 - 推奨回路に記載   |
| 抵抗 10kΩ                   |             | GPS取説 - 推奨回路に記載   |
|ジャンパーケーブル            | 指定なし   |  |


# 接続図


![SampleGpsfzz_ブレッドボード.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/559938/34d43928-8ab7-4da9-90b5-e4dfbdd5424e.png)

※今回、「1PPS出力」は使用しないので、未接続になっています。
　評価基板によって、RX2,TX2は、D16, D17と記載されています。


# モジュール

GPSモジュールからNMEAフォーマットで送られてきます。

制御文字などが入っているため、パースする必要があります。

調査したところ、micropyGPSというライブラリを使うとできそうなことがわかりました。


[inmcm/micropyGPS](https://github.com/inmcm/micropyGPS)


ただ、README.mdに下記の記載があります。

```
ESP32
You can follow the setup instructions for the pyboard.
The only difference is, that you shoud use micropyGPS as a frozen module.
Otherwise there will be exceptions, because there is not enough heap space available.
```

ヒープが足りなくなるから、"frozen module"として扱ってねとのこと。


# コード

動作確認したコードは以下となります。


ファイル名：sample_gps.py

```
from machine import UART
from micropyGPS import MicropyGPS
import utime, gc, _thread

uart = UART(2, baudrate=9600, timeout=200)
my_gps = MicropyGPS(local_offset=0, location_formatting='dd')

def test():
    n = 0
    mem_free = gc.mem_free()
    tm_last = 0
    while True:
        len = uart.any()
        if len > 0:
            b = uart.read(len)
            for x in b:
                if 10 <= x <= 126:
                    stat = my_gps.update(chr(x))
                    if stat:
                        tm = my_gps.timestamp
                        tm_now = (tm[0] * 3600) + (tm[1] * 60) + int(tm[2])
                        if (tm_now - tm_last) >= 10:
                            print('=' * 20)
                            print(my_gps.date_string(), tm[0], tm[1], int(tm[2]))
                            print("latitude:", my_gps.latitude[0], ", longitude:", my_gps.longitude[0])
                            print("altitude:", my_gps.altitude)
                            print("satellites_used:", my_gps.satellites_used)
                            n += 1
                            tm_last = tm_now
                            if (n % 10) == 0:
                                print("Mem free:", gc.mem_free(), mem_free - gc.mem_free())
                                gc.collect()
        else:
            utime.sleep_ms(100)

testth=_thread.start_new_thread(test, ())
```

# ファイル構成

```
>>> import os
>>> os.listdir()
['boot.py', 'project.pymakr', 'sample_gps.py', 'micropyGPS.py']
```

# 実行結果例

10秒ごとに、printのログが表示されます。
※xxxは伏せています。

```
>>> import sample_gps
I (58850) uart: ALREADY NULL
>>> ====================
00/00/00 12 59 11
latitude: 36.xxxxxx , longitude: 139.xxx
altitude: 139.5
satellites_used: []
====================
02/09/20 12 59 21
latitude: 36.xxxxxx , longitude: 139.xxx
altitude: 139.5
satellites_used: [3, 1, 193, 30, 8, 194]
====================
02/09/20 12 59 31
latitude: 36.xxxxxx , longitude: 139.xxx
altitude: 139.5
satellites_used: [3, 1, 193, 30, 194]
====================
02/09/20 12 59 41
latitude: 36.xxxxxx , longitude: 139.xxx
altitude: 139.5
satellites_used: [11, 3, 1, 17, 193, 30, 8, 194]

...
```

# 気づいたことと


## 最初の起動は時間がかかる
取説にも記載されていますが、時間がかかります
"40秒～数十分"と記載。
私の場合は、2分ほどかかりました。
受信できるとLEDの点滅で教えてくれます。

## 各項目の精度について
当たり前かもしれませんが、時刻はきっちり取れています。
緯度経度は、数十～１００メートルぐらいといった感じでしょうか。
十分な精度だと思います。
ただ、ログ上は同じ値になっていますが、海抜は安定していない気がします。
40メートル　～ 180メートルの値をとってしまう。

## ヒープ領域について
gc.collect()を実施しないと、利用可能なヒープが減っていきます。
上記のコードで、数時間ほど走らせてましたが、
とりあえず落ちることはなかったです。
もう少しエージングして確認しますが、
ダメなら別の方法が必要になるかもしれません。



# 参考にさせていただいたサイト

* [micropyGPS](https://github.com/inmcm/micropyGPS)
* [Raspberry Pi3のPythonでGPSを扱う](https://ambidata.io/blog/2017/08/02/gps/)