突然ですが家にNTPサーバー建てたいですよね?
今回はどこのご家庭にも転がっているはずのRaspberry Pi 4Bを使ったサーバーの建て方を紹介します。
まずはGNSSモジュールです。AliexpressでU-Blox M10を搭載したモジュールを買いました。アンテナ付きで1,700円くらいです。
NTPサーバーとして動かす場合は必ずPPS出力がついているものを選んでください。USB接続タイプは精度が出ないためだめです。
https://ja.aliexpress.com/item/1005004219674527.html
余談ですが、U-blox M10は1.5GHz帯のほとんどの信号に対応しています。感度も文句なしのためお勧めです。マルチバンド対応のZED-F9Pを買おうとすると途端に値段が跳ね上がるのであまりお勧めはしないです(ロマンですが)
| システム | 信号 |
|---|---|
| GPS | L1C/L1A |
| QZSS | L1C/L1A/L1S |
| GLONASS | L1OF |
| BeiDou | B1I/B1C |
| Galileo | E1B/E1C |

NTPサーバーには不要なのですが、RTC(Real-Time-Clock)も購入しておきましょう。安いのでDS3231がお勧めです。
https://ja.aliexpress.com/item/1005007143842437.html
Raspberry PiのGPIOとGNSSモジュールを接続します。RX/TXは反転するのでそこだけ注意です。
| Pi4B | GNSS |
|---|---|
| PIN4 5V Power | VCC |
| PIN6 GND | GND |
| PIN8 GPIO14 UART0 TX | RX |
| PIN10 GPIO15 UART0 RX | TX |
| PIN12 GPIO18 PCM CLK | PPS |

RaspberryPiはかなり発熱するのでアルミケースに入れます。高さがなくてコードがギリギリなので注意です。
https://ja.aliexpress.com/item/4000907704024.html

Raspberry Pi自体のセットアップは割愛します。今回の環境ではDebian 12ベースのRaspbian Bookwormを使います。
まずはGPIOの設定を行うため/boot/firmware/config.txtに以下を追記します
# RTC DS3231の設定
dtoverlay=i2c-rtc,ds3231
# PPSの設定
dtoverlay=pps-gpio,gpiopin=18
# UARTを有効化
enable_uart=1
再起動後gpsdをインストールします。
sudo apt install gpsd gpsd-clients python3-gps
/etc/default/gpsdを編集します。
DEVICES="/dev/ttyS0 /dev/pps0"
# baudを38400に固定
# NMEAを配信するなら-G必須
GPSD_OPTIONS="-n -G -s 38400"
USBAUTO="false"
LISTEN_ANY="true"
シリアル通信が行えるように設定が必要です。
1.sudo raspi-config
2.Interface Options > Serial Port
3.”Would you like a login shell to be accessible over serial?” → No
4.”Would you like the serial port hardware to be enabled?” → Yes
5.再起動
/etc/chrony/chrony.confにGNSSとPPSを時刻ソースとして使うよう設定しておきます。
念のためNICTも時刻ソースにしておきます。
refclock SHM 0 poll 1 delay 0.2 refid NMEA noselect
refclock PPS /dev/pps0 poll 1 lock NMEA refid PPS
pool ntp.nict.jp iburst
poll 1は2^[1]=2秒ごとにソースを確認するという意味で、delay 0.2はNMEA自体に起因する遅延があることを示しています。
ここまで問題なければchronyを再起動します。
sudo systemctl restart chronyd
同期状況を確認します。
$ chronyc sources -v
.-- Source mode '^' = server, '=' = peer, '#' = local clock.
/ .- Source state '*' = current best, '+' = combined, '-' = not combined,
| / 'x' = may be in error, '~' = too variable, '?' = unusable.
|| .- xxxx [ yyyy ] +/- zzzz
|| Reachability register (octal) -. | xxxx = adjusted offset,
|| Log2(Polling interval) --. | | yyyy = measured offset,
|| \ | | zzzz = estimated error.
|| | | \
MS Name/IP address Stratum Poll Reach LastRx Last sample
===============================================================================
#? NMEA 0 1 377 2 +147ms[ +147ms] +/- 108ms
#* PPS 0 1 377 2 +465ns[ +522ns] +/- 1161ns
^- ntp-b2.nict.go.jp 1 6 17 57 -2735us[-2736us] +/- 11ms
^- ntp-a3.nict.go.jp 1 6 17 57 -2557us[-2558us] +/- 11ms
^- ntp-k1.nict.jp 1 6 17 57 -2404us[-2405us] +/- 7427us
^- ntp-b3.nict.go.jp 1 6 17 58 -2946us[-2947us] +/- 10ms
^- 2001:a7ff:102::a 1 6 17 57 -2440us[-2442us] +/- 6622us
^- 2001:a7ff:102::b 1 6 17 57 -3159us[-3160us] +/- 7318us
PPSのところに*マークがついていたら時刻ソースとして使われていて、精度も問題ない証です。
特に問題なければ、sudo hwclock -wでハードウェアクロックに書き込みます。基本的には自動的に同期されるので問題ないです。
Raspberry PiはRTCを搭載していないため、fake-hwclockが有効になっている。RTCをのっけたら不要なのでこれを無効にします。
sudo apt-get remove fake-hwclock
sudo update-rc.d -f fake-hwclock remove
sudo systemctl disable fake-hwclock
NTPサーバーとして動かしたければ/etc/chrony/chrony.confに許可するIPを追記するだけでOK。
allow 192.168.1.0/24
NMEAをTCPで配信することもできます。/lib/systemd/system/gpsd.socketを編集します
# ListenStreamのコメントアウトを外す。
ListenStream=[::]:2947
ListenStream=0.0.0.0:2947
設定をリロードします。
sudo systemctl daemon-reload
sudo systemctl stop gpsd.service
sudo systemctl restart gpsd.socket
sudo systemctl start gpsd.service
u-centerで接続する場合はsocatを用いて生データでの転送が必要になります。gpsdと競合するので同時稼働はできません。
# socatのインストール
sudo apt install socat
# gpsdを止める
sudo systemctl stop gpsd.socket gpsd.service
# シリアルポートをTCP転送する
sudo socat TCP-LISTEN:2947,fork,reuseaddr FILE:/dev/ttyS0,b38400,raw
u-centerでTCP接続を選ぶとネットワーク越しにいつもの画面が見れます。ニチャニチャ可能です

Raspberry Pi 5からはイーサネットがPTPをサポートするようになりました。
家庭内で運用するのはなかなかハードルが高そうですがいつかやってみたいですね。

コメント