把 PC的系统时间 通过USB转串口发出来 来模拟 PPS+GPRMC 授时, 这大冷天的, 用来在室内测试MCU或者SOC的授时功能, 传感器的授时与线束检测, 测试干扰等等, 还是比较合适的.
如下图, 左边为 USB转9针RS232串口, 右边为 USB转TTL串口
原理:
- PPS 有 3V3 / 5V /
12V等规格, 这里用串口芯片的RTS引脚来模拟PPS(DTR引脚也可以), 左边RS232的DB9口中虽然也有RTS引脚, 但是实测是±9V, 所以用右边的USB转TTL芯片的3.3V的RTS来代替 - GPRMC 是RS232 电平, 直接用左边DB9中的PIN3–TXD引脚发出来就可以了
- 图左都是RS232电平, 图右都是TTL电平, 所以才用了两个来混搭, 如果自己打板子用一个USB转串口芯片+RS232芯片就够了
Python3 的脚本1.py
如下(Win下为 COM*, Ubuntu下为/dev/ttyUSB*, 需要先安装pyserial和nmeasim
)
#!/usr/bin/python3
# python3 -m pip install pyserial
# python3 -m pip install nmeasim
from nmeasim.models import GpsReceiver
from threading import Timer
from datetime import datetime
import serial
ttl_ser = serial.Serial('COM7') # 右边板子的串口号, 用到RTS或者DTR引脚, 模拟PPS
rs232_ser = serial.Serial(port="COM14", baudrate=9600) # 左边板子的串口号, 用到TXD, 9600波特率, 模拟GPRMC
gps = GpsReceiver(output=('RMC',)) # 单GPRMC输出
# https://gitlab.com/nmeasim/nmeasim/-/blob/master/nmeasim/models.py
# output=("GGA", "GLL", "GSA", "GSV", "RMC", "VTG", "ZDA")
def pps_high():
ttl_ser.setRTS(False) # -9V, 3.3V, PPS输出高, 如果用DTR引脚就setDTR
def pps_low():
ttl_ser.setRTS(True) # 9V, 0V, PPS输出低
def pps_init():
# print('pps_init')
pps_low() # 初始低电平
def gprmc_out():
gps.date_time = datetime.now() # 获取电脑的系统时间
gps.__lat_sign = 'N' # GPRMC中的一些信息, 只要时间的话下面这些参数可以不用设置
gps.lat = 39.1234
gps.__lon_sign = 'N'
gps.lon = 116.5678
gps.__mag_sign = 'E'
gps.mag_var = 4.1
gps.kph = 1.0
gps.heading = 1.0
rs232_ser.write(gps.get_output()[0].encode('utf-8') + b'\r\n') # 发出GPRMC信息, 结尾加上\r\n
# print(gps.get_output()[0].encode('utf-8'))
# ts = datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S.%f')[:-3]
# print('gprmc_out :', ts, ts[-3:])
# print()
def pps_out():
pps_high()
ts = datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S.%f')[:-3] # 精确到ms
print(ts)
Timer(1 - int(ts[-3:])/1000, pps_out).start() # 每次都进行补偿
Timer(0.02, pps_init).start() # PPS高电平持续时间20ms, 示波器实测约32ms
Timer(0.10, gprmc_out).start() # PPS上升沿后100ms, 发出GPRMC
pps_init()
pps_out()
运行python3 1.py
, 环境为 Win10, i7-8086K, 测试时间为 2021年12月30日, 北京时间减去8小时就是下面GPRMC中的时间
换算成十六进制, 结尾一定要有0x0D, 0x0A, 如果没有, 以Velodyne的激光雷达VLP-16为例, 即便网页可能有之前的GPS Position信息, 但是Wireshark里面抓到的512字节的数据包只会显示PPS Locked, 却没有GPRMC信息
左边为PPS发出的时间戳, 加上8小时刚好是北京时间, 精度在4ms以内, 通用测试还是可以的
PPS波形(CP2104芯片, PPS高电平持续时间, 示波器实测脉宽比设置的20ms多出12ms, 不过PPS用的上升沿, 这个应该影响不大)
两个脉冲上升沿的间隔 1s
上升沿有点惨不忍睹 快1ms了, 这带来的PPS误差又多了1ms, 把9600bps改成115200bps也没有改善, 换成CH340或者空载差别也不大, 如果用MCU来模拟可能会好一点, 或者加个74芯片
如果只是单纯授时, 脚本中不要定位信息也是可以的, 如下
def gprmc_out():
gps.date_time = datetime.now()
rs232_ser.write(gps.get_output()[0].encode('utf-8') + b'\r\n')
# $GPRMC,024941.113,A,0000.000,N,00000.000,E,0.0,0.0,301221,,,A*64
# $GPRMC,024942.119,A,0000.000,N,00000.000,E,0.0,0.0,301221,,,A*6D
# $GPRMC,024943.114,A,0000.000,N,00000.000,E,0.0,0.0,301221,,,A*61
# $GPRMC,024944.113,A,0000.000,N,00000.000,E,0.0,0.0,301221,,,A*61
# $GPRMC,024945.119,A,0000.000,N,00000.000,E,0.0,0.0,301221,,,A*6A
用VLP-16做个测试, 首先看下VLP-16用户手册中时间同步的要求:
- PPS + 每秒一次的NMEA V2.3 GPRMC 或 GPGGA
- PPS是固定的, 后面的NMEA 可以通过 串口 或者 以太网口 发送, 以太网口需要通过 TCP/UDP/广播 发送 NMEA 消息 到 10110 端口, 这里就不考虑了, 以下GPRMC只指通过串口 RS232电平 发出来的信息
- PPS和GPRMC在高电平要能提供至少2mA的电流, 可能是为了抗干扰, 加了类似光耦的装置? 想要一根线挂很多激光雷达可能不太行
- PPS是TTL电平, 3.3V/5V, 脉宽10us-200ms, 下面程序里设置成20ms
- GPRMC是RS232电平, 9600bps, 格式可以是 HHMMSS, HHMMSS.s, HHMMSS.ss, 或 HHMMSS.sss(上面程序用的这个), 结尾要有0x0D, 0x0A, 也就是
\r\n
或者叫<CR><LF>
, 时序要求见下图, 下面程序里设置成PPS上升沿100ms后发出
一开始网页界面重叠, 还以为是雷达坏了
其实是浏览器的字体设置成特大了, 改成推荐的中就正常了(相信有遇到同样情况的)
没有 PPS+GPRMC
授时的时候显示
发出PPS+GPRMC后, 网页显示锁定
Wireshark也能抓到GPRMC的包
00f4
位置的02
代表PPS Locked
, 测试完成.
欢迎扫描二维码关注本人微信公众号, 及时获取最新文章: