激光雷達和相機的時間同步是做自動駕駛感知方面實驗的基礎,目前網路上給出的各種解決方案都不是很完整,博主也走了不少彎路,最后探索出一個較為完整的低成本解決方案(重點是低成本,可靠性一般),這是第一次在CSDN上寫作,寫得不好還請各位看官批評指正哈哈!
文章目錄
- 總體技術路線
- 設備選型
- 激光雷達和相機的內部時鐘同步
- GPS到激光雷達的時間同步
- GPS到樹莓派的時間同步/樹莓派做PTP授時服務器
- 樹莓派串口配置
- 開啟樹莓派pps-gpio
- 關閉樹莓派ntpd功能
- 使用gpsd和chronyd對樹莓派進行授時,使用ptp4l把樹莓派配置為授時服務器
- gpsd配置
- chronyd配置
- PTP4l配置
- 樹莓派到工控機的時間同步
- 更改ptp4l組態檔
- 更改chronyd組態檔
- 樹莓派到相機的時間同步
- 激光雷達和相機的同步采集
- 更進一步
- 參考文獻
- 本博文原創,轉發請注明出處!
總體技術路線
激光雷達和相機的時間同步是多傳感器融合是先決條件,但是精確的時間同步需要涉及到軟體和硬體的相關知識,因此也是不大容易實作的,下面是目前網路上已有的資料(截止到2021.03.21):
- 激光雷達與相機標定時的時間同步問題怎么進行解決?
- 在自動駕駛領域,如何實作激光雷達和相機的時間同步呢?
- 激光雷達與相機標定的時間戳同步問題
- Camera-LIDAR_Detection_Fusion
- 無人駕駛中和傳感器有關的事兒
其中蘇笑云大佬的回答是比較清晰,大佬提到:更徹底的解決方法是選擇可以觸發拍攝的相機(必須是硬體線控),根據激光雷達的幀周期同步觸發相機的拍攝,實作雷達和相機的完全幀同步,實作完全的毫秒級同步, 本文也是根據這個解決方案來做的,所謂激光雷達與相機時間同步其實涉及到兩個問題:一個是激光雷達和相機的內部時鐘要同步;一個是要對采集出來的點云和影像進行時間對齊,因此本文也是從這兩個方面來進行技術路線的描述的,本文的技術路線也參考了上述的論文《Camera-LIDAR_Detection_Fusion》,有一說一,這篇本科畢業論文寫得很不錯!
設備選型
- GPS,能夠輸出PPS和NMEA串口信號,淘寶有很多款可以支持,不過買回來需要用示波器測驗一下,博主就踩過劣質GPS的坑…
- 樹莓派,作為網路授時主時鐘,應該隨便一款應該都行,博主使用的是樹莓派4B+
- 相機,要能夠支持外部硬體觸發,要能支持PTP時間同步功能,要能支持輸出影像曝光時相機的內部時間戳,博主使用的是Basler的工業相機
- 激光雷達,要能支持基于PPS和NMEA的時間同步(或者PTP時間同步,雖然博主沒有調通這個功能),能夠支持輸出點云采集時激光雷達內部的時間戳,博主使用的是速騰激光雷達
- 單片機,把GPS輸出的PPS信號轉發為同相位的10Hz方波,給相機做硬體觸發,要求單片機支持定時器,中斷,GPIO,博主還沒來得及實作單片機的功能,目測STM32就可以了,
激光雷達和相機的內部時鐘同步

激光雷達和相機的內部時鐘同步示意圖
GPS到激光雷達的時間同步
這個需要參考的激光雷達說明檔案啦,像速騰激光雷達,還對PPS和NMEA串口信號的格式做個限制,所以需要提前用示波器看買來的GPS模塊是否符合要求,這一步成功之后,在RSVIEW的web端的GPS Data一欄會顯示串口資訊、GPS Status和PPS Status一欄Locked,
GPS到樹莓派的時間同步/樹莓派做PTP授時服務器
這一步比較麻煩,這里主要使用的是gpsd、chronyd、ptp4l這幾個軟體,博主假設樹莓派已經刷了官方系統,接好了各種外設,
樹莓派串口配置
由于樹莓派外設一共包含兩個串口,一個稱之為硬體串口(/dev/ttyAMA0),一個稱之為mini串口(/dev/ttyS0),硬體串口由硬體實作,有單獨的波特率時鐘源,性能高、可靠,樹莓派(3/4代)板載藍牙模塊,默認的硬體串口是分配給藍牙模塊使用的,而性能較差的mini串口是分配給GPIO串口 TXD0、RXD0,但是我們不能使用mini串口,因此得把硬體串口分配給GPIO串口 TXD0、RXD0,具體的方法在網上可以查到很多資源,這里推薦樹莓派的官方教程,這一步做完后,接好線,然后使用串口工具cutecom就可以查到GPS發過來的串口信號了,也可以使用gpsmon對GPS信號進行決議,
開啟樹莓派pps-gpio
為什么精確授時需要pps和NMEA缺一不可呢?這是因此設備處理NMEA資訊(通常是串口信號)需要較長時間,處理完就已經早就錯過NMEA資訊所描述的那個時刻了,而PPS是一個1hz的方波,方波的上升沿可以觸發設備的硬體中斷功能,同時記錄下這個時刻,這樣處理完NMEA資訊的時候,就知道對應的是哪個時刻了,開啟樹莓派pps-gpio功能的教程是這個,配置完成后,重啟樹莓派,使用ppstest去測驗,
關閉樹莓派ntpd功能
因為我們需要讓樹莓派跟gps同步,因此需要關閉樹莓派ntpd功能,避免樹莓派通過網路時間同步,在命令列輸入rcconf,安裝提示操作就可以了,很簡單,
使用gpsd和chronyd對樹莓派進行授時,使用ptp4l把樹莓派配置為授時服務器
終于到重點了,這里先對這三個軟體的功能做一個介紹,
gpsd的功能是決議NMEA資訊和pps信號,獲取當前GPS時間,但是它沒有辦法給樹莓派系統授時;chronyd能夠給樹莓派系統授時,但是需要從gpsd獲取當前GPS時間,chronyd和gpsd的通訊是通過共享記憶體實作的,這需要對chronyd做一定的配置;ptp4l是PTP同步,即精確網路時間同步協議的軟體,它需要從chronyd獲取系統當前時間,然后發布到局域網,給相機和工控機授時,ptp4l與chronyd的通訊也是通過共享記憶體,下面分別介紹怎么配置這三個軟體:
gpsd配置
其實并不需要配置,直接開啟就完事了哈哈,
sudo killall -9 gpsd chronyd
sudo gpsd -n -G /dev/ttyAMA0
但是開啟之后,需要用一些軟體來測驗一下有沒有開啟成功,如下面所示:
gpsmon
----------------------------------------------------------
/dev/ttyAMA0 u-blox>
┌──────────────────────────┐┌─────────────────────────────────────────────────┐ or":12}
│Ch PRN Az El S/N Flag U ││ECEF Pos: -2324739.37m +5387509.44m +2492042.31m │ ver":"u-blox","subtype":"SW ROM CORE 3.01 (107888),HW 00080000,FWVER=SPG 3.01,PROTVER=18","activated":"20
│ 0 3 224 6 28 060f Y ││ECEF Vel: +0.02m/s +0.03m/s +0.01m/s │ 1,"cycle":1.00,"mincycle":0.25}]}
│ 1 4 262 62 26 060f Y ││ │ false,"timing":false,"split24":false,"pps":true}
│ 2 7 313 8 30 070f Y ││LTP Pos: 23.150042180° 113.340458154° 96.91m │
│ 3 8 208 56 28 060f Y ││LTP Vel: 0.03m/s 272.8° 0.02m/s │
│ 4 9 303 36 28 070f Y ││ │
│ 5 11 0 165 29 0710 ││Time: 51 15:33:40.00 │
│ 6 16 21 43 28 070f Y ││Time GPS: 2150+446242.000 Day: 5 │
│ 7 18 51 3 25 040c ││ │
│ 8 21 179 8 0 010c ││Est Pos Err 11.51m Est Vel Err 0.00m/s │
│ 9 22 201 3 0 010c ││PRNs: 6 PDOP: 2.6 Fix 0x03 Flags 0xdf │
│10 26 48 26 0 010c │└─────────────────── NAV_SOL ─────────────────────┘
│11 27 75 81 35 070f Y │┌─────────────────────────────────────────────────┐
│12 31 109 21 43 070c ││DOP [H] 1.8 [V] 2.0 [P] 2.6 [T] 1.6 [G] 3.1 │
│13 127 256 21 0 0004 │└─────────────────── NAV_DOP ─────────────────────┘
│14 128 236 47 39 070c │┌─────────────────────────────────────────────────┐
│15 132 223 55 0 0104 ││TOFF: 0.095508862 PPS: -0.000000278 │
└────── NAV_SVINFO ────────┘└─────────────────────────────────────────────────┘
------------------- PPS offset: 0.000000096 ------
(60) b56201063400300d991aa5640300660803df98ba24f2c8af1c20278eda0e740400000200000003000000030000002200000009010306e04a0300214c
(26) b56201041200300d991a36010901a000c500b2004c00a1004ca3
(24) b56201201000300d991aa56403006608120745000000f938
------------------- PPS offset: 0.000000368 ------
sudo ntpshmon
----------------------------------------------------------
pi@raspberrypi:~ $ sudo ntpshmmon
ntpshmmon version 1
# Name Seen@ Clock Real L Prec
sample NTP0 1616731155.261334631 1616731155.090788722 1616731155.000000000 0 -20
sample NTP1 1616731155.261480981 1616731154.999999776 1616731155.000000000 0 -30
sample NTP1 1616731156.001005646 1616731155.999999600 1616731156.000000000 0 -30
sample NTP0 1616731156.091572631 1616731156.090540716 1616731156.000000000 0 -20
sample NTP1 1616731157.000122016 1616731156.999999202 1616731157.000000000 0 -30
sample NTP0 1616731157.090672594 1616731157.090357912 1616731157.000000000 0 -20
sample NTP1 1616731158.000105988 1616731157.999998915 1616731158.000000000 0 -30
sample NTP0 1616731158.090650363 1616731158.090550734 1616731158.000000000 0 -20
sample NTP1 1616731159.000270238 1616731158.999998408 1616731159.000000000 0 -30
sample NTP0 1616731159.091943158 1616731159.090915761 1616731159.000000000 0 -20
chronyd配置
chronyd有一個默認組態檔,修改組態檔即可,下面是整個組態檔,復制黏貼保存為conf即可,其中最后三行代碼是重點,配置了跟gpsd和ptp4l的共享記憶體引數,
# Welcome to the chrony configuration file. See chrony.conf(5) for more
# information about usuable directives.
pool 2.debian.pool.ntp.org iburst
# 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
# This directive enables kernel synchronisation (every 11 minutes) of the
# real-time clock. Note that it can’t be used along with the 'rtcfile' directive.
rtcsync
# Step the system clock instead of slewing it if the adjustment is larger than
# one second, but only in the first three clock updates.
makestep 1 3
server 0.cn.pool.ntp.org
server 1.cn.pool.ntp.org
server 2.cn.pool.ntp.org
server 3.cn.pool.ntp.org
driftfile /var/lib/chrony/drift
allow
refclock SHM 0 refid GPS precision 1e-1 offset 0.9999 delay 0.2
refclock SHM 1 refid PPS precision 1e-7
refclock SHM 2 refid PTP precision 1e-7
組態檔保存后,開啟chronyd,
sudo chronyd -f /path/to/mychrony.conf
chronyc sources -v
等待半分鐘,應該會顯示系統已經與pps同步,如下:
pi@raspberrypi:~ $ chronyc sources -v
210 Number of sources = 11
.-- Source mode '^' = server, '=' = peer, '#' = local clock.
/ .- Source state '*' = current synced, '+' = combined , '-' = not combined,
| / '?' = unreachable, 'x' = time may be in error, '~' = time too variable.
|| .- xxxx [ yyyy ] +/- zzzz
|| Reachability register (octal) -. | xxxx = adjusted offset,
|| Log2(Polling interval) --. | | yyyy = measured offset,
|| \ | | zzzz = estimated error.
|| | | \
MS Name/IP address Stratum Poll Reach LastRx Last sample
===============================================================================
#x GPS 0 4 377 18 -909ms[ -909ms] +/- 200ms
#* PPS 0 4 377 18 -470ns[ -580ns] +/- 1129ns
#? PTP 0 4 0 - +0ns[ +0ns] +/- 0ns
^- 203.107.6.88 2 7 377 89 -1073us[-1074us] +/- 36ms
^- ntp1.ams1.nl.leaseweb.net 3 6 377 17 -21ms[ -21ms] +/- 252ms
^? time.cloudflare.com 0 6 0 - +0ns[ +0ns] +/- 0ns
^- 119.28.206.193 2 7 277 82 +13ms[ +13ms] +/- 42ms
^- ntp6.flashdance.cx 2 7 363 21 -10ms[ -10ms] +/- 205ms
^- 139.199.215.251 2 7 277 94 -2922us[-2923us] +/- 46ms
^- 139.199.214.202 2 7 375 221 -2571us[-2571us] +/- 26ms
^- ntp7.flashdance.cx 2 7 377 85 -22ms[ -22ms] +/- 215ms
Known Issue:有時候樹莓派需要聯網才能跟pps同步,,,有哪位大佬知道為啥的麻煩指導一波
PTP4l配置
組態檔如下,其中重點是這幾個引數priority1、logAnnounceInterval、logSyncInterval、time stamping、ntpshm_segment,前四者是為了保證相機能夠通過PTP與樹莓派時間同步(具體解釋見《Camera-LIDAR_Detection_Fusion》這篇本科畢業論文,或者見Basler官方檔案),最后一個是為了是ptp4l能跟chronyd通訊,
[global]
#
# Default Data Set
#
twoStepFlag 1
slaveOnly 0
# priority1 128
priority1 127
priority2 128
domainNumber 0
#utc_offset 37
clockClass 248
clockAccuracy 0xFE
offsetScaledLogVariance 0xFFFF
free_running 0
freq_est_interval 1
dscp_event 0
dscp_general 0
#
# Port Data Set
#
logAnnounceInterval 1
# logSyncInterval 0
logSyncInterval -1
logMinDelayReqInterval 0
logMinPdelayReqInterval 0
announceReceiptTimeout 3
syncReceiptTimeout 0
delayAsymmetry 0
fault_reset_interval 4
neighborPropDelayThresh 20000000
#
# Run time options
#
assume_two_step 0
logging_level 6
path_trace_enabled 0
follow_up_info 0
hybrid_e2e 0
net_sync_monitor 0
tx_timestamp_timeout 1
use_syslog 1
# verbose 0
verbose 1
summary_interval 0
kernel_leap 1
check_fup_sync 0
#
# Servo Options
#
pi_proportional_const 0.0
pi_integral_const 0.0
pi_proportional_scale 0.0
pi_proportional_exponent -0.3
pi_proportional_norm_max 0.7
pi_integral_scale 0.0
pi_integral_exponent 0.4
pi_integral_norm_max 0.3
step_threshold 0.0
first_step_threshold 0.00002
max_frequency 900000000
# clock_servo pi
clock_servo ntpshm
sanity_freq_limit 200000000
# ntpshm_segment 0
ntpshm_segment 2
#
# Transport options
#
transportSpecific 0x0
ptp_dst_mac 01:1B:19:00:00:00
p2p_dst_mac 01:80:C2:00:00:0E
udp_ttl 1
udp6_scope 0x0E
uds_address /var/run/ptp4l
#
# Default interface options
#
network_transport UDPv4
delay_mechanism E2E
# time_stamping hardware
time_stamping software
tsproc_mode filter
delay_filter moving_median
delay_filter_length 10
egressLatency 0
ingressLatency 0
boundary_clock_jbod 0
#
# Clock description
#
productDescription ;;
revisionData ;;
manufacturerIdentity 00:00:00
userDescription ;
timeSource 0xA0
組態檔保存后,開啟ptp4l,
/usr/sbin/ethtool --set-eee eth0 eee off
/usr/sbin/ifconfig eth0 192.168.2.158
nohup /usr/sbin/ptp4l -f /path/to/myptp4l.conf -i eth0 &
樹莓派到工控機的時間同步
由于樹莓派已經配置為PTP授時服務器(master),那么工控機只要配置成PTP授時客戶端(slave)即可,工控機使用的是ptp4l和chronyd兩個軟體,ptp4l與樹莓派通訊獲取當前時間,并通過共享記憶體的方式傳遞給chronyd,而chronyd更改系統時間,使系統時間與樹莓派同步,
更改ptp4l組態檔
首先ptp4l的組態檔需要做一點兒修改,主要是ntpshm_segment要改為0,全部組態檔如下:
[global]
#
# Default Data Set
#
twoStepFlag 1
# slaveOnly 0
slaveOnly 1
priority1 128
priority2 128
domainNumber 0
clockClass 248
clockAccuracy 0xFE
offsetScaledLogVariance 0xFFFF
free_running 0
freq_est_interval 1
dscp_event 0
dscp_general 0
#
# Port Data Set
#
logAnnounceInterval 1
logSyncInterval 0
logMinDelayReqInterval 0
logMinPdelayReqInterval 0
announceReceiptTimeout 3
syncReceiptTimeout 0
delayAsymmetry 0
fault_reset_interval 4
neighborPropDelayThresh 20000000
#
# Run time options
#
assume_two_step 0
logging_level 6
path_trace_enabled 0
follow_up_info 0
hybrid_e2e 0
tx_timestamp_timeout 1
use_syslog 1
verbose 0
summary_interval 0
kernel_leap 1
check_fup_sync 0
#
# Servo Options
#
pi_proportional_const 0.0
pi_integral_const 0.0
pi_proportional_scale 0.0
pi_proportional_exponent -0.3
pi_proportional_norm_max 0.7
pi_integral_scale 0.0
pi_integral_exponent 0.4
pi_integral_norm_max 0.3
step_threshold 0.0
first_step_threshold 0.00002
max_frequency 900000000
# clock_servo pi
clock_servo ntpshm
sanity_freq_limit 200000000
ntpshm_segment 0
#
# Transport options
#
transportSpecific 0x0
ptp_dst_mac 01:1B:19:00:00:00
p2p_dst_mac 01:80:C2:00:00:0E
udp_ttl 1
udp6_scope 0x0E
uds_address /var/run/ptp4l
#
# Default interface options
#
network_transport UDPv4
delay_mechanism E2E
# time_stamping hardware
time_stamping software
tsproc_mode filter
delay_filter moving_median
delay_filter_length 10
egressLatency 0
ingressLatency 0
boundary_clock_jbod 0
#
# Clock description
#
productDescription ;;
revisionData ;;
manufacturerIdentity 00:00:00
userDescription ;
timeSource 0xA0
組態檔保存后,開啟ptp4l
sudo killall -9 ptp4l chronyd
nohup sudo ptp4l -f /path/to/myptp4l.conf -i enp3s0 &
更改chronyd組態檔
chronyd的組態檔更改如下,主要還是refclock SHM的配置,至于為啥工控機和樹莓派的chronyd組態檔長得很不一樣,猜測應該是不同架構的軟體包組態檔有所差異吧,
#refclock SHM 0 delay 0.5 refid NEMA
refclock SHM 0 refid PTP precision 1e-7
refclock SHM 1 offset 0 delay 0.001 refid PPS
#refclock SOCK /var/run/chrony.ttyS1.sock delay 0.0 refid SOCK
# C(20180207) Setings for using USB non-PPS GPS device and GPSD
# NEMA is too inaccurate and chrony will not use anyway!
# Need to fiddle with offset (seconds) to make sure refclock is considered
# watch the output of 'chronyc sources' to see 'Last Sample'
#
# refclock SHM 0 offset 0.05 refid NMEA
server clock.fmt.he.net iburst
server clock.sjc.he.net iburst
server time.cloudflare.com iburst
server time.google.com iburst
server time.nist.gov
server gpstime.la-archdiocese.net
#server time1.google.com iburst
#server time2.google.com iburst
#server time3.google.com iburst
#server time4.google.com iburst
#pool 0.ubuntu.pool.ntp.org iburst
#pool 2.debian.pool.ntp.org offline iburst
# Specify IP address (interface) that chronyd CLIENT will bind to
# The bindacqaddress directive sets the network interface to which
# chronyd will bind its NTP client sockets
# bindacqaddress 0.0.0.0
# Allow other NTP clients in our zone to query time
allow 10.3/16
allow 10.30.0/24
# (CHANGED): chronyd version 3.2 commandkey directive is no longer supported
# This directive sets the key ID used for authenticating user commands via the
# 'chronyc' program at run time.
# commandkey 1
# End of customized settings - EXCEPT lines labeled with (CHANGED)
# ------------------------------------------------------------------------
# Look here for the admin password needed for chronyc. The initial
# password is generated by a random process at install time. You may
# change it if you wish.
keyfile /etc/chrony/chrony.keys
# I moved the driftfile to /var/lib/chrony to comply with the Debian
# filesystem standard.
driftfile /var/lib/chrony/chrony.drift
# Comment this line out to turn off logging.
log tracking measurements statistics
logdir /var/log/chrony
# Stop bad estimates upsetting machine clock.
maxupdateskew 100.0
# Dump measurements when daemon exits.
dumponexit
# Specify directory for dumping measurements.
dumpdir /var/lib/chrony
# This directive lets 'chronyd' to serve time even if unsynchronised to any
# NTP server.
#local stratum 10
# This directive designates subnets (or nodes) from which NTP clients are allowed
# to access to 'chronyd'.
#allow foo.example.net
#allow 10/8
#allow 0/0 (allow access by any IPv4 node)
#allow ::/0 (allow access by any IPv6 node)
# This directive forces `chronyd' to send a message to syslog if it
# makes a system clock adjustment larger than a threshold value in seconds.
logchange 0.5
# This directive defines an email address to which mail should be sent
# if chronyd applies a correction exceeding a particular threshold to the
# system clock.
# mailonchange root@localhost 0.5
# This directive tells 'chronyd' to parse the 'adjtime' file to find out if the
# real-time clock keeps local time or UTC. It overrides the 'rtconutc' directive.
hwclockfile /etc/adjtime
# This directive enables kernel synchronisation (every 11 minutes) of the
# real-time clock. Note that it can’t be used along with the 'rtcfile' directive.
rtcsync
組態檔保存后,開啟chronyd,靜待60秒后,看chronyc sources是不是PTP時鐘源,
sudo chronyd -f /path/to/chrony/mychrony.conf
sleep 60
chronyc sources
樹莓派到相機的時間同步
博主使用的是Basler工業相機,支持PTP時間同步,因此只需要使用相機的sdk開啟ptp時間同步即可,這里比較麻煩的一點是,Basler的官方ROS包暫時不支持開啟PTP同步(雖然已經有人提交了代碼了,但是一直沒有merge到主分支里面),因此需要自己根據相機的sdk擼代碼了,這里推薦兩份參考資料,看官們可以根據此修改一點兒官方ros包的代碼,接下來,博主默認Basler相機已經能夠開啟PTP時間同步,且發布出來的ros topic的時間戳是相機內部時間戳!
- https://github.com/iron-ox/pylon-ros-camera/pull/1/files
- https://github.com/magazino/pylon_camera/pull/38/files
至此,所有設備都直接或者間接同步到GPS時間了,
激光雷達和相機的同步采集
正如前文所說,要實作激光雷達和相機的同步采集,需要根據激光雷達的幀周期同步觸發相機的拍攝,實作雷達和相機的完全幀同步, 那問題來了,觸發信號從哪里來呢?答案是GPS的PPS信號!PPS是一個1HZ的方波,它的每個上升沿的時刻都是整秒時刻,誤差是納秒級的,因此是一個絕佳的觸發信號,那么,如果實作了激光雷達和相機均在PPS信號上升沿的時候采集資料,且打上各自時鐘的時間戳,那么就實作了我們的目標了,
但是,由于激光雷達和相機采集資料的方式不同,我們只能近似地保證激光雷達和相機的同步采集,如下圖所示,激光雷達的激光束不斷地360度旋轉,假設幀率為10Hz的話,那么一幀點云中采集時刻最早的一個點和采集時刻最晚的一個點時間相差100ms,而相機就不同了,相機是瞬間曝光的,因此影像里面所有像素點的采集時刻都是一樣的,這就導致了我們只能近似地保證激光雷達和相機的同步采集,具體方法就是當激光束旋轉到相機視野中央的時候,觸發相機,這樣就保證了相機視野內的點云采集時間是跟影像采集時間是近似的,為什么說是近似的呢?對于相機視野中央的那些點云,它們的采集時間是跟影像采集時間一致的,但是對于相機視野邊緣的那些點云,它們的采集時間就跟影像采集時間要有一定的時間偏差了,根據相機視野的大小和點云采集幀率的不同,時間偏差可能會有5ms~20ms左右,
理論有了,那么怎么實施呢?插句題外話,KITTI資料集是怎么保證激光雷達和相機同步采集的?那個時候,機械式激光雷達還是外部旋轉式的(類似于陀螺一樣),作者在激光雷達外部貼了一個光電傳感器,但激光雷達旋轉到一定角度時,光電傳感器觸發,接通了相機的觸發電路,從而相機曝光,但是現在的激光雷達為了小型化,高度集成,旋轉元件都在內部了,因此也就無法采取跟KITTI資料集一樣的方式了,不過,聰明的激光雷達制造商想出了一個相位鎖定功能,也就是輸入PPS,但PPS上升沿到來時,激光雷達的激光束恰好旋轉到一定的角度,那么我們反過來想一下,激光雷達的激光束旋轉到一定角度時,PPS上升沿剛好到來,那么我們把PPS信號當做相機硬體觸發信號,不就可以觸發相機了嘛,
于是乎,我們設定激光雷達的相位鎖定角度為相機視野中央,如果相機視野朝著車輛正前方,激光雷達的坐標系也是朝著車輛正前方的話,相位鎖定角度應該是0度,那么問題就這樣解決了,每當激光雷達的激光束旋轉到0度位置,也就是相機視野正中央,PPS上升沿剛好到來,相機也因此觸發,就這樣就實作了激光雷達和相機的同步采集,采集到的點云和影像分別附上采集時激光雷達和相機的內部時間戳,傳輸到工控機,(速騰激光雷達ROS包有一個配置引數use_lidar_time記得設定為true),博主實驗獲取的時間戳如下所示:
| 左相機 | 右相機 | 雷達 |
|---|---|---|
| 2021-02-05 16:11:31.000003019 1612512691.000003019 | 2021-02-05 16:11:31.000006118 1612512691.000006118 | 2021-02-05 16:11:29.250094891 1612512689.250094891 |
| 2021-02-05 16:11:32.000003323 1612512692.000003323 | 2021-02-05 16:11:31.999999862 1612512691.999999862 | 2021-02-05 16:11:29.350159883 1612512689.350159883 |
| 2021-02-05 16:11:33.000005627 1612512693.000005627 | 2021-02-05 16:11:32.999997910 1612512692.999997910 | 2021-02-05 16:11:29.450208902 1612512689.450208902 |
| 2021-02-05 16:11:29.550231934 1612512689.550231934 | ||
| 2021-02-05 16:11:29.650233030 1612512689.650233030 | ||
| 2021-02-05 16:11:29.750208855 1612512689.750208855 | ||
| 2021-02-05 16:11:29.850153923 1612512689.850153923 | ||
| 2021-02-05 16:11:29.950089931 1612512689.950089931 | ||
| 2021-02-05 16:11:30.050039053 1612512690.050039053 | ||
| 2021-02-05 16:11:30.150043011 1612512690.150043011 | ||
| 2021-02-05 16:11:30.250089884 1612512690.250089884 | ||
| 2021-02-05 16:11:30.350174904 1612512690.350174904 | ||
| 2021-02-05 16:11:30.450262070 1612512690.450262070 | ||
| 2021-02-05 16:11:30.550323009 1612512690.550323009 | ||
| 2021-02-05 16:11:30.750334978 1612512690.750334978 | ||
| 2021-02-05 16:11:30.850276947 1612512690.850276947 | ||
| 2021-02-05 16:11:30.950206041 1612512690.950206041 | ||
| 2021-02-05 16:11:31.050145864 1612512691.050145864 | ||
| 2021-02-05 16:11:31.150121927 1612512691.150121927 | ||
| 2021-02-05 16:11:31.250118971 1612512691.250118971 | ||
| 2021-02-05 16:11:31.350147009 1612512691.350147009 | ||
| 2021-02-05 16:11:31.450216055 1612512691.450216055 | ||
| 2021-02-05 16:11:31.550293922 1612512691.550293922 | ||
| 2021-02-05 16:11:31.650341988 1612512691.650341988 | ||
| 2021-02-05 16:11:31.750362873 1612512691.750362873 | ||
| 2021-02-05 16:11:31.850353956 1612512691.850353956 | ||
| 2021-02-05 16:11:31.950303078 1612512691.950303078 | ||
| 2021-02-05 16:11:32.050214052 1612512692.050214052 | ||
| 2021-02-05 16:11:32.150120020 1612512692.150120020 | ||
| 2021-02-05 16:11:32.250038862 1612512692.250038862 | ||
| 2021-02-05 16:11:32.350008965 1612512692.350008965 | ||
| 2021-02-05 16:11:32.450034857 1612512692.450034857 | ||
| 2021-02-05 16:11:32.550119877 1612512692.550119877 | ||
| 2021-02-05 16:11:32.650241852 1612512692.650241852 | ||
| 2021-02-05 16:11:32.750367880 1612512692.750367880 | ||
| 2021-02-05 16:11:32.850463867 1612512692.850463867 | ||
| 2021-02-05 16:11:32.950510025 1612512692.950510025 | ||
| 2021-02-05 16:11:33.050494909 1612512693.050494909 | ||
| 2021-02-05 16:11:33.150435925 1612512693.150435925 | ||
| 2021-02-05 16:11:33.250333071 1612512693.250333071 | ||
| 2021-02-05 16:11:33.350236893 1612512693.350236893 | ||
| 2021-02-05 16:11:33.450165987 1612512693.450165987 | ||
| 2021-02-05 16:11:33.550113916 1612512693.550113916 | ||
| 2021-02-05 16:11:33.650095940 1612512693.650095940 | ||
| 2021-02-05 16:11:33.750138998 1612512693.750138998 | ||
| 2021-02-05 16:11:33.850213051 1612512693.850213051 | ||
| 2021-02-05 16:11:33.950275898 1612512693.950275898 |
我們來分析一下上表所示的時間戳,可以看到,相機一秒鐘觸發一次,觸發的時間點為整秒時刻(雖然時間有幾微秒的偏差,但應該的PTP時間同步的誤差來著),而激光雷達的采集時間是10HZ,時間戳有點兒奇怪,在一秒內的時間戳是0.05s,0.15s,0.25s,0.35s…0.85s,0.95s,需要說明的是,這是速騰激光雷達ROS包打出來的時間戳,而速騰激光雷達ROS包是以一幀點云(360度為一幀)的最后一個資料包的時間作為時間戳的,
這里涉及到一個點云分幀的概念,即激光雷達連續地做掃描,而一幀點云一般只有360度,因此有一個點云分幀角度作為起始角度和結束角度,需要注意的是,假設我們以90度作為點云分幀的角度,那么89度和91度的點云采集時間就相差100ms了哦!明白了點云分幀角度的概念之后,我們應該設定點云分幀角度在相機視野外,這樣才能保證點云和影像的同時性,博主把點云分幀角度設定為180度,相位鎖定角度為0度,點云采集幀率為10Hz,因此,點云的時間戳如0.15s,其實代表著激光束掃描到180度的時刻為0.15秒,因此180度為該幀點云的結束角度,所以這個時刻其實是晚于激光束掃描到0度(也就是相位鎖定角度)的時刻的,結合點云采集幀率計算,激光束掃描到0度的時刻應該是0.10秒,因此,我們在做點云和影像時間對齊時,應該把點云的時間戳減0.05秒,然后再進行對齊,
我們來找一下表格里面時間對齊的影像和點云,以左相機為例,UTC時間1612512691.000003019這幀影像,應該對應UTC時間1612512691.050145864這幀點云,算一下時間差1612512691.050145864-0.05-1612512691.000003019=0.000142845,也就是0.1ms,達到了亞毫秒級同步了,
至此,我們實作了激光雷達和相機內部時鐘的同步,以及點云采集和影像采集的時間同步,本博文的基本目標已經完成了,
更進一步
細心的看官肯定發現了,上面給出的解決方案,相機的采集幀率只有1Hz,而點云的采集幀率有10Hz,這在很多場景下沒法使用,這時候,單片機就派上用場了,我們可以使用單片機,把PPS信號轉發為任意頻率、但是跟PPS信號同相位的方波,這樣就可以控制相機的采集頻率了,下圖就展示了單片機的輸入輸出,把PPS信號轉發為同相位的5HZ相機觸發信號,具體的實作原理需要使用到中斷、定時器、GPIO輸入輸出等功能,應該是最基礎的單片機應用,博主還沒有來得及實作,在這里就不獻丑了,
參考文獻
為了使博文不至于冗長,博主省略了很多細節和原理介紹,下面這些參考文獻可供學習使用,
https://www.researchgate.net/publication/339630757_Camera-LIDAR_Detection_Fusion
https://connecttech.com/resource-center/kdb349-gps-time-synchronization-linux/
https://blog.csdn.net/xiaohu50/article/details/78731534
https://gpsd.gitlab.io/gpsd/gpsd-time-service-howto.html#_ptp_with_software_timestamping
https://t.codebug.vip/questions-1646062.htm
http://www.rjsystems.nl/en/2100-ntpd-garmin-gps-18-lvc-gpsd.php#rslt
https://gpsd.gitlab.io/gpsd/gpsd-time-service-howto.html#_feeding_chrony_from_gpsd
https://livox-wiki-cn.readthedocs.io/zh_CN/latest/tutorials/timestamp_sychronization.html#id14
https://wiki.alpinelinux.org/wiki/Chrony_and_GPSD
https://blog.csdn.net/ReCclay/article/details/104679944
https://www.raspberrypi.org/documentation/configuration/uart.md
https://blog.csdn.net/qishi_blog/article/details/52843696?utm_source=blogxgwz7&utm_medium=distribute.pc_relevant.none-task-blog-baidujs_title-2&spm=1001.2101.3001.4242
本博文原創,轉發請注明出處!
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/271617.html
標籤:其他
