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

/etc/default/gpsdGPSD_OPTIONS="-S 115200" が書かれているのに、なぜボーレートが変わらないのか?
実はここ、gpsd起動方法と設定の優先順位に関係する“落とし穴”。

✅ 結論から言うと…
GPSD_OPTIONS="-S 115200"あくまで "シリアルデバイスを gpsd が自分で開くとき" にだけ有効
でも /dev/ttyUSB0 を自動的に systemd が先に開いていたり、
gpsd.socket 経由で起動されていたら → このオプションは無視される!

systemd override.conf に以下を追加する。場所がシステムによって、変わるみたいだけど、

sudo systemctl edit gpsd と打ってみればわかる。 私の場合は、/etc/systemd/system/gpsd.service.d の下に、overide.conf を作るようになっていた。デフォルトではgpsd.service.dはないので、事前に作成しておかないと、override.conf は作られないようです。

Editing "/etc/systemd/system/gpsd.service.d/override.conf" canceled: temporary file is empty.

こうなって、作られない場合は、自分でoveride.conf を作ってあげる。

[Service]
ExecStartPre=/bin/stty -F /dev/ttyUSB0 115200
↑ これなら gpsd が起動する前に、確実に正しい速度でデバイスが開かれる!
→ gpsd はすでに 115200 で開かれたデバイスを使える。

📌 補足:じゃあ /etc/default/gpsd はいらない?
場合によっては使えるけど、systemd 主体の今の構成ではほとんど使われないことが多い。

なので、こういう運用がおすすめ:

設定方法 推奨度
/etc/default/gpsd の -S 指定 ⚠️ 古い構成向け。systemdでは無視されがち
override.conf の ExecStartPre で stty ✅ シンプルで確実。

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

ちなみに、ネットワークから取るのを優先して、ネットワークがつながっていない時は、GPSから取ることもできます。

pool 2.debian.pool.ntp.org iburst

refclock SHM 0 refid GPS offset 0.05

の両方を書いておけばいい。もし、どちらかを優先させていのならば、優先させたいほうに、 prefer をつける。

refclock SHM 0 offset 0.05 refid GPS prefer

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               
===============================================================================
#x GPS                           0   4   377    18    +60ms[  +60ms] +/-  211us
^- 2001:49f0:d0d9:5::f           4   6   377    16  -1773us[-1773us] +/-   61ms
^- time1.gin.ntt.net             2   6   377    18  +3058us[+3034us] +/-   75ms
^- 108.160.132.224.vultruse>     2   6   377    14   +283us[ +283us] +/-   28ms
^* 47.79.37.210                  2   6   377    17  +3211ns[  -21us] +/- 6819u

⏱ 時刻同期の状態の見方(復習)

記号意味
#* GPSGPSが現在の時刻ソース(ネット切断時など)
#? GPSGPSは見えてるけど、まだchronyの評価中(ネットがあると使われないことも)
^*ネット上のNTPが現在使われているソース

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