以前 GPS モジュールを見失ったら gpsd を再起動させる で対応しようとしたが上手くいかず暫く放置していたが、改めて考える。
考えられる GPS 時刻が取れなくなる原因
- GPS モジュールと gpsd が通信速度が合わずに通信できない
- gpsd 再起動後にセマフォを使った ntpd との通信が上手くいかなくなる
確認方法
-
GPS モジュールと gpsd 間
a)ntpshmmonで該当モジュールの出力があるか確認
b)gpsmonで、該当モジュールの出力を確認
gpsmon localhost:2947:/dev/ttyUSBn
c)gpscatで、該当モジュールの出力を確認
gpscat localhost:2947:/dev/ttyUSBn -
gpsd と ntpd 間<
a)ntpq -p | grep SHMで、reach 欄が 0 でない
b)ntpq -c associationsで、対象の condition と last_event が「reject unreachable」になっていない (対象はntpq -c apeerで assid を確認)
解消方法
- GPS モジュールと gpsd 間
gpsd を再起動 - gpsd と ntpd 間
ntpd を再起動
スクリプト化
- GPS モジュールと gpsd 間
検出 (gpsd)
# /home/pi/opt/gpsd-3.18.1/ntpshmmon -t 3
ntpshmmon version 1
# Name Seen@ Clock Real L Prec
sample NTP0 1568759552.858062790 1565059095.067431939 1565059095.000000000 0 -20
sample NTP2 1568759552.858158518 1568759552.001487029 1568759552.000000000 0 -30
sample NTP3 1568759552.858191018 1564716014.348685357 1564716014.000000000 0 -20
sample NTP4 1568759552.858222112 1564716015.000534782 1564716015.000000000 0 -20
sample NTP5 1568759552.858252476 1564716986.066649638 1564716986.000000000 0 -20
sample NTP6 1568759552.858282632 1564716986.996633827 1564716987.000000000 0 -20
sample NTP2 1568759553.001645576 1568759553.001487139 1568759553.000000000 0 -30
sample NTP2 1568759554.001593915 1568759554.001486051 1568759554.000000000 0 -30
sample NTP2 1568759555.001652722 1568759555.001486057 1568759555.000000000 0 -30
この 2行目の Name 欄を抜き出して uniq して 6行あれば全ての GPS レシーバと通信できている。
前回も載せたスクリプト
# !/bin/sh
NTPSHMMON=/home/pi/opt/gpsd-3.18.1/ntpshmmon
count=`$NTPSHMMON -t 3 | grep sample | cut --delim=" " -f 2 | sort -u | wc -l`
if [ $count -ne 6 ]; then
logger -p local0.notice "$0: ntpshm ckeck, error detected."
echo | /root/bin/gpsd_restart
fi
/root/bin/gpsd_restart は gpsd を再起動するスクリプト。
再起動 (gpsd)
# !/bin/sh
SYSTEMCTL=/bin/systemctl
STTY=/bin/stty
GPSCTL=/home/pi/opt/gpsd-3.18.1/gpsctl
IPCRM=/usr/bin/ipcrm
MKTEMP=/bin/mktemp
LOCKDIR=/tmp/`basename $0`
LOCKPID=$LOCKDIR/pid
# SHM segments
# http://doc.ntp.org/4.2.8/drivers/driver28.html
clear_shm (){
# セマフォを削除します
# 通常、セグメントサイズを変更した場合のみ実行すればよい
# https://github.com/rnorris/gpsd/blob/master/SConstruct#LC1963
# 削除すると key は一緒でも shmid が変わるので ntpd の再起動が必要になる。やっちゃダメ。
# for i in 0x4e545030 0x4e545031 0x4e545032 0x4e545033 0x4e545034 0x4e545035 0x4e545036 0x4e545037 0x47505344;do
# $IPCRM -M $i
# done
}
stty_speed () {
for i in /dev/ttyS0 /dev/ttyUSB0 /dev/ttyUSB1; do
$STTY -F $i 115200
done
}
# already running other process?
if [ -d $LOCKDIR ]
then
# LOCKDIRがある
if [ -f $LOCKPID ]
then
# PIDファイルがあってそのプロセスがない or ある
kill -0 `cat $LOCKPID`
if [ $? -ne 0 ]; then
rm -rf $LOCKDIR && break
else
logger -p local0.notice "$0: still running."
exit
fi
fi
fi
# make lock directory
mkdir $LOCKDIR
if [ $? -ne 0 ]; then
logger -p local0.notice "$0: lockfile make error."
exit
fi
echo $$ > $LOCKPID
while read LINE; do
$SYSTEMCTL stop gpsd
clear_shm
/bin/sleep 1
sync
$SYSTEMCTL start gpsd
logger -p local0.notice "$0: gpsd restart to me!"
done
# remove lock directory
rm -rf $LOCKDIR
- gpsd と ntpd 間
検出 (ntpd)
# ntpq -p
remote refid st t when poll reach delay offset jitter
==============================================================================
+ntp-a3.nict.go. .NICT. 1 u 1375 68m 377 10.311 0.431 1.508
+ntp-b2.nict.go. .NICT. 1 u 66m 68m 377 13.518 1.582 1.541
+ntp-b3.nict.go. .NICT. 1 u 1537 68m 377 13.007 1.783 2.277
*ntp-a2.nict.go. .NICT. 1 u 102 68m 377 12.483 1.370 1.337
-ats1.e-timing.n .PPS. 1 u 60m 68m 273 11.622 0.282 0.987
-cwa225.bai.ne.j 210.171.0.34 4 u 71m 68m 377 6.457 2.216 1.619
-cwa201.bai.ne.j 210.171.0.34 4 u 47m 68m 377 5.647 3.896 5.895
SHM(0) .NEMA. 0 l 47d 1 0 0.000 -61.442 0.000
SHM(2) .PPS. 0 l 47d 1 0 0.000 0.509 0.000
SHM(3) .NEMA. 0 l 47d 1 0 0.000 -75.459 0.000
SHM(4) .PPS. 0 l 47d 1 0 0.000 -0.529 0.000
SHM(5) .NEMA. 0 l 47d 1 0 0.000 -69.134 0.000
SHM(6) .PPS. 0 l 47d 1 0 0.000 -0.257 0.000
remote が SHM を含み、reach が 0 の項目があるかチェック。
ntpq -p | awk '($0~/SHM/ && $7==0){print "error";exit}'
再起動 (ntpd)
GPS モジュールの reach が 0 になっていたら gpsd が正常に動いているかを確認し、動いていなければ ntpd の再起動。
ntpq -p | awk '($0~/SHM/ && $7==0){print "error";exit 255}' || systemctl restart ntpd
スクリプトをまとめてみる
流れ
- gpsd が GPS モジュールから時刻を取得できているか? (ntpshmmon)
→ できている 3
→ できていない 2 - gpsd を再起動し終了
ntpd でも時刻が取得できていない筈だが、それで通信の可否は判定できない。 - ntpd が gpsd から時刻を取得できているか? (ntpq)
→ できている (終了) - ntpd を再起動し終了
判断用とログ用でコマンドを 2回起動していたりしますがまぁ、
ただいま書換え中...
# !/bin/bash
# 初期設定
SYSTEMCTL=/bin/systemctl
STTY=/bin/stty
IPCRM=/usr/bin/ipcrm
LOGGER=/usr/bin/logger
TR=/usr/bin/tr
AWK=/home/pi/opt/bin/awk
NTPQ=/home/pi/opt/bin/ntpq
NTPSHMMON=/home/pi/opt/gpsd-3.18.1/ntpshmmon
PYTHONPATH=/home/pi/opt/lib/python2.7/site-packages:/usr/local/lib/python2.7/site-packages:/usr/lib/pypy/lib-python/2.7/site-packages
export PYTHONPATH
GPSTTYS="/dev/ttyS0 /dev/ttyUSB0 /dev/ttyUSB1"
# debug
trap 'echo "[${BASH_SOURCE:-$0}:$LINENO] - "$BASH_COMMAND" abnomal status"' ERR
# 二重起動防止 (ロック)
MKTEMP=/bin/mktemp
LOCKDIR=/tmp/`basename $0`
LOCKPID=$LOCKDIR/pid
if [ -d $LOCKDIR ]; then
# LOCKDIRがある
if [ -f $LOCKPID ]; then
# PIDファイルがあってそのプロセスがない or ある
kill -0 `cat $LOCKPID`
if [ $? -ne 0 ]; then
rm -rf $LOCKDIR
else
$LOGGER -p local0.notice "$0: still running."
exit
fi
else
rmdir $LOCKDIR
fi
fi
# make lock directory
trap 'rm -rf $LOCKDIR' 1 2 3 15
trap 'rm -rf $LOCKDIR' EXIT
mkdir $LOCKDIR
if [ $? -ne 0 ]; then
$LOGGER -p local0.notice "$0: lockfile make error."
exit
fi
echo $$ > $LOCKPID
stty_speed () {
echo -n $GPSTTYS | xargs -d " " -n 1 -i'{}' $STTY -F '{}' 115200
}
# セマフォを削除
# http://doc.ntp.org/4.2.8/drivers/driver28.html
# セグメントサイズを変更した場合のみ実行すればよい
# https://github.com/rnorris/gpsd/blob/master/SConstruct#LC1963
# 削除すると key は一緒でも shmid が変わるので ntpd の再起動が必要になる。普段はやっちゃダメ。
clear_shm (){
echo shemapho clear
for i in 0x4e545030 0x4e545031 0x4e545032 0x4e545033 0x4e545034 0x4e545035 0x4e545036 0x4e545037 0x47505344; do
$IPCRM -M $i
done
}
check_gpsd (){
RESULT="`$NTPSHMMON -t 3 | $TR '\n' @`"
if [ `echo $RESULT | $TR @ '\n' | $AWK '/NTP[0-9]/{print $2}' | sort -u | wc -l` -ne 6 ]; then
echo "$NTPSHMMON error detected"
echo $RESULT | $TR @ '\n'
echo $RESULT | $TR @ '\n' | $AWK '/NTP[0-9]/{print $2}' | sort -u
$SYSTEMCTL stop gpsd
stty_speed
/bin/sleep 1
$SYSTEMCTL start gpsd
$LOGGER -p local0.notice "$0: gpsd restart to me!"
echo 'gpsd: Restart done!'
exit 255
fi
}
check_ntpd (){
RESULT="`$NTPQ -p | $TR '\n' @`"
echo "$RESULT" | $TR @ '\n' | $AWK '($0~/SHM/ && $7==0){exit 255}' || \
( echo "ntpd error detected" ;\
echo "$RESULT" | $TR @ '\n' | $AWK '($0~/SHM/ && $7==0){print}' ;\
$SYSTEMCTL restart ntp ;\
$LOGGER -p local0.notice "$0: ntpd restart to me!";\
exit 255 )
}
check_gpsd && check_ntpd
定期的に起動してチェックする
*/10 * * * * /root/bin/gps_time_check
rsyslog で ntp 関連のログを別ファイルに保存する
# ntpd & gpsd logging
# 出力の書式
template (name="ntp_mess" type="string" string="%timereported% %hostname% %syslogfacility-text%.%syslogseverity-text% %syslogtag% %msg%\n")
# 出力ファイル名
template (name="NtpLogfile" type="string" string="/var/log/ntp.log_%$year%%$month%")
# kernel メッセージで ppp や、usb, ch341 (sub-serial インターフェイス) が含まれていたらロギング
if $syslogfacility-text == 'kern' and (
re_match($msg,'pps pps[0-9]+:') or ($msg contains "usb") or ($msg contains "ch341")
)
then {
action(type="omfile" template="ntp_mess" dynaFile="NtpLogfile")
}
# systemd からのメッセージで gps や ntp という文字列が含まれる場合はロギング
if ($syslogtag contains 'systemd') and ($msg contains_i 'gps' or $msg contains_i 'ntp')
then {
action(type="omfile" template="ntp_mess" dynaFile="NtpLogfile")
}
# プログラム名に ntpd や gpsd という文字列が含まれる場合はロギング
if ($programname == 'ntpd') or ($programname == 'gpsd')
then {
action(type="omfile" template="ntp_mess" dynaFile="NtpLogfile")
}
# メッセージ部分に再起動スクリプトのファイル名が含まれていたらロギング
if ($msg contains '/root/bin/gps_time_check')
then {
action(type="omfile" template="ntp_mess" dynaFile="NtpLogfile")
}
rsyslog の設定を反映させる
> sudo systemctl restart rsyslog
その後
> bash -c 'while true; do date; ntpq -p; echo; sleep 10; done'
2019年 9月 22日 日曜日 16:10:26 JST
remote refid st t when poll reach delay offset jitter
=======================================================================================================
-ntp-a3.nict.go.jp .NICT. 1 u 192 256 377 9.7247 0.7944 4.4669
-ntp-b2.nict.go.jp .NICT. 1 u 185 256 377 8.9898 0.2955 1.4627
-ntp-b3.nict.go.jp .NICT. 1 u 191 256 377 9.9750 0.9161 0.8876
-ntp-a2.nict.go.jp .NICT. 1 u 180 256 377 9.0554 0.4391 21.2595
-61-114-187-55.secomtrust.net .PPS. 1 u 185 256 377 10.5863 0.6503 1.6526
-cwa225.bai.ne.jp 210.171.0.34 4 u 193 256 377 2.3816 0.3855 3.1480
-cwa201.bai.ne.jp 210.171.0.34 4 u 216 256 377 1.3140 0.3483 1.5777
xSHM(0) .NEMA. 0 l - 1 377 0.0000 -48.3162 0.9223
+SHM(2) .PPS. 0 l 1 1 377 0.0000 0.5475 0.0349
xSHM(3) .NEMA. 0 l - 1 377 0.0000 -61.3037 1.6150
+SHM(4) .PPS. 0 l 1 1 377 0.0000 -0.2275 0.0460
xSHM(5) .NEMA. 0 l - 1 377 0.0000 -61.7563 18.4702
*SHM(6) .PPS. 0 l 1 1 377 0.0000 -0.2266 0.0295
相変わらず jitter が小さいですねぇ。これで安定するかな? (いや、再起動してたら安定してないけど)
ntpviz でグラフ化してみた
GPS を常に見るようになって offset (青) は小さくなりましたね。ただ、pps 信号が毎秒チェックするので Frequency Offsets (赤) の変動が凄い。

作成方法:> ntpviz -d ntpstats/ -n Ras1 -p 31 -o ./htdocs で html ドキュメントを作成
※Raspberry Pi だと全然終わらない (140分以上) ので Windows Subsystem for Linux で入れた Debian GNU/Linux へログをコピーして実行 (3分)。Debian で gnuplot, NTPsec のインストール済み。
NICT 群とのずれを比較しようとしたけど、GPS を見てない間は更新頻度が低いのか、点線で描かれてしまい読み難くて判断がつかない。いくらか良くなってるかな?

作成方法:> ntpviz --peer-offsets "133.243.238.163,133.243.238.164,133.243.238.243,133.243.238.244" -d ntpstats/ -n Ras1 -p 31 -g > htdocs/nict.png