Skip to main content

ROSBag Doctor

ROSBag Doctor

CI Python ROS 2 License

Find bad ROS 2 recordings before they become bad datasets. rosbag-doctor checks SQLite3 and MCAP bags for timing gaps, bad rates, timestamp problems, incomplete topic coverage, and configured sensor-sync limits. It works directly on bag files and does not require a ROS installation.

At a glance

rosbag-doctor my_recording/ --config doctor.yaml
ROSBag Doctor  FAIL
sqlite3 · 1 file(s) · 773 messages · 5.99 s

Topic               Messages      Rate   Max gap   p95 jitter   Coverage
/camera/image_raw         173   28.83 Hz  266.7 ms      0.0 ms      99.6%
/imu                      600  100.00 Hz   10.0 ms      0.0 ms     100.0%

Sensor sync
camera-imu  p95 offset 3.67 ms  max offset 3.67 ms

1 error, 0 warnings
✗ /camera/image_raw  Maximum gap 266.7 ms exceeds 100.0 ms

The example above comes from the checked-in demo recording. The camera stream deliberately loses several frames; the IMU remains healthy.

What it checks

Without a config file, ROSBag Doctor performs conservative checks that are useful on unknown recordings:

  • missing files referenced by metadata.yaml
  • metadata message-count mismatches
  • conflicting message types for the same topic
  • MCAP CRC failures when checksums are present
  • timestamp regressions
  • repeated timestamps
  • timestamp zeroes
  • unusually large gaps on otherwise regular streams
  • empty bags and topics

With a YAML policy, it can enforce:

  • required topics and topic globs
  • expected rate with tolerance
  • maximum message gap
  • p95 timing jitter
  • minimum recording coverage
  • minimum message count
  • maximum topic start delay or early stop
  • p95 and worst-case timestamp offset across sensor streams
  • minimum or maximum bag duration

Every check can be exported as JSON, and a failing policy returns exit code 1 for CI.

Supported inputs

  • ROS 2 SQLite3 bags (.db3 and .sqlite3)
  • MCAP files (.mcap)
  • split rosbag2 directories described by metadata.yaml
  • direct bag files when metadata.yaml is unavailable

ROSBag Doctor reads recording timestamps and topic metadata. It does not deserialize ROS messages, so it can inspect timing without having the message packages installed.

Install

From a clone:

git clone https://github.com/sylvesterkaczmarek/rosbag-doctor.git
cd rosbag-doctor
python -m pip install .

For development:

python -m pip install -e '.[dev]'
pytest

Check a bag

rosbag-doctor ./rosbag2_2026_08_09-00_15_42

Use a policy when the expected recording contract is known:

rosbag-doctor ./run-042 --config doctor.yaml

Write a JSON report:

rosbag-doctor ./run-042 --config doctor.yaml --json report.json

Print JSON to stdout:

rosbag-doctor ./run-042 --format json

Treat warnings as failures:

rosbag-doctor ./run-042 --strict

Exit codes:

Code Meaning
0 pass, or warnings without --strict
1 one or more health checks failed
2 bad input, unreadable bag, or invalid config

Define expected recording quality

version: 1

topics:
  /imu:
    required: true
    rate_hz: 200
    rate_tolerance: 0.05
    max_gap_ms: 20
    max_jitter_ms: 2
    min_coverage: 0.98

  /camera/*:
    required: true
    rate_hz: 30
    rate_tolerance: 0.10
    max_gap_ms: 100

sync:
  - name: camera-imu
    reference: /camera/image_raw
    topics: [/camera/image_raw, /imu]
    max_p95_offset_ms: 8
    max_offset_ms: 20

Exact topic rules take precedence over globs. See docs/configuration.md for all fields.

Make a baseline from a good run

A known-good bag can seed a policy:

rosbag-doctor baseline ./known-good-run -o doctor.yaml

The generated file marks observed topics as required and adds coverage limits. Rate and gap rules are inferred only for streams that look periodic, so event-driven topics are not automatically treated as fixed-rate sensors. Review the policy once, commit it with the robot software, then use it on later recordings.

Compare two runs

rosbag-doctor compare ./run-before-change ./run-after-change

This reports added and removed topics plus changes in effective rate and maximum gap. JSON output is also available:

rosbag-doctor compare ./before ./after --format json

Use it in CI

- name: Check recorded test data
  run: |
    rosbag-doctor artifacts/test-run \
      --config config/rosbag-doctor.yaml \
      --json rosbag-doctor-report.json

A failed recording returns a non-zero exit code, so a hardware-in-the-loop or simulation pipeline can stop before a broken bag is uploaded or used for evaluation.

See docs/ci.md for a complete example.

Demo without ROS

The repository includes a small generator that writes a rosbag2-compatible SQLite database with a deliberate camera dropout:

python examples/make_demo_bag.py .demo-bag
rosbag-doctor .demo-bag --config examples/doctor.yaml

The command should fail because the configured camera gap limit is exceeded.

How the numbers are calculated

For each topic, ROSBag Doctor keeps the recorded timestamp sequence and calculates:

  • effective rate as (message_count - 1) / recorded_duration
  • median period from positive consecutive timestamp differences
  • maximum gap from the largest positive consecutive difference
  • p95 jitter from absolute deviation around the median period
  • coverage as the topic time span divided by the bag time span
  • sensor offset using nearest timestamps to the configured reference stream

Timestamp regressions are checked in recorded order rather than hidden by sorting the bag first.

See docs/checks.md for definitions and issue codes.

Scope

ROSBag Doctor checks recording-container integrity and timeline health. It does not currently inspect message payloads, image corruption, ROS header stamps, TF graph connectivity, calibration correctness, or whether sensor values are physically plausible.

That distinction is intentional. The tool can run on a laptop or CI runner without ROS message packages and can catch recording failures before payload-specific analysis begins.

See docs/formats.md and docs/limitations.md.

Repository layout

rosbag-doctor/
├── .github/workflows/       # CI
├── assets/social/           # repository social card
├── docs/                    # checks, config, CI, formats and limitations
├── examples/                # demo bag generator and policy
├── src/rosbag_doctor/       # readers, statistics, checks and CLI
├── tests/                   # SQLite, MCAP, policy, baseline and CLI tests
├── CITATION.cff
├── LICENSE
├── Makefile
├── pyproject.toml
└── README.md

Cite this repository

If you use or adapt this repository, please cite:

Kaczmarek, S. (2026). ROSBag Doctor. GitHub. https://github.com/sylvesterkaczmarek/rosbag-doctor

@software{Kaczmarek_2026_ROSBag_Doctor,
  author = {Sylvester Kaczmarek},
  title  = {{ROSBag Doctor}},
  year   = {2026},
  url    = {https://github.com/sylvesterkaczmarek/rosbag-doctor}
}

License

MIT. See LICENSE.

© Sylvester Kaczmarek · https://www.sylvesterkaczmarek.com

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

rosbag_doctor-0.1.1.tar.gz (26.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

rosbag_doctor-0.1.1-py3-none-any.whl (23.1 kB view details)

Uploaded Python 3

File details

Details for the file rosbag_doctor-0.1.1.tar.gz.

File metadata

  • Download URL: rosbag_doctor-0.1.1.tar.gz
  • Upload date:
  • Size: 26.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for rosbag_doctor-0.1.1.tar.gz
Algorithm Hash digest
SHA256 6fafb277e3ece83e46f74620e15662c8106f260e72cd9a618a91665d5297d760
MD5 5690929a44567106d9a730fb77ca35d3
BLAKE2b-256 97439dfaee7a0e64b9246a7f860584432f5d9ccb98d5d22c823f5ad250843b28

See more details on using hashes here.

Provenance

The following attestation bundles were made for rosbag_doctor-0.1.1.tar.gz:

Publisher: release.yml on sylvesterkaczmarek/rosbag-doctor

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file rosbag_doctor-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: rosbag_doctor-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 23.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for rosbag_doctor-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 3de55878524a43b1ce95813de00bf339652f2a7b8fb66dbaf64cf5fb50f8e7bd
MD5 5f43b7f07b992f858affe01dac1645de
BLAKE2b-256 03e321cacc87719ab9be942602dc85d0ad0c330c522ba5ed0af7cfb2bbeefdd1

See more details on using hashes here.

Provenance

The following attestation bundles were made for rosbag_doctor-0.1.1-py3-none-any.whl:

Publisher: release.yml on sylvesterkaczmarek/rosbag-doctor

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page