RaspberyPiとGPSユニットを使って、Stratum 1なナノ秒単位で調整できるNTPサーバを作ってみた。
情報は色々とネットに落ちているけど、できるだけ簡素な工作で、簡易的な構築で、長期的な運用ができると思われる方法で作ってみる方針。
Table of Contents
材料
- Raspberry Pi 4B
- それと運用に必要なACケーブルやらケースやらmicroSDHCカードやら。
- GPSユニット YIC GT-902PMGG
- https://akizukidenshi.com/catalog/g/gM-12905/
- アンテナ一体型でCOM(UART)出力とPPS出力があるGPSユニット。PPS出力とは”Pulse Per Second”、1秒ごとに信号が出力される端子のこと。この信号を拾ってナノ秒単位で時刻を調整する。
- ケーブルの先端は端子加工されていない仕様だったのでハンダ付けが必要。
赤=Vcc 橙=Tx 緑=Rx 茶=PPS 黒=GND。駆動電圧はVccは3V、Rx,Txは3.3V、ラズパイにちょうど良い。 - シリアル通信のボーレートはデフォルトで9600bps。これを115200bpsあたりに上げないと、衛星を大量に捕捉しすぎたときにデータ転送が追いつかなくなってgpsdがバグる仕様あり。
- ケーブルが1.5mしかないので、屋外まで引っ張る場合は5線以上のケーブルをハンダ付けして延長しても良い(精度はともかく)。
- ついでにラズパイのピンヘッダをケース外まで延長して、ケース外で接続できるように実装する方が便利。
- コネクタ付ケーブル 20cm 40P オスオス
- https://akizukidenshi.com/catalog/g/gC-15869/
5本を半分に切ってGPSユニットの配線をオスピンに作り替える用。
- https://akizukidenshi.com/catalog/g/gC-15869/
- コネクタ付ケーブル 20cm 40P メスメス
- https://akizukidenshi.com/catalog/g/gC-15868/
- 5本をラズパイのGPIOからケース外に出す用。
- FTDI USBシリアル変換ケーブル (3.3V)
- https://akizukidenshi.com/catalog/g/gM-05840/
- ピンソケットタイプのシリアルケーブル。
- PCからGPSユニットを設定するために必要。
- ドライバ https://ftdichip.com/drivers/ (Windows10なら不要)
- u-center (GNSS evaluation software for Windows)
- https://www.u-blox.com/en/product/u-center
- GPSユニット設定・確認ツール。u-center2ではなく、M8チップ対応のu-center。
準備
Raspberry Pi側のGPIOピンヘッダと、GPSユニットの結線
RaspberryPi 4BとGPSユニット YIC GT-902PMGGの場合
- 1または17ピン(3.3V) – 赤(Vcc)
- 8ピン(UART_TX) – 緑(Rx)
- 10ピン(UART_RX) – 橙(Tx)
- 12ピン(GPIO18) – 茶(PPS)
- 14ピン(GND) – 黒(GND)
参考: https://deviceplus.jp/raspberrypi/raspberrypi-gpio/ (ページ途中にRaspberryPi 4BのGPIOピンヘッダ配置図がある)
RaspberryPiのピンヘッダ引き出し
GPSユニットにメスピンケーブルを直接ハンダ付けしても良いが、メンテナンスのためにケース外で接続できた方が便利なので。

GPSユニットの配線加工
GPSユニットと、オスピンコネクタケーブルをハンダ付けして、RaspberryPiから引き出したメスピンケーブルに接続できるようにしておく。

GPSユニットの設定変更
シリアル通信のボーレートを9600bpsから115200bpsあたりに上げないと、衛星を大量に捕捉しすぎたときにCOMポートの通信が追いつかなくなってgpsdがバグる。
コレの仕様のせいで、起動直後は動作するのに1日ほどでバグってしまい、3日ほど悩んだ。
- FTDI USBシリアル変換ケーブルでPCのCOMポートに接続
- この時点ではまだボーレートは9600bpsのまま。
- u-centerで接続
- Receiver→Connection→COMn(PCに認識されているCOMポート)
- モニタ画面に衛星や地図のプロットが動き出す
- ボーレートの設定変更
- View→Messages View
- 左ペインで UBX→CFG→PRT
- Poll
- 右ペインで Target: 1 – UART1, Baudrate: 115200
- Send
- ボーレートを変えて接続
- Receiver→Connection→Disconnect
- Receiver→Baudrate→115200
- Receiver→Connection→COMn
- モニタが動き出すか確認
- BBR(不揮発性メモリ)に書き込み
- View→Messages View
- 左ペインで UBX→CFG→CFG
- 右ペインで Save current Configuration
- Send
Raspberry Pi OS
今回はRaspberry Pi 4Bを使用した。
Raspberry Pi OS Lite 64bitを、SSH有効にしてmicroSDに書き込み。
構築
Raspberry Pi OSの設定
PCからTeraTermProでSSH接続して設定。
なお、お好みによってご自由に。
# Raspberry Piのファームウェアアップデート
sudo rpi-eeprom-update# Raspberry Pi OSのパッケージソフトウェアアップデート
sudo apt update
sudo apt -y dist-upgrade
sudo apt -y autoremove
sudo apt autoclean# スワップファイルの無効化
sudo dphys-swapfile swapoff
sudo apt remove dphys-swapfile
sudo apt autoremove# Raspberry PiとOSの設定
sudo raspi-config
- System Options → Boot / Auto Login → Console
- Display Options → Screen Blanking → No
- Interface Options → Serial Port → No → Yes
- Localisation Options → Timezone → Asia → Tokyo
- Localisation Options → Keyboard → Generic 105-key (Intl) PC → Other → Japanese → Japanese → The default for the keyboard layout → No compose key
#VIMのキーバインド設定
vi .vimrc
set nocompatible set backspace=indent,eol,start
# rootユーザー用VIMキーバインド(.vimrcと同じ内容)
sudo vi /root/.vimrc
set nocompatible set backspace=indent,eol,start
# IPV6無効化
sudo vi /etc/sysctl.conf
net.ipv6.conf.all.disable_ipv6 = 1 net.ipv6.conf.default.disable_ipv6 = 1
# ネットワーク設定の変更(IPアドレスの設定が必要な場合)
sudo vi /etc/dhcpcd.conf
interface eth0 static ip_address=192.168.0.10/24 statoc routers=192.168.0.1 static domain_name_servers=192.168.0.2 192.168.1.2
# SSHの設定
sudo vi /etc/ssh/sshd_config
PermitRootLogin no
# DNS関係ツール(digやtracerouteなど)
sudo apt install dnsutils
gpsd
gpsdがGPSユニットとシリアル通信を行い、PPS(秒信号基準の補正)やSHM(タイムコード基準の補正)ポートを作ってくれる。
参考
- https://nllllll.com/other/raspberrypi-gpsmodule-ntpserver/
- https://mirahouse.jp/n10/blog/2019/raspberry-pi-gps-ntp/
sudo vi /boot/cmdline.txt
#console=tty1 console=serial0,115200 root=PARTUUID=478e1abe-02 rootfstype=ext4 fsck.repair=yes rootwait console=tty1 root=PARTUUID=478e1abe-02 rootfstype=ext4 fsck.repair=yes rootwait
- ちなみにcmdline.txtのオプションにipv6.disable=1を入れるとIPv6を完全に殺すことができるが、なぜかchronyがバグるので入れていない。
sudo vi /boot/config.txt
#dtoverlay=vc4-kms-v3d #max_framebuffers=2 [all] dtoverlay=pps-gpio,gpiopin=18,assert_falling_edge=true dtoverlay=disable-bt enable_uart=1 core_freq=250
- core_freq指定しなくても動いているけどとりあえず設定しておいた。
# gpsdインストール
sudo apt install gpsd gpsd-clients pps-tools
# GPIOでPPSを受けるモジュールを組み込み
sudo vi /etc/modules
pps-gpio
# 諸々の設定反映のため再起動
sudo reboot
このあたりでGPSユニットを接続しておくと良い。
# gpsdの設定
sudo vi /etc/default/gpsd
#DEVICES="" DEVICES="/dev/ttyAMA0 /dev/pps0" # Other options you want to pass to gpsd #GPSD_OPTIONS="" GPSD_OPTIONS="-n -s 115200" # Automatically hot add/remove USB GPS devices via gpsdctl #USBAUTO="true" USBAUTO="false" START_DAEMON="true"
- raspi4はBluetoothを使用しないとttyS0ではなくttyAMA0になるみたい。
- GPSD_OPTIONSのsオプションでシリアル通信のボーレートを 115200bpsに変更している。
stty -F /dev/ttyAMA0 115200 でボーレートを設定してもgpsdが9600に戻してしまうため。
sudo vi /lib/systemd/system/gpsd.socket
#ListenStream=[::1]:2947 SocketMode=0600 #SocketMode=0666 #BindIPv6Only=yes
- SocketModeは666に設定した方が良いとの情報があったが、設定せずに動いているのでそのままにしている。
# gpsdの自動起動と起動
sudo systemctl daemon-reload
sudo systemctl enable gpsd
sudo systemctl start gpsd
sudo systemctl enable gpsd.socket
sudo systemctl start gpsd.socketsudo ppstest /dev/pps0
sudo gpsmon -n
NTPサーバ(chrony)
Raspberry Piにデフォルトでインストールされているsystemd-timesyncdはクライアント機能しか無いので、chronyに置き換える。
ちなみにRaspberryPiには内部保持時計がなく、毎回起動時に外部から時刻を取得しないといけない。
chronyがgpsdのPPSやSHMポートを参照して時刻補正を行ってくれる。
なお、chronyをインストールすると自動的にsystemd-timesyncdはアンインストールされる。
# NTPクライアントを停止
sudo systemctl disable systemd-timesyncd
sudo systemctl stop systemd-timesyncd# NTPサーバ(chrony)インストール
sudo apt install chrony
sudo vi /etc/chrony/chrony.conf
#pool 2.debian.pool.ntp.org iburst pool NTP.JamFunk.jp noselect pool ntp.nict.jp #log tracking measurements statistics log tracking measurements statistics rtc refclocks tempcomp refclock PPS /dev/pps0 lock GPS refid PPS precision 1e-9 offset 0 poll 2 refclock SHM 0 refid GPS precision 1e-1 offset 0. poll 2
- poolやserverで、もし自前で立てたGPS NTPを相互に参照する場合は、noselectオプションを後ろに付けて参照しないようにすること。
- 捕捉しなくなったり誤差が大きくなりすぎた場合は、自動的に他のNTPサーバを参照する動きになっている。
- お互いに捕捉しなくなった場合は、相互に参照しても仕方ないので。
- logとlogdirで、/var/log/chronyに詳細な履歴が落ちてくる。
- SHM(GPS)とPPSのrefclockのoffsetで大まかな測定誤差を修正する。
- sudo gpsmon -nでGSA+PPSのTOFF値とPPS値を調べる。
- TOFFが0.055xxxxxxならGPSをoffset 0.055あたりで設定する。
TOFFの値はGPS捕捉情報(文字列)が送られてくるので誤差がどうしても大きくなってしまい、ms単位になっているはず。
しかも捕捉数が変われば捕捉情報の量も変わるのでどうしても設定した後も変動してしまう。
よって、本来であればほぼ1日監視するかログの統計を取って、捕捉の変動がどのくらいあるか見ないといけないらしい。 - PPSのoffsetを調整する。
-0.899999なら-0.900あたりで設定する。
代替機器のタイミングでSHMほど変動はないはず。多分。 - sudo chronyc sourcesで、PPSとGPS(SHM)のadjust offsetがus単位とms単位まで近づいていることと、PPSに*が付いていることを確認。
数日監視してみること。
後述のZabbixのchronyテンプレートで、referenceが変化したらトリガー発動を仕込んだら変動に気づきやすいかも。
# chrony設定反映
sudo systemctl restart chrony
sudo systemctl status chrony
# chrony参照先状況
chronyc sources -v
snmp
SNMP経由でサーバのチェックを行うならば。
sudo apt install snmpd snmp
sudo vi /etc/snmp/snmpd.conf
sysLocation Studio JamPack DCJn sysContact support_at_jamfunk.net #agentaddress 127.0.0.1,[::1] agentaddress udp:161 #view systemonly included .1.3.6.1.2.1.1 #view systemonly included .1.3.6.1.2.1.25.1 #rocommunity public default -V systemonly #rocommunity6 public default -V systemonly #rouser authPrivUser authpriv -V systemonly com2sec sec_all localhost snmp_all com2sec sec_all 192.168.0.0/24 snmp_all group grp_all v1 sec_all group grp_all v2c sec_all group grp_all usm sec_all view view_all included .1 80 access grp_all "" any noauth exact view_all none none disk /
sudo systemctl enable snmpd
sudo systemctl start snmpd
Zabbix Agent
chronyの参照状況をZabbix Agent経由でZabbix Serverに送るなら。
wget https://repo.zabbix.com/zabbix/5.0/raspbian/pool/main/z/zabbix-release/zabbix-release_5.0-2+debian11_all.deb
sudo dpkg -i zabbix-release_5.0-2+debian11_all.deb
sudo apt update
sudo apt install zabbix-agentsudo vi /etc/zabbix/zabbix_agentd.conf
AllowKey=system.run[chronyc *] Server=192.168.0.2 #Zabbix Serverのアドレス ListenPort=10050 StartAgents=3 ServerActive=192.168.0.2 #Zabbix Serverにアクティブでデータを送るなら Hostname=NTP-DCJn
sudo systemctl enable zabbix-agent
sudo systemctl start zabbix-agent
Zabbix Server用chrony監視テンプレート
Zabbix ServerからZabbix Agentのホスト経由でchronyの状況を取得するためのテンプレート
- template_chrony_accuracy_japanese
https://github.com/zabbix/community-templates/tree/main/Applications/NTP/template_chrony_accuracy_japanese - すながわがトリガーをちょっと追加したバージョン(参照先変化トリガー)
20221023_zabbix_templates_chrony_jampack.xml
使用中のZabbix ServerのバージョンのXMLをダウンロードして、Zabbix Serverにテンプレートとしてインポートする。
ホストの設定をする。


