Skip to main content

Host CLI for ROS OTA communication sessions.

Project description

ROS Communication DevContainer

CI Coverage PyPI Python License

The ROS Communication DevContainer is a Docker-based solution designed to streamline the bidirectional synchronization of ROS2 topics between two Linux machines. It provides built-in compression and routing capabilities for over-the-air (OTA) data transfer: selected topics are remapped into an OTA namespace and transmitted either via direct DDS (CycloneDDS) or through a Zenoh router. When desired, the session can also place local application nodes and OTA-facing bridge nodes into separate ROS 2 domain IDs and automatically generate a standard ROS 2 domain_bridge configuration for the /com/... boundary. This project aligns with the publication “Scalable Remote Operation for Autonomous Vehicles: Integration of Cooperative Perception and Open Source Communication.”

Key Features
  • Minimal Dependencies: Only Docker is needed to get started, simplifying the setup process.
  • Isolation: Operates in a separate Docker container, ensuring minimal impact on existing ROS setups.
  • Centralized Configuration Management: All configurations are stored and managed in this repository.
  • Compression: Built-in compression capabilities for efficient data transfer.
  • QoS Configuration: Flexible Quality of Service settings for optimized communication.

Getting Started

Prerequisites

  • Docker installed on all machines
  • Git for configuration management
  • ros2docker v0.1.2 or newer. The local installer below installs the pinned supported range into this checkout's virtual environment.
  • Machines connected to the same network (VPN or local WLAN)

Convenience CLI: rosotacom

This repository's main entrypoint for starting ROS communication sessions is the checkout-local rosotacom command. Each checkout owns its own .venv, so multiple rosotacom versions can coexist without global symlink drift.

Install

cd /path/to/ros_communication_devcontainer && ./install.sh
source .venv/bin/activate
rosotacom --version
python -m rosotacom --version
rosotacom doctor

Legacy global symlinks are still available when explicitly requested:

./install.sh --global-symlink

Basic Setup

rosotacom uses three layers of configuration/runtime state:

  • A project setup file (rosotacom.yaml) points to host-local resources such as ros2docker.json, static sessions/, ignored session-instances/, and data_dict.json.
  • A session config defines the communication behavior for one run: peers, addresses, topics, QoS, processing, and transport choices.
  • A session instance stores one concrete run: generated config, catmux pane logs, smoke debug output, and future rosbags.

No rosotacom.yaml is discovered automatically. Wire one explicitly with a flag or with ROSOTACOM_CONFIG:

rosotacom examples create ./rosotacom_examples
cd ./rosotacom_examples
eval "$(rosotacom setup-env ./rosotacom.yaml)"
rosotacom doctor

The copied packaged example project uses this layout:

rosotacom.yaml
ros2docker.json
data_dict.json
sessions/
session-instances/
scripts/

See the example project README for the copyable example layout.

The example data_dict.json uses 127.0.0.1 for both peers so the examples can run on one host and show how data:<key> references work. For two-machine runs, replace those values with each machine's reachable IP address or hostname.

Write or edit session configs under sessions/<name>/:

  • session-definition.yaml for a self-contained session
  • session-parametrization.yaml for a template plus parameters

Run rosotacom on each peer with the same active setup but a different identity:

# on peer "a"
rosotacom start 1_heartbeat_cyclone-ota --identity a

# on peer "b"
rosotacom start 1_heartbeat_cyclone-ota --identity b

rosotacom reads the static session input and creates generated files under session-instances/<date>/<session>_<timestamp>_<id>/config/, including per-peer plugin/session specs, topic lists, optional QoS, and optional domain_bridge.yaml. Catmux pane output is logged under the same instance in logs/<peer>/catmux/.

Usage Examples

Create and wire the example project first:

rosotacom examples create ./rosotacom_examples
cd ./rosotacom_examples
eval "$(rosotacom setup-env ./rosotacom.yaml)"

Run the local heartbeat smoke test:

rosotacom smoke

The smoke test verifies both directions through the communication path: it waits for /com/in/a/heartbeat_a and /heartbeat_a in peer b, plus /com/in/b/heartbeat_b and /heartbeat_b in peer a. For each checked topic it also reports a SMOKE_METRIC line with the received rate (hz) and end-to-end latency (delay_s) so rate and latency regressions are visible. It prints the session-instances/... artifact path so failures (and the per-peer logs/<peer>/catmux/... pane output) can be inspected after the containers stop.

Live status / debugging overview

Enable a continuously-updated, per-topic pipeline overview by setting shared.use_status_overview: true in the session definition (see the ready-made 1_heartbeat_status example). For every configured topic it tracks where the topic currently is in the communication pipeline (furthest stage reached and the first stage that is missing/broken), plus last-message age, Hz, mean size, and latency.

The running session writes, under session-instances/.../logs/<peer>/status/:

  • status.json — machine-readable snapshot (source of truth) for tools/agents, refreshed on a short interval and on every state transition,
  • status.txt — a human-rendered table, and
  • events.jsonl — one line per state transition (when/where a topic stalled).

Read it from the host with the status command:

rosotacom status 1_heartbeat_status            # human-readable table
rosotacom status 1_heartbeat_status --json     # machine-readable, for tools/agents
rosotacom status 1_heartbeat_status --watch    # live refresh

Phase 1 reports each peer's locally-observable stages (outbound up to the /ota topic this peer publishes; inbound from the received /ota topic through the republished application topic). Combine both peers' files for the full end-to-end picture; cross-peer confirmation is reserved for a later phase.

Run the CI heartbeat smoke matrix locally:

just test-e2e-smoke

Run the heartbeat example manually:

./scripts/1_heartbeat/run_machine_a.sh
./scripts/1_heartbeat/run_machine_b.sh

For examples with external application containers, use the matching machine script directory. Example:

cd scripts/2_native_chatter/machine_a
./run_external.py
./run_communication.sh

The sessions/ directory contains the built-in session definitions:

  • 1_heartbeat_fastdds: minimal heartbeat exchange over FastDDS
  • 1_heartbeat_cyclone-ota: heartbeat with CycloneDDS OTA config
  • 1_heartbeat_zen-endpoints: heartbeat with native Zenoh connected endpoints
  • 1_heartbeat_fastdds-local_cyclone-ota: local FastDDS with CycloneDDS OTA config
  • 1_heartbeat_cyclone-local_fastdds-ota: local CycloneDDS with FastDDS OTA
  • 1_heartbeat_cyclone-local_zenoh-ros2dds-ota: local CycloneDDS with Zenoh-ROS2DDS OTA
  • 2_native_chatter: bridge /chatter from machine_b to machine_a
  • 3_comp_occ_grid: compressed occupancy grid over DDS
  • 4_comp_occ_grid_zen: compressed occupancy grid through Zenoh
  • 5_sized_payload: sized payload test over DDS
  • 6_sized_payload_zen: sized payload test through Zenoh

Development

For contributor setup, local checks, PR workflow, CI, and releases, see CONTRIBUTING.md. CI behavior is summarized in docs/ci.md, releases in docs/release.md, and issue-driven work tracking in docs/work-items.md.

Choosing the Transport Layer: CycloneDDS or Zenoh

  • Use CycloneDDS when all machines share the same ROS_DOMAIN_ID. This is the simplest and most direct configuration.

  • Use Zenoh when peers cannot rely on one shared DDS domain, or when you want to split local application nodes and OTA-facing bridge nodes into different ROS 2 domains on each peer. In that split-domain setup this repository generates a standard ROS 2 domain_bridge for /com/... topics locally, while Zenoh carries the /ota/... traffic between peers.

Position in the OTA Communication Landscape

This repository fits into a broader set of ROS-based OTA communication approaches:

  • Direct ROS 2 DDS Communication Native DDS (CycloneDDS, Fast DDS), often with custom configuration for constrained or long-range links. The examples in this repository use CycloneDDS to illustrate this approach.

  • ROS 2 over Router-like Backbones Some RMW have their own DDS Routers such as eProsima/DDS-Router. Example 4 uses Zenoh to act as a lightweight router layer.

  • MQTT-based Approaches Common in cloud/IoT scenarios. Example: ika-rwth-aachen/mqtt_client

  • Custom TCP/UDP Teleoperation Stacks Some frameworks implement their manual tcp/udp transportion layers. Example: TUMFTM/teleoperated_driving

How to Cite

If you wish to cite the ROS Communication DevContainer in your work, please use the following citation:

@InProceedings{gontscharow_scalable,
  author    = {Gontscharow, Martin and Doll Jens and Schotschneider, Albert and Bogdoll, Daniel and Orf Stefan and Jestram Johannes and Zofka, Marc and Z\"{o}llner, J. Marius},
  title     = {{Scalable Remote Operation for Autonomous Vehicles: Integration of Cooperative Perception and Open Source Communication}},
  booktitle = {2024 IEEE Intelligent Vehicles Symposium (IV)},
  year      = {2024}
}

Acknowledgements

The research leading to these results was conducted within the project ÖV-LeitmotiF-KI and was funded by the German Federal Ministry for Digital and Transport (BMDV), grant number 45AVF3004A-G. Responsibility for the information and views set out in this publication lies entirely with the authors.

Project details


Release history Release notifications | RSS feed

This version

2.1

Download files

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

Source Distribution

rosotacom-2.1.tar.gz (1.5 MB view details)

Uploaded Source

Built Distribution

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

rosotacom-2.1-py3-none-any.whl (476.6 kB view details)

Uploaded Python 3

File details

Details for the file rosotacom-2.1.tar.gz.

File metadata

  • Download URL: rosotacom-2.1.tar.gz
  • Upload date:
  • Size: 1.5 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for rosotacom-2.1.tar.gz
Algorithm Hash digest
SHA256 98549663853b016b41ac76a0ddc156c061111d1eca1844b45e22f63cb2021e22
MD5 02e8598bdcaa70799eef6b8c17014cb2
BLAKE2b-256 da07d31a140c28dd70d5d24594dd7a3d3a90ca62acd230876104e90f7e807a57

See more details on using hashes here.

Provenance

The following attestation bundles were made for rosotacom-2.1.tar.gz:

Publisher: release.yml on develNor/ros_communication_devcontainer

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

File details

Details for the file rosotacom-2.1-py3-none-any.whl.

File metadata

  • Download URL: rosotacom-2.1-py3-none-any.whl
  • Upload date:
  • Size: 476.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for rosotacom-2.1-py3-none-any.whl
Algorithm Hash digest
SHA256 430de52e3b2efc5f74c6adf2cc909ad24977b37d2c3cc4d7d7b8a609d539b389
MD5 ec8f55b052e8279a77f24c5f2bdc57f9
BLAKE2b-256 b2fb42d7f0e33f05b8ae369d3d9f2e42381ebbf947979a49bb953dca14cfee97

See more details on using hashes here.

Provenance

The following attestation bundles were made for rosotacom-2.1-py3-none-any.whl:

Publisher: release.yml on develNor/ros_communication_devcontainer

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