Raspberry Pi3のPythonでGPSモジュールを扱ったメモです。Raspberry Pi3のOSバージョンは
Raspbian GNU/Linux 8.0 (jessie)
です。
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
「9 Advanced Options」を選択し、さらに「 A8 Serial Enable/Disable shell and kernel messages on the serial connection 」を選択します。「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」を削除し、リブートします。
Pythonのシリアルモジュールをインストールする
Pythonのシリアルモジュールをインストールします。
pi$ sudo apt-get install python-serial
これで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)
プログラムを動かすと、3秒ごとに次のような結果が出力されました。緯度経度の小数点以下は伏せてあります。
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は「準天頂衛星初号機みちびき」です。