Sensors are not hardware-synchronized; estimators must tolerate asynchronous arrival and estimate per-stream delays.
Per-stream stamping:
PX4 stamps onboard (clock NTP-disciplined to host, sent with host time);
the LSM9DS1 has no clock and is stamped by round-trip compensation t = t_request + 0.5·(t_response − t_request);
the RealSense maps its internal clock to host (~1 ms).
CSV t is the ROS header.stamp in POSIX seconds, not zeroed.
nodelet_rosbag writes bag records at ros::Time::now(), not at the incoming message-header stamp.
Timestamps are software-stamped approximate sample times, not guaranteed unique or strictly monotonic. Sample/row order is the authoritative sequence; file order is the tie-breaker within a file.
Ground-truth sensors get an extra post-processing time calibration producing the offsets t_mag_gps and t_pximu_imugt (the keys in time_info.yaml / ground_truth/time_offset.yaml).
The GNSS-time trap (load-bearing).
Raw rtk_gps{1,2}.csv have t == t_gps (the GNSS clock, to <5e-7 s), which is offset from the px4_imu / ground_truth_*system clock by the per-run t_pximu_imugt/t_mag_gps.
Measured offsets:
outdoor_17,141,924 s (~82.66 days);
transitions ~5 s;
Mars 0.68–2.62 s.
The lanes already on the system/IMU clock are ground_truth_8hz/80hz.csv and the *_data_revised.csv.
Joining raw RTK to the IMU by bare timestamp is wrong by this offset.
px4_gps.csvt, by contrast, is on the system/IMU clock (99.6–99.9% of its samples fall inside the px4_imu span); fuse it directly without GPS-time conversion.
time_info.yamlt_total equals t_end − t_begin within 1e-3 on every run that has it (transition_3 has none).
Of the six Mars runs carrying both time_info.yaml and ground_truth/time_offset.yaml, five disagree on the offset values; only mars_17 agrees.
The split is by GT family: time_info.yaml matches Family A, the published primary system-clock pair ground_truth_8hz.csv / ground_truth_80hz.csv, while ground_truth/time_offset.yaml matches Family B, the separate helper pair outdoor_gt.csv / outdoor_gt_interpolate.csv.
mars_14 is the cleanest witness: Family A ships 672 / 15742 rows, while Family B ships 608 / 14520.
Pick the file that matches the lane you are using.
On the transition runs the clock offsets live only in ground_truth/time_offset.yaml.
transition_1/transition_2time_info.yaml carries just t_total/t_begin/t_end (no offset keys),
and transition_3 ships no time_info.yaml at all
so read t_mag_gps/t_pximu_imugt for the transitions from time_offset.yaml, never time_info.yaml.