多传感器的时间同步

摘要:本文利用GPS的GPRMC消息及PPS信号,对多种传感器进行时间同步,涉及了不同的方法,总有一个适合你传感器的方法。

时间同步基础


gprmc是gps所返回的一种国际标准信息,里面不仅带有经纬度欧拉角等信息,还带有当前的utc时间。但是数据的传输需要时间,往往所接收到的gprmc信息中的utc时间相比实际时间相差几百毫秒。而pps脉冲(每秒一个脉冲)精度非常高,可以达到几百毫秒,利用pps脉冲和gprmc中的utc时间,就可以精度校准系统的时间。

gps信息回顾


本文方法理论上使用绝大多少GPS。这里所使用的星网宇达xw-gi5610,其带有3路com,com0 rs232接电脑,输出gpfpd;com1固定422;com2接rtk,使gps接受rtk信号。另外有5V的pps脉冲,但是这个脉冲一般情况为高电平,触发时低电平,故使用的时候需要反相。

GPRMC+PPS同步


一些传感器原生支持GPRMC+PPS同步,比如rs-lidar-16雷达等。但是需要注意PPS的电平,以及串口的协议。比如这里GPS为5V的PPS,RS422的串口,雷达端支持3.3V TTL的串口,3.3V的PPS因此需要自行设计转换电路,如下图(仅举例,不详细介绍)。
电平转换电路

基于网络时间的同步


一些使用网络的传感器,如Livox Horizon雷达,不支持GPRMC+PPS同步,取而代之的是PTP网络同步协议(或NTP)。但是一般的GPS只有GPRMC+PPS的输出,为了实现PTP同步,这里使用一块OrangePi Zero读取TTL电平的GPRMC和PPS脉冲。

orangepi

尽管orangepi zero(以下简称zero)所使用的全志H2芯片内置了rtc,但是zero没有引出rtc的供电引脚,因此在掉电之后,系统时间会停滞不前,这在我们的车辆环境上不可容忍。因此加装了一块i2c接口的ds1307模块,接线如下。

外设 zero引脚 zero引脚序号
TXD UART1_RX/PG06 PIN10
RXD UART1_TX/PG07 PIN8
PPS SIM_CLK/PA07 PIN12
SCK TWI1-SCK/PA18 PIN11
SDA TWI1-SDA/PA18 PIN13
VCC 3.3V PIN1
GND GND

NTP同步

随后使用gpsd读取gps数据,传入chrony,使orangepi zero成为一个ntp时间服务器。

PTP同步

另外由于orangepi zero的网卡支持软件ptp时间戳,所以使用ptp4l建立一个ptp主时钟。至此orangepi时间服务器建立完成。
除了传感器,工控机也可以使用NTP或PTP同步时间。比如Livox的雷达就支持PTP时间同步。

参考配置

注意本文所用的为orangepi zero,系统为 armbian


rtc配置

sudo armbian-config

  1. Select System and click on OK
  2. Click on hardware and click OK
  3. turn on i2c-0

/etc/default/hwclock
加上两句,配置rtc1为默认rtc

1
2
HWCLOCKACCESS=yes
HCTOSYS_DEVICE=rtc1

新建/etc/systemd/system/ds1307.service文件,内容如下

1
2
3
4
5
6
7
8
9
10
11
[Unit]
Description=ds1307 service
Before=hwclock.service chronyd.service

[Service]
Type=oneshot
ExecStart=/etc/ds1307.sh
PrivateTmp=true

[Install]
WantedBy=multi-user.target

新建/etc/ds1307.sh文件,内容如下

1
2
3
4
5
6
#!/bin/sh
echo "ds1307 0x68" > /sys/class/i2c-adapter/i2c-0/new_device
sleep 1
hwclock -s -f /dev/rtc1
hwclock --systohc -f /dev/rtc1
sleep 1

赋予权限sudo chmod +x /etc/ds1307.sh

重新加载服务sudo systemctl daemon-reload

开机启动sudo systemctl enable ds1307.service

gps配置

sudo armbian-config

  1. Select System and click on OK
  2. Click on hardware and click OK
  3. turn on pps-gpio and uart1
  4. Click on Edit Boot Environment (you can also edit this file directly /boot/armbianEnv.txt)
  5. Add two lines to tell the Orange Pi Zero to use PA7 for PPS and uart1 for GPS NMEA messages
1
2
overlays=uart1 pps-gpio
param_pps_pin=PA7

安装相关软件

1
2
3
4
5
sudo apt-get update
sudo apt-get upgrade
sudo apt-get remove ntp
sudo apt-get install chrony ptpd
sudo apt-get install pps-tools gpsd-clients

之后插入pps和gprmc,重启

检查GPS信号

1
2
sudo ppstest /dev/pps0
gpsmon /dev/ttyS1

In order for NTPsec to recognise the GPS PPS combo we need to create some symlinks in /dev

1
2
sudo ln -sF /dev/ttyS1 /dev/gps1
sudo ln -sF /dev/pps0 /dev/gpspps1

Create a new file in /etc/udev/rules.d called 99-gps.rules with the following:

1
2
KERNEL=="pps0",SYMLINK+="gpspps1",GROUP="dialout", MODE="0660"
KERNEL=="ttyS1", SYMLINK+="gps1",GROUP="dialout", MODE="0660"

配置chrony

/etc/chrony/chrony.conf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# This directive specify the location of the file containing ID/key pairs for
# NTP authentication.
keyfile /etc/chrony/chrony.keys

# This directive specify the file into which chronyd will store the rate
# information.
driftfile /var/lib/chrony/chrony.drift

# Uncomment the following line to turn logging on.
#log tracking measurements statistics

# Log files location.
logdir /var/log/chrony

# Stop bad estimates upsetting machine clock.
maxupdateskew 100.0

leapsectz right/UTC
makestep 1.0 -1
# GPS配置
refclock PPS /dev/gpspps1 lock GPSD prefer refid PPS
refclock SHM 0 offset 0.0 delay 0.2 refid GPSD

# 允许其他客户端连接
allow

#server 192.168.1.194 minpoll 2 maxpoll 4 polltarget 30 maxdelaydevratio 2 iburst
#leapsectz right/UTC
#makestep 1.0 -1
#rtconutc
#rtcfile /var/lib/chrony/rtc
#rtcdevice /dev/rtc0
rtcdevice /dev/rtc1
hwclockfile /etc/adjtime
rtcautotrim 30
rtcsync

修改/etc/systemd/system/chronyd.service文件,内容如下(即设置让它在ds1302之后启动)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
[Unit]
Description=chrony, an NTP client/server
Documentation=man:chronyd(8) man:chronyc(1) man:chrony.conf(5)
Conflicts=systemd-timesyncd.service openntpd.service ntp.service ntpsec.service
After=network.target ds1307.service
ConditionCapability=CAP_SYS_TIME

[Service]
Type=forking
PIDFile=/run/chronyd.pid
EnvironmentFile=-/etc/default/chrony
ExecStart=/usr/sbin/chronyd $DAEMON_OPTS
ExecStartPost=-/usr/lib/chrony/chrony-helper update-daemon
PrivateTmp=yes
ProtectHome=yes
ProtectSystem=full

[Install]
Alias=chronyd.service
WantedBy=multi-user.target

重新加载服务sudo systemctl daemon-reload

开机启动sudo systemctl enable chronyd.service

配置ptp

1
2
3
sudo apt install ptpd
# 删除默认的ptpd.service(如果有)
sudo rm /etc/systemd/system/ptpd.service

新建/etc/init.d/ptpd
以下为文件内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#!/bin/sh
#
# /etc/init.d script for ptpd

### BEGIN INIT INFO
# Provides: ptpd
# Required-Start: $network $remote_fs
# Required-Stop: $network $remote_fs
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: start and stop ptpd
# Description: ptpd is the Precision Time Protocol daemon (IEEE1588-2008)
### END INIT INFO

PATH=/sbin:/usr/sbin:/bin:/usr/bin
DESC="Precision Time Protocol daemon"
NAME=ptpd
DAEMON=/usr/sbin/$NAME
PIDFILE=/var/run/ptpd2.lock
SCRIPTNAME=/etc/init.d/$NAME
# Exit if the package is not installed
[ -x "$DAEMON" ] || exit 0

case $1 in
start)
a=$( ip addr show to 192.168.1.194/16 | wc -l )
until [ "$a" -gt 0 ]
do
a=$( ip addr show to 192.168.1.194/16 | wc -l )
echo Sleeping
sleep 1
done
#What it does:
#print all address of ipv4 interfaces | filter out the link-local address(es) | substitute all the remaining information except for the ': if-name ' part. | strip the leading ': ' and trailing ' '.
#Lastly, the $(...) is called 'command substution' which in this case dumps the output into the variable IF_NAME.
IF_NAME=$(ip -o -4 addr | grep -e 192.\168 | sed -n 's/.*\(: [a-zA-Z0-9]* \).*/\1/ p' | sed -n 's/: \([a-zA-Z0-9]*\) /\1/ p')
start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON -v -- -i $IF_NAME -M \
|| return 0
;;
stop)
start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE --name $NAME
;;
*)
echo "Usage: {start|stop}"
;;
esac

随后更新

1
2
3
4
sudo update-rc.d ptpd start 98 2 3 4 5 . stop 2 0 1 6 
sudo systemctl daemon-reload
sudo systemctl enable ptpd
sudo systemctl restart ptpd

参考资料

Livox雷达时间同步文档

作者

Yida

发布于

2020-11-15

更新于

2022-03-01

许可协议

评论