一、原理
GNSS输出两条信息,一条是时间周期为1s的同步脉冲信号PPS,脉冲宽度5ms~100ms;一条是通过标准串口输出GPRMC标准的时间同步报文。GPRMC报文中的时间是通过NTP获得的。
同步脉冲前沿时刻与GPRMC报文的发送在同一时刻,误差为ns级别,误差可以忽略。GPRMC是一条包含UTC时间(精确到秒),经纬度定位数据的标准格式报文。
PPS秒脉冲为物理电平输出,接收及处理PPS信号的时间在ns级别,依旧可以忽略。但GPRMC数据一般通过波特率9600的串口发送,发送、接收、处理时间tx在ms级别,是时间同步的关键。
1)设备收到PPS秒脉冲信号后,将内部以晶振为时钟源的系统时间里的毫秒及以下时间清零,并由此开始计算毫秒时间。
(2)当收到GPRMC数据后,提取报文里的时、分、秒、年、月、日UTC时间。
(3)将收到秒脉冲到解析出GPRMC中UTC时间所用的时间tx,与UTC整秒时间相加,同步给系统时间,至此已完成一次时间同步。下一秒再进行相同的过程,每秒准确校准一次。
但是PPS+GPRMC存在如下问题。
(1)PPS是一个低功率的脉冲电平信号,驱动电流少的只有0.5mA,多的也就20mA,带几个同步节点(激光雷达和其他需要时间同步的节点),十几个就很困难了。
(2)PPS是无屏蔽的单线脉冲信号,十几根PPS线穿梭在车内,极易受到车内恶劣电磁环境的干扰,届时根本无法区分出是干扰脉冲还是同步脉冲。
(3)GPRMC通过RS232串口发送同步报文,RS232是一种1对1的全双工通信形式,也可以通过主从形式实现1对几数据传输。但对十几,实属罕见,只能通过试验验证到底可不可行。但至少线束工程师是打死不愿答应的。
(4)当时钟源丢失的时候,所有需要时间同步的设备都一下子没有了主心骨,每个小弟都可以自立门户,没有二当家的及时站出来,主持大局。这对功能安全要求极高的自动驾驶系统来说,根本无法接受。
二、PPS+GPRMC接入工控机
需满足条件:
1.工控机支持;(不支持的设备可以考虑GPIO)
2.GNSS给出PPS和GPRMC,接入到设备;
我们的工控机往往采用的都是linux内核的ubuntu系统,例如目前主流使用的Ubuntu18.04以及20.04。
工控机支持,首先工控机要能够接收到PPS信号以及GPRMC串口信息等,有内部晶振控制授时(这个一般目前的工控机都具备)
打开你的设备手册
找COM口的说明(一般通过9针COM接入)
查阅发现4个COM口都是支持RS232 mode的也就是GNSS接入的Mode,这里需要指明的是这四个COM口对应设备的(ttyS0~ttyS3)。可以发现Pin1是可以接收DCD的,也就是这个pin接入PPS,RX为接收口、TX为发出口、5Pin为GND。
接下来查阅GNSS手册,根据要求接线:
参考接线方式(需要根据pin定制),将最右边的看作GNSS
确认GPRMC是否正常接入:
下载诸如cutecom等串口管理工具来查看
sudo apt install cutecom
如果你插入到COM1口:
点击open device能看到GPRMC的滚动输出说明GPRMC正常接入了
确认PPS是否正常接入:
PPS如何传到系统层呢?查询ubuntu的系统kernel版本后,在linux doc中:
PPS - Pulse Per Second — The Linux Kernel documentation
可以找到关于PPS的内容,发现LinuxPPS目前已经是内置了。
检查pps状态:
grep '^CONFIG_PPS' /boot/config-$(uname -r)
输出应为:
CONFIG_PPS=m (为y也没问题)
CONFIG_PPS_CLIENT_LDISC=m
配置PPS_ldisc.service
将下述etc/systemd/system/pps_ldisc.service 放到/etc/systemd/system下
[Unit]
Description=Modprobe pps_ldisc
After=setserial.service
[Service]
Type=oneshot
ExecStart=/sbin/modprobe pps_core
ExecStart=/sbin/modprobe pps_ldisc
[Install]
WantedBy=gpsd.service
执行:
systemctl enable pps_ldisc.service
systemctl start pps_ldisc.service
#第一行使得开机能自启,第二行启动这个service
(非必要)安装Setserial ,此举是为了低延迟和提升准确率
sudo apt-get install setserial
安装后,在var/lib/setserial/autoserial.conf 中修改:
#
###AUTOSAVE-ONCE###
###AUTOSAVE-ONCE###
###AUTOSAVE###
#
# If you want to configure this file by hand, use
# dpkg-reconfigure setserial
# and change the configuration mode of the file to MANUAL. If you do not do this, this file may be overwritten automatically the next time you upgrade the
# package.
#
# dpkg-reconfigure setserial ... set configuration mode to MANUAL
# Added next line for ttyS1 for Garmin 18 LVC GPS
# From: http://www.rjsystems.nl/en/2100-ntpd-garmin-gps-18-lvc-gpsd.php
# Only needed to add 'low_latency' to default port configuration
# Print out current port configuration:
# setserial -G /dev/ttyS1
/dev/ttyS1 uart 16550A port 0x02f8 irq 3 baud_base 115200 spd_normal skip_test low_latency
#该文件仅需修改上面的端口映射ttyS1代表COM2口,此地需要根据你真实接入的串口修改,
#UART越大,内部buffer就越大(16550A有16位的buffer),但是对于本任务来说,不用UART更好,
#因为缓冲区会增加延迟从而降低精度;为了最大限度地降低 CPU 利用率,默认情况下,
串口流量通常会延迟 5 到 10 毫秒。但是,在这种情况下,使用了 low_latency 设置,
#设置高一点的CPU负载是值得的。
#115200是波特率,可以尝试改为9600,如果改动后找不到数据了,就改回来
然后运行:
dpkg-reconfigure setserial
点击OK,选择为MANUAL;(可能会有错误提示)
重启该service:
for op in stop start; do systemctl $op setserial.service; done
pps测试:
sudo ppswatch /dev/pps1
#pps1后面的数字根据实际情况来 可使用ppsfind --help
说明PPS正常