Help us understand the problem. What is going on with this article?

Raspberry pi3とGPSモジュールを接続してNTPサーバを構築

はじめに

趣味と実益を兼ねて、Raspberry pi3のNTPサーバ化に挑戦しました。まず第一段階として、Raspberry piにGPSモジュールを接続し、緯度・経度情報などを取得できるようにしました。そして、第二段階としてNTPの機能を導入し、Stratum1のNTPサーバを動かすことができました。

使用機材

利用環境

pi@raspberrypi:~ $ uname -a
Linux raspberrypi 4.19.75-v7+ #1270 SMP Tue Sep 24 18:45:11 BST 2019 armv7l GNU/Linux

配線

ここの「外部機器との接続方法 (マイコンと接続する場合)」を参考にRaspbnerry piと接続すれば動作します。
Raspberry pi3のGPIOピンの図を参考に、5V同士、GND同士を接続し、Raspberry PiのTXにGPSモジュールのRXを、Raspberry PiのRXにGPSモジュールのTXを接続するようにしてください。
余裕があれば、後日図面を作成します。

設定変更&コマンド入力

  1. RaspberryにはOSインストールやキーボードなどの初期設定を行っておく
  2. sudo raspi-configを入力
  3. 5 Interfacing Optionsを選択
  4. P6 Serialを選択し、有効化
  5. Escキーでコンソール画面に戻った後、下記のコマンドを入力
sudo apt-get install gpsd gpsd-clients pps-tools
sudo timedatectl set-timezone Asia/Tokyo
sudo vim /boot/cmdline.txt #下記の設定例をもとに変更
sudo vim /boot/config.txt #下記の設定例をもとに変更
sudo vim /etc/modules #下記の設定例をもとに変更
sudo vim /etc/default/gpsd #下記の設定例をもとに変更
sudo systemctl status serial-getty@ttyS0.service #serial-getty@ttyS0.serviceの有効になっているか確認
sudo systemctl stop serial-getty@ttyS0.service
sudo systemctl disable serial-getty@ttyS0.service
sudo systemctl status serial-getty@ttyS0.service #serial-getty@ttyS0.serviceの無効になっているか確認
sudo reboot

上記の設定を終了した段階でGPSおよびPPSによるタイムパルスを受信することができる。

設定ファイル入力例

/boot/cmdline.txt

console=serial0,115200の削除

#dwc_otg.lpm_enable=0 console=serial0,115200 console=tty1 root=PARTUUID=250d3bf4-02 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait
dwc_otg.lpm_enable=0 console=tty1 root=PARTUUID=250d3bf4-02 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait

/boot/config.txt

core_freq=250enable_uart=1dtoverlay=pps-gpio,gpiopin=18を追記。
シリアルコンソールの通信速度をコアクロックを変更することで調整した。詳細はここの記事で分かりやすく解説されている。
GPSモジュールの1PPSの配線を、Raspberry piの12番ピン(GPIO 18)に接続しているため、上記の記述を行う。
以前は拡張ピンであるGPIO 18をPPSドライバで使えるようにするため、カーネルをリビルドする必要があったようだが(参考1参考2)、今回使用するRaspbianのバージョンではdtoverlayの文を記述すればよい。(前記の文献より、2014年以降に出たRaspbianは標準で1PPSの信号を受信できるようになっているらしいが、ソース元は未発見。いずれにせよ環境構築する際に最新のRaspbianを利用すれば問題ない)

(省略)
[all]
#dtoverlay=vc4-fkms-v3d

core_freq=250
enable_uart=1
dtoverlay=pps-gpio,gpiopin=18

/etc/modules

末尾にpps-gpioを追加

# /etc/modules: kernel modules to load at boot time.
#
# This file contains the names of kernel modules that should be loaded
# at boot time, one per line. Lines beginning with "#" are ignored.
pps-gpio

/etc/default/gpsd

DEVICESにGPSモジュールを指定。
シリアル接続および1PPS信号の読み取りを行えるように設定。

GPSD_OPTIONS-nを指定することで、NTPクライアントが一人もアクティブでない状態でも更新するように動作させられる(ここの「Running GPSD」の項目で確認可能)

hub@iothub:~ $ sudo cat /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="false"

# 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"

GPS起動およびタイムパルス受信確認

gpsmonまたはcgps -sでGPS情報が取れているか確認可能。
gpsmonでタイムパルスの受信確認が可能。

  • gpsmonによる出力
    gpsmon.PNG

  • cgps -sによる出力
    cgps.PNG

オプションの-sを抜くと、GPSで取得したデータのがJSON形式で確認できるようになります。

NTPの設定

下記の手順でコマンドを投入。

sudo apt-get install ntp
sudo vim /etc/ntp.conf
sudo reboot

/etc/ntp.confの設定例は以下の通り。

/etc/ntp.conf

serverでgpsdが時刻を提供しているアドレスを、fudgeでハードウェア時計を指定する。poolは全てコメントアウトする。
fudge文にある「stratum」オプションで、参照先をどのstratumで扱うか設定できるため、stratum 1と指定すると、Raspberry piをstratum1のNTPサーバとして動作させられます。

# pool.ntp.org maps to about 1000 low-stratum NTP servers.  Your server will
# pick a different set every time it starts up.  Please consider joining the
# pool: <http://www.pool.ntp.org/join.html>
#pool 0.debian.pool.ntp.org iburst
#pool 1.debian.pool.ntp.org iburst
#pool 2.debian.pool.ntp.org iburst
#pool 3.debian.pool.ntp.org iburst
server 127.127.28.2 minpoll 3 maxpoll 3 true
fudge 127.127.28.2 refid SHM2 stratum 0
disable monitor

restrictで、NTPクライアントの所属するネットワークを指定する。Raspberry piは、このrestrictで指定されたネットワークとNTPで通信する。

# Clients from this (example!) subnet have unlimited access, but only if
# cryptographically authenticated.
#restrict 192.168.123.0 mask 255.255.255.0 notrust
restrict 192.168.55.0 mask 255.255.255.0

トラブルシューティング

GPSモジュールから情報を取得できない

GPSモジュールからGPS情報を取得できず、時刻同期に失敗するケースが発生した。
gpsd.socketを確認すると、下記のようなログが出力された。

pi@iothub:~ $ 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: failed (Result: resources)
   Listen: /var/run/gpsd.sock (Stream)
           [::1]:2947 (Stream)
           127.0.0.1:2947 (Stream)

Dec 01 00:27:23 iothub systemd[1]: gpsd.socket: Failed to create listening socket ([::1]:2947): Cannot assign requested address
Dec 01 00:27:23 iothub systemd[1]: gpsd.socket: Failed to listen on sockets: Cannot assign requested address
Dec 01 00:27:23 iothub systemd[1]: gpsd.socket: Failed with result 'resources'.
Dec 01 00:27:23 iothub systemd[1]: Failed to listen on GPS (Global Positioning System) Daemon Sockets.
Dec 01 00:34:08 iothub systemd[1]: gpsd.socket: Failed to create listening socket ([::1]:2947): Cannot assign requested address
Dec 01 00:34:08 iothub systemd[1]: gpsd.socket: Failed to listen on sockets: Cannot assign requested address
Dec 01 00:34:08 iothub systemd[1]: gpsd.socket: Failed with result 'resources'.
Dec 01 00:34:08 iothub systemd[1]: Failed to listen on GPS (Global Positioning System) Daemon Sockets.

gpsdでは基本的にIPv4とIPv6双方でソケットを生成し、ntpdに対してGPS情報を提供している。gpsd.socket: Failed to create listening socket ([::1]:2947): Cannot assign requested addressとあるように、IPv6のリンクローカルアドレスをインタフェースで無効化すると、ソケット生成に失敗し、gpsdが異常終了してしまう。

そのため、/etc/sysctl.confを編集し、IPv6アドレスをインタフェースで有効化すると、リンクローカルアドレスがいずれかのインタフェースに割り当てられ上記の問題が解決する。

ppsの信号を受信しない

下記のような出力が表示される事象が発生。

# ppstest /dev/pps0
trying PPS source "/dev/pps0"
found PPS source "/dev/pps0"
ok, found 1 source(s), now start fetching data...
time_pps_fetch() error -1 (Connection timed out)
time_pps_fetch() error -1 (Connection timed out)
time_pps_fetch() error -1 (Connection timed out)

また、gpsmonで確認すると、PPS・位置情報の欄に何も表示されていなかった。

結果としては、単にGPS信号を受信できていなかっただけだった。GPS信号の処理とPPS信号の処理は別々に動作してそうだったけれど、知識不足でわからないので、また調べようと思います。

あとがき

Raspberry Piを再起動してから5~10分くらいしてから、NTPで正常に時刻同期できるようになります。Windowsマシンなどで時刻同期の確認が取れます。

また、NTPデーモンとしてchronyというものがあるのですが、apt-getコマンドを使ってインストールすると、勝手にntpdが排除(マスキング)されてしまうので注意してください。

(2019/10/26 追記)
chronyでも動作させてみました。詳しくはここで。

参考サイト

RCA3610
Raspberry piを使って自宅のスマートホーム化を目指す人。 単発系の企画だらけなので、そろそろ統合して何か大きいものを作りたい。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした