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,这是授时所必须的。另外也十分建议板载电池,这有助于在热启动时有更快的定位和获取时间的速度。板载天线接口,可扩展天线。

BD-GPS

软件调整

正点原子 GPS+ 北斗双定位模块 S1216 开发工具包

推荐使用 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 上搜到的资料……