ABEJA Tech Blog

中の人の興味のある情報を発信していきます

GPSで高精度なNTPサーバーを作ってみた ~ミスってMTG遅刻常習犯にもなった話~

はじめに

こんにちは。ABEJA大田黒です。これはABEJAアドベントカレンダー2022の6日目の記事です!凄く唐突ですが....タイムマネジメントは社会人の基本!そしてタイムマネジメントを支えるPCの時計は精度をよくしたいですよね?!という事で、今回はGPS衛星 + RaspberryPiを使ったNTPサーバー (Stratum1)を構築方法について紹介します。

NTPとは?

ネットワークを使って時刻合わせをする有名な仕組みとしてNTP(Network Time Protocol)があります。電波時計のネットワーク版といったところでしょうか。NTPでは、図1のような時間源の階層構造を持ちます。それぞれの層は「Stratum N」と表現され、最上位の基準クロックは「Stratum 0」、そこの同期しているサーバーをStratum 1、Stratum1に同期しているサーバーをStratum 2...といった具合に、階層的に時刻同期をする仕組みを持ちます。一般的にStratum0は、原子時計などの高精度な計時装置となります。

Fig1 Stratum構造

今回Stratum1構築にあたり、同期先のStratum0が必要となります。今回はStratum0として、GPS衛星の内部の原子時計を利用します。 実はGPS衛星には、セシウム原子時計およびルビジウム原子時計が搭載されています。 これらの誤差は、30万年に1秒以下とも言われていています。そんなハイテクなモノがはるか上空に浮かんでいると思うと、テンションが上がりますね!

今回作るもの・レシピ

Fig2 作るものの構成

今回は、写真のような構成を作ります。レシピは意外と簡単です。最近、GPSモジュールが安く買えるようになってきています。参考までに私は秋月電子などで調達をしました。

  • RaspberryPi
  • GPSモジュール
    • GPSモジュール本体
    • GPSアンテナ

akizukidenshi.com

構築手順 (HW)

今回は、下記のような構成でハードウェアを構築します。GPSアンテナ、GPSモジュール、RaspberryPiが主な主役です。

Fig3 装置全体感

このGPSモジュールはGPS衛星からのL1電波からの情報を「時刻や位置を含む情報」に変換し、NMEA形式で送信します。それをUART経由で受け取る事により、衛星の時刻情報などを得ます。また複数の衛星を補足しており、三次元測定モードになっている場合は超高精度な1秒のパルス信号を供給してくれます。このパルス信号(1PPS信号)をGPIOで受け取る事で、RaspberryPi内部での正確な1秒のカウントを可能にします。GPSモジュールには1PPS信号ラインにLEDがついており、下記のように信号を確認することができます。初回起動時は衛星補足するのに時間がかかるので、信号がでるまで1~2分かかりました。(私の場合、締め切った室内ではダメで、ベランダに出ないとだめでした。電波強度の問題だと思われます。)

  • 接続参考情報
    • GPSモジュール側UART TxD ⇔ RaspberryPi上のUART RxD
    • GPSモジュール側UART RxD ⇔ RaspberryPi上のUART TxD
    • GPSモジュール側の1PPS出力⇔RaspberryPi上のGPIO18

構築手順 (SW)

今回は、内部的には下記のようなソフトウェア構成でGPSモジュールのデータ受信~NTPサーバー機能を提供します。今回、HW的に接続された1PPS信号をLinux上でデバイスファイルとして扱えるようにするために、PPS GPIO Kernel Driverというものを使います。

Fig4 ソフトウェア内部の全体感

シリアルポート・カーネル関連設定

  • コンソールの無効化
pi@raspberrypi:~ $ sudo vim /boot/cmdline.txt
console=tty1 root=PARTUUID=XXXXXX rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait quiet splash plymouth.ignore-serial-consoles
pi@raspberrypi:~ $ sudo systemctl stop serial-getty@ttyS0.service
pi@raspberrypi:~ $ sudo systemctl disable serial-getty@ttyS0.service
  • UARTとタイムパルスを有効化
pi@raspberrypi:~ $ sudo vim/boot/config.txt
enable_uart=1
dtoverlay=pps-gpio,gpiopin=18,assert_falling_edge=true
  • カーネルモジュール pps-gpio を有効化
pi@raspberrypi:~ $ sudo vim /etc/modules
i2c-dev
pps-gpio

gpsdのインストールと設定

  • 必要ファイルをapt経由でインストール
pi@raspberrypi:~ $ sudo apt install gpsd gpsd-clients pps-tools
  • gpdsに必要な設定を実施
pi@raspberrypi:~ $ sudo vim /etc/default/gpsd
# Default settings for the gpsd init script and the hotplug wrapper.
# Start the gpsd daemon automatically at boot time
START_DAEMON="true"
# Use USB hotplugging to add new USB devices automatically to the daemon
USBAUTO="true"
# Devices gpsd should collect to at boot time.
# They need to be read/writeable, either by user gpsd or the group dialout.
DEVICES="/dev/ttyS0 /dev/pps0"
# Other options you want to pass to gpsd
GPSD_OPTIONS="-n"
  • gpsdのサービス自動起動を有効化し再起動
pi@raspberrypi:~ $ sudo systemctl enable gpsd.socket
pi@raspberrypi:~ $ reboot

ntpのインストールと設定

再びaptでサクッといれます。よくある設定では、上位Stratumサーバーのドメイン名やIPアドレスを指定する事が多いですが、今回は手元にGPS衛星からの時刻情報と高精度な1PPS信号が来ているので、そこに同期するように設定をします。下記は設定例です。

pi@raspberrypi:~ $ sudo apt install ntp
pi@raspberrypi:~ $ sudo vim /etc/ntp.conf
# 比較用のNTPサーバー群
server ntp.nict.jp iburst
server ntp1.jst.mfeed.ad.jp iburst
server time.google.com iburst
# GPS信号を利用する設定
server 127.127.28.2 minpoll 4 maxpoll 4  prefer
fudge 127.127.28.2 time1 0.000 refid GPS
# PPS信号を利用する設定
server 127.127.22.0 minpoll 4 maxpoll 4
fudge 127.127.22.0 refid PPS
# LAN内からのアクセスを許可
restrict 192.168.123.0 mask 255.255.255.0 notrust

127.127.28.2はgpsd内部のSharedMemoryを指す特殊アドレス

127.127.22.0は、PPS信号が取れる /dev/pps0を指す特殊アドレス

動作確認

PPS信号の取り込み

カーネルモジュールが正しく動作していると、GPSモジュールからの1PPS信号をデバイスファイル経由で取り込む事ができます。一秒おきにメッセージが流れ続けるはずです。

Fig5 PPS信号取り込みテストの様子

家庭内PCと同期テスト

Windowsだと時計機能から下記のようにNTPサーバーが設定可能です。

Fig6 NTP同期設定

性能評価(結果)

Fig7 Offset, Jitter評価の様子

こちらはntpqのステータス画面です。上位Stratumサーバーとの時刻同期状況やその他時刻源との同期状況を表示したものです。 軌道上のGPS衛星の原子時計とのズレ(Offset)は数十nsecオーダー。安定性(Jitter)は数nsecオーダー。このレベル感であれば、リモートMTGにもばっちりの時間でJOINする事ができるんじゃないでしょうか。これはわくわくが止まりませんね!これで、私が住んでいる千葉県内で5番目ぐらいに時刻精度のいいPCになったんじゃないでしょうか。ご家庭に原子時計をお持ちの人がいたら確実に負けるなーと思いつつ、構築当時はルンルン気分で浮かれてました。(後日談で事件が起きます)

後日談

NTPサーバーを構築して運用してから数か月が経過した頃。事件が起きます。なぜかリモートMTGの時間になると毎回SlackでDMが飛んでくるようになりました。どうやらRaspberryPiの電源が切れていて長い間正しく時刻同期ができず、PCの時計がずれていたようです。気づかないうちにリモートMTGに2~3分遅れる遅刻常習犯になっていました。ABEJAの皆様にご迷惑をおかけしてしまいました。

その後、皆様に謝罪をし、通常のNTPサーバーに同期先を戻し、普段通りの時刻精度のPCになったのでありました。おしまい!

採用メッセージ


株式会社ABEJAでは共に働く仲間を募集しています! 技術が好きなエンジニアの方!ぜひこちらの採用ページからエントリーください。

careers.abejainc.com