rosotacom-dev 2.5.dev71__tar.gz → 2.5.dev73__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.dev71 → rosotacom_dev-2.5.dev73}/PKG-INFO +1 -1
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/docs/findings/cyclone-fragment-equal-to-max-drops-fragmented-samples.md +15 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/cli.py +27 -5
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/ota_configs/cyclonedds_scoped.xml.template +3 -2
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/ota_configs/cyclonedds_tuned.xml.template +9 -2
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/ota_configs/get_ota_xml.py +81 -2
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/session/content/base/session_plugin_base.yaml +6 -4
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/session/creation/generate_session_files.py +25 -2
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom_dev.egg-info/PKG-INFO +1 -1
- rosotacom_dev-2.5.dev73/src/rosotacom_dev.egg-info/scm_version.json +8 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/tests/contract/test_generated_topics_have_a_producer.py +1 -1
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/tests/unit/test_cli.py +82 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/tests/unit/test_concurrency.py +73 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/tests/unit/test_ota_link_configs.py +42 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/tests/unit/test_ota_xml.py +55 -0
- rosotacom_dev-2.5.dev71/src/rosotacom_dev.egg-info/scm_version.json +0 -8
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/.devcontainer/devcontainer.json.template +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/.devcontainer/re_generate_devcontainer_json.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/.github/CODEOWNERS +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/.github/ISSUE_TEMPLATE/documentation-audit.md +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/.github/ISSUE_TEMPLATE/implementation-cleanup.md +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/.github/ISSUE_TEMPLATE/quality-workflow.md +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/.github/ISSUE_TEMPLATE/redesign.md +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/.github/ISSUE_TEMPLATE/release-process.md +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/.github/ISSUE_TEMPLATE/repository-diagnosis.md +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/.github/ISSUE_TEMPLATE/test-ci-audit.md +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/.github/ISSUE_TEMPLATE/work-item.md +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/.github/actions/setup-just/action.yml +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/.github/dependabot.yml +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/.github/workflows/benchmark-calibrate.yml +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/.github/workflows/benchmark-gate.yml +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/.github/workflows/dev-release.yml +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/.github/workflows/image-scan.yml +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/.github/workflows/nightly-e2e.yml +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/.github/workflows/pr-lightweight.yml +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/.github/workflows/pr-merge-gate.yml +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/.github/workflows/release.yml +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/.pre-commit-config.yaml +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/AGENTS.md +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/CONCURRENCY.md +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/CONTRIBUTING.md +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/DEVELOPMENT_PRINCIPLES.md +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/LICENSE.txt +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/MANIFEST.in +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/README.md +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/budgets.jsonl +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/calibration/README.md +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/calibration/capacity-size-tight-cyclone.json +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/calibration/probe-loss-gop-tight-cyclone.json +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/calibration/probe-loss-nominal-cyclone.json +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/calibration/probe-loss-tight-cyclone.json +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/calibration/probe-loss-tight-fastdds.json +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/calibration/probe-loss-tight-zenoh.json +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/codecov.yml +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/deployment-configuration.md +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/docs/benchmark-ab.md +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/docs/benchmark-bag-as-load.md +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/docs/ci.md +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/docs/ffmpeg-keyframes.md +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/docs/findings/README.md +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/docs/findings/a-transport-element-doubles-every-fastdds-sample.md +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/docs/findings/cyclone-spdp-discovery-bursts.md +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/docs/findings/delay-alone-no-loss.md +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/docs/findings/fastdds-datagram-cap-drops-large-samples.md +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/docs/findings/graph-derived-types-block-a-non-graph-transport.md +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/docs/findings/head-of-line-irregularity.md +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/docs/findings/jitter-loss-bandwidth-latency.md +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/docs/findings/keyframe-loss-kills-the-next-deltas.md +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/docs/findings/lifespan-is-enforced-by-one-reader-and-not-the-other.md +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/docs/findings/lighter-message-loss.md +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/docs/findings/one-domain-two-cyclone-configs-stop-interoperating.md +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/docs/findings/oversubscription-queues-not-losses.md +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/docs/findings/reorder-becomes-reader-loss.md +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/docs/findings/repro/decode_chain_repro.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/docs/findings/repro/reorder_drop_repro.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/docs/findings/sender-rows-make-a-dead-link-look-loss-free.md +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/docs/findings/zero-loss-boundaries-18kb-20hz.md +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/docs/forensics-report.md +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/docs/geo-link-map.md +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/docs/github-repository-settings.md +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/docs/link-bandwidth.md +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/docs/link-trace.md +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/docs/ota-pcap.md +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/docs/owner-runbook.md +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/docs/performance-bands.md +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/docs/playbooks/README.md +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/docs/quality-model.md +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/docs/release-notes/TEMPLATE.md +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/docs/release-notes/v2.1.md +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/docs/release-notes/v2.2.md +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/docs/release-notes/v2.3.md +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/docs/release-notes/v2.4.md +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/docs/release.md +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/docs/rfcs/0001-expectation-driven-test-suite.md +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/docs/rfcs/0002-expectation-concepts.md +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/docs/rfcs/0003-metric-backbone.md +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/docs/rfcs/0004-network-profiles.md +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/docs/rfcs/0005-benchmark-genres-and-ci.md +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/docs/rfcs/0006-dynamic-qos.md +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/docs/rfcs/0007-regression-gate.md +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/docs/rfcs/README.md +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/docs/testing.md +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/docs/work-items.md +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/install.sh +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/justfile +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/media/control_center.png +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/media/echo_test.png +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/media/forensics-report-example.png +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/media/host.png +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/media/vehicle.png +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/pyproject.toml +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/requirements.txt +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/rosotacom.yaml +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/session-configuration.md +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/setup.cfg +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/__init__.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/__main__.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/anonymize.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/bag_ground_truth.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/benched_set.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/benchmark.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/benchmark_delta.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/bundle_check.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/cli_benchmark.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/deployment.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/ffmpeg_packet.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/forensics.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/geomap.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/image_cache.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/netem_dist.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/network_preflight.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/network_profiles.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/network_shaper.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/plots.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/py.typed +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/benched-set.yaml +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/examples/.gitignore +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/examples/README.md +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/examples/__init__.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/examples/bags/8_drop_reference/metadata.yaml +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/examples/deployment.example.yaml +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/examples/dist/field-20260817.dist +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/examples/profiles.yaml +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/examples/ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/examples/ros2docker.lyrical.json +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/examples/rosotacom.yaml +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/examples/scenarios/2_native_chatter/scenario-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/examples/scripts/1_heartbeat/run_machine_a.sh +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/examples/scripts/1_heartbeat/run_machine_b.sh +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_a/external.lyrical.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_a/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_a/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_a/run_external.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_a/wait_for_echo_topic.sh +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_b/external.lyrical.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_b/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_b/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_b/run_external.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_a/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_a/external_session.yaml +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_a/foxglove.json +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_a/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_a/run_external.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_b/costmap_1second/costmap_1second_0.mcap +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_b/costmap_1second/metadata.yaml +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_b/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_b/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_b/run_external.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_a/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_a/external_session.yaml +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_a/foxglove.json +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_a/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_a/run_external.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_b/costmap_1second/costmap_1second_0.mcap +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_b/costmap_1second/metadata.yaml +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_b/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_b/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_b/run_external.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_a/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_a/external_session.yaml +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_a/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_a/run_external.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_b/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_b/external_session.yaml +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_b/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_b/run_external.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_a/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_a/external_session.yaml +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_a/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_a/run_external.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_b/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_b/external_session.yaml +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_b/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_b/run_external.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/examples/sessions/10_restamp/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/examples/sessions/11_trickle/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/examples/sessions/12_content_integrity/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/examples/sessions/13_link_latency/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/examples/sessions/14_remote_assist_anonymized/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/examples/sessions/15_remote_assist_anonymized_costmap/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/examples/sessions/16_remote_assist_anonymized_camera/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/examples/sessions/17_synthetic_camera_quality/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/examples/sessions/1_heartbeat/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/examples/sessions/1_heartbeat_status/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/examples/sessions/2_native_chatter/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/examples/sessions/3_comp_occ_grid/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/examples/sessions/4_comp_occ_grid_zen/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/examples/sessions/5_sized_payload/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/examples/sessions/6_sized_payload_zen/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/examples/sessions/7_latched_static/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/examples/sessions/8_drop/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/examples/sessions/9_throttle/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/examples/sessions/bench_1_1_capacity/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/examples/sessions/bench_1_2_load_sweep/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/examples/sessions/bench_1_3_ramp/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/examples/sessions/bench_1_4_recovery/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/examples/sessions/bench_1_5_camera/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ros2docker.json.example +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ros2docker.lyrical.json.example +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/.vscode/c_cpp_properties.json +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/.vscode/settings.json +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_easy_mode.xml.template +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_initial_peer_list.xml.template +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_v2.xml.template +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_v3.xml.template +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_v4.xml.template +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_v5.xml.template +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/ota_configs/create_zenoh_json5.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/ota_configs/cyclonedds_local_participants.xml.template +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/ota_configs/cyclonedds_minimal.xml.template +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/ota_configs/fastdds_easy_mode.xml.template +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/ota_configs/fastdds_local.xml.template +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/ota_configs/fastdds_tuned.xml.template +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/ota_configs/fastdds_unicast.xml.template +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/ota_configs/utils.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/ota_configs/zenoh.json5.template +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/ros2src/.gitkeep +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/ros2src/com_cpp/CMakeLists.txt +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/ros2src/com_cpp/COLCON_IGNORE +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/ros2src/com_cpp/LICENSE.txt +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/ros2src/com_cpp/package.xml +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/ros2src/com_cpp/src/hz_monitor.cpp +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/ros2src/com_cpp/src/universal_compressor.cpp +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/ros2src/com_cpp/src/universal_decompressor.cpp +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/ros2src/com_msgs/CMakeLists.txt +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/ros2src/com_msgs/LICENSE.txt +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/ros2src/com_msgs/msg/CompressedData.msg +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/ros2src/com_msgs/msg/EchoHeartbeat.msg +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/ros2src/com_msgs/msg/OtaStamped.msg +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/ros2src/com_msgs/msg/SizedPayload.msg +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/ros2src/com_msgs/package.xml +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/ros2src/com_py/LICENSE.txt +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/ros2src/com_py/com_py/__init__.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/ros2src/com_py/com_py/base_bridge_relay.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/ros2src/com_py/com_py/bridge_in.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/ros2src/com_py/com_py/bridge_out.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/ros2src/com_py/com_py/ffmpeg_flags.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/ros2src/com_py/com_py/heartbeat_echo.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/ros2src/com_py/com_py/hz_monitor.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/ros2src/com_py/com_py/image_bandwidth_reducer.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/ros2src/com_py/com_py/image_pixel_capper.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/ros2src/com_py/com_py/lanelet_saver.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/ros2src/com_py/com_py/latch_relay.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/costmap_remapper.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/marker_remapper.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/speed_test.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/tf_remapper.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/traffic_monitor.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/wifi_network_analysis_1.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/ros2src/com_py/com_py/link_bytes.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/ros2src/com_py/com_py/link_trace.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/ros2src/com_py/com_py/local_global_frame_bridge.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/ros2src/com_py/com_py/localization_map_split_reduce_saver.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/ros2src/com_py/com_py/msg_transform.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/ros2src/com_py/com_py/ota_pcap.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/ros2src/com_py/com_py/pair_management.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/ros2src/com_py/com_py/playout_pacer.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/ros2src/com_py/com_py/playout_pacer_core.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/ros2src/com_py/com_py/pub_sub_pair.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/ros2src/com_py/com_py/qos.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/ros2src/com_py/com_py/relay_in.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/ros2src/com_py/com_py/relay_out.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/ros2src/com_py/com_py/restamp.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/ros2src/com_py/com_py/sized_publisher.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/ros2src/com_py/com_py/stage_latency.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/ros2src/com_py/com_py/stage_latency_core.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/ros2src/com_py/com_py/status_overview.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/ros2src/com_py/com_py/status_overview_core.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/ros2src/com_py/com_py/tf_map_to_cart_saver.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/ros2src/com_py/com_py/topic_monitor.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/ros2src/com_py/com_py/topic_resolution.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/ros2src/com_py/com_py/trickle.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/ros2src/com_py/com_py/universal_compressor.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/ros2src/com_py/com_py/universal_decompressor.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/ros2src/com_py/com_py/universal_ota_unwrapper.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/ros2src/com_py/com_py/universal_ota_wrapper.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/ros2src/com_py/package.xml +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/ros2src/com_py/resource/com_py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/ros2src/com_py/setup.cfg +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/ros2src/com_py/setup.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/ros2src/com_py/test/test_copyright.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/ros2src/com_py/test/test_flake8.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/ros2src/com_py/test/test_pep257.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/session/content/network/up_connectivity.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/session/content/network/wifi_network_analysis_2.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/session/creation/anonymize_bag.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/session/creation/catmux_log_setup.sh +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/session/creation/create_session_yaml.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/session/creation/run_session.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/session/creation/run_session_in_external_terminal.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/resources/ws/session/creation/strip_ansi.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/status_eval.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/stream_stats.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/trace_profiles.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/transit.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom/video_quality.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom_dev.egg-info/SOURCES.txt +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom_dev.egg-info/dependency_links.txt +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom_dev.egg-info/entry_points.txt +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom_dev.egg-info/requires.txt +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom_dev.egg-info/scm_file_list.json +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/src/rosotacom_dev.egg-info/top_level.txt +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/terminology.md +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/tests/contract/test_benched_set_registry.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/tests/contract/test_findings.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/tests/contract/test_lyrical_runtime_compat.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/tests/contract/test_markdown_links.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/tests/contract/test_ota_source_bundle.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/tests/contract/test_package_metadata.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/tests/contract/test_packaged_resources.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/tests/contract/test_profile_covers_generated_commands.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/tests/contract/test_pytest_policy.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/tests/contract/test_readme_examples.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/tests/contract/test_security_maintenance_config.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/tests/contract/test_session_configuration_doc.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/tests/contract/test_session_template_substitution.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/tests/contract/test_workflow_contracts.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/tests/e2e/conftest.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/tests/e2e/test_anonymize_e2e.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/tests/e2e/test_benchmark_ab.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/tests/e2e/test_benchmark_capacity.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/tests/e2e/test_benchmark_replay.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/tests/e2e/test_parallel_smoke.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/tests/e2e/test_smoke.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/tests/e2e/test_timeline_stepping.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/tests/e2e/test_video_quality_e2e.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/tests/sessions/generate_rmw_matrix.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/tests/sessions/rmw_matrix/1_heartbeat_cyclone-local_zenoh-ros2dds-ota/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/tests/sessions/rmw_matrix/1_heartbeat_cyclone-ota/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/tests/sessions/rmw_matrix/1_heartbeat_cyclone-ota-tuned/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/tests/sessions/rmw_matrix/1_heartbeat_fastdds/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/tests/sessions/rmw_matrix/1_heartbeat_fastdds-default/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/tests/sessions/rmw_matrix/1_heartbeat_zen-endpoints/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/tests/unit/test_anonymize.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/tests/unit/test_bag_ground_truth.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/tests/unit/test_benched_set.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/tests/unit/test_benchmark.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/tests/unit/test_benchmark_delta.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/tests/unit/test_bundle_check.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/tests/unit/test_catmux_pane_logging.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/tests/unit/test_cli_benchmark.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/tests/unit/test_container_shaping.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/tests/unit/test_deployment.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/tests/unit/test_ffmpeg_flags.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/tests/unit/test_ffmpeg_packet.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/tests/unit/test_field_profiles.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/tests/unit/test_forensics.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/tests/unit/test_geomap.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/tests/unit/test_image_cache.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/tests/unit/test_link_bytes.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/tests/unit/test_link_trace.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/tests/unit/test_netem_dist.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/tests/unit/test_network_preflight.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/tests/unit/test_network_profiles.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/tests/unit/test_network_shaper.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/tests/unit/test_ota_pcap.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/tests/unit/test_ota_unwrapper.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/tests/unit/test_ota_wrapper.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/tests/unit/test_playout_pacer.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/tests/unit/test_plots.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/tests/unit/test_pub_sub_pair_types.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/tests/unit/test_qos_fallback_logging.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/tests/unit/test_relay_optional_parameters.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/tests/unit/test_ros_node_entity_ownership.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/tests/unit/test_session_pipeline.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/tests/unit/test_stage_latency.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/tests/unit/test_status_eval.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/tests/unit/test_status_overview.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/tests/unit/test_status_overview_observer.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/tests/unit/test_stream_stats.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/tests/unit/test_terminology_stage_ownership.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/tests/unit/test_trace_profiles.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/tests/unit/test_transit.py +0 -0
- {rosotacom_dev-2.5.dev71 → rosotacom_dev-2.5.dev73}/tests/unit/test_video_quality.py +0 -0
|
@@ -73,6 +73,21 @@ the same MTU budget the 1200 B was chosen for — only the header room is added
|
|
|
73
73
|
and the value works on both versions, so it is one number rather than a branch
|
|
74
74
|
on the distribution.
|
|
75
75
|
|
|
76
|
+
The 1200 B profile stays reachable, deliberately. It is what every 0.10.5 run
|
|
77
|
+
before 2026-08-20 carried, so a comparison against one of those runs has to be
|
|
78
|
+
able to reproduce it rather than approximate it:
|
|
79
|
+
|
|
80
|
+
```yaml
|
|
81
|
+
shared:
|
|
82
|
+
rmw:
|
|
83
|
+
ota:
|
|
84
|
+
cyclone: {config: cyclonedds_tuned.xml, fragment_size: 1200B}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
`get_ota_xml.py` warns on stderr whenever the rendered fragment reaches the
|
|
88
|
+
datagram cap, naming 11.0.1 — a profile worth choosing on purpose is not one
|
|
89
|
+
worth choosing by accident.
|
|
90
|
+
|
|
76
91
|
## Publication notes
|
|
77
92
|
|
|
78
93
|
A distribution bump silently changed what a profile *means*, and the profile
|
|
@@ -794,6 +794,31 @@ def _new_instance_id() -> str:
|
|
|
794
794
|
return hashlib.sha1(seed.encode("utf-8")).hexdigest()[:8]
|
|
795
795
|
|
|
796
796
|
|
|
797
|
+
#: The timestamp every instance directory carries between its session slug and
|
|
798
|
+
#: its id: `<slug>_YYYY-MM-DD_HH-MM-SS_<id>`. Spelled out digit by digit rather
|
|
799
|
+
#: than left as `*`, because a session's name may be a *prefix* of another
|
|
800
|
+
#: session's name and `f"{slug}_*"` then collects the other session's instances
|
|
801
|
+
#: too. `ccng_remote_assist_*` matches every `ccng_remote_assist_kilted_dds_*`,
|
|
802
|
+
#: and because the matches are ordered by name, `[-1]` answers with the wrong
|
|
803
|
+
#: session's run whenever the longer name sorts after a digit — which `k` does.
|
|
804
|
+
#:
|
|
805
|
+
#: That is not hypothetical. On 2026-08-21 it made `rosotacom status
|
|
806
|
+
#: ccng_remote_assist` report a `ccng_remote_assist_kilted_dds` run that had
|
|
807
|
+
#: been shut down 45 minutes earlier, so three two-host runs concluded their
|
|
808
|
+
#: link never came up while it was in fact carrying traffic for eleven minutes.
|
|
809
|
+
#: Nothing in the reading said it came from another session.
|
|
810
|
+
_INSTANCE_STAMP_GLOB = "[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]_[0-9][0-9]-[0-9][0-9]-[0-9][0-9]"
|
|
811
|
+
|
|
812
|
+
|
|
813
|
+
def _instance_glob(session_slug: str, instance_id: str | None = None) -> str:
|
|
814
|
+
"""The pattern matching this session's instances, and no other session's.
|
|
815
|
+
|
|
816
|
+
With the stamp pinned, the names sort chronologically, so `sorted(...)[-1]`
|
|
817
|
+
is the newest instance rather than merely the last name.
|
|
818
|
+
"""
|
|
819
|
+
return f"*/{session_slug}_{_INSTANCE_STAMP_GLOB}_{instance_id or '*'}"
|
|
820
|
+
|
|
821
|
+
|
|
797
822
|
def _session_instances_root(runtime: RuntimeConfig) -> Path:
|
|
798
823
|
return (runtime.session_instances_dir or (Path.cwd() / "session-instances")).resolve()
|
|
799
824
|
|
|
@@ -818,7 +843,7 @@ def _resolve_session_instance(
|
|
|
818
843
|
resolved_instance_id = _safe_path_token(instance_id or _new_instance_id())
|
|
819
844
|
|
|
820
845
|
if instance_id:
|
|
821
|
-
matches = sorted(root.glob(
|
|
846
|
+
matches = sorted(root.glob(_instance_glob(session_slug, resolved_instance_id)))
|
|
822
847
|
if matches:
|
|
823
848
|
host_dir = matches[-1].resolve()
|
|
824
849
|
else:
|
|
@@ -8781,10 +8806,7 @@ def smoke(args: argparse.Namespace) -> int:
|
|
|
8781
8806
|
def _find_latest_instance_dir(runtime: RuntimeConfig, session: ResolvedSession, instance_id: str | None) -> Path:
|
|
8782
8807
|
root = _session_instances_root(runtime)
|
|
8783
8808
|
session_slug = _session_instance_slug(session, runtime)
|
|
8784
|
-
if instance_id
|
|
8785
|
-
pattern = f"*/{session_slug}_*_{_safe_path_token(instance_id)}"
|
|
8786
|
-
else:
|
|
8787
|
-
pattern = f"*/{session_slug}_*"
|
|
8809
|
+
pattern = _instance_glob(session_slug, _safe_path_token(instance_id) if instance_id else None)
|
|
8788
8810
|
matches = sorted(p for p in root.glob(pattern) if p.is_dir())
|
|
8789
8811
|
if not matches:
|
|
8790
8812
|
raise RuntimeError(
|
|
@@ -47,8 +47,9 @@ template, not a replacement, and a session that does not name it is unchanged.
|
|
|
47
47
|
</Interfaces>
|
|
48
48
|
<MulticastRecvNetworkInterfaceAddresses>none</MulticastRecvNetworkInterfaceAddresses>
|
|
49
49
|
<!-- Strictly below MaxMessageSize; see cyclonedds_tuned.xml for what
|
|
50
|
-
making them equal cost
|
|
51
|
-
|
|
50
|
+
making them equal cost, and for why the number is settable
|
|
51
|
+
(`shared.rmw.<side>.cyclone.fragment_size`) rather than literal. -->
|
|
52
|
+
<FragmentSize>#fragment_size</FragmentSize>
|
|
52
53
|
<MaxMessageSize>1200B</MaxMessageSize>
|
|
53
54
|
<MaxRexmitMessageSize>1200B</MaxRexmitMessageSize>
|
|
54
55
|
</General>
|
|
@@ -16,8 +16,15 @@
|
|
|
16
16
|
sample: 1200/1200 delivers nothing on 11.0.1 and everything on
|
|
17
17
|
0.10.5; 1024/1200 delivers on both. The datagram stays inside the
|
|
18
18
|
same MTU budget the 1200B was chosen for; only the header room is
|
|
19
|
-
added.
|
|
20
|
-
|
|
19
|
+
added.
|
|
20
|
+
|
|
21
|
+
The default is that 1024B. It is a placeholder rather than a literal
|
|
22
|
+
because both values are correct on 0.10.5, so which one a run used is
|
|
23
|
+
a property of the session and not of the installed package version:
|
|
24
|
+
`shared.rmw.<side>.cyclone.fragment_size`. Asking for one that fills
|
|
25
|
+
the datagram is allowed — it is what the Kilted-era link ran — and
|
|
26
|
+
get_ota_xml.py says so on stderr rather than refusing. -->
|
|
27
|
+
<FragmentSize>#fragment_size</FragmentSize>
|
|
21
28
|
<MaxMessageSize>1200B</MaxMessageSize>
|
|
22
29
|
<MaxRexmitMessageSize>1200B</MaxRexmitMessageSize>
|
|
23
30
|
</General>
|
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
"""Unified OTA DDS XML generator.
|
|
3
3
|
|
|
4
4
|
Loads an XML template from /ws/ota_configs/<config>(.template), detects which
|
|
5
|
-
placeholders it uses (#host_ip, #peer, #easy_mode_ip, #spdp_interval
|
|
6
|
-
substitutes already resolved addresses, and prints the
|
|
5
|
+
placeholders it uses (#host_ip, #peer, #easy_mode_ip, #spdp_interval,
|
|
6
|
+
#fragment_size), substitutes already resolved addresses, and prints the
|
|
7
|
+
resulting XML to stdout.
|
|
7
8
|
|
|
8
9
|
Replaces the old per-template scripts (get_fastdds_xml.py,
|
|
9
10
|
get_fastdds_easy_mode_xml.py, get_cyclonedds_xml.py).
|
|
@@ -28,9 +29,22 @@ KNOWN_PLACEHOLDERS = {
|
|
|
28
29
|
#: profile and half the local one.
|
|
29
30
|
"#local_domain",
|
|
30
31
|
"#ota_domain",
|
|
32
|
+
#: How large an RTPS fragment this link sends. A template resolves it so
|
|
33
|
+
#: that the number is a property of the session rather than of the
|
|
34
|
+
#: installed package: 1024B and 1200B are both correct on CycloneDDS
|
|
35
|
+
#: 0.10.5, only the smaller one is correct on 11.0.1, and a run comparing
|
|
36
|
+
#: the two ROS distributions has to be able to say which it used.
|
|
37
|
+
"#fragment_size",
|
|
31
38
|
}
|
|
32
39
|
PLACEHOLDER_PATTERN = re.compile(r"#[A-Za-z_][A-Za-z0-9_]*")
|
|
33
40
|
DEFAULT_SPDP_INTERVAL = "30s"
|
|
41
|
+
#: Strictly below the templates' MaxMessageSize; see cyclonedds_tuned.xml for
|
|
42
|
+
#: what making the two equal cost under ROS 2 Lyrical.
|
|
43
|
+
DEFAULT_FRAGMENT_SIZE = "1024B"
|
|
44
|
+
|
|
45
|
+
#: CycloneDDS size suffixes, and what each one is worth in bytes.
|
|
46
|
+
SIZE_UNITS = {"B": 1, "KB": 1000, "KIB": 1024, "MB": 1000_000, "MIB": 1024 * 1024}
|
|
47
|
+
SIZE_PATTERN = re.compile(r"(\d+)\s*(B|kB|KB|KiB|MB|MiB)?\Z")
|
|
34
48
|
|
|
35
49
|
|
|
36
50
|
def _template_path(name: str) -> str:
|
|
@@ -86,6 +100,60 @@ def _resolved_spdp_interval(value: str) -> str:
|
|
|
86
100
|
return interval
|
|
87
101
|
|
|
88
102
|
|
|
103
|
+
def _parse_size(value: str) -> int:
|
|
104
|
+
"""A CycloneDDS size, in bytes, or None when it is not one this script wrote.
|
|
105
|
+
|
|
106
|
+
Used both to validate what a session asked for and to read the template's
|
|
107
|
+
own MaxMessageSize back out of the rendered XML, so the warning below can
|
|
108
|
+
compare the two.
|
|
109
|
+
"""
|
|
110
|
+
match = SIZE_PATTERN.fullmatch(value.strip())
|
|
111
|
+
if not match:
|
|
112
|
+
return None
|
|
113
|
+
return int(match.group(1)) * SIZE_UNITS[(match.group(2) or "B").upper()]
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def _resolved_fragment_size(value: str) -> str:
|
|
117
|
+
size = value.strip()
|
|
118
|
+
if not size:
|
|
119
|
+
raise ValueError("Fragment size must be a non-empty size.")
|
|
120
|
+
parsed = _parse_size(size)
|
|
121
|
+
if parsed is None:
|
|
122
|
+
raise ValueError("Fragment size must be a byte size, e.g. '1024B', '1200B' or '4KiB'.")
|
|
123
|
+
if parsed <= 0:
|
|
124
|
+
raise ValueError("Fragment size must be > 0.")
|
|
125
|
+
return size
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def _warn_if_fragment_fills_the_datagram(content: str, path: str) -> None:
|
|
129
|
+
"""Say so when the rendered profile is the one Lyrical cannot carry.
|
|
130
|
+
|
|
131
|
+
An RTPS message carries headers as well as its fragment, so a fragment of
|
|
132
|
+
exactly MaxMessageSize cannot be sent at all. CycloneDDS 0.10.5 coped with
|
|
133
|
+
that; 11.0.1 drops every fragmented sample and drops it silently, with the
|
|
134
|
+
endpoints matched and small samples still arriving. That combination is a
|
|
135
|
+
legitimate thing to ask for -- it is what the Kilted-era link ran, and
|
|
136
|
+
reproducing it is the reason the fragment size is settable -- so this warns
|
|
137
|
+
rather than refuses. Refusing would make the older profile unreachable; not
|
|
138
|
+
saying anything would let it be chosen by accident.
|
|
139
|
+
"""
|
|
140
|
+
fragment = re.search(r"<FragmentSize>([^<]+)</FragmentSize>", content)
|
|
141
|
+
maximum = re.search(r"<MaxMessageSize>([^<]+)</MaxMessageSize>", content)
|
|
142
|
+
if not fragment or not maximum:
|
|
143
|
+
return
|
|
144
|
+
fragment_bytes = _parse_size(fragment.group(1))
|
|
145
|
+
maximum_bytes = _parse_size(maximum.group(1))
|
|
146
|
+
if fragment_bytes is None or maximum_bytes is None or fragment_bytes < maximum_bytes:
|
|
147
|
+
return
|
|
148
|
+
print(
|
|
149
|
+
f"WARNING - {os.path.basename(path)} renders FragmentSize {fragment.group(1)} against "
|
|
150
|
+
f"MaxMessageSize {maximum.group(1)}. A fragment leaves no room for the RTPS header, so "
|
|
151
|
+
"on CycloneDDS 11.0.1 (ROS 2 Lyrical) no fragmented sample will arrive, silently. "
|
|
152
|
+
"Correct on 0.10.5 (Kilted), which is what this profile reproduces.",
|
|
153
|
+
file=sys.stderr,
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
|
|
89
157
|
def _resolve_peer_ips(value: str) -> list:
|
|
90
158
|
seen = set()
|
|
91
159
|
unique = []
|
|
@@ -162,6 +230,7 @@ def main(
|
|
|
162
230
|
peer: str = None,
|
|
163
231
|
easy_mode_ip: str = None,
|
|
164
232
|
spdp_interval: str = DEFAULT_SPDP_INTERVAL,
|
|
233
|
+
fragment_size: str = DEFAULT_FRAGMENT_SIZE,
|
|
165
234
|
local_domain: str = None,
|
|
166
235
|
ota_domain: str = None,
|
|
167
236
|
) -> str:
|
|
@@ -195,6 +264,9 @@ def main(
|
|
|
195
264
|
if "#spdp_interval" in found:
|
|
196
265
|
content = content.replace("#spdp_interval", _resolved_spdp_interval(spdp_interval))
|
|
197
266
|
|
|
267
|
+
if "#fragment_size" in found:
|
|
268
|
+
content = content.replace("#fragment_size", _resolved_fragment_size(fragment_size))
|
|
269
|
+
|
|
198
270
|
for placeholder, value, option in (
|
|
199
271
|
("#local_domain", local_domain, "--local-domain"),
|
|
200
272
|
("#ota_domain", ota_domain, "--ota-domain"),
|
|
@@ -211,6 +283,7 @@ def main(
|
|
|
211
283
|
raise RuntimeError(f"Template '{os.path.basename(path)}' uses #peer but --peer was not provided.")
|
|
212
284
|
content = _expand_peer_block(content, _resolve_peer_ips(peer))
|
|
213
285
|
|
|
286
|
+
_warn_if_fragment_fills_the_datagram(content, path)
|
|
214
287
|
return content
|
|
215
288
|
|
|
216
289
|
|
|
@@ -268,6 +341,12 @@ if __name__ == "__main__":
|
|
|
268
341
|
default=DEFAULT_SPDP_INTERVAL,
|
|
269
342
|
help=f"CycloneDDS SPDP interval duration (#spdp_interval, default: {DEFAULT_SPDP_INTERVAL}).",
|
|
270
343
|
)
|
|
344
|
+
parser.add_argument(
|
|
345
|
+
"--fragment-size",
|
|
346
|
+
dest="fragment_size",
|
|
347
|
+
default=DEFAULT_FRAGMENT_SIZE,
|
|
348
|
+
help=f"CycloneDDS RTPS fragment size (#fragment_size, default: {DEFAULT_FRAGMENT_SIZE}).",
|
|
349
|
+
)
|
|
271
350
|
args = parser.parse_args()
|
|
272
351
|
output = args.output
|
|
273
352
|
rendered = main(**{k: v for k, v in vars(args).items() if v is not None and k != "output"})
|
|
@@ -7,6 +7,7 @@ parameters:
|
|
|
7
7
|
local_config_file: ${peer_dir}/local_dds.xml # destination path for the resolved local DDS XML
|
|
8
8
|
local_easy_mode_ip: # resolved address for #easy_mode_ip (only honored when the template uses it)
|
|
9
9
|
local_spdp_interval: # CycloneDDS SPDP interval override, e.g. 150s. Empty => template default.
|
|
10
|
+
local_fragment_size: # CycloneDDS RTPS fragment size, e.g. 1200B. Empty => template default.
|
|
10
11
|
use_domain_bridge: false
|
|
11
12
|
local_domain_id: # pinned per-peer ROS_DOMAIN_ID (from peer_settings.<peer>.domain_id)
|
|
12
13
|
ota_domain_id:
|
|
@@ -39,6 +40,7 @@ parameters:
|
|
|
39
40
|
ota_config_file: ${peer_dir}/ota_dds.xml # destination path for the resolved DDS XML
|
|
40
41
|
ota_easy_mode_ip: # resolved address for #easy_mode_ip (only honored when the template uses it)
|
|
41
42
|
ota_spdp_interval: # CycloneDDS SPDP interval override, e.g. 150s. Empty => template default.
|
|
43
|
+
ota_fragment_size: # CycloneDDS RTPS fragment size, e.g. 1200B. Empty => template default.
|
|
42
44
|
# Z2D (zenoh_ros2dds) parameters — used only when use_zenoh_ros2dds=true
|
|
43
45
|
zen_mode: # e.g. router, peer or client
|
|
44
46
|
zen_endpoint_role: # e.g. listen or connect
|
|
@@ -299,7 +301,7 @@ common:
|
|
|
299
301
|
before_commands:
|
|
300
302
|
- if [ '${local_domain_id}' != "None" ] && [ -n '${local_domain_id}' ]; then export ROS_DOMAIN_ID='${local_domain_id}'; fi
|
|
301
303
|
- 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
|
|
302
|
-
- 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
|
|
304
|
+
- 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}"); [ '${local_fragment_size}' != "None" ] && [ -n '${local_fragment_size}' ] && local_args+=(--fragment-size "${local_fragment_size}"); 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
|
|
303
305
|
- if [ '${before_command}' != "None" ]; then ${before_command}; fi
|
|
304
306
|
|
|
305
307
|
windows:
|
|
@@ -345,7 +347,7 @@ windows:
|
|
|
345
347
|
if: use_domain_bridge
|
|
346
348
|
splits:
|
|
347
349
|
- commands:
|
|
348
|
-
- 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
|
+
- 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}"); [ '${ota_fragment_size}' != "None" ] && [ -n '${ota_fragment_size}' ] && ota_args+=(--fragment-size "${ota_fragment_size}"); 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
351
|
- ros2 run domain_bridge domain_bridge --wait-for-publisher false ${domain_bridge_config_file}
|
|
350
352
|
- name: IN
|
|
351
353
|
if: in
|
|
@@ -353,7 +355,7 @@ windows:
|
|
|
353
355
|
- commands:
|
|
354
356
|
- if [ '${ota_domain_id}' != "None" ] && [ -n '${ota_domain_id}' ]; then export ROS_DOMAIN_ID='${ota_domain_id}'; fi
|
|
355
357
|
- 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
|
|
356
|
-
- 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
|
|
358
|
+
- 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}"); [ '${ota_fragment_size}' != "None" ] && [ -n '${ota_fragment_size}' ] && ota_args+=(--fragment-size "${ota_fragment_size}"); 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
|
|
357
359
|
# For zenoh_ros2dds the OTA domain is loopback-only (zenoh is the inter-host
|
|
358
360
|
# transport), so confine discovery to localhost instead of statically peering
|
|
359
361
|
# the remote host — otherwise the OTA-domain DDS double-delivers alongside zenoh.
|
|
@@ -380,7 +382,7 @@ windows:
|
|
|
380
382
|
- commands:
|
|
381
383
|
- if [ '${ota_domain_id}' != "None" ] && [ -n '${ota_domain_id}' ]; then export ROS_DOMAIN_ID='${ota_domain_id}'; fi
|
|
382
384
|
- 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
|
|
383
|
-
- 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
|
|
385
|
+
- 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}"); [ '${ota_fragment_size}' != "None" ] && [ -n '${ota_fragment_size}' ] && ota_args+=(--fragment-size "${ota_fragment_size}"); 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
|
|
384
386
|
# For zenoh_ros2dds the OTA domain is loopback-only (zenoh is the inter-host
|
|
385
387
|
# transport), so confine discovery to localhost instead of statically peering
|
|
386
388
|
# the remote host — otherwise the OTA-domain DDS double-delivers alongside zenoh.
|
|
@@ -194,7 +194,8 @@ class YamlBlockScalar:
|
|
|
194
194
|
# - a string: cyclone | fastdds | zenoh_connect_endpoints | zenoh_ros2dds | <raw rmw string>
|
|
195
195
|
# (zenoh_ros2dds is allowed for ota only; raw rmw strings are for local only)
|
|
196
196
|
# - a tagged-union mapping with exactly one key (the RMW name):
|
|
197
|
-
# {cyclone: {config?: <fname.xml>, easy_mode_ip?: <address>, spdp_interval?: <duration
|
|
197
|
+
# {cyclone: {config?: <fname.xml>, easy_mode_ip?: <address>, spdp_interval?: <duration>,
|
|
198
|
+
# fragment_size?: <size, e.g. 1200B>}}
|
|
198
199
|
# {fastdds: {config?: <fname.xml>, easy_mode_ip?: <address>}}
|
|
199
200
|
# {zenoh_connect_endpoints: {transport?: tcp|udp, main_peer?: <peer_key>, main_port?: 7447}}
|
|
200
201
|
# {zenoh_ros2dds: {transport?: udp|tcp, main_peer?: <peer_key>, main_port?: 7447}}
|
|
@@ -207,7 +208,11 @@ _OTA_SHORTS = {"cyclone", "fastdds", *_NATIVE_ZENOH_OTA_SHORTS, "zenoh_ros2dds"}
|
|
|
207
208
|
_LOCAL_SHORTS = {"cyclone", "fastdds", "zenoh"}
|
|
208
209
|
_SHORTCUT_ALLOWED = {"cyclone", "fastdds", "zenoh"}
|
|
209
210
|
|
|
210
|
-
_DDS_CFG_KEYS = {"config", "easy_mode_ip", "spdp_interval"}
|
|
211
|
+
_DDS_CFG_KEYS = {"config", "easy_mode_ip", "spdp_interval", "fragment_size"}
|
|
212
|
+
#: A CycloneDDS size: digits and an optional unit. Validated here so an
|
|
213
|
+
#: unusable value is a session error rather than a profile the DDS stack
|
|
214
|
+
#: silently ignores on its way to defaults.
|
|
215
|
+
_DDS_SIZE_RE = re.compile(r"(\d+)\s*(B|kB|KB|KiB|MB|MiB)?\Z")
|
|
211
216
|
_ZEN_OTA_CFG_KEYS = {"transport", "main_peer", "main_port"}
|
|
212
217
|
#: Inter-host transports the native zenoh router may be pointed at. Both are
|
|
213
218
|
#: plain zenoh locator schemes; tls/quic would additionally need certificates
|
|
@@ -280,6 +285,7 @@ class RmwSideSpec:
|
|
|
280
285
|
dds_config: Optional[str] = None
|
|
281
286
|
dds_easy_mode_ip: Optional[str] = None
|
|
282
287
|
dds_spdp_interval: Optional[str] = None
|
|
288
|
+
dds_fragment_size: Optional[str] = None
|
|
283
289
|
# zenoh (native) and zenoh_ros2dds
|
|
284
290
|
zen_main_peer: Optional[str] = None
|
|
285
291
|
zen_transport: Optional[str] = None
|
|
@@ -345,6 +351,19 @@ def _parse_rmw_side(value: Any, ctx: str, *, is_local: bool) -> RmwSideSpec:
|
|
|
345
351
|
raise RuntimeError(f"{ctx}.{impl}.spdp_interval must be a non-empty duration if provided.")
|
|
346
352
|
_validate_positive_seconds(cfg["spdp_interval"], f"{ctx}.{impl}.spdp_interval")
|
|
347
353
|
spec.dds_spdp_interval = cfg["spdp_interval"].strip()
|
|
354
|
+
if cfg.get("fragment_size") is not None:
|
|
355
|
+
if impl != "cyclone":
|
|
356
|
+
raise RuntimeError(f"{ctx}.{impl}.fragment_size is only supported for CycloneDDS.")
|
|
357
|
+
if not isinstance(cfg["fragment_size"], str) or not cfg["fragment_size"].strip():
|
|
358
|
+
raise RuntimeError(f"{ctx}.{impl}.fragment_size must be a non-empty size if provided.")
|
|
359
|
+
size = cfg["fragment_size"].strip()
|
|
360
|
+
match = _DDS_SIZE_RE.fullmatch(size)
|
|
361
|
+
if not match or int(match.group(1)) <= 0:
|
|
362
|
+
raise RuntimeError(
|
|
363
|
+
f"{ctx}.{impl}.fragment_size must be a positive byte size, e.g. '1024B' or '1200B'; "
|
|
364
|
+
f"got {cfg['fragment_size']!r}."
|
|
365
|
+
)
|
|
366
|
+
spec.dds_fragment_size = size
|
|
348
367
|
elif _is_native_zenoh_ota(impl):
|
|
349
368
|
extra = set(cfg.keys()) - _ZEN_OTA_CFG_KEYS
|
|
350
369
|
if extra:
|
|
@@ -2279,6 +2298,8 @@ def func(
|
|
|
2279
2298
|
)
|
|
2280
2299
|
if side.impl == "cyclone" and side.dds_spdp_interval:
|
|
2281
2300
|
items.append(("local_spdp_interval", side.dds_spdp_interval))
|
|
2301
|
+
if side.impl == "cyclone" and side.dds_fragment_size:
|
|
2302
|
+
items.append(("local_fragment_size", side.dds_fragment_size))
|
|
2282
2303
|
return items
|
|
2283
2304
|
|
|
2284
2305
|
def _build_ota_rmw_items() -> List[Tuple[str, Any]]:
|
|
@@ -2306,6 +2327,8 @@ def func(
|
|
|
2306
2327
|
)
|
|
2307
2328
|
if ota.impl == "cyclone" and ota.dds_spdp_interval:
|
|
2308
2329
|
items.append(("ota_spdp_interval", ota.dds_spdp_interval))
|
|
2330
|
+
if ota.impl == "cyclone" and ota.dds_fragment_size:
|
|
2331
|
+
items.append(("ota_fragment_size", ota.dds_fragment_size))
|
|
2309
2332
|
return items
|
|
2310
2333
|
|
|
2311
2334
|
def _build_zenoh_block(
|
|
@@ -315,7 +315,7 @@ SPEC_OWNS = (
|
|
|
315
315
|
#: options. Listed by pattern so an unclassified newcomer fails the guard.
|
|
316
316
|
NO_TOPIC = (
|
|
317
317
|
r"dir_path|before_command|peer_dir|session_dir",
|
|
318
|
-
r"(rmw|ota|local)_(local|ota|config_template|config_file|easy_mode_ip|spdp_interval|domain_id|name)",
|
|
318
|
+
r"(rmw|ota|local)_(local|ota|config_template|config_file|easy_mode_ip|spdp_interval|fragment_size|domain_id|name)",
|
|
319
319
|
r"domain_bridge_config_file|use_domain_bridge",
|
|
320
320
|
r"ip_(local|remote)|remote_name|qos_config_file|topic_types_file",
|
|
321
321
|
r"in|out|use_zenoh_(rmw|ros2dds)",
|
|
@@ -3166,6 +3166,88 @@ def test_run_session_passes_cyclone_spdp_interval_to_plugin(tmp_path: Path) -> N
|
|
|
3166
3166
|
assert plugin["parameters"]["ota_spdp_interval"] == "150s"
|
|
3167
3167
|
|
|
3168
3168
|
|
|
3169
|
+
def test_run_session_passes_cyclone_fragment_size_to_plugin(tmp_path: Path) -> None:
|
|
3170
|
+
"""The number reaches the peer that renders the profile, not just the YAML."""
|
|
3171
|
+
from session.creation import run_session
|
|
3172
|
+
|
|
3173
|
+
source = tmp_path / "sessions" / "fragment"
|
|
3174
|
+
output = tmp_path / "session-instances" / "2026-01-01" / "fragment_run" / "config"
|
|
3175
|
+
source.mkdir(parents=True)
|
|
3176
|
+
(source / "session-definition.yaml").write_text(
|
|
3177
|
+
"\n".join(
|
|
3178
|
+
[
|
|
3179
|
+
"peers:",
|
|
3180
|
+
" a: {}",
|
|
3181
|
+
" b: {}",
|
|
3182
|
+
"shared:",
|
|
3183
|
+
" rmw:",
|
|
3184
|
+
" local: cyclone",
|
|
3185
|
+
" ota:",
|
|
3186
|
+
" cyclone:",
|
|
3187
|
+
" fragment_size: 1200B",
|
|
3188
|
+
"topics:",
|
|
3189
|
+
" a_to_b:",
|
|
3190
|
+
" - topic: /x",
|
|
3191
|
+
" type: std_msgs/msg/String",
|
|
3192
|
+
"",
|
|
3193
|
+
]
|
|
3194
|
+
),
|
|
3195
|
+
encoding="utf-8",
|
|
3196
|
+
)
|
|
3197
|
+
|
|
3198
|
+
peer_dir = run_session._resolve_peer_dir(
|
|
3199
|
+
str(source),
|
|
3200
|
+
str(output),
|
|
3201
|
+
"a",
|
|
3202
|
+
force=True,
|
|
3203
|
+
rewrite_formatting=False,
|
|
3204
|
+
peer_address=["a=127.0.0.1", "b=127.0.0.2"],
|
|
3205
|
+
)
|
|
3206
|
+
|
|
3207
|
+
plugin = yaml.safe_load((Path(peer_dir) / "plugin.yaml").read_text(encoding="utf-8"))
|
|
3208
|
+
assert plugin["parameters"]["ota_fragment_size"] == "1200B"
|
|
3209
|
+
|
|
3210
|
+
|
|
3211
|
+
def test_run_session_rejects_a_fragment_size_no_template_can_use(tmp_path: Path) -> None:
|
|
3212
|
+
"""An unusable size is a session error, not a profile that renders wrong."""
|
|
3213
|
+
from session.creation import run_session
|
|
3214
|
+
|
|
3215
|
+
source = tmp_path / "sessions" / "bad_fragment"
|
|
3216
|
+
output = tmp_path / "session-instances" / "2026-01-01" / "bad_fragment_run" / "config"
|
|
3217
|
+
source.mkdir(parents=True)
|
|
3218
|
+
(source / "session-definition.yaml").write_text(
|
|
3219
|
+
"\n".join(
|
|
3220
|
+
[
|
|
3221
|
+
"peers:",
|
|
3222
|
+
" a: {}",
|
|
3223
|
+
" b: {}",
|
|
3224
|
+
"shared:",
|
|
3225
|
+
" rmw:",
|
|
3226
|
+
" local: cyclone",
|
|
3227
|
+
" ota:",
|
|
3228
|
+
" cyclone:",
|
|
3229
|
+
" fragment_size: plenty",
|
|
3230
|
+
"topics:",
|
|
3231
|
+
" a_to_b:",
|
|
3232
|
+
" - topic: /x",
|
|
3233
|
+
" type: std_msgs/msg/String",
|
|
3234
|
+
"",
|
|
3235
|
+
]
|
|
3236
|
+
),
|
|
3237
|
+
encoding="utf-8",
|
|
3238
|
+
)
|
|
3239
|
+
|
|
3240
|
+
with pytest.raises(RuntimeError, match="positive byte size"):
|
|
3241
|
+
run_session._resolve_peer_dir(
|
|
3242
|
+
str(source),
|
|
3243
|
+
str(output),
|
|
3244
|
+
"a",
|
|
3245
|
+
force=True,
|
|
3246
|
+
rewrite_formatting=False,
|
|
3247
|
+
peer_address=["a=127.0.0.1", "b=127.0.0.2"],
|
|
3248
|
+
)
|
|
3249
|
+
|
|
3250
|
+
|
|
3169
3251
|
def test_create_session_yaml_injects_catmux_logging_command(tmp_path: Path) -> None:
|
|
3170
3252
|
from session.creation import create_session_yaml
|
|
3171
3253
|
|
|
@@ -943,3 +943,76 @@ def test_a_pinned_peer_confines_its_containers(tmp_path: Path) -> None:
|
|
|
943
943
|
# And without one, nothing is added: the flag must not appear on a peer that
|
|
944
944
|
# was never pinned, or every unpinned run changes shape too.
|
|
945
945
|
assert "--cpuset" not in rosotacom._ota_start_parts(target, "a", "id-1", [], mode="detached")
|
|
946
|
+
|
|
947
|
+
|
|
948
|
+
# --------------------------------------------------- instance resolution by name
|
|
949
|
+
#
|
|
950
|
+
# A session's instances are found by globbing its slug. The slug of one session
|
|
951
|
+
# can be a prefix of another's — `ccng_remote_assist` and
|
|
952
|
+
# `ccng_remote_assist_kilted_dds` are the pair that exposed it — and a pattern
|
|
953
|
+
# that ends the slug with `*` then matches both. The matches are ordered by
|
|
954
|
+
# name, so the answer is whichever sorts last, and a letter sorts after a digit:
|
|
955
|
+
# the *other* session's run wins over this session's own newest one.
|
|
956
|
+
#
|
|
957
|
+
# What that cost: on 2026-08-21 `rosotacom status ccng_remote_assist` reported a
|
|
958
|
+
# `ccng_remote_assist_kilted_dds` run that had been shut down 45 minutes
|
|
959
|
+
# earlier. Three two-host runs waited ten minutes each and concluded their link
|
|
960
|
+
# never came up, while their own status file said it had been OK the whole time.
|
|
961
|
+
|
|
962
|
+
|
|
963
|
+
def _session(tmp_path: Path, name: str) -> rosotacom.ResolvedSession:
|
|
964
|
+
host_dir = tmp_path / "sessions" / name
|
|
965
|
+
host_dir.mkdir(parents=True, exist_ok=True)
|
|
966
|
+
return rosotacom.ResolvedSession(host_dir, f"/session/{name}", "test")
|
|
967
|
+
|
|
968
|
+
|
|
969
|
+
def _instance(root: Path, slug: str, stamp: str, instance_id: str) -> Path:
|
|
970
|
+
day, _, _ = stamp.partition("_")
|
|
971
|
+
path = root / day / f"{slug}_{stamp}_{instance_id}"
|
|
972
|
+
path.mkdir(parents=True, exist_ok=True)
|
|
973
|
+
return path
|
|
974
|
+
|
|
975
|
+
|
|
976
|
+
def test_a_longer_session_name_does_not_capture_this_session_s_instances(tmp_path: Path) -> None:
|
|
977
|
+
runtime = _runtime(tmp_path)
|
|
978
|
+
root = tmp_path / "instances"
|
|
979
|
+
mine = _instance(root, "ccng_remote_assist", "2026-08-21_21-42-01", "35285739")
|
|
980
|
+
# Older, another session, and its name sorts after mine because 'k' > '2'.
|
|
981
|
+
_instance(root, "ccng_remote_assist_kilted_dds", "2026-08-21_20-57-05", "52a752d6")
|
|
982
|
+
|
|
983
|
+
found = rosotacom._find_latest_instance_dir(runtime, _session(tmp_path, "ccng_remote_assist"), None)
|
|
984
|
+
|
|
985
|
+
assert found == mine.resolve()
|
|
986
|
+
|
|
987
|
+
|
|
988
|
+
def test_the_longer_name_still_finds_its_own_newest(tmp_path: Path) -> None:
|
|
989
|
+
runtime = _runtime(tmp_path)
|
|
990
|
+
root = tmp_path / "instances"
|
|
991
|
+
_instance(root, "ccng_remote_assist", "2026-08-21_21-42-01", "35285739")
|
|
992
|
+
_instance(root, "ccng_remote_assist_kilted_dds", "2026-08-21_20-48-37", "643792ab")
|
|
993
|
+
newest = _instance(root, "ccng_remote_assist_kilted_dds", "2026-08-21_20-57-05", "52a752d6")
|
|
994
|
+
|
|
995
|
+
found = rosotacom._find_latest_instance_dir(runtime, _session(tmp_path, "ccng_remote_assist_kilted_dds"), None)
|
|
996
|
+
|
|
997
|
+
assert found == newest.resolve()
|
|
998
|
+
|
|
999
|
+
|
|
1000
|
+
def test_instances_are_ordered_by_their_stamp(tmp_path: Path) -> None:
|
|
1001
|
+
runtime = _runtime(tmp_path)
|
|
1002
|
+
root = tmp_path / "instances"
|
|
1003
|
+
_instance(root, "link", "2026-08-20_23-59-59", "aaaaaaaa")
|
|
1004
|
+
newest = _instance(root, "link", "2026-08-21_00-00-01", "00000000")
|
|
1005
|
+
|
|
1006
|
+
found = rosotacom._find_latest_instance_dir(runtime, _session(tmp_path, "link"), None)
|
|
1007
|
+
|
|
1008
|
+
# The id sorts first among these two; the stamp is what has to decide.
|
|
1009
|
+
assert found == newest.resolve()
|
|
1010
|
+
|
|
1011
|
+
|
|
1012
|
+
def test_a_named_instance_of_another_session_is_not_answered(tmp_path: Path) -> None:
|
|
1013
|
+
runtime = _runtime(tmp_path)
|
|
1014
|
+
root = tmp_path / "instances"
|
|
1015
|
+
_instance(root, "ccng_remote_assist_kilted_dds", "2026-08-21_20-57-05", "52a752d6")
|
|
1016
|
+
|
|
1017
|
+
with pytest.raises(RuntimeError, match="No session instance found"):
|
|
1018
|
+
rosotacom._find_latest_instance_dir(runtime, _session(tmp_path, "ccng_remote_assist"), "52a752d6")
|
|
@@ -91,6 +91,48 @@ def test_only_cyclone_caps_the_datagram_and_fast_dds_must_not() -> None:
|
|
|
91
91
|
assert "max_msg_size=" not in resolved, config
|
|
92
92
|
|
|
93
93
|
|
|
94
|
+
def test_every_bootstrap_forwards_the_fragment_size_it_was_given() -> None:
|
|
95
|
+
"""One forgotten window renders the default and nothing says so.
|
|
96
|
+
|
|
97
|
+
The OTA profile is rendered in three windows (COM, IN, OUT) and the local
|
|
98
|
+
one in a fourth. A session that names a fragment size and gets it in three
|
|
99
|
+
of the four has two profiles on one host, which is the failure mode
|
|
100
|
+
cyclonedds_scoped.xml exists to remove — and it would look healthy.
|
|
101
|
+
"""
|
|
102
|
+
plugin_base = PLUGIN_BASE.read_text(encoding="utf-8")
|
|
103
|
+
|
|
104
|
+
assert plugin_base.count('ota_args+=(--fragment-size "${ota_fragment_size}")') == 3
|
|
105
|
+
assert plugin_base.count('local_args+=(--fragment-size "${local_fragment_size}")') == 1
|
|
106
|
+
# Declared, so an unset one renders as "None" and is skipped rather than
|
|
107
|
+
# left as a literal ${...} in the command line.
|
|
108
|
+
assert "\n ota_fragment_size:" in plugin_base
|
|
109
|
+
assert "\n local_fragment_size:" in plugin_base
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def test_a_session_may_ask_the_packaged_templates_for_the_older_profile() -> None:
|
|
113
|
+
"""Both shipped Cyclone OTA templates resolve the size, not just one.
|
|
114
|
+
|
|
115
|
+
The two-profile arrangement renders cyclonedds_tuned.xml and the scoped one
|
|
116
|
+
renders cyclonedds_scoped.xml. A Kilted-versus-Lyrical comparison needs the
|
|
117
|
+
same fragment size whichever arrangement it runs, so neither template may
|
|
118
|
+
keep the number as a literal.
|
|
119
|
+
"""
|
|
120
|
+
module = _load(OTA_CONFIGS / "get_ota_xml.py", "rosotacom_get_ota_xml_fragment")
|
|
121
|
+
for config in ("cyclonedds_tuned.xml", "cyclonedds_scoped.xml"):
|
|
122
|
+
rendered = str(
|
|
123
|
+
module.main(
|
|
124
|
+
config=config,
|
|
125
|
+
host_ip="10.0.0.1",
|
|
126
|
+
peer="10.0.0.2",
|
|
127
|
+
fragment_size="1200B",
|
|
128
|
+
local_domain="47",
|
|
129
|
+
ota_domain="48",
|
|
130
|
+
)
|
|
131
|
+
)
|
|
132
|
+
assert "<FragmentSize>1200B</FragmentSize>" in rendered, config
|
|
133
|
+
assert f"<MaxMessageSize>{OTA_DATAGRAM_BYTES}B</MaxMessageSize>" in rendered, config
|
|
134
|
+
|
|
135
|
+
|
|
94
136
|
def test_both_default_ota_templates_pin_the_interface_and_the_peer() -> None:
|
|
95
137
|
for config in ("cyclonedds_tuned.xml", "fastdds_tuned.xml"):
|
|
96
138
|
resolved = _resolved(config)
|