秋月電子で販売されているGPS受信モジュールを購入した。
これがなかなか難物でした。
ハードウェア
まず、ピンを見ると次のとおり。
データ入力、データ出力、1PPSがある。
1PPSを知らなかったのですが、1 pulse per secondといい、データが出るらしい。これとシリアル通信は別物。
ところが巷の体験記によると1PPSのほうが正確だとかいう話がある。
さらに気をつけなければいけないのが、この受信機はアンテナがプアなので(アンテナは別売)窓際でしばらく待たないと衛星と同機が取れません。同機が取れるとLEDが点滅します。
1PPSを選んだ理由
さて、以下では1PPSを使うための設定をメモしていきます。
普通のシリアル通信を避ける大きな理由があります。
1PPSを使うパッケージのインプリがgpsdというデーモンを使っています。
これは素晴らしいことで、クライアント側プログラムは問い合わせさえすれば最新の情報が入手できます。
一方、シリアル通信でやるならば自分でマルチスレッドを作ることになります。
どこかで書くつもりですが、PythonはThreadingを避けることが推奨されています。GIL(Global Interpreter Lock)により必ずしもコーダーの意思どおりにマルチスレッドが動かないからです。
せいぜい、asyncioとawaitを使う程度にするべきのようです。
Raspberry PIとの接続
さて、1PPSを使うにしろ配線は以下のように、いい感じでできます。
(以下、図、手順はhttps://denor.jp/さんに頼っています。オリジナルはこちらだそうです)
シリアル通信(UART)のためにTXD0, TXD0としてすでにアサインされているため、これを外す必要があります。
- /boot/cmdline.txtを編集し、
console=serial0,115200
を削除します。おそらくconsole=tty1というのがあると思いますが、それは残します。 - 次にシリアルコンソールを無効化します。
sudo systemctl stop serial-getty@ttyS0.service sudo systemctl disable serial-getty@ttyS0.service
systemctlはサービスをコントロールするコマンドです。
- /boot/config.txtに次の1行を追加します。
enable_uart=1
1PPSの出力を受け取る定義
- /boot/config.txtを編集し、次の1行を追加。
dtoverlay=pps-gpio,gpiopin=18,,assert_falling_edge=true
- /etc/modulesに次の1行を追加します。
pps-gpio
再起動します。
次のコマンドでpps-gpioが読み込まれていることを確認しましょう。
lsmod|grep pps
gpsデーモンと周辺のツールインストール
- gpsdとpps-toolsをインストール
sudo apt install gpsd gpsd-clients pps-tools
- /etc/default/gpsdに以下を書き込みます。
STAERT_DAEMON="true" DEVICES="/dev/ttyS0 /dev/pps0" GPSD_OPTIONS="-n"
オプションの-nはポーリングしないということらしいです?
- systemdの設定を変更し、gpsd.socketを有効にします。
sudo systemctl enable gpsd.socket
再起動しすると、/dev/ttyS0と/dev/pps0をターゲットデバイスとしてgpsdが起動します。(dmesgを確認)
GPS信号の受信
GPSモジュールは点滅していますか?
次のコマンドで一秒おきにデータが出力されます。
sudo ppstest /dev/pps0
gpsmonを起動してみます。フルスクリーンで出ます。
gpsdのAPI
gps3をpythonに追加します。
pip3 install gps3
a
from gps3 import gps3
gps_socket = gps3.GPSDSocket()
data_stream = gps3.DataStream()
gps_socket.connect()
gps_socket.watch()
for new_data in gps_socket:
if new_data:
data_stream.unpack(new_data)
print('time : ', data_stream.TPV['time'])
print('lat : ', data_stream.TPV['lat'])
print('lon : ', data_stream.TPV['lon'])
print('alt : ', data_stream.TPV['alt'])