Edited at

Raspberry Pi3のPythonでGPSを扱う

Raspberry Pi3のPythonでGPSモジュールを扱ったメモです。Raspberry Pi3のOSバージョンは

Raspbian GNU/Linux 8.0 (jessie)

Raspbian GNU/Linux 9.4 (stretch) (2018年10月5日修正)

です。

Raspberry Pi3 + GPS


GPSモジュール

GPSモジュールは秋月電子の「GPS受信機キット 1PPS出力付き 『みちびき』対応」を使いました。

このGPSモジュールは、受信したGPSデーターをシリアルで送出します。Raspberry Pi3でシリアル通信するにはUSBポートを使う方法とGPIOピンを使う方法があります。USBポートを使う場合はUSBシリアル変換モジュールが必要になるので、今回はGPIOピンを使いました。

Raspberry Pi3とGPSモジュールとは次のように接続します。

Raspberry Pi3
GPSモジュール

04(5v)
5V

06(Ground)
GND

08(TXD0)
RXD

10(RXD0)
TXD

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


Raspberry Pi3のPythonでシリアル通信

Raspberry Pi3でシリアル通信をするには、raspi-configでシリアルを有効化し、シリアルをコンソールとして使わない設定をします。


raspi-configでシリアルの有効化

次のようにraspi-configを起動し、シリアルを有効にします。

pi$ sudo raspi-config

「5 Interfacing Options」を選択し、さらに「 P6 Serial 」を選択します。「Would you like a login shell to be accessible over serial?」に対してYesを選択、Finishし、リブートします。

pi$ sudo reboot

/dev/serial0というデバイスが作られます。

pi$ ls /dev/se*

/dev/serial0 /dev/serial1


/boot/cmdline.txtの修正

/boot/cmdline.txtを修正し、serial0をコンソールとして使わないように設定します。

pi$ cat /boot/cmdline.txt 

dwc_otg.lpm_enable=0 console=tty1 console=serial0,115200 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait quiet splash plymouth.ignore-serial-consoles

エディターで「console=serial0,115200」を削除し、リブートします。

pi$ sudo reboot


Pythonのシリアルモジュールをインストールする

Pythonのシリアルモジュールをインストールします。(2018年10月5日: python-serialからpyserialに変更)

pi$ pip install pyserial

pyenvを使っていない場合はpip3でインストールしてください。

これでRaspberry Pi3のPythonでシリアル通信ができるようになります。Raspberry Pi3にGPSモジュールを接続し、次のようにPythonを立ち上げて、確認すると、GPSデーターが読めているのが確認できます。

pi$ python3

>>> import serial
>>> s = serial.Serial('/dev/serial0', 9600, timeout=10)
>>> print(s.readline())
b'\x00\x00\xc0\x00\xfe\x00pK&&KLN\xcb14,302,,06,08,254,27,30,07,230,29*70\r\n'
>>> print(s.readline())
b'$GPGSV,4,4,14,23,05,150,19,14,04,054,*74\r\n'
>>>

1回目のreadline()は中途半端なデーターになっていますが、2回目以降のreadline()はGPSデーターが読めているようです。


PythonのGPSライブラリー

GPSモジュールから送られてくるデーターはNMEA-0183というフォーマットの文字列です。NMEA-0183のデーター形式については「NMEA 0183 sentences データ解析」というサイトが分かりやすいです。

GPSモジュールはGPS衛星からの信号を受信し、時刻、緯度、経度、海抜高度、測位に利用した衛星の数やID、それぞれの衛星の位置(方位角と仰角)などの情報をNMEA-0183フォーマットの文字列として送出します。

この文字列データーをプログラムで扱いやすいデーターに変換するPythonライブラリーがあります。Webを検索すると、micropyGPSpynmea2が見つかりました。

micropyGPSはPython3.xとMicroPythonで動作するGPSデーターの解析ライブラリーで、GPSデーターを入力すると、それを解析してGPSオブジェクトにデーターを追加、更新していきます。GPSオブジェクトのデーターとして時刻、緯度、経度、測位に利用した衛星の数やIDなどの情報が得られます。ドキュメントもしっかりしています。

pynmea2はGPSデーターを1行ずつパースするだけのようで、ドキュメントも貧弱そうに見えます。

ということで、ライブラリーとしてはmicropyGPSを使うことにしました。使うためにはGithubからmicropyGPS.pyをダウンロードして、Pythonを起動するディレクトリーに置くだけです。


Pythonプログラム

GPSデーターを読むPythonプログラムは次のようになりました。GPSモジュールからデーターを読み、

GPSオブジェクトにデーターを追加、更新する処理をスレッドにして動かし、そのデーターを3秒毎に出力しています。

MicroGPSオブジェクトを生成する時の引数として、タイムゾーンの時差(日本は+9時間)と、緯度経度の出力フォーマットを指定しています。出力フォーマットは次の形式が指定できるようです。

'ddm'   10進の度、分 (40° 26.767′ N)

'dms' 10進の度、分、秒 (40° 26′ 46″ N)
'dd' 10進の度 (40.446° N)

import serial

import micropyGPS
import threading
import time

gps = micropyGPS.MicropyGPS(9, 'dd') # MicroGPSオブジェクトを生成する。
# 引数はタイムゾーンの時差と出力フォーマット

def rungps(): # GPSモジュールを読み、GPSオブジェクトを更新する
s = serial.Serial('/dev/serial0', 9600, timeout=10)
s.readline() # 最初の1行は中途半端なデーターが読めることがあるので、捨てる
while True:
sentence = s.readline().decode('utf-8') # GPSデーターを読み、文字列に変換する
if sentence[0] != '$': # 先頭が'$'でなければ捨てる
continue
for x in sentence: # 読んだ文字列を解析してGPSオブジェクトにデーターを追加、更新する
gps.update(x)

gpsthread = threading.Thread(target=rungps, args=()) # 上の関数を実行するスレッドを生成
gpsthread.daemon = True
gpsthread.start() # スレッドを起動

while True:
if gps.clean_sentences > 20: # ちゃんとしたデーターがある程度たまったら出力する
h = gps.timestamp[0] if gps.timestamp[0] < 24 else gps.timestamp[0] - 24
print('%2d:%02d:%04.1f' % (h, gps.timestamp[1], gps.timestamp[2]))
print('緯度経度: %2.8f, %2.8f' % (gps.latitude[0], gps.longitude[0]))
print('海抜: %f' % gps.altitude)
print(gps.satellites_used)
print('衛星番号: (仰角, 方位角, SN比)')
for k, v in gps.satellite_data.items():
print('%d: %s' % (k, v))
print('')
time.sleep(3.0)

プログラムを動かすと、次のような結果が出力されました。緯度経度の小数点以下は伏せてあります。

14:02:19.0

緯度経度: 35.********, 139.********
海抜: 51.900000
測位利用衛星: [17, 28, 6, 3, 193, 1, 22, 8]
衛星番号: (仰角, 方位角, SN比)
193: (59, 173, 40)
3: (71, 124, 24)
6: (13, 259, 27)
1: (49, 42, 16)
8: (15, 115, 21)
42: (48, 170, 34)
11: (40, 69, None)
14: (4, 47, None)
17: (42, 317, 15)
19: (20, 307, None)
22: (56, 66, 21)
23: (10, 145, None)
28: (63, 248, 38)
30: (3, 224, 16)

「衛星番号」の次からの行が捕捉した衛星の衛星番号と仰角、方位角、SN比です。衛星番号193は「準天頂衛星初号機みちびき」です。