新しい中華GPSモジュールとChronyで作るNTPサーバ (中編)

前編では怪しい中華GPSモジュールを買っちゃったこととArmbian最新ソースからビルドしたPPS対応イメージについて書いた。一応今回が本題の内容になる。

構成

NMEA → gpsd → Chrony
1PPS → Chrony

Armbian(Debian, Ubuntu)の新しいバージョンではChronyは最初からシステムに入っている。オプション等を指定して自分でビルドする必要もなしでそのまま使える。

Chronyはネットワーク上の時刻ソースからの同期はとても簡単だが、ntpdと違ってNMEAなどのリファレンスクロックドライバは揃っていないようで、gpsd等の補助を必要とするみたい。gpsd以外で小型で単体のNMEA用ドライバのようなものが無いかと思ってググったけど見つけられなかった。
1PPSはChronyだけでもいけるっぽい。ググったところ、他の人はNMEAと1PPSの両方をgpsdに読ませて、Chronyではその2つをgpsdから貰うような設定が多いようだが、「がとらぼ」ではNMEAだけをgpsdに読ませてChronyに渡し、1PPSは直接Chronyに読ませることにする。どちらが精度が高いのかは不明。
ntpdではNMEAも1PPSもntpdで直接読める(それでもgpsdでNMEAを読ませる設定にしてる人が多い)ので「がとらぼ」で1PPSを使ったNTPサーバではgpsdなしで両方ntpdに読ませる設定でやっていた。余計なものは極力使いたくないのでgpsdはなしにしたいところだが、現在のChronyではできないっぽい(知らないだけ?)ので気に入らないが諦めてgpsdを使うことにする。

gpsdの設定

gpsdはArmbianのシステムには入っていないが、パッケージは用意されているのでそれを使うことにする。
$ sudo apt update                       #パッケージ情報を最新に更新
$ sudo apt install gpsd gpsd-clients    #パッケージインストール

gpsd-clientsは衛星の捕捉状況を表示したい等gpsd-clientsに入っているツールをどうしても使いたいということでなければ特には不要。

この記事では接続したGPSモジュールのシリアルポートが/dev/ttyS1とする。
シリアルポート名は使っているPC, シングルボードコンピュータ, OSで違うので実際にNMEAを受信できているポートを指定する。/devにあるttyで始まるデバイスで sudo cat /dev/ttyS0 などでNMEAセンテンスがズラズラ表示され続けるポートを見つければ良い。(Linuxのシリアルポート名にはttyS*みたいに大文字のSが付くみたい)

設定ファイルはArmbianのパッケージでインストールすると /etc/default/gpsd になるよう。この設定ファイルのpathは/lib/systemd/system/gpsd.serviceで指定されているので気に入らなければ変更。(要サービスの再有効可)

/etc/default/gpsd
1
2
3
4
5
START_DAEMON="true"
USBAUTO="false"
DEVICES="/dev/ttyS1"
GPS_BAUD=115200
GPSD_OPTIONS="-n"

この内、4行目は要注意。次回の記事で予定のGPSモジュールの設定変更を実施しなければ多くの安価なGPSモジュールは初期値が4800/9600bps程度なので115200bpsを指定するとおそらく通信できなくなる(gpsd側が通信できないだけでGPSモジュールやPC/シングルボードコンピュータが壊れるわけではない)。GPSモジュールの通信速度の初期値を指定するか4行目自体を無しにする方が良い。

1PPSをgpsdで受けたいのであれば2行目は DEVICES="/dev/ttyS1 /dev/pps0" のような指定になる。

gpsdサービスを起動する。
$ sudo systemctl enable gpsd.socket  (有効化されていなければ実行,おそらく不要)
$ sudo systemctl enable gpsd.service  (次が実行できなければ実行,おそらく不要)
$ sudo systemctl start gpsd.service
gpsdサービスを動かすにはgpsd.serviceとgpsd.socketの2つが要る。メインのサービスはgpsd.serviceだが元から起動・停止したいならgpsd.socket。 すでにサービスが動いているなら「start」の代わりに「restart」。
gpsdの起動ステータスを確認する。
$ sudo systemctl status gpsd.socket
● gpsd.socket - GPS (Global Positioning System) Daemon Sockets
   Loaded: loaded (/lib/systemd/system/gpsd.socket; enabled; vendor preset: enabled)
   Active: active (running) since Thu 2020-07-09 19:29:38 JST; 15h ago
   Listen: /var/run/gpsd.sock (Stream)
           [::1]:2947 (Stream)
           127.0.0.1:2947 (Stream)
    Tasks: 0 (limit: 851)
   Memory: 44.0K
   CGroup: /system.slice/gpsd.socket

Warning: Journal has been rotated since unit was started.

これはgpsd.serviceではダメでgpsd.socketを指定する。問題が発生していればこの後にエラー等が表示される筈。

gpsdでのGPS衛星の補足情報を確認したいならgpsmoncgps -sを使う。(要gpsd-clientsパッケージ)。まぁ、見る必要は無いんだけど。

Chronyの設定

最新のArmbian (Debian, Ubuntu)ではChronyはシステムに入っているし逆にntpdは入っていないのでChronyを設定するだけ。他のディストリビューションや古いArmbian(Debian, Ubuntu)では標準がntpdが動いていてChronyが入っていないのでChronyをインストールしてntpdを停める(アンインストールする)必要があるかもしれない。Chronyとntpdはコンフリクトするので同時使用はできない。

Chronyサービスの制御ファイルは/lib/system/system/chrony.serviceだが、/etc/systemd/system/chronyd.serviceからシンボリックリンクになっているのでサービス名としてはchrony.serviceとchronyd.serviceの2つがあることになる。実体は1つ。ややこしいのでこういうのはやめて欲しい。

Chronyの設定ファイルはパッケージでインストールすると /etc/chrony/chrony.conf になる。

/etc/chrony/chrony.conf (設定例)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
server ntp1.v6.mfeed.ad.jp prefer
server ntp2.v6.mfeed.ad.jp
server ntp3.v6.mfeed.ad.jp

keyfile /etc/chrony/chrony.keys
driftfile /var/lib/chrony/chrony.drift
logdir /var/log/chrony
log measurements statistics tracking refclocks
local stratum 1

allow 192.168.0.0/24

initstepslew 15 ntp1.v6.mfeed.ad.jp ntp2.v6.mfeed.ad.jp
maxupdateskew 100.0
rtcsync
makestep 1 3

#NMEA
refclock SHM 0 refid NMEA

#PPS
refclock PPS /dev/pps0  refid PPS trust

こんな感じ。ntpdと似た感じな設定に見えるが、ntpd用そのままではダメなのでドキュメントを参照しながらの設定になる筈。
このNTPサーバへの参照許可は192.168.0.0/24にしている。NMEA/PPSのoffset, delayの設定は入れていない。個体差があるので普通は暫く動かして統計情報を録った上で必要に応じて変更することになる筈。

設定行の後にコメントをつけるとChronyがエラーで起動しない。この書き方はntpdではエラーにならないので最初chronyが起動しない理由が判らなかった。

#これは問題ない
#comment
blah blah

#こんな書き方はエラーになる
blah blah   #comment
chronyは設定ファイルで指定した入出力ファイルが存在しないとエラーになるっぽい。(停まりはしない)
/var/lib/chrony/chrony.drift.tmp
/var/log/chrony/measurements.log
/var/log/chrony/statistics.log
/var/log/chrony/tracking.log
この辺りのファイルは存在とパーミッションを確認。

何のファイルを入出力するかは利用者それぞれだと思うけどdriftファイル辺りは設定する人が多いと思うのでファイルを作成してchronyが読み書きできるパーミッションに設定する。
最初、driftファイルと統計用に出力設定したファイルを用意し忘れてchronyのサービスを再起動するとNMEA, PPSの値が入らないなど何か変な挙動を示して意味がわからなかったけど、これが原因だった。chronyは標準で入ってるのでdriftファイルはあるものだと思い込んでたし統計用ファイルは設定で指定すれば自動的に作成されるものだと思いこんでいた。

$ sudo systemctl status chrony
● chrony.service - chrony, an NTP client/server
   Loaded: loaded (/lib/systemd/system/chrony.service; enabled; vendor preset: enabled)
   Active: active (running) since Thu 2020-07-09 19:31:13 JST; 3h 41min ago
     Docs: man:chronyd(8)
           man:chronyc(1)
           man:chrony.conf(5)
  Process: 1307 ExecStartPre=/bin/mkdir /tmp/chrony (code=exited, status=0/SUCCESS)
  Process: 1308 ExecStartPre=/bin/chown _chrony:_chrony /tmp/chrony (code=exited, status=0/SUCCESS)
  Process: 1309 ExecStartPre=/bin/chmod 600 /tmp/chrony (code=exited, status=0/SUCCESS)
  Process: 1310 ExecStart=/usr/sbin/chronyd $DAEMON_OPTS (code=exited, status=0/SUCCESS)
  Process: 1319 ExecStartPost=/usr/lib/chrony/chrony-helper update-daemon (code=exited, status=0/SUCCESS)
 Main PID: 1312 (chronyd)
    Tasks: 2 (limit: 851)
   Memory: 1.2M
   CGroup: /system.slice/chrony.service
           ├─1312 /usr/sbin/chronyd -F -1
           └─1313 /usr/sbin/chronyd -F -1

Jul 09 19:31:07 hoge chronyd[1312]: Loaded seccomp filter
Jul 09 19:31:11 hoge chronyd[1312]: Could not open log file /var/log/chrony/statistics.log
Jul 09 19:31:11 hoge chronyd[1312]: System's initial offset : 0.001967 seconds fast of true (slew)
Jul 09 19:31:13 hoge systemd[1]: Started chrony, an NTP client/server.
Jul 09 19:32:00 hoge chronyd[1312]: Selected source PPS
Jul 09 20:32:04 hoge chronyd[1312]: Could not open temporary driftfile /var/lib/chrony/chrony.drift.tmp for writing

chronyのサービスを起動してステータスを確認し、ファイルが開けないというエラーが発生していないことを確認する。上の例では黄字が指定されたファイルが開けないことを示している。

1
2
3
4
5
6
7
8
9
/var/log.hdd/chrony/*.log {
    compress
    missingok
    nocreate
    sharedscripts
    postrotate
        /usr/bin/chronyc cyclelogs > /dev/null 2>&1 || true
    endscript
}

Chronyのログローテーションの設定は自動で入っているが、そのログ用ディレクトリの想定が /var/log.hdd/chrony になっている。この記事では /var/log/chrony にログを置くことを想定しているので1行目の黄色字の「.hdd」部分を削除する。

$ sudo logrotate -dv /etc/logrotate.conf
$ service logrotate restart

1行目を実行してエラーが発生しないことを確認。意外とディレクトリのパーミッション等でエラーが出るので必要に応じて修正。
エラーが無いか修正したら2行目でログローテートのサービスを再起動。

ChronyのNTPサーバとしての稼働状況の確認

chronyc sources 時刻ソース別の状態 -vを付けると簡易説明付きになる -nを付けるとIPアドレスで表示
chronyc sourcestats 時刻ソース別の状況 -vを付けると簡易説明付きになる
chronyc activity 時刻ソースの種類別の状態
sudo chronyc clients このNTPサーバを参照しているホストの参照状況
sudo chronyc serverstats パケットやコマンドの送受信状況
chronyc -a 対話式で状態表示や一時的な設定変更を行う

chronycはいろいろできるけどよく使いそうな確認用の5種と対話式の1つを例として挙げた。この5つの内、clientsとserverstatsを表示するには権限が必要。ntpq -pの代わりのようにchronyc sourcesを使うことが多いかな。(ちょっと違うんだけど)

次回はGPSモジュールの設定を行う。調整はその後かな。

関連記事:

新しい中華GPSモジュールとChronyで作るNTPサーバ (前編)

前回(といっても既に3年以上前だけど)、NanoPi NEO用に購入したGPSモジュールだが、1PPSは正常そうに見えるがNMEAの取得タイミングが最初からなんかずっとヘン。グラフにするとノコギリの刃のようなギザギザ三角波が描かれる。他にあるGPSモジュールで取得したNMEAのグラフとは明らかに違うし、他の人がネットに上げている情報でもこんなグラフ見たことがない。とはいえ、遥かに精度の高い1PPSを録っているのだからNMEAのタイミングが少々ヘンでも全く問題はないということで放置してたけどやっぱり時々気になるのよね。

新しいGPSモジュールとChronyでNTPサーバ 1
問題のGPSモジュールを使っているNTPサーバのNMEAのoffsetのグラフ。謎の規則性があるんだけど何を示しているのかわからないノコギリの刃のようなグラフ。上下の振れ幅も約30msと大きめ。

新しいGPSモジュールとChronyでNTPサーバ 2
別のNTPサーバのNMEAのoffsetのグラフ。上下の振れ幅が10ms程度で変な規則性もなくこちらは正常。

新しいGPSモジュールとChronyでNTPサーバ 3
で、購入したのがubloxのNEO-M8Nを搭載したGPSモジュール。これはTCXOなので温度変化に強いやつ。
画像では商品価格が975円で送料が343円になってるけど、セール中に購入したので694円で送料が340円だった。NEO-M8Nなら破格の安さと思った。

新しいGPSモジュールとChronyでNTPサーバ 4
届いた商品。下にあるのは大きさ比較用のmicroSDカード。
ん?!なんか違う・・・

新しいGPSモジュールとChronyでNTPサーバ 5
そもそもGPSレシーバのチップメーカーがubloxではなく中科華微電子(杭州中科微电子有限公司?)。そしてチップの型番はATGM332D。チップに偽ラベルを貼るでもなく堂々とパチもん送ってきやがった。さすが中華。
ただ、このATGM332D、ICはAT6558-5N-31というやつでデータシートによるとそんなには悪くないらしい。5N-3XはGPSと北斗対応バージョン。TCXOみたいだし、ubloxのUBXバイナリコマンドも使えるようだし。ubloxのチップをそのまま置き換えられるというのはそういうことなのねという感じ。
なので今回はこの中華GPSモジュールを使ってみようと思う。

スペックで比較するとubloxのNEO-M8NのGPSのTracking sensitivity: -167 dBmに対してAT6558は -162 dBm。
ウォームスタート(ホットスタート)が、NEO-M8NとAT6558がともに1秒。コールドスタートはNEO-M8Nは26秒に対してAT6558が32秒。 性能に差がないわけじゃないので念の為。

新しいGPSモジュールとChronyでNTPサーバ 6
基板の裏。外部アンテナ接続用のSMA(左上)、同じくIPEX(左下)がある。オンボードのアンテナは無い。というかオンボードアンテナ無しを敢えて購入。NMEAがおかしいGPSモジュールはオンボードアンテナがあってジャンパスイッチ等でそのアンテナを切るというのができないのを異常の原因として疑ったので。
中央下に見えてる丸いのはボタン電池。これがあると電源を入れ直したときなどにウォームスタートが効いて衛星の捕捉開始までの時間が圧倒的に速い。電池が付く付かないでおそらく値段は変わらないと思うので電池が付くタイプの方が個人的には良いと思う。

新しいGPSモジュールとChronyでNTPサーバ 7
手前にある小さい基板が今回購入したもの。奥側が前回購入したublox NEO6のGPSモジュール。大きさがだいぶ違う。

新しいGPSモジュールとChronyでNTPサーバ 8
左側が新しく購入したGPSモジュール。右側が古い方。その中央に見えてる汚い白い四角いのはオンボードアンテナ。
赤枠で囲ったところが今回購入したポイントの1つ。ピンの並びとピッチが全く同じなので旧基板から5ピンまるごとごっそり抜いてそのまま新しい方に挿すだけ。簡単。

外部アンテナのSMA端子も差し替えたら交換完了。

しばらくArmbianのビルドをサボってたけど久しぶりにPPS対応カーネルで作ってみた。カーネルオプションは以前の記事を参照。なお、Timer frequencyはこれまで1000Hzで作っていたが、NanoPiNEOだと荷が重いかなと思ったので初期値の250Hzにした。これで調子が悪いようなら作り直す予定。イメージはminimalにしている。

置き場所(Google Drive)
Armbian_20.08.0-trunk_Nanopineo_buster_current_5.4.50_minimal.7z

NanoPi NEO用のArmbianは暫く初期起動で有線Networkが無効という嫌がらせ状態になっていたが、今回のビルドではDHCPのあるLANに接続すれば自動的にネットワークが使えるようになっていた。また、NanoPi NEOの電源用のmicroUSBのケーブルをACアダプタではなくPCに接続すればそのPCからUSBシリアル経由で通信できるのは以前と同じ。DHCPから静的な設定に変えるとき(しかも違うネットワーク用に変えるとき)にarmbian-configを使うと結構ウンコなのでトラブることがあるが、USBシリアル経由なら簡単確実かも。個人的にはarmbian-configなんて使わないで/etc/network/interfaces, /etc/resolv.conf, /etc/hostname の3ファイル直編集がオススメだけど。(特にネットワーク替えの場合)

1PPSを使う場合は/boot/ArmbianEnv.txtの編集をお忘れなく。変更の仕方は以前の記事と同じ。

で、Debianの新しいバージョンでは標準搭載のNTPサーバがntpdではなくChronyになっている。Chronyが流行りのようなので逆らわずにChronyでやることにした。比較的簡単だし。

と、いうことで、次回は中編としてChronyの設定、さらに次々回は後編としてGPSモジュールの操作を予定している。

関連記事:
Up