RaspberryPi[8] ラズパイにGPSを接続してシステム時刻を合わせる

USB GPSの接続

ラズパイにUSBのGPSを接続してみます。使用するGPSは UbloxのGPSです。UbloxはU-centerというソフトがありますが、Windows版しかないようなので、当面はコンソール使用して、そのうちプログラム化するつもりです。

まずは、USBにGPSを指して、

lsusb とたたいて、USBの接続を確認します。こんな感じです。

$lsusb

BUs 001 Device 003: ID 1546:xxxx U-Blox AG u-block GNSS receiver

GPSとデバイスと通信する gpsd デーモンがあるようなので、まずはこれをインストールします。

$sudo apt-get install -y gpsd gpsd-clients

$sudo gpsmon

で、GPSのデータが表示されます。どうも、tcp://localhost:2947 とも出るので、これでアクセスができるのかなと。

DEVICEも表示されてました。私の場合は、/dev/ttyACM0 でした。

gpsd の自動機能

/etc/default/gpsd を修正します。

DEVICES="/dev/tty/XXXX" 私の場合は、/dev/ttyACM0

GPSD_OPTIONS="-N -F /var/run/gpsd.sock -b -n"

あとは修正なしで。

gpsdの自動起動を有効にする

$sudo systemctl enable gpsd

GPSのデフォルトボーレートは 9600 のようです。違うボーレートを使うときに下記のように明示的に記載したほうがよさそうです。

# Devices gpsd should collect to at boot time.
# They need to be read/writeable, either by user gpsd or the group dialout.
DEVICES=""

# Other options you want to pass to gpsd
GPSD_OPTIONS=""

# Automatically hot add/remove USB GPS devices via gpsdctl
USBAUTO="true"

START_DAEMON="true"
DEVICES="/dev/ttyACM0"
GPSD_OPTIONS="-n"
GPSD_OPTIONS="-S 115200"
GPSD_SOCKET="/var/run/gpsd.sock

NTPサーバーの構築

NTPサーバとしてchronyをインストールします。NTPサーバにはntpd もありますが、どうも古いらしくchronyがおすすめのようです。 

$ sudo apt-get install chrony

/etc/chrony/chrony.conf の設定 GPSを使うときに下記追記が必用

refclock SHM 0 refid GPS offset 0.05

chronyサービスの自動起動有効

$ sudo systemctl enable chrony 

これで、自動でシステム時刻が合います。時に、cron 等で設定する必要はないみたい。

時刻同期の確認

$ chronyc sources -v

RTCの設定

GPSが動いていれば特にRTCは必要ないようですが、GPSが死んだり、起動時にGPS同期できるまでは時刻が安定しないので、RTCでその間保管してあげる方法もあるようです。

✅ RTCなしでも chrony だけで時刻同期は可能。
✅ ただし、起動直後の時刻ズレを防ぎたい場合は RTC があると便利。
✅ GPSの捕捉が遅い場合や、オフライン環境ではRTCを使うほうが安心。

🔹 もしRTCを使うなら、chrony で時刻を合わせた後に RTC に書き込むと良い

RTCの認識
/boot/config.txt に
dtoverlay=i2c-rtc,ds3231 を追加

fake-hwclock を無効化するために、
sudo systemctl disable fake-hwclock
sudo systemctl stop fake-hwclock

fake-hwclock の設定を削除(念のため)。
sudo apt remove fake-hwclock

RTCからシステムクロックを読み込む設定
起動時にRTCの時刻を適用するようにする。
/etc/rc.localに
hwclock -s 
これで、起動時にRTCの時刻をシステムクロックに適用できる。

その後、chrony がGPSに同期したら、RTCに定期的に書き込みを行う。しかし、これはスクリプトを書かないとだめ

同期出来たら、RTCに書き込むスクリプトを定期的にcronで実行する。

#!/bin/bash

# 許容できるオフセット(秒単位)
THRESHOLD=0.05

echo "Waiting for chrony to synchronize..."

while true; do
    # `chronyc tracking` の出力から `System time offset` を取得
    OFFSET=$(chronyc tracking | grep "System time offset" | awk '{print $4}')

    # 絶対値に変換
    OFFSET_ABS=$(echo $OFFSET | awk '{ print ($1 < 0) ? -$1 : $1 }')

    # 許容範囲内なら RTC に書き込む
    if (( $(echo "$OFFSET_ABS < $THRESHOLD" | bc -l) )); then
        echo "Chrony is synchronized. Writing to RTC..."
        sudo hwclock -w
        exit 0
    fi

    # 5秒ごとに再チェック
    sleep 5
done