【填坑】用树莓派+GPS模块搭建Stratum 1 NTP服务器

天锦 发表于 奴隶的创建与管理 分类,标签:

折腾完InfluxDB,咱接着折腾 NTP,因为时序数据库对时间要求比较高,就想到了搭建个一级的NTP服务器,硬件自然还是接着蹂躏我的那块树莓派3B(活着真不容易2333~

参考了网上的很多文章,多是东拼西凑得来的,坑很多,最终还是决定再写一篇!

硬件准备

一张树莓派3B、一个GPS模块一个(带PPS输出),GPS天线、杜邦线、电源、TTL串口线。

测试GPS模块

在折腾之前,先测试你的GPS模块都一切正常,接上GPS天线,把模块放置到开阔空旷的空间方便GPS模块搜星定位,把模块TXD,RXD线接到USB转串口TTL模块上,先在Window系统中测试模块能够正常定位,别折腾到最后是GPS模块的问题,保证模块正常工作后再在树莓派上折腾。

树莓派安装系统

建议到树莓派官网上下载full版本的系统镜像安装,我起初安装了lite版本的镜像,在添加PPS的时候死活是注册不了PPS源到Linux内核,更换了系统之后正常了。

反复验证,跟lite还是full版本的镜像无关,详见关于PPS的坑。树莓派官方的系统就OK了

线路连接

参考树莓派官网手册得到了树莓派的IO引脚定义

https://www.raspberrypi.org/documentation/usage/gpio/README.md

gpio-numbers-pi2.png

具体详细引脚定义可以在树莓派系统中执行pinout命令查看

[root@raspberrypi:~]# pinout

Pi_3_IO.png

我的模块是5V的供电,按照下表连接线路

GPS模块 树莓派
VCC (2)5V
GND (6)GND
TXD (10)GPIO15
PPS (12)GPIO18

GPIO15是树莓派串口的RXD接口,GPIO18则是树莓派pps-gpio默认的IO接口,后面会详细介绍。

设置树莓派串口

使用raspi-config工具启用串口并禁用通过串口登陆系统

[root@raspberrypi:~]# raspi-config

uart_config_1.png

uart_config_2.png

uart_config_3.png

需要注意的是Raspberry-Pi 3相比于1和2在使用串口的时候会有问题,原因是树莓派CPU内部有两个串口,一个是硬件串口(官方称为PL011 UART),一个是迷你串口(官方成为mini-uart)。在树莓派2B/B+这些老版树莓派上,官方设计时都是将“硬件串口”分配给GPIO中的UART(GPIO14&GPIO15),因此可以独立调整串口的速率和模式。而树莓派3的设计上,官方在设计时将硬件串口分配给了新增的蓝牙模块上,而将一个没有时钟源,必须由内核提供时钟参考源的“迷你串口”分配给了GPIO的串口,这样以来由于内核的频率本身是变化的,就会导致“迷你串口”的速率不稳定,这样就出现了无法正常使用的情况。

需要在/boot/config.txt修改

enable_uart=0

enable_uart=1

然后添加

dtoverlay=pi3-miniuart-bt
force_turbo=1

修改/boot/cmdline.txt 

删除所有的console=xxx的语句,例如将

dwc_otg.lpm_enable=0 console=tty1 root=/dev/mmcblk0p7 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait

修改为

dwc_otg.lpm_enable=0 root=/dev/mmcblk0p7 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait

修改蓝牙服务,编辑/lib/systemd/system/hciuart.service 

修改[Unit]中的After字段,由

After=dev-serial1.device

改成

After=dev-ttyS0.device

修改[Service]中的ExecStart字段,由

ExecStart=xxx(根据具体表示)

改成

ExecStart=/usr/lib/hciattach /dev/ttyS0 bcm43xx 460800 noflow -

注:其中的bcm43xx真的是xx哦

重启Raspberry Pi, 串口接下来可以用作通信

测试串口

在终端中用cat命令输出/dev/ttyAMA0的信息,可以看到GPS的相关信息

[root@raspberrypi:~]# cat /dev/ttyAMA0 
$GPRMC,073811.00,A,2923.85607,N,10553.02783,E,0.352,,300419,,,A*7D
$GPVTG,,T,,M,0.352,N,0.653,K,A*27
$GPGGA,073811.00,2923.85607,N,10553.02783,E,1,09,1.05,300.5,M,-27.0,M,,*79
$GPGSA,A,3,19,07,13,01,22,11,28,17,30,,,,1.68,1.05,1.32*0A
$GPGSV,4,1,13,01,65,073,23,03,15,129,,04,04,206,09,07,46,181,38*7F
$GPGSV,4,2,13,08,18,054,,11,56,041,17,13,07,294,31,17,35,269,39*72
$GPGSV,4,3,13,18,41,048,,19,14,254,22,22,20,107,16,28,46,329,19*79
$GPGSV,4,4,13,30,66,241,36*4A

安装gpsd后可以用gpsd查看GPS信息

root@raspberrypi:~# apt install gpsd gpsd-clients -y

用gpsmon查看GPS定位信息

root@raspberrypi:~# gpsmon /dev/ttyAMA0

可以看到

gps_info.png

如果数据不正常,可以用minicom或者stty设置端口的波特率为9600 8n1之后再试。

设置PPS

在/boot/config.txt文件中添加

dtoverlay=pps-gpio,gpiopin=18

在/etc/modules文件中添加

pps-gpio

重启树莓派后可以在/dev下面应该能看到pps0这个设备

[root@raspberrypi:~]# ls /dev/pps0
/dev/pps0

lsmod | grep pps能看到pps_gpio和pps_core两个模块

[root@raspberrypi:~]# lsmod | grep pps
pps_gpio               16384  0
pps_core               16384  2 pps_gpio

dmesg | grep pps应该能看到注册了PPS源相关字样

[root@raspberrypi:~]# dmesg | grep pps
[    1.966648] pps_core: LinuxPPS API ver. 1 registered
[    1.966657] pps_core: Software ver. 5.3.6 - Copyright 2005-2007 Rodolfo Giometti <giometti@linux.it>
[    1.981050] pps pps0: new PPS source pps@12.-1
[    1.981139] pps pps0: Registered IRQ 169 as PPS source

至此,PPS驱动设置完成,安装pps-tools以对PPS源测试

[root@raspberrypi:~]# apt install pps-tools -y

使用ppstest对pps0进行测试

[root@raspberrypi:~]# 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 1556611258.100036986, sequence: 13093 - clear  0.000000000, sequence: 0
source 0 - assert 1556611259.100037438, sequence: 13094 - clear  0.000000000, sequence: 0
source 0 - assert 1556611260.100037681, sequence: 13095 - clear  0.000000000, sequence: 0

每一秒输出一条,如果发现输出间隔不是1s,可能是连线错误或者gps模块未设置导致。

关于PPS的坑

树莓派因为没有BIOS,所以Raspbian对设备的加载都是依赖在/boot/config.txt中的配置来加载。当Linux内核加载时,会读取/boot/config.txt中的设备配置和设备参数配置来把设备动态加载到Device Tree(DT)中。所以是在/boot/config.txt文件中添加dtoverlay=pps-gpio,gpiopin=18而不是在/boot/cmdline.txt中添加,我所搜索到的文章 https://blog.csdn.net/xiaohu50/article/details/78731534 中有错误,致使我在/boot/cmdline.txt中添加了dtoverlay=pps-gpio,gpiopin=18,导致系统能够正常加载mod但是无法注册pps源,也就是dmesg中只能看到

[root@raspberrypi:~]# dmesg | grep pps
[    1.966648] pps_core: LinuxPPS API ver. 1 registered
[    1.966657] pps_core: Software ver. 5.3.6 - Copyright 2005-2007 Rodolfo Giometti <giometti@linux.it>

而没有显示

[    1.981050] pps pps0: new PPS source pps@12.-1
[    1.981139] pps pps0: Registered IRQ 169 as PPS source

最终查阅了树莓派设备树的相关资料才发现https://blog.csdn.net/xiaohu50/article/details/78731534 这篇文章有错误,应该将dtoverlay=pps-gpio,gpiopin=18添加到/boot/config.txt而不是添加到/boot/cmdline.txt中。非常感谢https://www.jianshu.com/p/80e713f91285 这篇文章。

安装NTP

系统自带的ntpd是阉割版的ntpd,不支持PPS,甚至有的系统都没有安装ntpd,所以需要到ntp官网下载ntp源码自行编译安装。

先卸载

[root@raspberrypi:~]# service ntp stop
[root@raspberrypi:~]# apt remove ntp

先安装编译所依赖的libcap-dev库:

[root@raspberrypi:~]# apt install libcap-dev -y

到 http://archive.ntp.org 下载最新的ntp源码到树莓派上

[root@raspberrypi:~]# wget http://archive.ntp.org/ntp4/ntp-4.2.8p13.tar.gz

解压配置编译安装

[root@raspberrypi:~]# tar xzf ntp-4.2.8p13.tar.gz
[root@raspberrypi:~]# cd ntp-4.2.8p13/
[root@raspberrypi:~/ntp-4.2.8p13]# ./configure --enable-linuxcaps
[root@raspberrypi:~/ntp-4.2.8p13]# make
[root@raspberrypi:~/ntp-4.2.8p13]# make install 
[root@raspberrypi:~/ntp-4.2.8p13]# cp /usr/local/bin/ntp* /usr/bin/
[root@raspberrypi:~/ntp-4.2.8p13]# cp /usr/local/sbin/ntp* /usr/sbin/
[root@raspberrypi:~/ntp-4.2.8p13]# service ntp start

配置NTPd从GPS获取时间

编辑/etc/ntp.conf添加NMEA

# NMEA refclock driver directly from serial port
server 127.127.20.1 mode 16 minpoll 4 iburst prefer true
fudge 127.127.20.1 flag1 1 flag2 0 flag3 0 flag4 0 time1 0.1 refid GPS

server, fudge的配置说明请参看man ntp.conf。这里的127.127.t.u并不是真实的ip地址,而是Reference clock,根据t来指定实际类型,根据u来指定设备。t对应的实际设备需要看文档,在源代码目录ntp/html/drivers/driverxx.html中也有。参考 driver20.html可知,若要从GPS设备中获取时间,需要将t写为20,也就是127.127.20.u,u为设备号,也就是/dev/gps0,/dev/gps1等类似于/dev/gpsu设备,通过创建GPS的串口的软连接可以得到/dev/gpsu,

我将我的串口/dev/ttyAMA0软连接到/dev/gps1,所以server的地址就应当是127.127.20.1

[root@raspberrypi:~]# ln -s /dev/ttyAMA0 /dev/gps1

driver20.html中提到:

Address: 127.127.20.u
Reference ID: GPS
Driver ID: GPS_NMEA
Serial Port: /dev/gpsu; 4800 - 115200 bps, 8-bits, no parity
Serial Port: /dev/gpsppsu; for just the PPS signal (this is tried first for PPS, before /dev/gpsu)

也就是不仅有/dev/gpsu,还要有/dev/gpsppsu,也就是GPS中的PPS,同样,通过创建软连接得到

[root@raspberrypi:~]# ln -s /dev/pps0 /dev/gpspps1

有的文章中有提到再添加一个单独的PPS设备的,其实没有必要的,因为GPS中的PPS信号已经通过driver20中的/dev/gpsppsu传入NTPd了,不需要再添加PPS Driver(driver22)(172.172.22.u)

配置完成后重启ntp

[root@raspberrypi:~]# service ntp restart

测试NTP

NTP重启后稍等几分钟后执行ntpq -crv -p应该可以看到以下信息:

[root@raspberrypi:~]# ntpq -crv -p
associd=0 status=0415 leap_none, sync_uhf_radio, 1 event, clock_sync,
version="ntpd 4.2.8p13@1.3847 Tue Apr 30 03:35:42 UTC 2019 (1)",
processor="armv7l", system="Linux/4.14.79-v7+", leap=00, stratum=1,
precision=-20, rootdelay=0.000, rootdisp=1.060, refid=GPS,
reftime=e0726e8f.ba9ef0c1  Tue, Apr 30 2019 14:49:51.728,
clock=e0726e94.81d1fa5b  Tue, Apr 30 2019 14:49:56.507, peer=6494, tc=4,
mintc=3, offset=-0.000261, frequency=2.297, sys_jitter=0.000954,
clk_jitter=0.001, clk_wander=0.000
     remote           refid      st t when poll reach   delay   offset  jitter
==============================================================================
 0.pool.ntp.org  .POOL.          16 p    -   64    0    0.000    0.000   0.001
oGPS_NMEA(1)     .GPS.            0 l    5   16  377    0.000    0.000   0.001
*203.107.6.88    10.137.38.86     2 u   33   64  377   44.138  -94.476   0.093
-45.43.30.59 (st 216.218.254.202  2 u  175   64  304  219.931  -98.853   1.722
-sv1.ggsrv.de    205.46.178.169   2 u   32   64  277  239.642  -98.971   2.007
+167.99.110.109  64.62.153.210    3 u   36   64  137  194.662  -98.467   0.349
-ntp.wdc1.us.lea 130.133.1.10     2 u   40   64  123  248.103  -94.458   0.758
-ntp6.flashdance 192.36.143.150   2 u   29   64  377  353.068  -91.349  12.499
-electrode.felix 56.1.129.236     3 u   35   64  375  236.587  -90.245   1.789
+119.28.183.184  100.122.36.4     2 u   24   64  377   50.639  -87.102   6.290

表中第一个字符(统计代码)是状态标识(参见 Peer Status Word),包含 " ","x","-","#","+","*","o":

" " – 无状态,表示:

    没有远程通信的主机

    "LOCAL" 即本机

    (未被使用的)高层级服务器

    远程主机使用的这台机器作为同步服务器

"x" – 已不再使用

"-" – 已不再使用

"#" – 良好的远程节点或服务器但是未被使用 (不在按同步距离排序的前六个节点中,作为备用节点使用)

"+" – 良好的且优先使用的远程节点或服务器(包含在组合算法中)

"*" – 当前作为优先主同步对象的远程节点或服务器

"o" – PPS 节点 (当优先节点是有效时)。实际的系统同步是源于秒脉冲信号(pulse-per-second,PPS),可能通过PPS 时钟驱动或者通过内核接口。

在同网段的Linux机器中使用ntpdate -d ip来测试NTP服务器是否正常授时

[root@linux ~]# ntpdate -d 10.60.60.100
30 Apr 14:48:21 ntpdate[24028]: ntpdate 4.2.6p5@1.2349-o Fri Apr 13 12:52:28 UTC 2018 (1)
Looking for host 10.60.60.100 and service ntp
host found : 10.60.60.100
transmit(10.60.60.100)
receive(10.60.60.100)
transmit(10.60.60.100)
receive(10.60.60.100)
transmit(10.60.60.100)
receive(10.60.60.100)
transmit(10.60.60.100)
receive(10.60.60.100)
server 10.60.60.100, port 123
stratum 1, precision -20, leap 00, trust 000
refid [GPS], delay 0.02611, dispersion 0.00003
transmitted 4, in filter 4
reference time:    e0726e3f.ba9ed2b5  Tue, Apr 30 2019 14:48:31.728
originate timestamp: e0726e3f.cfb24bac  Tue, Apr 30 2019 14:48:31.811
transmit timestamp:  e0726e3c.1aa8c4c5  Tue, Apr 30 2019 14:48:28.104
filter delay:  0.02612  0.02611  0.02629  0.02615 
         0.00000  0.00000  0.00000  0.00000 
filter offset: 3.706743 3.706803 3.706777 3.706823
         0.000000 0.000000 0.000000 0.000000
delay 0.02611, dispersion 0.00003
offset 3.706803
30 Apr 14:48:28 ntpdate[24028]: step time server 10.60.60.100 offset 3.706803 sec
[root@linux ~]#

可以看到NTP服务器已经使用了GPS作为时间源给Client授时。

参考博文

https://blog.csdn.net/xiaohu50/article/details/78731534

https://blog.csdn.net/qishi_blog/article/details/52843696

https://www.jianshu.com/p/80e713f91285


0 篇评论

发表我的评论