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を検索すると、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)

プログラムを動かすと、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は「準天頂衛星初号機みちびき」です。