GPS センサを使って位置情報取得と時刻補正をする 

Raspberry Pi に GPS センサを接続し、 gpsd と chrony の サービス を有効にして位置情報取得と時刻補正をする

# 動作環境

- HW: Raspberry Pi 4B
- OS: Raspberry Pi OS
- センサ： [GNSS 受信機キット(秋月電子)](https://akizukidenshi.com/catalog/g/gK-13850/)
- USB 変換器: [ＵＳＢシリアル変換モジュール(秋月電子)](https://akizukidenshi.com/catalog/g/gM-11007/)

# 配線接続

用意した GPS センサは UART 接続用だが、Raspberry Pi 以外の機器にも適用するため変換器を使用して USB 接続する

![gps.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/928808/5f957786-3258-182b-3955-087eb0e9236e.jpeg)

# 接続確認

USB 変換器が認識されると`/dev/ttyUSB0`が作成される
通信内容を読み取り GPS センサが接続されていることを確認する

```sh:
cat /dev/ttyUSB0
```

コマンド実行すると、下記のような [NMEA 形式](https://ja.wikipedia.org/wiki/NMEA_0183)の応答がある
(注) 既に gpsd を設定・起動していると`Device or resource busy`と表示される

```shell:
GNGLL,3422.1331,N,13518.0431,E,141613.000,A,A*48
GNGSA,A,3,17,28,04,14,09,03,19,06,22,,,,1.19,0.86,0.82*18
...
```

# gpsd を有効にして位置情報を取得する

## 位置情報を受け取る仕組み

GPS センサから NMEA 形式の信号を受け取った gpsd は、[gpsd_json 形式](https://gpsd.gitlab.io/gpsd/gpsd_json.html)に変換した位置情報レポートを TCP/IP 通信(ポート2947)で配信する。レポートの内容は cgps などの gpsd クライアントを使用して簡単に表示できる

## gpsd、gpsd クライアントのインストール

```sh:
sudo apt install gpsd gpsd-clients
```

## gpsd 設定

`/etc/default/gpsd`を編集する

```:/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="true"

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

# Other options you want to pass to gpsd
GPSD_OPTIONS="-F /var/run/gpsd.sock -b -n -r"
```

オプションの意味は`man gpsd`で確認できる

> -F ソケットのファイルパス
> -b デバイス保護モード(GPS センサへの設定書き込み禁止)
> -n リクエストがくるまでセンサ接続待機する機能を無効にする。
> -r 補正完了前でも GPS の時刻を使用する。RTC 内蔵センサなら補正完了前でも有効な時刻が取得できる

gpsd を再起動する

```sh:
sudo systemctl restart gpsd.service
```

## 位置情報を取得する

cgps や gpsmon などの gpsd クライアントを使用して位置情報を取得する

```sh:
cgps -s
```

こちらの[ライブラリ](https://github.com/wadda/gps3)を使用すると python で位置情報を取得することもできる

# chrony を有効にして位置情報を取得する

## chrony とは

ntpd とは異なる NTP 実装。ホストマシンが頻繁にシャットダウンやネットワーク切断状態となるケースで安定して動作することが特徴[[公式]](https://chrony.tuxfamily.org/faq.html#_how_does_chrony_compare_to_ntpd)。CentOS や Red Hat では ntpd に変わりデフォルトとなっていることから信頼性も高い

chorny は gpsd が shared memory に書き込んだ情報を読み取って時刻補正する

## chrnoy 設定

Raspberry Pi OS ではデフォルトで`systemd-timesyncd`が起動しているので無効化する

```sh:
sudo systemctl stop systemd-timesyncd
sudo systemctl disable systemd-timesyncd
```

chrony をインストールする

```sh:
sudo apt install chrony
```

`/etc/chrony/chrony.conf`を編集する

```:/etc/chrony/chrony.conf
# ネットワーク上の時刻サーバとの同期させない場合はコメントアウト
# pool 2.debian.pool.ntp.org iburst

# shared memoryから読み取る設定を追加
refclock SHM 0 refid GPS precision 1e-1
```

chrony を再起動する

```sh:
sudo systemctl restart chrony.service
```

`chrony sources`コマンドで状況を確認できる
暫く放置して GPS の左側に\*が表示されたら時刻同期完了している

```
210 Number of sources = 1
MS Name/IP address         Stratum Poll Reach LastRx Last sample
===============================================================================
#* GPS                           0   4   377    20    +18ms[  +32ms] +/-  100ms

```

# 参考

http://manpages.ubuntu.com/manpages/focal/man8/gpsd.8.html
https://manpages.ubuntu.com/manpages/precise/man5/gpsd_json.5.html 
https://gpsd.gitlab.io/gpsd/gpsd-time-service-howto.html#_feeding_chrony_from_gpsd
https://gpsd.gitlab.io/gpsd/client-howto.html#_introduction