Diagnose sensor/recorder clock sync issues (offset, drift, jitter, gaps) in ROS2 mcap recordings, with an interactive HTML dashboard.
Project description
clockdoctor
Diagnose sensor/recorder clock sync issues in ROS2 .mcap recordings — offset,
drift, jitter, gaps, coverage — and get an interactive, self-contained HTML
dashboard out the other end. No GUI app to install; the dashboard is one HTML
file you can open locally or send to someone else.
Install
pip install clockdoctor
Use
clockdoctor path/to/recording.mcap
That's it — it decodes every topic, runs the analysis, and writes (next to the input file):
<name>_dashboard.html— open this in a browser<name>_timestamps.csv— one row per message<name>_timeline_data.json— the data backing the dashboard
Point it at an already-extracted *_messages.jsonl instead of a .mcap and
it skips straight to analysis.
What it checks, per topic
- Clock offset vs. drift vs. jitter — a linear regression over recorder-time-minus-source-time, so a fixed epoch bug (offset) is never confused with the source clock genuinely running at a different rate (drift); jitter is what's left after removing both.
- Cadence regularity on both the recorder clock and the sensor's own clock — distinguishes recorder-side buffering from real sensor irregularity.
- Gaps, duplicates, out-of-order timestamps, coverage (does a topic start late or end early relative to the rest of the recording?).
- Works whether a topic's clock lives in a ROS
header.stampor is embedded as JSON inside astd_msgs/Stringpayload (--embedded-timestamp-key).
Options
clockdoctor recording.mcap --topic /some/topic # extraction: restrict to one topic
clockdoctor recording.mcap --out-dir ./out # write outputs elsewhere
clockdoctor recording.mcap --embedded-timestamp-key ts
Explicit subcommands are also available if you want to run extraction and
analysis as separate steps: clockdoctor extract recording.mcap /
clockdoctor analyze recording_messages.jsonl.
Scope
Only ROS2/CDR-encoded .mcap channels are decoded (via mcap-ros2-support).
ROS1 bags and protobuf/flatbuffer-encoded mcap channels are out of scope.
Extraction only pulls out header (stamp + frame_id) and, for std_msgs/String
topics, the raw string — never point clouds, images, scan arrays, poses, or any
other bulk sensor payload, since none of that is needed for sync analysis. For
a LaserScan/Odometry/Imu-heavy recording that keeps the intermediate JSONL a
fraction of the size a full decode would produce.
License
Apache License 2.0 — see LICENSE.
The analyzer itself only ever reads a documented JSONL row schema (see the
top of src/clockdoctor/analyze.py), so any other producer — a different
logger, a reshaped CSV/DB export — can feed it directly without going through
mcap at all.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file clockdoctor-0.1.0.tar.gz.
File metadata
- Download URL: clockdoctor-0.1.0.tar.gz
- Upload date:
- Size: 35.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
18cd0b15eea0c6ee2124c526a22762a1e0ae1978379a71a82168234cc6e9754f
|
|
| MD5 |
aff320b579a898efe6510a50029374fb
|
|
| BLAKE2b-256 |
d9dc30885c8a5ee8a2d937063b4c9f2074824f9118da7a48b10fb3aae947bb09
|
Provenance
The following attestation bundles were made for clockdoctor-0.1.0.tar.gz:
Publisher:
publish.yml on Benjamin-Tan/clockdoctor
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
clockdoctor-0.1.0.tar.gz -
Subject digest:
18cd0b15eea0c6ee2124c526a22762a1e0ae1978379a71a82168234cc6e9754f - Sigstore transparency entry: 2256321435
- Sigstore integration time:
-
Permalink:
Benjamin-Tan/clockdoctor@ad2e1236ed2d314c66663049174edbddd5fc63f2 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/Benjamin-Tan
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@ad2e1236ed2d314c66663049174edbddd5fc63f2 -
Trigger Event:
release
-
Statement type:
File details
Details for the file clockdoctor-0.1.0-py3-none-any.whl.
File metadata
- Download URL: clockdoctor-0.1.0-py3-none-any.whl
- Upload date:
- Size: 33.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b5148689cb98ccb81f87bd6db3e7fa6db68ed211ad7fd630c4584f692c6222e4
|
|
| MD5 |
eae763c04444d2ecc0b8ae68cf8f8680
|
|
| BLAKE2b-256 |
4f68411e4f9c2f6ea469f5d5f4121533d25ac1355e4d5e7742da2dff05fd4e24
|
Provenance
The following attestation bundles were made for clockdoctor-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on Benjamin-Tan/clockdoctor
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
clockdoctor-0.1.0-py3-none-any.whl -
Subject digest:
b5148689cb98ccb81f87bd6db3e7fa6db68ed211ad7fd630c4584f692c6222e4 - Sigstore transparency entry: 2256321443
- Sigstore integration time:
-
Permalink:
Benjamin-Tan/clockdoctor@ad2e1236ed2d314c66663049174edbddd5fc63f2 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/Benjamin-Tan
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@ad2e1236ed2d314c66663049174edbddd5fc63f2 -
Trigger Event:
release
-
Statement type: