rosotacom-dev 2.5.dev65__tar.gz → 2.5.dev66__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/PKG-INFO +1 -1
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/findings/README.md +1 -0
- rosotacom_dev-2.5.dev66/docs/findings/one-domain-two-cyclone-configs-stop-interoperating.md +94 -0
- rosotacom_dev-2.5.dev66/src/rosotacom/resources/ws/ota_configs/cyclonedds_scoped.xml.template +87 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ota_configs/get_ota_xml.py +75 -30
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/session/content/base/session_plugin_base.yaml +4 -4
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom_dev.egg-info/PKG-INFO +1 -1
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom_dev.egg-info/SOURCES.txt +2 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom_dev.egg-info/scm_file_list.json +2 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom_dev.egg-info/scm_version.json +2 -2
- rosotacom_dev-2.5.dev66/tests/unit/test_ota_xml.py +134 -0
- rosotacom_dev-2.5.dev65/tests/unit/test_ota_xml.py +0 -70
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/.devcontainer/devcontainer.json.template +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/.devcontainer/re_generate_devcontainer_json.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/.github/CODEOWNERS +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/.github/ISSUE_TEMPLATE/documentation-audit.md +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/.github/ISSUE_TEMPLATE/implementation-cleanup.md +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/.github/ISSUE_TEMPLATE/quality-workflow.md +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/.github/ISSUE_TEMPLATE/redesign.md +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/.github/ISSUE_TEMPLATE/release-process.md +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/.github/ISSUE_TEMPLATE/repository-diagnosis.md +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/.github/ISSUE_TEMPLATE/test-ci-audit.md +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/.github/ISSUE_TEMPLATE/work-item.md +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/.github/actions/setup-just/action.yml +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/.github/dependabot.yml +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/.github/workflows/benchmark-calibrate.yml +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/.github/workflows/benchmark-gate.yml +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/.github/workflows/dev-release.yml +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/.github/workflows/image-scan.yml +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/.github/workflows/nightly-e2e.yml +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/.github/workflows/pr-lightweight.yml +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/.github/workflows/pr-merge-gate.yml +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/.github/workflows/release.yml +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/.pre-commit-config.yaml +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/AGENTS.md +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/CONCURRENCY.md +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/CONTRIBUTING.md +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/DEVELOPMENT_PRINCIPLES.md +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/LICENSE.txt +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/MANIFEST.in +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/README.md +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/budgets.jsonl +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/calibration/README.md +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/calibration/capacity-size-tight-cyclone.json +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/calibration/probe-loss-gop-tight-cyclone.json +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/calibration/probe-loss-nominal-cyclone.json +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/calibration/probe-loss-tight-cyclone.json +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/calibration/probe-loss-tight-fastdds.json +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/calibration/probe-loss-tight-zenoh.json +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/codecov.yml +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/deployment-configuration.md +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/benchmark-ab.md +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/benchmark-bag-as-load.md +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/ci.md +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/ffmpeg-keyframes.md +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/findings/a-transport-element-doubles-every-fastdds-sample.md +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/findings/cyclone-fragment-equal-to-max-drops-fragmented-samples.md +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/findings/cyclone-spdp-discovery-bursts.md +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/findings/delay-alone-no-loss.md +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/findings/fastdds-datagram-cap-drops-large-samples.md +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/findings/graph-derived-types-block-a-non-graph-transport.md +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/findings/head-of-line-irregularity.md +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/findings/jitter-loss-bandwidth-latency.md +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/findings/keyframe-loss-kills-the-next-deltas.md +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/findings/lifespan-is-enforced-by-one-reader-and-not-the-other.md +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/findings/lighter-message-loss.md +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/findings/oversubscription-queues-not-losses.md +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/findings/reorder-becomes-reader-loss.md +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/findings/repro/decode_chain_repro.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/findings/repro/reorder_drop_repro.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/findings/sender-rows-make-a-dead-link-look-loss-free.md +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/findings/zero-loss-boundaries-18kb-20hz.md +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/forensics-report.md +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/geo-link-map.md +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/github-repository-settings.md +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/link-bandwidth.md +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/link-trace.md +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/owner-runbook.md +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/performance-bands.md +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/playbooks/README.md +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/quality-model.md +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/release-notes/TEMPLATE.md +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/release-notes/v2.1.md +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/release-notes/v2.2.md +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/release-notes/v2.3.md +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/release-notes/v2.4.md +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/release.md +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/rfcs/0001-expectation-driven-test-suite.md +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/rfcs/0002-expectation-concepts.md +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/rfcs/0003-metric-backbone.md +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/rfcs/0004-network-profiles.md +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/rfcs/0005-benchmark-genres-and-ci.md +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/rfcs/0006-dynamic-qos.md +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/rfcs/0007-regression-gate.md +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/rfcs/README.md +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/testing.md +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/docs/work-items.md +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/install.sh +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/justfile +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/media/control_center.png +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/media/echo_test.png +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/media/forensics-report-example.png +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/media/host.png +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/media/vehicle.png +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/pyproject.toml +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/requirements.txt +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/rosotacom.yaml +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/session-configuration.md +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/setup.cfg +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/__init__.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/__main__.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/anonymize.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/bag_ground_truth.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/benched_set.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/benchmark.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/benchmark_delta.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/bundle_check.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/cli.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/cli_benchmark.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/deployment.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/ffmpeg_packet.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/forensics.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/geomap.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/image_cache.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/netem_dist.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/network_preflight.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/network_profiles.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/network_shaper.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/plots.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/py.typed +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/benched-set.yaml +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/.gitignore +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/README.md +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/__init__.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/bags/8_drop_reference/metadata.yaml +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/deployment.example.yaml +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/dist/field-20260817.dist +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/profiles.yaml +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/ros2docker.lyrical.json +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/rosotacom.yaml +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scenarios/2_native_chatter/scenario-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/1_heartbeat/run_machine_a.sh +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/1_heartbeat/run_machine_b.sh +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_a/external.lyrical.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_a/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_a/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_a/run_external.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_a/wait_for_echo_topic.sh +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_b/external.lyrical.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_b/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_b/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_b/run_external.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_a/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_a/external_session.yaml +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_a/foxglove.json +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_a/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_a/run_external.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_b/costmap_1second/costmap_1second_0.mcap +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_b/costmap_1second/metadata.yaml +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_b/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_b/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_b/run_external.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_a/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_a/external_session.yaml +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_a/foxglove.json +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_a/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_a/run_external.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_b/costmap_1second/costmap_1second_0.mcap +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_b/costmap_1second/metadata.yaml +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_b/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_b/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_b/run_external.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_a/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_a/external_session.yaml +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_a/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_a/run_external.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_b/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_b/external_session.yaml +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_b/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_b/run_external.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_a/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_a/external_session.yaml +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_a/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_a/run_external.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_b/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_b/external_session.yaml +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_b/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_b/run_external.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/sessions/10_restamp/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/sessions/11_trickle/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/sessions/12_content_integrity/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/sessions/13_link_latency/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/sessions/14_remote_assist_anonymized/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/sessions/15_remote_assist_anonymized_costmap/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/sessions/16_remote_assist_anonymized_camera/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/sessions/17_synthetic_camera_quality/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/sessions/1_heartbeat/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/sessions/1_heartbeat_status/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/sessions/2_native_chatter/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/sessions/3_comp_occ_grid/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/sessions/4_comp_occ_grid_zen/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/sessions/5_sized_payload/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/sessions/6_sized_payload_zen/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/sessions/7_latched_static/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/sessions/8_drop/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/sessions/9_throttle/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/sessions/bench_1_1_capacity/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/sessions/bench_1_2_load_sweep/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/sessions/bench_1_3_ramp/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/sessions/bench_1_4_recovery/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/examples/sessions/bench_1_5_camera/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ros2docker.json.example +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ros2docker.lyrical.json.example +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/.vscode/c_cpp_properties.json +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/.vscode/settings.json +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_easy_mode.xml.template +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_initial_peer_list.xml.template +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_v2.xml.template +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_v3.xml.template +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_v4.xml.template +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_v5.xml.template +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ota_configs/create_zenoh_json5.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ota_configs/cyclonedds_local_participants.xml.template +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ota_configs/cyclonedds_minimal.xml.template +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ota_configs/cyclonedds_tuned.xml.template +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ota_configs/fastdds_easy_mode.xml.template +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ota_configs/fastdds_local.xml.template +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ota_configs/fastdds_tuned.xml.template +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ota_configs/fastdds_unicast.xml.template +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ota_configs/utils.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ota_configs/zenoh.json5.template +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/.gitkeep +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_cpp/CMakeLists.txt +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_cpp/COLCON_IGNORE +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_cpp/LICENSE.txt +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_cpp/package.xml +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_cpp/src/hz_monitor.cpp +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_cpp/src/universal_compressor.cpp +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_cpp/src/universal_decompressor.cpp +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_msgs/CMakeLists.txt +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_msgs/LICENSE.txt +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_msgs/msg/CompressedData.msg +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_msgs/msg/EchoHeartbeat.msg +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_msgs/msg/OtaStamped.msg +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_msgs/msg/SizedPayload.msg +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_msgs/package.xml +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/LICENSE.txt +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/com_py/__init__.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/com_py/base_bridge_relay.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/com_py/bridge_in.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/com_py/bridge_out.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/com_py/ffmpeg_flags.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/com_py/heartbeat_echo.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/com_py/hz_monitor.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/com_py/image_bandwidth_reducer.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/com_py/image_pixel_capper.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/com_py/lanelet_saver.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/com_py/latch_relay.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/costmap_remapper.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/marker_remapper.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/speed_test.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/tf_remapper.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/traffic_monitor.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/wifi_network_analysis_1.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/com_py/link_bytes.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/com_py/link_trace.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/com_py/local_global_frame_bridge.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/com_py/localization_map_split_reduce_saver.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/com_py/msg_transform.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/com_py/pair_management.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/com_py/playout_pacer.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/com_py/playout_pacer_core.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/com_py/pub_sub_pair.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/com_py/qos.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/com_py/relay_in.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/com_py/relay_out.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/com_py/restamp.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/com_py/sized_publisher.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/com_py/stage_latency.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/com_py/stage_latency_core.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/com_py/status_overview.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/com_py/status_overview_core.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/com_py/tf_map_to_cart_saver.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/com_py/topic_monitor.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/com_py/topic_resolution.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/com_py/trickle.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/com_py/universal_compressor.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/com_py/universal_decompressor.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/com_py/universal_ota_unwrapper.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/com_py/universal_ota_wrapper.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/package.xml +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/resource/com_py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/setup.cfg +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/setup.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/test/test_copyright.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/test/test_flake8.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/ros2src/com_py/test/test_pep257.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/session/content/network/up_connectivity.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/session/content/network/wifi_network_analysis_2.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/session/creation/anonymize_bag.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/session/creation/catmux_log_setup.sh +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/session/creation/create_session_yaml.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/session/creation/generate_session_files.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/session/creation/run_session.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/session/creation/run_session_in_external_terminal.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/resources/ws/session/creation/strip_ansi.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/status_eval.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/stream_stats.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/trace_profiles.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/transit.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom/video_quality.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom_dev.egg-info/dependency_links.txt +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom_dev.egg-info/entry_points.txt +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom_dev.egg-info/requires.txt +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom_dev.egg-info/top_level.txt +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/terminology.md +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/contract/test_benched_set_registry.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/contract/test_findings.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/contract/test_generated_topics_have_a_producer.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/contract/test_lyrical_runtime_compat.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/contract/test_markdown_links.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/contract/test_ota_source_bundle.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/contract/test_package_metadata.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/contract/test_packaged_resources.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/contract/test_profile_covers_generated_commands.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/contract/test_pytest_policy.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/contract/test_readme_examples.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/contract/test_security_maintenance_config.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/contract/test_session_configuration_doc.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/contract/test_session_template_substitution.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/contract/test_workflow_contracts.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/e2e/conftest.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/e2e/test_anonymize_e2e.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/e2e/test_benchmark_ab.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/e2e/test_benchmark_capacity.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/e2e/test_benchmark_replay.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/e2e/test_parallel_smoke.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/e2e/test_smoke.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/e2e/test_timeline_stepping.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/e2e/test_video_quality_e2e.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/sessions/generate_rmw_matrix.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/sessions/rmw_matrix/1_heartbeat_cyclone-local_zenoh-ros2dds-ota/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/sessions/rmw_matrix/1_heartbeat_cyclone-ota/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/sessions/rmw_matrix/1_heartbeat_cyclone-ota-tuned/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/sessions/rmw_matrix/1_heartbeat_fastdds/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/sessions/rmw_matrix/1_heartbeat_fastdds-default/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/sessions/rmw_matrix/1_heartbeat_zen-endpoints/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/unit/test_anonymize.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/unit/test_bag_ground_truth.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/unit/test_benched_set.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/unit/test_benchmark.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/unit/test_benchmark_delta.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/unit/test_bundle_check.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/unit/test_catmux_pane_logging.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/unit/test_cli.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/unit/test_cli_benchmark.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/unit/test_concurrency.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/unit/test_container_shaping.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/unit/test_deployment.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/unit/test_ffmpeg_flags.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/unit/test_ffmpeg_packet.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/unit/test_field_profiles.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/unit/test_forensics.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/unit/test_geomap.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/unit/test_image_cache.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/unit/test_link_bytes.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/unit/test_link_trace.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/unit/test_netem_dist.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/unit/test_network_preflight.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/unit/test_network_profiles.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/unit/test_network_shaper.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/unit/test_ota_link_configs.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/unit/test_ota_unwrapper.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/unit/test_ota_wrapper.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/unit/test_playout_pacer.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/unit/test_plots.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/unit/test_pub_sub_pair_types.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/unit/test_qos_fallback_logging.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/unit/test_relay_optional_parameters.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/unit/test_ros_node_entity_ownership.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/unit/test_session_pipeline.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/unit/test_stage_latency.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/unit/test_status_eval.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/unit/test_status_overview.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/unit/test_status_overview_observer.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/unit/test_stream_stats.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/unit/test_trace_profiles.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/unit/test_transit.py +0 -0
- {rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/tests/unit/test_video_quality.py +0 -0
|
@@ -32,6 +32,7 @@ living verification hook.
|
|
|
32
32
|
- [A bridge that learns types from the graph cannot use a transport that does not carry the graph](graph-derived-types-block-a-non-graph-transport.md) - over `zenoh_ros2dds` the payload topic never arrived in either run: the bridge routes a topic once a local reader exists and the reader waited for the bridge, leaving only `Pending=1` in a log.
|
|
33
33
|
- [A Fast DDS datagram cap stops every message larger than it](fastdds-datagram-cap-drops-large-samples.md) - copying CycloneDDS's 1200 B fragment size into the Fast DDS OTA profile makes every sample above the cap never arrive, at 1200 B and at 8192 B, sync and async — while the 84 B heartbeat keeps flowing at 10 Hz.
|
|
34
34
|
- [A fragment sized exactly like the datagram cap stops every fragmented sample](cyclone-fragment-equal-to-max-drops-fragmented-samples.md) - CycloneDDS 11.0.1 delivers nothing above one fragment when `FragmentSize` equals `MaxMessageSize`, where 0.10.5 delivers everything on the identical profile; a 40 B string still crosses, and discovery, endpoint announcement and proxy-writer matching all succeed while no sample arrives.
|
|
35
|
+
- [Two CycloneDDS configurations on one domain stop interoperating](one-domain-two-cyclone-configs-stop-interoperating.md) - on 11.0.1 a publisher and a subscriber on the same host and domain deliver nothing when one carries the local profile and the other the OTA profile, where 0.10.5 delivers in all four combinations; discovery, endpoint announcement and matching all succeed while no sample moves.
|
|
35
36
|
- [A lost keyframe silences exactly the next gop_size−2 deltas](keyframe-loss-kills-the-next-deltas.md) - libavcodec emits nothing for them, the last delta decodes with artifacts, the next keyframe restores clean decode; a lost delta never blocks decode — so the display hole is gop_size × frame period, deterministically.
|
|
36
37
|
- [Any transport element in a Fast DDS profile doubles every sample on the wire](a-transport-element-doubles-every-fastdds-sample.md) - 366 datagrams for 180 samples against 183 without it; `<builtinTransports>DEFAULT` is a no-op selection and doubles too, so the trigger is the element's presence — removing it takes the shipped OTA profile from 2.10x the payload to 1.04x at identical delivery.
|
|
37
38
|
- [Lifespan is enforced by one DDS reader and not the other](lifespan-is-enforced-by-one-reader-and-not-the-other.md) - under the same 20% oversubscription both stacks queue alike (472 and 433 delivered at ~1.1-1.2 s); with `lifespan: 0.7` CycloneDDS is unchanged and delivers 9.1% inside the bound, while Fast DDS drops to 4 delivered and never exceeds 570 ms — the policy decides shown-vs-suppressed, not how long the wait is.
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# Two CycloneDDS Configurations on One Domain Stop Interoperating
|
|
2
|
+
|
|
3
|
+
## Claim
|
|
4
|
+
|
|
5
|
+
On CycloneDDS 11.0.1 two participants on the **same host and the same domain**
|
|
6
|
+
exchange no data when they are given different configurations. On 0.10.5 they
|
|
7
|
+
do. Discovery is unaffected in the failing combination — the topic appears in
|
|
8
|
+
`ros2 topic list`, both sides announce their endpoints, the reader builds its
|
|
9
|
+
proxy writers — and no sample is delivered.
|
|
10
|
+
|
|
11
|
+
This is what a session relies on without saying so. A peer renders two whole
|
|
12
|
+
configurations, a local one and an OTA one, and exports `CYCLONEDDS_URI` twice,
|
|
13
|
+
so the second replaces the first: processes started after it view the *local*
|
|
14
|
+
domain through the *OTA* profile while the relay and the application containers
|
|
15
|
+
view it through the local one. Under 0.10.5 that mixture worked. Under 11.0.1
|
|
16
|
+
the bridge subscribes on the local domain, receives nothing, forwards nothing
|
|
17
|
+
into the OTA domain, and the far peer receives nothing — with every stage
|
|
18
|
+
reporting itself healthy.
|
|
19
|
+
|
|
20
|
+
## Setup
|
|
21
|
+
|
|
22
|
+
- Host pair / topology: for the effect itself, one host is enough — two
|
|
23
|
+
containers from the same communication image, `--network host`, one ROS
|
|
24
|
+
domain, one publisher and one subscriber. The session it was found in runs
|
|
25
|
+
across two hosts joined by a point-to-point VPN.
|
|
26
|
+
- Session: none for the isolated measurement; a `std_msgs/msg/String` at 2 Hz
|
|
27
|
+
and `ros2 topic echo … --once`. The two configurations are the ones a session
|
|
28
|
+
renders: `cyclonedds_local_participants.xml` and `cyclonedds_tuned.xml`.
|
|
29
|
+
- rosotacom SHA: measured on the packaged 2.5.dev61 images; re-runs record
|
|
30
|
+
theirs.
|
|
31
|
+
- Profile: none — no impairment; the effect needs none.
|
|
32
|
+
- Seed policy: deterministic (no netem, no random load), `n=1` per cell; the
|
|
33
|
+
effect is present/absent, not a distribution.
|
|
34
|
+
- Stacks: `ros-kilted-cyclonedds` 0.10.5-2noble against
|
|
35
|
+
`ros-lyrical-cyclonedds` 11.0.1-4resolute.
|
|
36
|
+
|
|
37
|
+
## Evidence
|
|
38
|
+
|
|
39
|
+
| publisher / subscriber | 0.10.5 | 11.0.1 |
|
|
40
|
+
|---|---|---|
|
|
41
|
+
| local / local | 12 B | 12 B |
|
|
42
|
+
| local / **ota** | 12 B | **0** |
|
|
43
|
+
| **ota** / local | 12 B | **0** |
|
|
44
|
+
| ota / ota | 12 B | 12 B |
|
|
45
|
+
|
|
46
|
+
Inside a failing session, one topic the relay publishes on the local domain:
|
|
47
|
+
|
|
48
|
+
```
|
|
49
|
+
/com/out/<peer>/can/twist/max10hz/ota_stamped, domain 47
|
|
50
|
+
subscriber with local_dds.xml : 512 B received
|
|
51
|
+
subscriber with ota_dds.xml : 0 B
|
|
52
|
+
domain 47 seen through local_dds.xml : 103 topics
|
|
53
|
+
domain 47 seen through ota_dds.xml : 29 topics
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Ruled out on the way to it, each measured with the real images on the same
|
|
57
|
+
hosts: cross-host delivery, same-host delivery under one profile,
|
|
58
|
+
`com_msgs/msg/OtaStamped`, the container's IPC namespace, `domain_bridge`
|
|
59
|
+
itself (minimal config, the session's full 27-topic config, with and without the
|
|
60
|
+
OTA profile, with and without `ROS_DOMAIN_ID` set), participant count (0, 6 and
|
|
61
|
+
12 extra participants), and adding the local profile's
|
|
62
|
+
`ParticipantIndex`/`MaxAutoParticipantIndex` to the OTA profile.
|
|
63
|
+
|
|
64
|
+
Verification: automated:
|
|
65
|
+
`pytest tests/unit/test_ota_xml.py::test_shipped_scoped_template_carries_both_domains_and_only_ota_restrictions`
|
|
66
|
+
holds the shape of the configuration that avoids the mixture — OTA restrictions
|
|
67
|
+
scoped to the OTA domain, the local domain left with default discovery. Manual,
|
|
68
|
+
for the effect itself: two containers on one host and one domain, one publisher
|
|
69
|
+
and one subscriber, each given one of the two rendered profiles, all four
|
|
70
|
+
combinations.
|
|
71
|
+
|
|
72
|
+
## Status
|
|
73
|
+
|
|
74
|
+
confirmed, 2026-08-20.
|
|
75
|
+
|
|
76
|
+
Addressed by `cyclonedds_scoped.xml.template`, which carries both domains in one
|
|
77
|
+
file with each section scoped by `Domain Id`, so one configuration can be shared
|
|
78
|
+
by every process on the host. It is an additional template: the two-file
|
|
79
|
+
arrangement is unchanged, and a session that does not name the new one behaves
|
|
80
|
+
exactly as before.
|
|
81
|
+
|
|
82
|
+
## Publication notes
|
|
83
|
+
|
|
84
|
+
The reportable part is not "a DDS version changed". It is that a configuration
|
|
85
|
+
which was *never* uniform became load-bearing without anybody choosing it: the
|
|
86
|
+
mixture had been there all along and was harmless, so nothing recorded it as a
|
|
87
|
+
property of the deployment. A measurement stack should state, beside the
|
|
88
|
+
middleware version, whether every process on a domain was configured
|
|
89
|
+
identically — because on one side of that version boundary the answer does not
|
|
90
|
+
matter and on the other it decides whether any data moves.
|
|
91
|
+
|
|
92
|
+
Second, it is another instance of the same trap as the datagram cap: a link that
|
|
93
|
+
passes discovery, endpoint matching and a heartbeat check while carrying
|
|
94
|
+
nothing. Neither check tests what the payload uses.
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<!--
|
|
3
|
+
One CycloneDDS configuration for both of a peer's domains, each section scoped
|
|
4
|
+
to the domain it belongs to.
|
|
5
|
+
|
|
6
|
+
Set it as `shared.rmw.ota.cyclone.config` and leave the local one unset: this
|
|
7
|
+
file already carries the local domain's section, so nothing has to overwrite
|
|
8
|
+
anything.
|
|
9
|
+
|
|
10
|
+
Why it exists. The two-file arrangement renders a local profile and an OTA
|
|
11
|
+
profile and exports CYCLONEDDS_URI twice, so the second replaces the first and
|
|
12
|
+
every process started after it views the *local* domain through the *OTA*
|
|
13
|
+
profile. On CycloneDDS 0.10.5 that was survivable: participants configured
|
|
14
|
+
differently on one host and one domain still exchanged data. On 11.0.1 they do
|
|
15
|
+
not — they discover each other, announce their endpoints, match, and deliver
|
|
16
|
+
nothing. Measured on one host, one domain, a publisher and a subscriber:
|
|
17
|
+
|
|
18
|
+
publisher / subscriber 0.10.5 11.0.1
|
|
19
|
+
local / local 12 B 12 B
|
|
20
|
+
local / ota 12 B 0
|
|
21
|
+
ota / local 12 B 0
|
|
22
|
+
ota / ota 12 B 12 B
|
|
23
|
+
|
|
24
|
+
A session whose relay publishes under one profile and whose bridge subscribes
|
|
25
|
+
under the other therefore hands nothing from the local domain into the OTA
|
|
26
|
+
domain, and the link carries nothing while every stage looks healthy
|
|
27
|
+
(docs/findings/one-domain-two-cyclone-configs-stop-interoperating.md).
|
|
28
|
+
|
|
29
|
+
Scoping fixes the cause rather than the symptom: the OTA settings apply to the
|
|
30
|
+
OTA domain, the local domain keeps default discovery with room for many
|
|
31
|
+
participants, and one file can be shared by every process on the host.
|
|
32
|
+
|
|
33
|
+
The two-file arrangement stays exactly as it was — this is an additional
|
|
34
|
+
template, not a replacement, and a session that does not name it is unchanged.
|
|
35
|
+
-->
|
|
36
|
+
<CycloneDDS xmlns="https://cdds.io/config">
|
|
37
|
+
<!--
|
|
38
|
+
The OTA domain: interface-pinned, unicast-only, with the datagram caps the
|
|
39
|
+
provisioned link is sized for. Identical to cyclonedds_tuned.xml except that
|
|
40
|
+
it says which domain it is for.
|
|
41
|
+
-->
|
|
42
|
+
<Domain Id="#ota_domain">
|
|
43
|
+
<General>
|
|
44
|
+
<AllowMulticast>false</AllowMulticast>
|
|
45
|
+
<Interfaces>
|
|
46
|
+
<NetworkInterface address="#host_ip"/>
|
|
47
|
+
</Interfaces>
|
|
48
|
+
<MulticastRecvNetworkInterfaceAddresses>none</MulticastRecvNetworkInterfaceAddresses>
|
|
49
|
+
<!-- Strictly below MaxMessageSize; see cyclonedds_tuned.xml for what
|
|
50
|
+
making them equal cost. -->
|
|
51
|
+
<FragmentSize>1024B</FragmentSize>
|
|
52
|
+
<MaxMessageSize>1200B</MaxMessageSize>
|
|
53
|
+
<MaxRexmitMessageSize>1200B</MaxRexmitMessageSize>
|
|
54
|
+
</General>
|
|
55
|
+
|
|
56
|
+
<Discovery>
|
|
57
|
+
<Peers>
|
|
58
|
+
<!--peer-block--><Peer Address="#peer"/><!--/peer-block-->
|
|
59
|
+
</Peers>
|
|
60
|
+
<EnableTopicDiscoveryEndpoints>false</EnableTopicDiscoveryEndpoints>
|
|
61
|
+
<LeaseDuration>60s</LeaseDuration>
|
|
62
|
+
<SPDPInterval>#spdp_interval</SPDPInterval>
|
|
63
|
+
</Discovery>
|
|
64
|
+
|
|
65
|
+
<Internal>
|
|
66
|
+
<SquashParticipants>true</SquashParticipants>
|
|
67
|
+
</Internal>
|
|
68
|
+
|
|
69
|
+
<Tracing>
|
|
70
|
+
<Verbosity>config</Verbosity>
|
|
71
|
+
<OutputFile>/tmp/cyclonedds.log</OutputFile>
|
|
72
|
+
</Tracing>
|
|
73
|
+
</Domain>
|
|
74
|
+
|
|
75
|
+
<!--
|
|
76
|
+
The local domain: default discovery, more participants. It pins no interface,
|
|
77
|
+
disables no multicast and sets no peer list, because intra-host discovery has
|
|
78
|
+
to keep working — the same reasoning as cyclonedds_local_participants.xml,
|
|
79
|
+
including why 119 and not higher.
|
|
80
|
+
-->
|
|
81
|
+
<Domain Id="#local_domain">
|
|
82
|
+
<Discovery>
|
|
83
|
+
<ParticipantIndex>auto</ParticipantIndex>
|
|
84
|
+
<MaxAutoParticipantIndex>119</MaxAutoParticipantIndex>
|
|
85
|
+
</Discovery>
|
|
86
|
+
</Domain>
|
|
87
|
+
</CycloneDDS>
|
|
@@ -15,8 +15,20 @@ import re
|
|
|
15
15
|
import sys
|
|
16
16
|
import tempfile
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
KNOWN_PLACEHOLDERS = {
|
|
19
|
+
"#host_ip",
|
|
20
|
+
"#peer",
|
|
21
|
+
"#easy_mode_ip",
|
|
22
|
+
"#spdp_interval",
|
|
23
|
+
#: A template that scopes its settings to one ROS domain resolves these.
|
|
24
|
+
#: Cyclone applies a <Domain> section to the domain its Id names, so a
|
|
25
|
+
#: single configuration can hold the OTA settings for the OTA domain and
|
|
26
|
+
#: leave the local domain alone — which is what lets every process on a
|
|
27
|
+
#: host share one configuration instead of half of them carrying the OTA
|
|
28
|
+
#: profile and half the local one.
|
|
29
|
+
"#local_domain",
|
|
30
|
+
"#ota_domain",
|
|
31
|
+
}
|
|
20
32
|
PLACEHOLDER_PATTERN = re.compile(r"#[A-Za-z_][A-Za-z0-9_]*")
|
|
21
33
|
DEFAULT_SPDP_INTERVAL = "30s"
|
|
22
34
|
|
|
@@ -48,6 +60,19 @@ def _resolved_address(value: str, label: str) -> str:
|
|
|
48
60
|
return address
|
|
49
61
|
|
|
50
62
|
|
|
63
|
+
def _resolved_domain(value: str, label: str) -> str:
|
|
64
|
+
"""A ROS domain id, validated rather than pasted into the XML.
|
|
65
|
+
|
|
66
|
+
An unusable Id is worse than a missing one: Cyclone keeps a <Domain>
|
|
67
|
+
section it cannot match to any domain, so the settings vanish without a
|
|
68
|
+
word and the link comes up on defaults.
|
|
69
|
+
"""
|
|
70
|
+
domain = str(value).strip()
|
|
71
|
+
if not domain.isdigit() or not 0 <= int(domain) <= 232:
|
|
72
|
+
raise ValueError(f"{label} must be a ROS domain id between 0 and 232, got {value!r}.")
|
|
73
|
+
return str(int(domain))
|
|
74
|
+
|
|
75
|
+
|
|
51
76
|
def _resolved_spdp_interval(value: str) -> str:
|
|
52
77
|
interval = value.strip().lower()
|
|
53
78
|
if not interval:
|
|
@@ -99,9 +124,7 @@ def _expand_peer_block(content: str, peer_ips: list) -> str:
|
|
|
99
124
|
|
|
100
125
|
has_markers = PEER_BLOCK_OPEN in content
|
|
101
126
|
if has_markers and (PEER_BLOCK_CLOSE not in content):
|
|
102
|
-
raise RuntimeError(
|
|
103
|
-
f"Template has '{PEER_BLOCK_OPEN}' without matching '{PEER_BLOCK_CLOSE}'."
|
|
104
|
-
)
|
|
127
|
+
raise RuntimeError(f"Template has '{PEER_BLOCK_OPEN}' without matching '{PEER_BLOCK_CLOSE}'.")
|
|
105
128
|
|
|
106
129
|
if len(peer_ips) == 1 and not has_markers:
|
|
107
130
|
return content.replace("#peer", peer_ips[0])
|
|
@@ -116,9 +139,7 @@ def _expand_peer_block(content: str, peer_ips: list) -> str:
|
|
|
116
139
|
|
|
117
140
|
matches = list(PEER_BLOCK_PATTERN.finditer(content))
|
|
118
141
|
if len(matches) != 1:
|
|
119
|
-
raise RuntimeError(
|
|
120
|
-
f"Template must contain exactly one peer-block region; found {len(matches)}."
|
|
121
|
-
)
|
|
142
|
+
raise RuntimeError(f"Template must contain exactly one peer-block region; found {len(matches)}.")
|
|
122
143
|
m = matches[0]
|
|
123
144
|
block = m.group(1)
|
|
124
145
|
if "#peer" not in block:
|
|
@@ -128,11 +149,11 @@ def _expand_peer_block(content: str, peer_ips: list) -> str:
|
|
|
128
149
|
|
|
129
150
|
# Preserve the indentation of the marker line so duplicated blocks align.
|
|
130
151
|
line_start = content.rfind("\n", 0, m.start()) + 1
|
|
131
|
-
indent = content[line_start:m.start()]
|
|
152
|
+
indent = content[line_start : m.start()]
|
|
132
153
|
sep = ("\n" + indent) if not indent.strip() else ""
|
|
133
154
|
|
|
134
155
|
rendered = sep.join(block.replace("#peer", ip) for ip in peer_ips)
|
|
135
|
-
return content[:m.start()] + rendered + content[m.end():]
|
|
156
|
+
return content[: m.start()] + rendered + content[m.end() :]
|
|
136
157
|
|
|
137
158
|
|
|
138
159
|
def main(
|
|
@@ -141,12 +162,14 @@ def main(
|
|
|
141
162
|
peer: str = None,
|
|
142
163
|
easy_mode_ip: str = None,
|
|
143
164
|
spdp_interval: str = DEFAULT_SPDP_INTERVAL,
|
|
165
|
+
local_domain: str = None,
|
|
166
|
+
ota_domain: str = None,
|
|
144
167
|
) -> str:
|
|
145
168
|
path = _template_path(config)
|
|
146
169
|
if not os.path.exists(path):
|
|
147
170
|
raise FileNotFoundError(f"Template not found: {path}")
|
|
148
171
|
|
|
149
|
-
with open(path,
|
|
172
|
+
with open(path, encoding="utf-8") as f:
|
|
150
173
|
content = f.read()
|
|
151
174
|
|
|
152
175
|
found = set(PLACEHOLDER_PATTERN.findall(content))
|
|
@@ -159,9 +182,7 @@ def main(
|
|
|
159
182
|
|
|
160
183
|
if "#host_ip" in found:
|
|
161
184
|
if not host_ip:
|
|
162
|
-
raise RuntimeError(
|
|
163
|
-
f"Template '{os.path.basename(path)}' uses #host_ip but --host-ip was not provided."
|
|
164
|
-
)
|
|
185
|
+
raise RuntimeError(f"Template '{os.path.basename(path)}' uses #host_ip but --host-ip was not provided.")
|
|
165
186
|
content = content.replace("#host_ip", _resolved_address(host_ip, "Host IP"))
|
|
166
187
|
|
|
167
188
|
if "#easy_mode_ip" in found:
|
|
@@ -169,45 +190,60 @@ def main(
|
|
|
169
190
|
raise RuntimeError(
|
|
170
191
|
f"Template '{os.path.basename(path)}' uses #easy_mode_ip but --easy-mode-ip was not provided."
|
|
171
192
|
)
|
|
172
|
-
content = content.replace(
|
|
173
|
-
"#easy_mode_ip", _resolved_address(easy_mode_ip, "Easy Mode IP")
|
|
174
|
-
)
|
|
193
|
+
content = content.replace("#easy_mode_ip", _resolved_address(easy_mode_ip, "Easy Mode IP"))
|
|
175
194
|
|
|
176
195
|
if "#spdp_interval" in found:
|
|
177
196
|
content = content.replace("#spdp_interval", _resolved_spdp_interval(spdp_interval))
|
|
178
197
|
|
|
198
|
+
for placeholder, value, option in (
|
|
199
|
+
("#local_domain", local_domain, "--local-domain"),
|
|
200
|
+
("#ota_domain", ota_domain, "--ota-domain"),
|
|
201
|
+
):
|
|
202
|
+
if placeholder in found:
|
|
203
|
+
if value is None or not str(value).strip():
|
|
204
|
+
raise RuntimeError(
|
|
205
|
+
f"Template '{os.path.basename(path)}' uses {placeholder} but {option} was not provided."
|
|
206
|
+
)
|
|
207
|
+
content = content.replace(placeholder, _resolved_domain(value, placeholder))
|
|
208
|
+
|
|
179
209
|
if "#peer" in found:
|
|
180
210
|
if not peer:
|
|
181
|
-
raise RuntimeError(
|
|
182
|
-
f"Template '{os.path.basename(path)}' uses #peer but --peer was not provided."
|
|
183
|
-
)
|
|
211
|
+
raise RuntimeError(f"Template '{os.path.basename(path)}' uses #peer but --peer was not provided.")
|
|
184
212
|
content = _expand_peer_block(content, _resolve_peer_ips(peer))
|
|
185
213
|
|
|
186
214
|
return content
|
|
187
215
|
|
|
188
216
|
|
|
189
217
|
if __name__ == "__main__":
|
|
190
|
-
parser = argparse.ArgumentParser(
|
|
191
|
-
description="Resolve placeholders in an OTA DDS XML template."
|
|
192
|
-
)
|
|
218
|
+
parser = argparse.ArgumentParser(description="Resolve placeholders in an OTA DDS XML template.")
|
|
193
219
|
parser.add_argument(
|
|
194
|
-
"-c",
|
|
220
|
+
"-c",
|
|
221
|
+
"--config",
|
|
222
|
+
required=True,
|
|
195
223
|
help="Template name (e.g. fastdds_v1.xml, cyclonedds.xml, fastdds_easy_mode.xml).",
|
|
196
224
|
)
|
|
197
225
|
parser.add_argument(
|
|
198
|
-
"-i",
|
|
226
|
+
"-i",
|
|
227
|
+
"--host-ip",
|
|
228
|
+
dest="host_ip",
|
|
199
229
|
help="Resolved local host address (#host_ip).",
|
|
200
230
|
)
|
|
201
231
|
parser.add_argument(
|
|
202
|
-
"-p",
|
|
232
|
+
"-p",
|
|
233
|
+
"--peer",
|
|
234
|
+
dest="peer",
|
|
203
235
|
help="Resolved peer address, or comma-separated addresses (#peer).",
|
|
204
236
|
)
|
|
205
237
|
parser.add_argument(
|
|
206
|
-
"-e",
|
|
238
|
+
"-e",
|
|
239
|
+
"--easy-mode-ip",
|
|
240
|
+
dest="easy_mode_ip",
|
|
207
241
|
help="Resolved Fast DDS Easy Mode address (#easy_mode_ip).",
|
|
208
242
|
)
|
|
209
243
|
parser.add_argument(
|
|
210
|
-
"-o",
|
|
244
|
+
"-o",
|
|
245
|
+
"--output",
|
|
246
|
+
dest="output",
|
|
211
247
|
help=(
|
|
212
248
|
"Write the rendered XML to this path, atomically. Prefer this over a shell "
|
|
213
249
|
"redirect: `> file` truncates the target before this script runs, so a "
|
|
@@ -216,6 +252,16 @@ if __name__ == "__main__":
|
|
|
216
252
|
"comes up carrying nothing."
|
|
217
253
|
),
|
|
218
254
|
)
|
|
255
|
+
parser.add_argument(
|
|
256
|
+
"--local-domain",
|
|
257
|
+
dest="local_domain",
|
|
258
|
+
help="Local ROS domain id, for a template that scopes a section to it (#local_domain).",
|
|
259
|
+
)
|
|
260
|
+
parser.add_argument(
|
|
261
|
+
"--ota-domain",
|
|
262
|
+
dest="ota_domain",
|
|
263
|
+
help="OTA ROS domain id, for a template that scopes a section to it (#ota_domain).",
|
|
264
|
+
)
|
|
219
265
|
parser.add_argument(
|
|
220
266
|
"--spdp-interval",
|
|
221
267
|
dest="spdp_interval",
|
|
@@ -224,8 +270,7 @@ if __name__ == "__main__":
|
|
|
224
270
|
)
|
|
225
271
|
args = parser.parse_args()
|
|
226
272
|
output = args.output
|
|
227
|
-
rendered = main(**{k: v for k, v in vars(args).items()
|
|
228
|
-
if v is not None and k != "output"})
|
|
273
|
+
rendered = main(**{k: v for k, v in vars(args).items() if v is not None and k != "output"})
|
|
229
274
|
if not output:
|
|
230
275
|
print(rendered)
|
|
231
276
|
raise SystemExit(0)
|
|
@@ -292,7 +292,7 @@ common:
|
|
|
292
292
|
before_commands:
|
|
293
293
|
- if [ '${local_domain_id}' != "None" ] && [ -n '${local_domain_id}' ]; then export ROS_DOMAIN_ID='${local_domain_id}'; fi
|
|
294
294
|
- if [ '${rmw_local}' != "None" ]; then case ${rmw_local} in cyclone) export RMW_IMPLEMENTATION=rmw_cyclonedds_cpp;; fastdds) export RMW_IMPLEMENTATION=rmw_fastrtps_cpp; export FASTDDS_BUILTIN_TRANSPORTS=${FASTDDS_BUILTIN_TRANSPORTS:-UDPv4};; zenoh) export RMW_IMPLEMENTATION=rmw_zenoh_cpp;; *) export RMW_IMPLEMENTATION='${rmw_local}';; esac; fi
|
|
295
|
-
- if [ '${local_config_template}' != "None" ] && [ -n '${local_config_template}' ]; then local_args=(--config "${local_config_template}" --host-ip "${ip_local}" --peer "${ip_remote}"); [ '${local_easy_mode_ip}' != "None" ] && [ -n '${local_easy_mode_ip}' ] && local_args+=(--easy-mode-ip "${local_easy_mode_ip}"); [ '${local_spdp_interval}' != "None" ] && [ -n '${local_spdp_interval}' ] && local_args+=(--spdp-interval "${local_spdp_interval}"); python3 /ws/ota_configs/get_ota_xml.py "${local_args[@]}" --output "${local_config_file}" || { echo "FATAL - could not render the local DDS profile ${local_config_template}; refusing to start on defaults." >&2; exit 1; }; case ${rmw_local} in cyclone) export CYCLONEDDS_URI="file://${local_config_file}";; fastdds) export FASTDDS_DEFAULT_PROFILES_FILE="${local_config_file}"; export RMW_FASTRTPS_USE_QOS_FROM_XML=1;; esac; fi
|
|
295
|
+
- if [ '${local_config_template}' != "None" ] && [ -n '${local_config_template}' ]; then local_args=(--config "${local_config_template}" --host-ip "${ip_local}" --peer "${ip_remote}"); [ '${local_domain_id}' != "None" ] && [ -n '${local_domain_id}' ] && local_args+=(--local-domain "${local_domain_id}"); [ '${ota_domain_id}' != "None" ] && [ -n '${ota_domain_id}' ] && local_args+=(--ota-domain "${ota_domain_id}"); [ '${local_easy_mode_ip}' != "None" ] && [ -n '${local_easy_mode_ip}' ] && local_args+=(--easy-mode-ip "${local_easy_mode_ip}"); [ '${local_spdp_interval}' != "None" ] && [ -n '${local_spdp_interval}' ] && local_args+=(--spdp-interval "${local_spdp_interval}"); python3 /ws/ota_configs/get_ota_xml.py "${local_args[@]}" --output "${local_config_file}" || { echo "FATAL - could not render the local DDS profile ${local_config_template}; refusing to start on defaults." >&2; exit 1; }; case ${rmw_local} in cyclone) export CYCLONEDDS_URI="file://${local_config_file}";; fastdds) export FASTDDS_DEFAULT_PROFILES_FILE="${local_config_file}"; export RMW_FASTRTPS_USE_QOS_FROM_XML=1;; esac; fi
|
|
296
296
|
- if [ '${before_command}' != "None" ]; then ${before_command}; fi
|
|
297
297
|
|
|
298
298
|
windows:
|
|
@@ -338,7 +338,7 @@ windows:
|
|
|
338
338
|
if: use_domain_bridge
|
|
339
339
|
splits:
|
|
340
340
|
- commands:
|
|
341
|
-
- if [ '${ota_config_template}' != "None" ] && [ -n '${ota_config_template}' ]; then ota_args=(--config "${ota_config_template}" --host-ip "${ip_local}" --peer "${ip_remote}"); [ '${ota_easy_mode_ip}' != "None" ] && [ -n '${ota_easy_mode_ip}' ] && ota_args+=(--easy-mode-ip "${ota_easy_mode_ip}"); [ '${ota_spdp_interval}' != "None" ] && [ -n '${ota_spdp_interval}' ] && ota_args+=(--spdp-interval "${ota_spdp_interval}"); python3 /ws/ota_configs/get_ota_xml.py "${ota_args[@]}" --output "${ota_config_file}" || { echo "FATAL - could not render the OTA DDS profile ${ota_config_template}; refusing to start on defaults." >&2; exit 1; }; case ${rmw_ota} in cyclone) export CYCLONEDDS_URI="file://${ota_config_file}";; fastdds) export FASTDDS_DEFAULT_PROFILES_FILE="${ota_config_file}"; export RMW_FASTRTPS_USE_QOS_FROM_XML=1;; esac; fi
|
|
341
|
+
- if [ '${ota_config_template}' != "None" ] && [ -n '${ota_config_template}' ]; then ota_args=(--config "${ota_config_template}" --host-ip "${ip_local}" --peer "${ip_remote}"); [ '${local_domain_id}' != "None" ] && [ -n '${local_domain_id}' ] && ota_args+=(--local-domain "${local_domain_id}"); [ '${ota_domain_id}' != "None" ] && [ -n '${ota_domain_id}' ] && ota_args+=(--ota-domain "${ota_domain_id}"); [ '${ota_easy_mode_ip}' != "None" ] && [ -n '${ota_easy_mode_ip}' ] && ota_args+=(--easy-mode-ip "${ota_easy_mode_ip}"); [ '${ota_spdp_interval}' != "None" ] && [ -n '${ota_spdp_interval}' ] && ota_args+=(--spdp-interval "${ota_spdp_interval}"); python3 /ws/ota_configs/get_ota_xml.py "${ota_args[@]}" --output "${ota_config_file}" || { echo "FATAL - could not render the OTA DDS profile ${ota_config_template}; refusing to start on defaults." >&2; exit 1; }; case ${rmw_ota} in cyclone) export CYCLONEDDS_URI="file://${ota_config_file}";; fastdds) export FASTDDS_DEFAULT_PROFILES_FILE="${ota_config_file}"; export RMW_FASTRTPS_USE_QOS_FROM_XML=1;; esac; fi
|
|
342
342
|
- ros2 run domain_bridge domain_bridge --wait-for-publisher false ${domain_bridge_config_file}
|
|
343
343
|
- name: IN
|
|
344
344
|
if: in
|
|
@@ -346,7 +346,7 @@ windows:
|
|
|
346
346
|
- commands:
|
|
347
347
|
- if [ '${ota_domain_id}' != "None" ] && [ -n '${ota_domain_id}' ]; then export ROS_DOMAIN_ID='${ota_domain_id}'; fi
|
|
348
348
|
- case ${rmw_ota} in cyclone) export RMW_IMPLEMENTATION=rmw_cyclonedds_cpp;; fastdds) export RMW_IMPLEMENTATION=rmw_fastrtps_cpp; export FASTDDS_BUILTIN_TRANSPORTS=${FASTDDS_BUILTIN_TRANSPORTS:-UDPv4};; zenoh) export RMW_IMPLEMENTATION=rmw_zenoh_cpp;; esac
|
|
349
|
-
- if [ '${ota_config_template}' != "None" ] && [ -n '${ota_config_template}' ]; then ota_args=(--config "${ota_config_template}" --host-ip "${ip_local}" --peer "${ip_remote}"); [ '${ota_easy_mode_ip}' != "None" ] && [ -n '${ota_easy_mode_ip}' ] && ota_args+=(--easy-mode-ip "${ota_easy_mode_ip}"); [ '${ota_spdp_interval}' != "None" ] && [ -n '${ota_spdp_interval}' ] && ota_args+=(--spdp-interval "${ota_spdp_interval}"); python3 /ws/ota_configs/get_ota_xml.py "${ota_args[@]}" --output "${ota_config_file}" || { echo "FATAL - could not render the OTA DDS profile ${ota_config_template}; refusing to start on defaults." >&2; exit 1; }; case ${rmw_ota} in cyclone) export CYCLONEDDS_URI="file://${ota_config_file}";; fastdds) export FASTDDS_DEFAULT_PROFILES_FILE="${ota_config_file}"; export RMW_FASTRTPS_USE_QOS_FROM_XML=1;; esac; fi
|
|
349
|
+
- if [ '${ota_config_template}' != "None" ] && [ -n '${ota_config_template}' ]; then ota_args=(--config "${ota_config_template}" --host-ip "${ip_local}" --peer "${ip_remote}"); [ '${local_domain_id}' != "None" ] && [ -n '${local_domain_id}' ] && ota_args+=(--local-domain "${local_domain_id}"); [ '${ota_domain_id}' != "None" ] && [ -n '${ota_domain_id}' ] && ota_args+=(--ota-domain "${ota_domain_id}"); [ '${ota_easy_mode_ip}' != "None" ] && [ -n '${ota_easy_mode_ip}' ] && ota_args+=(--easy-mode-ip "${ota_easy_mode_ip}"); [ '${ota_spdp_interval}' != "None" ] && [ -n '${ota_spdp_interval}' ] && ota_args+=(--spdp-interval "${ota_spdp_interval}"); python3 /ws/ota_configs/get_ota_xml.py "${ota_args[@]}" --output "${ota_config_file}" || { echo "FATAL - could not render the OTA DDS profile ${ota_config_template}; refusing to start on defaults." >&2; exit 1; }; case ${rmw_ota} in cyclone) export CYCLONEDDS_URI="file://${ota_config_file}";; fastdds) export FASTDDS_DEFAULT_PROFILES_FILE="${ota_config_file}"; export RMW_FASTRTPS_USE_QOS_FROM_XML=1;; esac; fi
|
|
350
350
|
# For zenoh_ros2dds the OTA domain is loopback-only (zenoh is the inter-host
|
|
351
351
|
# transport), so confine discovery to localhost instead of statically peering
|
|
352
352
|
# the remote host — otherwise the OTA-domain DDS double-delivers alongside zenoh.
|
|
@@ -373,7 +373,7 @@ windows:
|
|
|
373
373
|
- commands:
|
|
374
374
|
- if [ '${ota_domain_id}' != "None" ] && [ -n '${ota_domain_id}' ]; then export ROS_DOMAIN_ID='${ota_domain_id}'; fi
|
|
375
375
|
- case ${rmw_ota} in cyclone) export RMW_IMPLEMENTATION=rmw_cyclonedds_cpp;; fastdds) export RMW_IMPLEMENTATION=rmw_fastrtps_cpp; export FASTDDS_BUILTIN_TRANSPORTS=${FASTDDS_BUILTIN_TRANSPORTS:-UDPv4};; zenoh) export RMW_IMPLEMENTATION=rmw_zenoh_cpp;; esac
|
|
376
|
-
- if [ '${ota_config_template}' != "None" ] && [ -n '${ota_config_template}' ]; then ota_args=(--config "${ota_config_template}" --host-ip "${ip_local}" --peer "${ip_remote}"); [ '${ota_easy_mode_ip}' != "None" ] && [ -n '${ota_easy_mode_ip}' ] && ota_args+=(--easy-mode-ip "${ota_easy_mode_ip}"); [ '${ota_spdp_interval}' != "None" ] && [ -n '${ota_spdp_interval}' ] && ota_args+=(--spdp-interval "${ota_spdp_interval}"); python3 /ws/ota_configs/get_ota_xml.py "${ota_args[@]}" --output "${ota_config_file}" || { echo "FATAL - could not render the OTA DDS profile ${ota_config_template}; refusing to start on defaults." >&2; exit 1; }; case ${rmw_ota} in cyclone) export CYCLONEDDS_URI="file://${ota_config_file}";; fastdds) export FASTDDS_DEFAULT_PROFILES_FILE="${ota_config_file}"; export RMW_FASTRTPS_USE_QOS_FROM_XML=1;; esac; fi
|
|
376
|
+
- if [ '${ota_config_template}' != "None" ] && [ -n '${ota_config_template}' ]; then ota_args=(--config "${ota_config_template}" --host-ip "${ip_local}" --peer "${ip_remote}"); [ '${local_domain_id}' != "None" ] && [ -n '${local_domain_id}' ] && ota_args+=(--local-domain "${local_domain_id}"); [ '${ota_domain_id}' != "None" ] && [ -n '${ota_domain_id}' ] && ota_args+=(--ota-domain "${ota_domain_id}"); [ '${ota_easy_mode_ip}' != "None" ] && [ -n '${ota_easy_mode_ip}' ] && ota_args+=(--easy-mode-ip "${ota_easy_mode_ip}"); [ '${ota_spdp_interval}' != "None" ] && [ -n '${ota_spdp_interval}' ] && ota_args+=(--spdp-interval "${ota_spdp_interval}"); python3 /ws/ota_configs/get_ota_xml.py "${ota_args[@]}" --output "${ota_config_file}" || { echo "FATAL - could not render the OTA DDS profile ${ota_config_template}; refusing to start on defaults." >&2; exit 1; }; case ${rmw_ota} in cyclone) export CYCLONEDDS_URI="file://${ota_config_file}";; fastdds) export FASTDDS_DEFAULT_PROFILES_FILE="${ota_config_file}"; export RMW_FASTRTPS_USE_QOS_FROM_XML=1;; esac; fi
|
|
377
377
|
# For zenoh_ros2dds the OTA domain is loopback-only (zenoh is the inter-host
|
|
378
378
|
# transport), so confine discovery to localhost instead of statically peering
|
|
379
379
|
# the remote host — otherwise the OTA-domain DDS double-delivers alongside zenoh.
|
|
@@ -72,6 +72,7 @@ docs/findings/jitter-loss-bandwidth-latency.md
|
|
|
72
72
|
docs/findings/keyframe-loss-kills-the-next-deltas.md
|
|
73
73
|
docs/findings/lifespan-is-enforced-by-one-reader-and-not-the-other.md
|
|
74
74
|
docs/findings/lighter-message-loss.md
|
|
75
|
+
docs/findings/one-domain-two-cyclone-configs-stop-interoperating.md
|
|
75
76
|
docs/findings/oversubscription-queues-not-losses.md
|
|
76
77
|
docs/findings/reorder-becomes-reader-loss.md
|
|
77
78
|
docs/findings/sender-rows-make-a-dead-link-look-loss-free.md
|
|
@@ -212,6 +213,7 @@ src/rosotacom/resources/ws/.vscode/settings.json
|
|
|
212
213
|
src/rosotacom/resources/ws/ota_configs/create_zenoh_json5.py
|
|
213
214
|
src/rosotacom/resources/ws/ota_configs/cyclonedds_local_participants.xml.template
|
|
214
215
|
src/rosotacom/resources/ws/ota_configs/cyclonedds_minimal.xml.template
|
|
216
|
+
src/rosotacom/resources/ws/ota_configs/cyclonedds_scoped.xml.template
|
|
215
217
|
src/rosotacom/resources/ws/ota_configs/cyclonedds_tuned.xml.template
|
|
216
218
|
src/rosotacom/resources/ws/ota_configs/fastdds_easy_mode.xml.template
|
|
217
219
|
src/rosotacom/resources/ws/ota_configs/fastdds_local.xml.template
|
{rosotacom_dev-2.5.dev65 → rosotacom_dev-2.5.dev66}/src/rosotacom_dev.egg-info/scm_file_list.json
RENAMED
|
@@ -57,6 +57,7 @@
|
|
|
57
57
|
"docs/findings/keyframe-loss-kills-the-next-deltas.md",
|
|
58
58
|
"docs/findings/lifespan-is-enforced-by-one-reader-and-not-the-other.md",
|
|
59
59
|
"docs/findings/lighter-message-loss.md",
|
|
60
|
+
"docs/findings/one-domain-two-cyclone-configs-stop-interoperating.md",
|
|
60
61
|
"docs/findings/oversubscription-queues-not-losses.md",
|
|
61
62
|
"docs/findings/reorder-becomes-reader-loss.md",
|
|
62
63
|
"docs/findings/repro/decode_chain_repro.py",
|
|
@@ -215,6 +216,7 @@
|
|
|
215
216
|
"src/rosotacom/resources/ws/ota_configs/create_zenoh_json5.py",
|
|
216
217
|
"src/rosotacom/resources/ws/ota_configs/cyclonedds_local_participants.xml.template",
|
|
217
218
|
"src/rosotacom/resources/ws/ota_configs/cyclonedds_minimal.xml.template",
|
|
219
|
+
"src/rosotacom/resources/ws/ota_configs/cyclonedds_scoped.xml.template",
|
|
218
220
|
"src/rosotacom/resources/ws/ota_configs/cyclonedds_tuned.xml.template",
|
|
219
221
|
"src/rosotacom/resources/ws/ota_configs/fastdds_easy_mode.xml.template",
|
|
220
222
|
"src/rosotacom/resources/ws/ota_configs/fastdds_local.xml.template",
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import importlib.util
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from types import ModuleType
|
|
6
|
+
|
|
7
|
+
import pytest
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def _module() -> ModuleType:
|
|
11
|
+
path = (
|
|
12
|
+
Path(__file__).resolve().parents[2]
|
|
13
|
+
/ "src"
|
|
14
|
+
/ "rosotacom"
|
|
15
|
+
/ "resources"
|
|
16
|
+
/ "ws"
|
|
17
|
+
/ "ota_configs"
|
|
18
|
+
/ "get_ota_xml.py"
|
|
19
|
+
)
|
|
20
|
+
spec = importlib.util.spec_from_file_location("test_get_ota_xml", path)
|
|
21
|
+
assert spec is not None and spec.loader is not None
|
|
22
|
+
module = importlib.util.module_from_spec(spec)
|
|
23
|
+
spec.loader.exec_module(module)
|
|
24
|
+
return module
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def test_ota_xml_uses_resolved_literal_addresses(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
|
|
28
|
+
module = _module()
|
|
29
|
+
template = tmp_path / "test.xml.template"
|
|
30
|
+
template.write_text("<host>#host_ip</host><peer>#peer</peer><easy>#easy_mode_ip</easy>\n", encoding="utf-8")
|
|
31
|
+
monkeypatch.setattr(module, "_template_path", lambda _name: str(template))
|
|
32
|
+
|
|
33
|
+
rendered = module.main(
|
|
34
|
+
config="test.xml",
|
|
35
|
+
host_ip="10.0.0.10",
|
|
36
|
+
peer="10.0.0.11",
|
|
37
|
+
easy_mode_ip="10.0.0.10",
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
assert rendered == "<host>10.0.0.10</host><peer>10.0.0.11</peer><easy>10.0.0.10</easy>\n"
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def test_ota_xml_renders_default_and_overridden_spdp_interval(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
|
|
44
|
+
module = _module()
|
|
45
|
+
template = tmp_path / "test.xml.template"
|
|
46
|
+
template.write_text("<SPDPInterval>#spdp_interval</SPDPInterval>\n", encoding="utf-8")
|
|
47
|
+
monkeypatch.setattr(module, "_template_path", lambda _name: str(template))
|
|
48
|
+
|
|
49
|
+
assert module.main(config="test.xml") == "<SPDPInterval>30s</SPDPInterval>\n"
|
|
50
|
+
assert module.main(config="test.xml", spdp_interval="150s") == "<SPDPInterval>150s</SPDPInterval>\n"
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def test_ota_xml_rejects_empty_resolved_address(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
|
|
54
|
+
module = _module()
|
|
55
|
+
template = tmp_path / "test.xml.template"
|
|
56
|
+
template.write_text("<host>#host_ip</host>\n", encoding="utf-8")
|
|
57
|
+
monkeypatch.setattr(module, "_template_path", lambda _name: str(template))
|
|
58
|
+
|
|
59
|
+
with pytest.raises(ValueError, match="non-empty resolved address"):
|
|
60
|
+
module.main(config="test.xml", host_ip=" ")
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def test_ota_xml_rejects_invalid_spdp_interval(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
|
|
64
|
+
module = _module()
|
|
65
|
+
template = tmp_path / "test.xml.template"
|
|
66
|
+
template.write_text("<SPDPInterval>#spdp_interval</SPDPInterval>\n", encoding="utf-8")
|
|
67
|
+
monkeypatch.setattr(module, "_template_path", lambda _name: str(template))
|
|
68
|
+
|
|
69
|
+
with pytest.raises(ValueError, match="seconds or milliseconds"):
|
|
70
|
+
module.main(config="test.xml", spdp_interval="2min")
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def test_ota_xml_scopes_sections_to_their_domains(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
|
|
74
|
+
module = _module()
|
|
75
|
+
template = tmp_path / "test.xml.template"
|
|
76
|
+
template.write_text('<Domain Id="#ota_domain"/><Domain Id="#local_domain"/>\n', encoding="utf-8")
|
|
77
|
+
monkeypatch.setattr(module, "_template_path", lambda _name: str(template))
|
|
78
|
+
|
|
79
|
+
rendered = module.main(config="test.xml", local_domain="47", ota_domain="48")
|
|
80
|
+
|
|
81
|
+
assert rendered == '<Domain Id="48"/><Domain Id="47"/>\n'
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def test_ota_xml_refuses_a_domain_it_cannot_use(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
|
|
85
|
+
"""A section Cyclone matches to no domain is silently ignored, so refuse first."""
|
|
86
|
+
module = _module()
|
|
87
|
+
template = tmp_path / "test.xml.template"
|
|
88
|
+
template.write_text('<Domain Id="#ota_domain"/>\n', encoding="utf-8")
|
|
89
|
+
monkeypatch.setattr(module, "_template_path", lambda _name: str(template))
|
|
90
|
+
|
|
91
|
+
for bad in ("233", "-1", "any", "", "4 7"):
|
|
92
|
+
with pytest.raises((ValueError, RuntimeError)):
|
|
93
|
+
module.main(config="test.xml", ota_domain=bad)
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def test_ota_xml_names_the_option_a_scoped_template_needs(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
|
|
97
|
+
module = _module()
|
|
98
|
+
template = tmp_path / "test.xml.template"
|
|
99
|
+
template.write_text('<Domain Id="#local_domain"/>\n', encoding="utf-8")
|
|
100
|
+
monkeypatch.setattr(module, "_template_path", lambda _name: str(template))
|
|
101
|
+
|
|
102
|
+
with pytest.raises(RuntimeError) as excinfo:
|
|
103
|
+
module.main(config="test.xml")
|
|
104
|
+
|
|
105
|
+
assert "--local-domain" in str(excinfo.value)
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def test_shipped_scoped_template_carries_both_domains_and_only_ota_restrictions() -> None:
|
|
109
|
+
"""The point of the file: OTA settings on the OTA domain, local domain left alone.
|
|
110
|
+
|
|
111
|
+
A section that pinned an interface or disabled multicast on the *local*
|
|
112
|
+
domain would recreate the failure it exists to avoid.
|
|
113
|
+
"""
|
|
114
|
+
module = _module()
|
|
115
|
+
rendered = module.main(
|
|
116
|
+
config="cyclonedds_scoped.xml",
|
|
117
|
+
host_ip="10.0.0.10",
|
|
118
|
+
peer="10.0.0.11",
|
|
119
|
+
local_domain="47",
|
|
120
|
+
ota_domain="48",
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
assert '<Domain Id="48">' in rendered
|
|
124
|
+
assert '<Domain Id="47">' in rendered
|
|
125
|
+
|
|
126
|
+
ota_section = rendered.split('<Domain Id="48">', 1)[1].split("</Domain>", 1)[0]
|
|
127
|
+
local_section = rendered.split('<Domain Id="47">', 1)[1].split("</Domain>", 1)[0]
|
|
128
|
+
|
|
129
|
+
assert "<AllowMulticast>false</AllowMulticast>" in ota_section
|
|
130
|
+
assert "10.0.0.10" in ota_section and "10.0.0.11" in ota_section
|
|
131
|
+
|
|
132
|
+
for restriction in ("AllowMulticast", "NetworkInterface", "Peer ", "MaxMessageSize"):
|
|
133
|
+
assert restriction not in local_section, restriction
|
|
134
|
+
assert "MaxAutoParticipantIndex" in local_section
|