Skip to content

DDS Source and Receive Timestamp Contract

Last updated: 2026-05-09

Why It Matters

ROS 2 sensor fusion often has three different timestamps for the same message: the application header stamp, the middleware source timestamp, and the subscriber receive timestamp. They answer different questions. The header stamp usually describes when the physical measurement is valid. The DDS/RMW source timestamp describes when the publisher wrote the sample. The receive timestamp describes when the subscription received it.

Using the wrong one hides root cause. A stale LiDAR frame can look fresh if the driver restamps on publish. A network backlog can look like sensor delay if the only recorded time is Header.stamp. A replay can look deterministic while the original DDS source/receive gap is missing.

Runtime Contract

TimestampOwnerMeaningUse for
msg.header.stampApplication / driver / estimatorMeasurement acquisition time or estimator validity time.Fusion alignment, TF query time, physical age.
rmw_message_info.source_timestampRMW / middleware publisher pathTime when the publisher published the message. Exact sampling point is implementation-specific but should be consistent.Pub-to-sub latency, queue/backlog diagnosis, recorder publish time.
rmw_message_info.received_timestampRMW / middleware subscription pathTime when the subscription received the message. Exact sampling point is implementation-specific but should be consistent.Middleware receive latency and recorder receive time.
DDS SampleInfo.source_timestampDDS DataWriterTime provided when the DataWriter wrote the sample.Vendor-level transport analysis.
DDS SampleInfo.reception_timestampDDS DataReaderTime when the sample entered reader history.Vendor-level receive analysis.
Recorder recv_timestamprosbag2 recorderNanosecond time when recorder received the message.Bag log time, incident reconstruction.
Recorder send_timestamprosbag2 recorder / RMWNanosecond time when message was published; falls back to receive time if unavailable.MCAP publish time, source-order replay analysis.

The contract is: fusion uses Header.stamp; latency analysis uses source and receive metadata; replay evidence preserves both when available.

Implementation Pattern

Use subscription callbacks that receive rclcpp::MessageInfo on timing-critical topics:

cpp
void lidar_callback(
  sensor_msgs::msg::PointCloud2::ConstSharedPtr msg,
  const rclcpp::MessageInfo & info)
{
  const auto & rmw_info = info.get_rmw_message_info();
  // msg->header.stamp: acquisition or validity time
  // rmw_info.source_timestamp: publisher-side middleware time
  // rmw_info.received_timestamp: subscriber-side middleware time
  // rmw_info.publication_sequence_number: gap detection with publisher GID
}

Store these fields in diagnostics or sidecar metadata for raw sensor topics, localization pose, /tf, and fused state outputs. Do not rewrite the application header to match middleware time unless the message type explicitly defines that as its semantics.

Failure Modes

Failure modeSymptomControl
Header equals publish timeFusion appears aligned but physical sensor skew remains.Driver tests compare hardware timestamp, header stamp, source timestamp, and receive timestamp.
Unsynced host clocksSource-to-receive latency is negative or implausible across machines.Chrony/PTP/gPTP offset monitoring and per-host clock metadata.
Reliable QoS backlogReceive intervals look smooth while header age grows.Alert on receive_timestamp - header_stamp and queue depth, not only topic rate.
Best-effort gaps hiddenSLAM drops scans with no visible exception.Track publication sequence gaps when supported and sensor frame counters.
Vendor timestamp semantics driftMiddleware change alters measured latency.Include RMW vendor/version in timing evidence and regression tests.
Recorder-only timestampIncident bag cannot separate sensor delay from DDS delay.MCAP/rosbag provenance contract requires send and receive timestamps where supported.
Sequence wrap or unsupported valueFalse gap alarms.Treat unsupported sentinel values and wraparound as explicit states.

QoS Interaction

QoS policyTiming implicationFusion recommendation
ReliabilityReliable can preserve old samples and increase tail latency under loss; best effort may drop.Raw high-rate sensors often prefer best effort plus freshness gates; state estimates often require reliable with tight depth.
History/depthDeep queues can deliver old data after compute stalls.Set depth from rate x acceptable queue delay, not arbitrary defaults.
DeadlineDetects missed publish periods.Configure for critical periodic topics and subscribe to deadline-missed events or diagnostics.
LifespanPrevents old samples from being delivered after validity expires.Use for commands, local maps, and freshness-critical state where supported by RMW.
LivelinessDetects publisher/process absence.Use with topic monitors for localization, safety, and command publishers.
DurabilityTransient local can deliver old latched data to late joiners.Use for maps and static transforms, not raw sensor or command streams.

Telemetry

MetricDefinitionPurpose
header_to_source_mssource_timestamp - Header.stampDriver and publisher queue delay.
source_to_receive_msreceived_timestamp - source_timestampMiddleware/network delay.
receive_to_callback_msCallback start steady time minus receive time when instrumented.Executor backlog.
header_to_callback_msCallback start ROS time minus Header.stamp.End-to-end data age.
publication_seq_gapDifference between consecutive publisher sequence numbers.Middleware/sample loss detection.
clock_offset_ms{host}Time sync offset from reference.Trust gate for cross-host latency metrics.

Acceptance Checks

  • Timing-critical subscriptions expose MessageInfo metadata in debug logs, metrics, or bag sidecars.
  • A controlled network-delay test increases source_to_receive_ms without changing sensor Header.stamp.
  • A controlled driver-delay test increases header_to_source_ms without being misclassified as DDS delay.
  • Sequence gaps are detected for supported RMW implementations and reported as unsupported otherwise.
  • QoS compatibility is checked at startup with ros2 topic info -v or an equivalent manifest validation.
  • Incident bags preserve receive and send/publish timestamps when the storage stack supports them.

Sources

Public research notes collected from public sources.