2. 时间戳基础:系统时间、UTC时间、GPS时间、传感器时间戳的获取方式
做多传感器融合,第一道坎就是时间。我见过太多项目,算法写得再漂亮,时间没对齐,结果全是废的。说白了,时间戳就是传感器的“身份证”,你得知道每个数据是什么时候出生的。
这一节,我们聊聊四种最常见的时间体系。嗯,别觉得基础,这里面的坑,我踩过不少。
2.1 系统时间:你最熟悉的“墙钟时间”
系统时间,就是你的电脑或嵌入式板卡上显示的时间。比如你在Linux里敲date命令看到的那个。
它的获取方式很简单:
// C++ 获取系统时间戳(毫秒级)
#include <chrono>
auto now = std::chrono::system_clock::now();
auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()).count();
但我要提醒你:系统时间不可靠。为什么?
- 用户可能手动改时间
- NTP同步时会有跳变
- 休眠唤醒后可能不准
所以,我个人习惯:系统时间只用来做“人可读”的日志记录,绝不用于传感器融合的时间基准。
2.2 UTC时间:全球统一的标准
UTC,协调世界时。你可以理解为“全球统一的时间标准”。它基于原子钟,非常稳定。
获取UTC时间的方式:
// 从系统时间转UTC
time_t rawtime;
struct tm * ptm;
time(&rawtime);
ptm = gmtime(&rawtime); // gmtime返回的就是UTC
printf("UTC: %s", asctime(ptm));
UTC和系统时间的关系?系统时间通常就是UTC加上时区偏移。比如北京时间是UTC+8。
这里有个关键点:传感器数据的时间戳,最好统一用UTC。这样不管你在北京、纽约还是伦敦,数据拿到手里,时间基准是一样的。
2.3 GPS时间:卫星给你的“绝对时间”
GPS时间,是GPS卫星系统内部使用的时间体系。它从1980年1月6日0点开始计时,单位是周+秒。
获取方式:
// 从GPS接收机获取时间(伪代码)
uint32_t gps_week; // GPS周
double gps_seconds; // 周内秒(精度可达纳秒级)
// 读取接收机数据
read_gps_time(&gps_week, &gps_seconds);
GPS时间和UTC有个差异:闰秒。因为地球自转在变慢,UTC会不定期加1秒(闰秒),但GPS时间不加。所以目前GPS时间比UTC快了18秒(2024年数据)。
| 时间体系 | 起点 | 精度 | 是否跳变 |
|---|---|---|---|
| 系统时间 | 1970-01-01 | 毫秒级 | 可能跳变 |
| UTC | 1972-01-01 | 纳秒级 | 闰秒调整 |
| GPS时间 | 1980-01-06 | 纳秒级 | 无跳变 |
2.4 传感器时间戳:硬件给你的“原始时间”
每个传感器都有自己的时钟。比如激光雷达、IMU、相机。它们的时间戳怎么来的?
- 相机:通常由硬件触发信号产生,精度在微秒级
- IMU:内部晶振计时,精度较高,但会漂移
- 激光雷达:每个点云帧都有时间戳,但不同厂商实现方式不同
获取方式示例(以ROS为例):
// 从ROS消息中获取传感器时间戳
sensor_msgs::Imu imu_msg;
ros::Time stamp = imu_msg.header.stamp;
double secs = stamp.toSec(); // 秒为单位
这里有个大坑:传感器时间戳和系统时间戳可能不同步。比如相机的时间戳是硬件给的,但你的电脑系统时间可能已经漂移了。
我的建议:
- 每个传感器的时间戳,尽量用硬件触发,别用软件打戳
- 定期用GPS时间校准传感器时钟
- 记录时间戳时,同时记录它的“来源”(系统时间?GPS?硬件?)
2.5 四种时间体系的关系图
下面这张图,是我自己总结的。四种时间体系的关系,一目了然:
2.6 实际项目中的选择
说了这么多,到底用哪个?
我个人经验:
- 有GPS信号的环境(室外无人车、无人机):直接用GPS时间作为主时钟。所有传感器通过PPS信号同步。
- 无GPS信号的环境(室内机器人、隧道):用UTC时间,但必须保证NTP稳定。或者用高精度晶振自己维护一个时间基准。
- 传感器内部时间戳:永远保留原始值。别自作聪明去转换,万一转换公式错了,数据就废了。
嗯,时间戳基础就聊这么多。下一节我们聊聊更具体的——怎么把这些时间戳对齐到同一个时间轴上。到时候我会分享一个我实际用过的对齐算法。