Raspberry Pi3のPythonでGPSモジュールを扱ったメモです。Raspberry Pi3のOSバージョンは
Raspbian GNU/Linux 8.0 (jessie)
Raspbian GNU/Linux 9.4 (stretch) (2018年10月5日修正)
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を検索すると、micropyGPSとpynmea2が見つかりました。
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は「準天頂衛星初号機みちびき」です。