用 RaspberryPi 与 GPS 构建 NTP 服务器
NTP 服务器 Network Time Protocol(NTP)是用来使计算机时间同步化的一种协议,它可以使计算机对其服务器或时钟源(如石英钟,GPS 等等)做同步化,它可以提供高精准度的时间校正(LAN 上与标准间差小于 1 毫秒,WAN 上几十毫秒),且可介由加密确认的方式来防止恶毒的协议攻击。时间按 NTP 服务器的等级传播。按照离外部 UTC 源的远近把所有服务器归入不同的 Stratum(层)中。
本文将介绍如何使用 RaspberryPi 和 GPS 模块构建一个 NTP 服务器,精度在 100 毫秒以内,基本满足一般业务对时需求和一些无法使用公网环境的授时需要。
GPS 模块的准备
硬件选择
我购买的是正点原子的 GPS+北斗双定位模块 S1216,其内核为 SkyTra 的 S1216F8-BD 芯片。支持串口和 PPS,宽供电 3.3V-5V,20Hz 更新速度,支持 IPX 天线,板载电池热启动速度极快。
选择 GPS 模块的几点要求,必须支持串口和 PPS,这是授时所必须的。另外也十分建议板载电池,这有助于在热启动时有更快的定位和获取时间的速度。板载天线接口,可扩展天线。
软件调整
推荐使用 GNSS 将模块的通信速度调整为 9600,关闭北斗频点(因为软件无法识别 BDNMEA 语句)
Raspberry Pi 的准备
特别鸣谢 BH8TWO 送的 RaspberryPi
连接线
Raspberry Pi | GPS |
---|---|
GND | GND |
5V | VCC |
TXD | RXD |
RXD | TXD |
GPIO 18 | PPS |
关于树莓派的 GPIO 定义,请参见 RaspberryPi 英文 WiKi
刷写系统
最小需要一个 8G 的 SD 卡,使用 NOOBS 安装系统,并做一些基础性的配置,例如 Root 密码、启用 SSH 远程登录、启用 GPIO 接口。
配置国内软件源
修改后的 /etc/apt/sources.list
#deb http://mirrordirector.raspbian.org/raspbian/ jessie main contrib non-free rpi
# Uncomment line below then 'apt-get update' to enable 'apt-get source'
#deb-src http://archive.raspbian.org/raspbian/ jessie main contrib non-free rpi
# use ustc mirror:
deb http://mirrors.ustc.edu.cn/raspbian/raspbian/ jessie main contrib non-free rpi
修改后的 /etc/apt/sources.d/raspi.list
#deb http://archive.raspberrypi.org/debian/ jessie main ui
# Uncomment line below then 'apt-get update' to enable 'apt-get source'
#deb-src http://archive.raspberrypi.org/debian/ jessie main ui
# use ustc mirror:
deb http://mirrors.ustc.edu.cn/archive.raspberrypi.org/debian/ jessie main ui
启用串口并禁用串口登录
sudo raspi-config
找到 Serial 选项,enable Serial,disable Serial Login。(博主记:因为当时没用保存截图,这里可能与实际情况又出入,你可以仔细找找类似的选项)
更新 RaspberryPi
sudo apt-get update
sudo apt-get dist-upgrade
sudo rpi-update
sudo reboot
检查串口
连接好 GPS 模块和 RaspberryPi 之后,使用 cat /dev/ttyAMA0
检查串口
串口输入如下数据系正常
$GPGSA,A,3,02,04,12,25,24,05,10,,,,,,02.4,01.1,02.1*07
$GPGLL,2834.2631,N,07720.5426,E,102954.00,A,A*6E
$GPGSV,3,1,07,02,71,345,50,04,40,038,48,12,62,315,47,25,20,321,45*7F
$GPGSV,3,2,07,05,41,167,23,10,48,086,23,24,24,236,30,,,,*48
$GPGSV,3,3,07,,,,,,,,,,,,,,,,*7E
安装 PPS-tools
sudo apt-get install pps-tools
sudo apt-get install libcap-dev
配置 PPS-tools
使用 sudo nano /boot/config.txt
修改文件,在文件的最后加入如下内容保存退出
dtoverlay=pps-gpio,gpiopin=18
使用 sudo vim /etc/modules
修改文件,在文件的最后加入如下内容保存并退出
pps-gpio
配置完毕重启生效
验证 PPS 是否工作
使用 lsmod | grep pps
验证模块是否正常加载
若输出如下信息系正常
pps_gpio 2555 0
pps_core 7092 1 pps_gpio
使用 dmesg | grep pps
命令检查 PPS GPIO 是否被配置
若输出如下信息系正常
使用 sudo ppstest /dev/pps0
将会看到类似下面的输出
trying PPS source "/dev/pps0"
found PPS source "/dev/pps0"
ok, found 1 source(s), now start fetching data...
source 0 - assert 1421066632.974111422, sequence: 1698 - clear 0.000000000, sequence: 0
source 0 - assert 1421066633.974045488, sequence: 1699 - clear 0.000000000, sequence: 0
正常情况下每一秒输出一条,如果发现输出间隔不是一秒,可能是连线错误或者 GPS 模块未设置导致的
配置 NTP 服务
有两个方案可以实现 NTP 服务,ntpd 和 chrony。但是 RaspberryPi 源中的 ntpd 是一个阉割的版本,里面不含 PPS 支持,所以如果你执意想使用 ntpd 的话,需要从源码编译,很不幸的是,博主编译了 n 次(n∈【1,6】)都没用成功,故我使用了 chrony。
chrony 的优点有:
同步更快,只需要几分钟收敛到最小误差,而 ntpd 可能需要几个小时。
对变频环境有优化。
对于断线和延迟有更好的优化。
chrony 的缺点(可以弥补):
仅支持 PPS,对于 GPS 的串口连接的 NMEA 语句没有支持,但可以通过 gpsd 的共享内存的方式来获取。
另外说一句 ntpd 和 chrony 冲突,请二者选其一。
安装 GPSD
sudo apt install gpsd gpsd-clients python-gps
修改 /etc/default/gpsd
文件如下
DEVICES="/dev/ttyAMA0"
GPSD_OPTIONS="-n -G"
配置 GPSD 开机启动
太简单了,不再赘述
检查 GPSD
使用 gpsd -s
来查看 GPSD 的数据,如果你在开阔的地方,你将会看到类似下面的输出
安装 chrony
chrony 官网 了解一下?
直接 apt 安装就好了,没这么麻烦
sudo apt install chrony
修改配置文件 /etc/chrony/chrony.conf
确保有以下内容(如果没有则添加)
leapsectz right/UTC
makestep 1.0 -1
rtcsync
refclock PPS /dev/pps0 lock GPSD prefer refid PPS
refclock SHM 0 offset 0.0 delay 0.2 refid GPSD
allow
解释一下 chrony.conf 配置文档,其中 :
makestep 1.0 -1表示超过1秒立刻修正,不回归
rtcsync每11分钟自动矫正系统rtc时钟
注意这里的 delay 的大小,delay 代表信号源往返信号的时间预估,其值的一半会作为信号的误差,且不同的信号源的范围需要 overlay。
如 pps 的 delay 和 offset 都很小,接近0,而 gpsd 的 offset 如果在100ms左右,这个时候就需要设置 delay 大于0.2(两倍100ms,我会设置0.3)。
否则的话,通过 `chronyc sources -v` 会看到型号元前面是 time may be error 的标志。
allow 允许局域网所有设备使用本服务器时间
配置完成后通过 sudo service chrony restart
重启服务
可以通过下面两个命令来查看连接状态
watch -n1 chronyc sources -v
watch -n1 chronyc sourcestats -v
尽情使用吧
精度说明
经过测试,基本精度在 60ms 左右,最好能到 10ms,基本够非精密业务授时使用,例如,我是给我们广播服务器授时用的。
特别鸣谢与参考资料
感谢 BH8TWO 送的 RaspberryPi
感谢 汽车工程学院 3D 打印社团 设计的 树莓派外壳
参考资料:
https://blog.csdn.net/xiaohu50/article/details/78731534
https://blog.csdn.net/qishi_blog/article/details/52843696
https://area-51.blog/2012/06/18/getting-gps-to-work-on-a-raspberry-pi/
等等在 Google 上搜到的资料……