ラズパイにGPSレシーバーを使ったプロジェクトです。使用したGPSレシーバーはUSB接続なのでGPIO端子を使わずに済み、電気系が苦手な人にとってお手軽でした。
Raspberry PiにはRTC(リアルタイムクロック)がないので、そういう意味で一般的なパソコンではないとラズパイダではお伝えしてきました。
通常、ラズパイがインターネットに接続できれば、ネット回線経由で時刻修正するため、ラズパイを起動する度に時刻は修正されます。完全にスタンドアローン(孤立)して使うと、時刻の修正はできないため時計(RTC)が付いていないRaspberry Piでは徐々に時間が狂ってしまいます。
セキュリティ関係や、物理的な問題でネットワークに接続させたくない事例もあるでしょう。特に産業用途などで見受けられます。
GPSレシーバーであれば、別電源の確保も必要無く、ラズパイとの接続もUSBケーブルだけで時刻修正できてしまうと便利ですよね。
今回のテストは屋内でしましたが、窓際に設置すればGPSデータをしっかりと受信できていました。——私の環境では、GPSモジュールを窓から5cmでも離すとデータがN/Aになりました。
終わってみれば、意外と簡単に実現できました。
今回使用したモノ
Raspberry Pi 4にRaspberry Pi OS bullseye(64bit)の環境です。
GPSレシーバーモジュールはGLONASS対応かどうかで、同じメーカーに2種類ありました。
今回使用したデバイス
信号プロトコル:NMEA-0183(通信速度 9600 bps)
感度:-148 dBm(コールドスタート時)
チップ:u-blox UBX-G7020-KTチップセット
コネクター&ケーブル:USB 71JA. 3m
よく見るとチップが違った。今回使用したタイプはGLONASS未対応、Android対応でした。片方はAndroid未対応。
対応衛星の名称
- GPS(米国)
- GLONASS(ロシア)
- BeiDou(中国)
- Galileo(欧州)
- みちびき(日本)
- NAVIC(インド)
今回はGPIOに接続するようなデバイスではなく、USBをサクッと挿すだけのお手軽レシーバーです。だからPPSは使いません。
ドライバは要らない
購入した製品にはWindows用の確認用アプリを入手できるURLが載っていました。
Raspberry PiというかLinuxだと標準でドライバがあります。
接続した後、dmesgコマンドで確認すると、「u-blox 7 - GPS/GNSS Receiver」が「cdc_acm 1-1.2:1.0: ttyACM0: USB ACM device」とUSB ACMデバイスとして認識されています。
ここで使うのは、ttyACM0というポートです。
dmesg
もしくは、マウントされているby-pathを表示してみます。(Raspberry Piだとby-idが無くてby-pathになっている)
ls -l /dev/serial/by-path/
platform-fd500000.pcie-pci-0000:01:00.0-usb-0:1.1:1.0 -> ../../ttyACM0
このようにttyACM0になっていることが分かります。
デバイスポートgps0に変更
ttyACM0を使用して問題ないのですけど、他にも同種のシリアル通信するモノを繋いだ時など、どちらか一見して判断できません。
例えば「gps0」みたいに分かりやすいデバイスポート名にしたいので、少し面倒ですが設定しました。
この段落はすっ飛ばしても構いません。その場合は、これ以降のgps0の部分はttyACM0に置き換えて読んでください。
.rulesの追加
プログラムで使用するにも名前が分かりやすい方が良いです。デバイスポート名を「gps0」としてルールを設定してみます。
Raspberry Pi OSだと、ポートのルール定義ファイル「99-com.rules」があります。そこに書き込まず、新たにルールファイルを新規作成しました。ファイル名は数字の連番にしないとなりませんから、80−としました。
sudo nano /etc/udev/rules.d/80-com.rules
書き込むのは、次のようにベンダーIDとプロダクトIDで指定して設定しました。lsusbか、dmesgで調べた時、「idVendor=1546, idProduct=01a7」とありました。
lsusb
このベンダーIDとプロダクトIDを控えておきます。
これを改行しないで書き込みます。
コマンドであれば対話式で追記できます。もちろんnanoで書き込んでも同じです。
sudo cat << EOS | sudo tee /etc/udev/rules.d/80-com.rules
書き込む内容は次の通りです。
KERNEL=="ttyACM0", ATTRS{idVendor}=="1546", ATTRS{idProduct}=="01a7", SYMLINK+="gps0"
これで起動時にgps0が作られるので、ここで再起動します。
gps0の確認
起動したら確認してみます。
ls -al /dev/gps0
表示がgps0 -> ttyACM0となっていればOKです。
USBにGPSモジュールを挿していれば、既に受信データの確認ができます。
cat /dev/gps0
これで$GPRMC〜
や$GPVTG〜
といったデータが、ターミナルにズラズラっと出てくると思います。
ただこれだと何を表しているのか全く分からない。解析するシフトをインストールしていきます。
gpsdのインストールと設定
GPSのデータは、NMEAフォーマット(NMEA0183)という形式です。この形式データを解析するためのソフトとして、GPS service daemon(gpsd)GPSd — Put your GPS on the net!が有名なのでインストールします。
sudo apt install gpsd gpsd-clients
続いて設定ファイルを修正します。
sudo nano /etc/default/gpsd
デバイス名を先程設定したgps0にし、起動オプションとして、-b -n
としました。これで上手く行きました。
他にも-F /var/run/gpsd.sock -b -n
という書き方もありまして、ちょっと違いがわかりません。-Fで指定しているファイルはデフォルトでは指定していません。どうなんでしょう。
ヘルプで見ると、-bはBluetooth-safeなのであった方がいいと思いました。
-b, --readonly = bluetooth-safe: open data sources read-only -D, --debug integer = set debug level, default 0 -F, --sockfile sockfile = specify control socket location, default none -f, --framing FRAMING = fix device framing to FRAMING (8N1, 8O1, etc.) -G, --listenany = make gpsd listen on INADDR_ANY -l, --drivers = list compiled in drivers, and exit. -n, --nowait = don't wait for client connects to poll GPS -N, --foreground = don't go into background -P, --pidfile pidfile = set file to record process ID -p, --passive = do not reconfigure the receiver automatically -r, --badtime = use GPS time even if no fix -S, --port PORT = set port for daemon, default 2947 -s, --speed SPEED = fix device speed to SPEED, default none -V, --version = emit version and exit.
# Devices gpsd should collect to at boot time.
# They need to be read/writeable, either by user gpsd or the group dialout.
DEVICES="/dev/gps0"
# Other options you want to pass to gpsd
GPSD_OPTIONS="-b -n"
# Automatically hot add/remove USB GPS devices via gpsdctl
USBAUTO=""
gpsdで使えるコマンド
gpsdで5種類の解析できるツールがあります。
- gpsmon -n
- cgps -s
- xgps (文字化けする)
- gpsplot
- gpsprof(gnuplotがないと怒られる)
1と2はSSH経由でもOKで、3と4は図が描画される(別ウィンドウ)のでSSH経由では動作しません。
今回は1と2で時刻や緯度経度を確認しました。他はまたの機会に・・・。
各ツールは終了させるのに、画面上部のプロンプトへそのままquit
またはq
と入力するか、Ctrl + C で終了できます。
gpsmon -n
cgps -s
これらで緯度経度が表示されているのが確認できれば、GPSからデータを取得していることになります。
ヒント
gpsdをシャットダウンしたい場合は、両方のユニットをシャットダウンする必要があります。gpsd.socketが再び起動する可能性があるため、gpsd.serviceをシャットダウンするだけでは不十分です。
これは少しハマりました。socketも指定しましょう。
sudo systemctl stop gpsd.socket gpsd.service
反映されないなら、どこか設定が異なっているかも知れません。再起動してみましょう。
トラブルシューティングのページは一読しておいた方が良かった。
今回使用したデバイス
時刻合わせをさせる
さて、ここからが本題です。
タイトル通り、時刻の修正をするために使ってみます。
今回使用したGPSデバイスモジュールはUSBケーブルが3mと長めですから、なんとか窓まで移動させられました。
先程のGPSデータに時刻が出ていましたよね。UTC時刻です。早速、ラズパイの時刻を修正させてみましょう。
プログラミングしなくてもgpsdとchronyでOK
GPSレシーバーから取得した時刻は、プログラムで読み込ませてシステムの時計を合わせることができます。
Pythonで書こう!と考えたけど、私は非エンジニアでプログラマー経験もありません。多分、書けません。
仕方なく検索してみると、参考になるプログラムもありました。
例えばこちら。
ラズパイの時計をGPSモジュールと同期させる 実装編:名刺サイズの超小型PC「ラズパイ」で遊ぶ(第61回) - ITmedia NEWS
確かにこれでもOKなんですけど、用意したシェルスクリプトをcronで定期的に実行することになります。
上記サイトのプログラミング部分だけ転載すると、シェルスクリプトはこんな感じ。
#!/bin/sh echo start at `/bin/date` GPSDATE="`/usr/bin/gpspipe -w | /usr/bin/head -10 | /bin/grep TPV | /bin/sed -r 's/.*"time":"([^"]*)".*/\1/' | /usr/bin/head -1`" echo $GPSDATE /bin/date -s "$GPSDATE" echo end at `/bin/date`
これでも構いません。しかし、
プログラミングしなくても、gpsdとchrony(またはntpd)を連携すればできることを知りました。
こちらならインストールと設定だけで済みそうです。うん、これがいい。
gpsdは既にインストールしてあるので、残りはchronyだけです。aptにあるntpdと同じntpサーバソフトです。
それに、gpsdの公式ページに”ネットがないスタンドアローン環境ではchronyの方が良い”という記述も見つかり、是非も無しって感じです。
タイムサービスデーモン
ntpdまたはchronyのいずれかをインストールする必要があります。パッケージシステムでUnixバリアントを実行している場合、パッケージはおそらく「ntp」(または「ntpsec」)と「chrony」または「chronyd」という名前になります。ntpdとchronyの間で、ntpdはより古く、より人気のある選択肢です。したがって、異常な状況で助けが必要な場合は、最も確立されたピアコミュニティを持つものです。一方、chronyはセットアップと設定が簡単であるという評判があり、時計が大幅にドリフトするのに十分な期間、マシンをインターネットから切断する必要がある状況では優れています。
ntpdとchronyは異なる哲学を持っており、ntpdは複数のソースからコンセンサス時間を導き出すことに関心があり、chronyは単一の最良のソースを特定し、それを綿密に追跡しようとします。
GPSD Time Service HOWTO
既にgpsdとchronyは連携するようになっています。これは更に好都合です。
Chronyのインストールと設定
早速、chronyをインストールしていきましょう。
先にsystemd-timesyncdを止めて無効にします。Raspberry Pi OSはsystemd-timesyncdで時刻合わせしているからです。
実際にchronyをインストールしようとすると、systemd-timesyncdは必要無く削除されちゃいます。削除しなくても無効化しておけばOKですね。
sudo systemctl stop systemd-timesyncd
sudo systemctl disable systemd-timesyncd
インストールはいつものaptコマンド。
sudo apt install chrony
設定ファイル(conf)の修正と追記
confファイルで設定するのはおよそ5箇所、最低2箇所の修正です。ここがややこしくて難しく感じました。
sudo nano /etc/chrony/chrony.conf
設定した内容はこちら。赤字がコメントアウトした箇所で、黄色が追記した箇所です。
ラズパイだけ時刻合わせをするなら、僅かに2箇所の修正で試せます。
# Use Debian vendor zone.
#pool 2.debian.pool.ntp.org iburst
# SHM(shared memory)から読み取る設定を追加
refclock SHM 0 refid GPS
chrony.confの修正・追記後
# Welcome to the chrony configuration file. See chrony.conf(5) for more
# information about usable directives.
# Include configuration files found in /etc/chrony/conf.d.
confdir /etc/chrony/conf.d
# Use Debian vendor zone.
#pool 2.debian.pool.ntp.org iburst
# Use time sources from DHCP.
sourcedir /run/chrony-dhcp
# Use NTP sources found in /etc/chrony/sources.d.
sourcedir /etc/chrony/sources.d
# This directive specify the location of the file containing ID/key pairs for
# NTP authentication.
keyfile /etc/chrony/chrony.keys
# This directive specify the file into which chronyd will store the rate
# information.
driftfile /var/lib/chrony/chrony.drift
# Save NTS keys and cookies.
ntsdumpdir /var/lib/chrony
# Uncomment the following line to turn logging on.
#log tracking measurements statistics
# Log files location.
logdir /var/log/chrony
# Stop bad estimates upsetting machine clock.
maxupdateskew 100.0
# This directive enables kernel synchronisation (every 11 minutes) of the
# real-time clock. Note that it can’t be used along with the 'rtcfile' directive.
rtcsync
# Step the system clock instead of slewing it if the adjustment is larger than
# one second, but only in the first three clock updates.
#makestep 1 3
leapsecmode slew
maxslewrate 1000
smoothtime 400 0.001024 leaponly
# Get TAI-UTC offset and leap seconds from the system tz database.
# This directive must be commented out when using time sources serving
# leap-smeared time.
leapsectz right/UTC
# SHM(shared memory)から読み取る設定を追加
refclock SHM 0 refid GPS
allow 192.168.0.0/24
local stratum 10
ザックリと解説
makestep 1 3となっている箇所をコメントアウトし、公式ページの推奨である3行を追加しました。leapsecmode slewのslewは閏秒の設定で、長い時間をかけ少しずつ修正していく形式です。stepがデフォルトです。閏秒の修正が不自然?に一気に変わるのを防ぐための設定です。
そのため、デフォルトだったmakestep 1 3
のままでも良いでしょう。
大事な点は2箇所だけ。
- pool 2.debian.pool.ntp.org iburstをコメントアウト
- SHMから読み取る設定(gpsdから取得する)
1は、外部のタイムサーバに接続してしまうとGPSの意味がなくなってしまうので今回はコメントアウトしています。
2は、共有メモリから時刻を読み取る設定です。gpsdと連携してデータを取得させていることになります。
# SHM(shared memory)から読み取る設定を追加
refclock SHM 0 refid GPS
オプションもたくさんあるのですが、色々と試した結果、USB接続のGPSモジュールであれば、シンプルな設定でOKでした。
ヒント
設定の反映はサービスの再起動でOKなのですが、chronydも一緒に指定しましょう。
sudo systemctl restart chrony chronyd
ラズパイを再起動してもOKです。
SHM(shared memory)から読み取る設定について
今回はUSB接続のデバイスということもあり、デフォルト値のままで試しています。
他にrefclock SHM 0 refid GPS precision 1e-1 offset 0.9999 delay 0.2
な書き方があります。
ここの記述は難しいので、公式サイトで確認してください。
シリアル通信がUSB接続なので、GPIO接続のPPTSではありません。オフセットとディレイは無くても構わないと解釈しました。
socket指定は上手くいかなかった
socketを指定するやり方もあるようです。自分では良い結果になりませんでしたね。
refclock SOCK /var/run/chrony.gps0.sock refid GPS precision 1e-1 offset 0.9999
確認してみる
chronycコマンドで確認してみます。
chronyc sources
ここで表示されるID名GPSの左に*印が表示されれば良く、Reachにある数字377なら、すべてのパケットが届いた証拠になります。
ちなみに、-vオプションで詳しい説明が出ます。
加えて、他のPCなどでラズパイのchronyをタイムサーバ(NTPサーバ)に指定した場合、接続しているクライアントが出てきます。
先程のconfファイルにallow行を指定していなければ確認する必要はありません。
sudo chronyc -a clients
トラッキング情報を表示するコマンド。
sudo chronyc tracking
Reference ID : 47505300 (GPS) Stratum : 1 Ref time (UTC) : Thu May 25 03:26:07 2023 System time : 0.000562014 seconds fast of NTP time Last offset : +0.000318895 seconds RMS offset : 0.001042068 seconds Frequency : 16.892 ppm fast Residual freq : +0.494 ppm Skew : 30.426 ppm Root delay : 0.200000003 seconds Root dispersion : 0.101114176 seconds Update interval : 16.0 seconds Leap status : Normal
どうやら、上手くいっているみたいですね。
タイムサーバ先として指定する方法
GPS+ラズパイをタイムサーバ先に指定する設定は、WindowsとMacで次のように指定します。
Windowsの場合
コントロールパネルにある日付と時刻の設定のインターネット時刻タブから、インターネット時刻サーバと同期するサーバを指定できます。
ここにRaspberry Pi のローカルアドレスを入力します。固定IPにしていないならホスト名でも大丈夫です。(例:testpi.localなど)
Macで同期
Macだと設定から一般の日付と時刻の設定にあるタイムサーバで変更します。同じくIPアドレスかホスト名を入れます。
Macの場合、実際に同期させるのはコマンドで行います。
sudo sntp -drsS アドレス
数回送信のうち1回くらい失敗がありましたが、Successとあり、最終的に誤差をアジャストしたと表示されます。refにある取得先がGPS、ラズパイのローカルIPアドレスも表示されています。
常時電源を入れているラズパイにUSBモジュールと仕込んでおけば、ローカルの時刻合わせ先に使えて実用的ですね。
stratunが1になっているのは気になります。わざと10に設定したのですけどね。0(GPS)から受け取るので、1でも間違いではないと思うのですけれど。あれれ?
ラズパイ+モバイルバッテリーでGPSロガー
今回はGPSで受信するデータからUTC時刻だけを利用しました。GPSなのに緯度経度は使っていない!
モバイルバッテリーで数時間動くZero系なら、緯度経度を利用したロガー&トラッカーみたいに使えそうですね。スマホのアプリでも同じようなのがあるかも知れませんがセキュリティやプライバシーが怖い・・・。
自前でどこにも繋がっていないラズパイ+GPSは安心です。
緯度経度の精度は10mくらいズレるかな? 受信する場所にも依るでしょうし、まぁそんなもんかなという印象です。
リーズナブルな価格で楽しめるデバイスの1つだと感じました。皆さんも是非トライしてください。
今回使用したデバイス