rosotacom-dev 2.5.dev57__tar.gz → 2.5.dev60__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.dev57 → rosotacom_dev-2.5.dev60}/PKG-INFO +1 -1
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/docs/findings/README.md +2 -0
- rosotacom_dev-2.5.dev60/docs/findings/a-transport-element-doubles-every-fastdds-sample.md +117 -0
- rosotacom_dev-2.5.dev60/docs/findings/lifespan-is-enforced-by-one-reader-and-not-the-other.md +108 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/cli.py +61 -1
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/ota_configs/fastdds_tuned.xml.template +40 -42
- rosotacom_dev-2.5.dev60/src/rosotacom/resources/ws/ota_configs/fastdds_unicast.xml.template +93 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/ros2src/com_py/com_py/playout_pacer_core.py +16 -3
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom_dev.egg-info/PKG-INFO +1 -1
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom_dev.egg-info/SOURCES.txt +2 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom_dev.egg-info/scm_file_list.json +2 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom_dev.egg-info/scm_version.json +2 -2
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/tests/unit/test_concurrency.py +94 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/tests/unit/test_ota_link_configs.py +35 -4
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/tests/unit/test_playout_pacer.py +54 -0
- rosotacom_dev-2.5.dev57/src/rosotacom/resources/ws/ota_configs/fastdds_unicast.xml.template +0 -71
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/.devcontainer/devcontainer.json.template +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/.devcontainer/re_generate_devcontainer_json.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/.github/CODEOWNERS +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/.github/ISSUE_TEMPLATE/documentation-audit.md +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/.github/ISSUE_TEMPLATE/implementation-cleanup.md +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/.github/ISSUE_TEMPLATE/quality-workflow.md +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/.github/ISSUE_TEMPLATE/redesign.md +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/.github/ISSUE_TEMPLATE/release-process.md +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/.github/ISSUE_TEMPLATE/repository-diagnosis.md +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/.github/ISSUE_TEMPLATE/test-ci-audit.md +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/.github/ISSUE_TEMPLATE/work-item.md +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/.github/actions/setup-just/action.yml +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/.github/dependabot.yml +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/.github/workflows/benchmark-calibrate.yml +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/.github/workflows/benchmark-gate.yml +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/.github/workflows/dev-release.yml +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/.github/workflows/image-scan.yml +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/.github/workflows/nightly-e2e.yml +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/.github/workflows/pr-lightweight.yml +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/.github/workflows/pr-merge-gate.yml +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/.github/workflows/release.yml +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/.pre-commit-config.yaml +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/AGENTS.md +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/CONCURRENCY.md +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/CONTRIBUTING.md +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/DEVELOPMENT_PRINCIPLES.md +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/LICENSE.txt +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/MANIFEST.in +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/README.md +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/budgets.jsonl +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/calibration/README.md +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/calibration/capacity-size-tight-cyclone.json +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/calibration/probe-loss-gop-tight-cyclone.json +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/calibration/probe-loss-nominal-cyclone.json +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/calibration/probe-loss-tight-cyclone.json +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/calibration/probe-loss-tight-fastdds.json +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/calibration/probe-loss-tight-zenoh.json +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/codecov.yml +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/deployment-configuration.md +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/docs/benchmark-ab.md +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/docs/benchmark-bag-as-load.md +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/docs/ci.md +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/docs/ffmpeg-keyframes.md +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/docs/findings/cyclone-spdp-discovery-bursts.md +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/docs/findings/delay-alone-no-loss.md +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/docs/findings/fastdds-datagram-cap-drops-large-samples.md +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/docs/findings/graph-derived-types-block-a-non-graph-transport.md +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/docs/findings/head-of-line-irregularity.md +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/docs/findings/jitter-loss-bandwidth-latency.md +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/docs/findings/keyframe-loss-kills-the-next-deltas.md +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/docs/findings/lighter-message-loss.md +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/docs/findings/oversubscription-queues-not-losses.md +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/docs/findings/reorder-becomes-reader-loss.md +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/docs/findings/repro/decode_chain_repro.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/docs/findings/repro/reorder_drop_repro.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/docs/findings/sender-rows-make-a-dead-link-look-loss-free.md +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/docs/findings/zero-loss-boundaries-18kb-20hz.md +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/docs/forensics-report.md +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/docs/geo-link-map.md +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/docs/github-repository-settings.md +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/docs/link-bandwidth.md +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/docs/link-trace.md +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/docs/owner-runbook.md +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/docs/performance-bands.md +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/docs/playbooks/README.md +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/docs/quality-model.md +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/docs/release-notes/TEMPLATE.md +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/docs/release-notes/v2.1.md +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/docs/release-notes/v2.2.md +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/docs/release-notes/v2.3.md +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/docs/release-notes/v2.4.md +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/docs/release.md +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/docs/rfcs/0001-expectation-driven-test-suite.md +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/docs/rfcs/0002-expectation-concepts.md +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/docs/rfcs/0003-metric-backbone.md +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/docs/rfcs/0004-network-profiles.md +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/docs/rfcs/0005-benchmark-genres-and-ci.md +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/docs/rfcs/0006-dynamic-qos.md +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/docs/rfcs/0007-regression-gate.md +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/docs/rfcs/README.md +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/docs/testing.md +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/docs/work-items.md +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/install.sh +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/justfile +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/media/control_center.png +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/media/echo_test.png +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/media/forensics-report-example.png +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/media/host.png +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/media/vehicle.png +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/pyproject.toml +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/requirements.txt +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/rosotacom.yaml +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/session-configuration.md +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/setup.cfg +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/__init__.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/__main__.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/anonymize.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/bag_ground_truth.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/benched_set.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/benchmark.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/benchmark_delta.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/bundle_check.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/cli_benchmark.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/deployment.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/ffmpeg_packet.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/forensics.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/geomap.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/image_cache.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/netem_dist.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/network_preflight.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/network_profiles.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/network_shaper.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/plots.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/py.typed +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/benched-set.yaml +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/examples/.gitignore +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/examples/README.md +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/examples/__init__.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/examples/bags/8_drop_reference/metadata.yaml +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/examples/deployment.example.yaml +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/examples/dist/field-20260817.dist +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/examples/profiles.yaml +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/examples/ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/examples/rosotacom.yaml +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/examples/scenarios/2_native_chatter/scenario-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/examples/scripts/1_heartbeat/run_machine_a.sh +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/examples/scripts/1_heartbeat/run_machine_b.sh +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_a/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_a/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_a/run_external.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_a/wait_for_echo_topic.sh +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_b/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_b/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_b/run_external.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_a/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_a/external_session.yaml +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_a/foxglove.json +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_a/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_a/run_external.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_b/costmap_1second/costmap_1second_0.mcap +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_b/costmap_1second/metadata.yaml +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_b/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_b/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_b/run_external.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_a/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_a/external_session.yaml +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_a/foxglove.json +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_a/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_a/run_external.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_b/costmap_1second/costmap_1second_0.mcap +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_b/costmap_1second/metadata.yaml +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_b/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_b/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_b/run_external.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_a/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_a/external_session.yaml +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_a/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_a/run_external.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_b/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_b/external_session.yaml +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_b/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_b/run_external.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_a/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_a/external_session.yaml +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_a/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_a/run_external.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_b/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_b/external_session.yaml +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_b/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_b/run_external.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/examples/sessions/10_restamp/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/examples/sessions/11_trickle/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/examples/sessions/12_content_integrity/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/examples/sessions/13_link_latency/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/examples/sessions/14_remote_assist_anonymized/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/examples/sessions/15_remote_assist_anonymized_costmap/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/examples/sessions/16_remote_assist_anonymized_camera/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/examples/sessions/17_synthetic_camera_quality/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/examples/sessions/1_heartbeat/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/examples/sessions/1_heartbeat_status/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/examples/sessions/2_native_chatter/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/examples/sessions/3_comp_occ_grid/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/examples/sessions/4_comp_occ_grid_zen/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/examples/sessions/5_sized_payload/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/examples/sessions/6_sized_payload_zen/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/examples/sessions/7_latched_static/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/examples/sessions/8_drop/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/examples/sessions/9_throttle/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/examples/sessions/bench_1_1_capacity/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/examples/sessions/bench_1_2_load_sweep/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/examples/sessions/bench_1_3_ramp/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/examples/sessions/bench_1_4_recovery/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/examples/sessions/bench_1_5_camera/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ros2docker.json.example +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/.vscode/c_cpp_properties.json +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/.vscode/settings.json +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_easy_mode.xml.template +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_initial_peer_list.xml.template +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_v2.xml.template +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_v3.xml.template +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_v4.xml.template +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_v5.xml.template +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/ota_configs/create_zenoh_json5.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/ota_configs/cyclonedds_local_participants.xml.template +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/ota_configs/cyclonedds_minimal.xml.template +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/ota_configs/cyclonedds_tuned.xml.template +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/ota_configs/fastdds_easy_mode.xml.template +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/ota_configs/fastdds_local.xml.template +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/ota_configs/get_ota_xml.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/ota_configs/utils.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/ota_configs/zenoh.json5.template +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/ros2src/.gitkeep +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/ros2src/com_cpp/CMakeLists.txt +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/ros2src/com_cpp/COLCON_IGNORE +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/ros2src/com_cpp/LICENSE.txt +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/ros2src/com_cpp/package.xml +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/ros2src/com_cpp/src/hz_monitor.cpp +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/ros2src/com_cpp/src/universal_compressor.cpp +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/ros2src/com_cpp/src/universal_decompressor.cpp +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/ros2src/com_msgs/CMakeLists.txt +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/ros2src/com_msgs/LICENSE.txt +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/ros2src/com_msgs/msg/CompressedData.msg +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/ros2src/com_msgs/msg/EchoHeartbeat.msg +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/ros2src/com_msgs/msg/OtaStamped.msg +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/ros2src/com_msgs/msg/SizedPayload.msg +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/ros2src/com_msgs/package.xml +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/ros2src/com_py/LICENSE.txt +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/ros2src/com_py/com_py/__init__.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/ros2src/com_py/com_py/base_bridge_relay.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/ros2src/com_py/com_py/bridge_in.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/ros2src/com_py/com_py/bridge_out.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/ros2src/com_py/com_py/ffmpeg_flags.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/ros2src/com_py/com_py/heartbeat_echo.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/ros2src/com_py/com_py/hz_monitor.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/ros2src/com_py/com_py/image_bandwidth_reducer.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/ros2src/com_py/com_py/image_pixel_capper.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/ros2src/com_py/com_py/lanelet_saver.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/ros2src/com_py/com_py/latch_relay.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/costmap_remapper.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/marker_remapper.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/speed_test.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/tf_remapper.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/traffic_monitor.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/wifi_network_analysis_1.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/ros2src/com_py/com_py/link_bytes.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/ros2src/com_py/com_py/link_trace.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/ros2src/com_py/com_py/local_global_frame_bridge.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/ros2src/com_py/com_py/localization_map_split_reduce_saver.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/ros2src/com_py/com_py/msg_transform.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/ros2src/com_py/com_py/pair_management.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/ros2src/com_py/com_py/playout_pacer.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/ros2src/com_py/com_py/pub_sub_pair.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/ros2src/com_py/com_py/qos.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/ros2src/com_py/com_py/relay_in.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/ros2src/com_py/com_py/relay_out.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/ros2src/com_py/com_py/restamp.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/ros2src/com_py/com_py/sized_publisher.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/ros2src/com_py/com_py/stage_latency.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/ros2src/com_py/com_py/stage_latency_core.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/ros2src/com_py/com_py/status_overview.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/ros2src/com_py/com_py/status_overview_core.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/ros2src/com_py/com_py/tf_map_to_cart_saver.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/ros2src/com_py/com_py/topic_monitor.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/ros2src/com_py/com_py/topic_resolution.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/ros2src/com_py/com_py/trickle.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/ros2src/com_py/com_py/universal_compressor.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/ros2src/com_py/com_py/universal_decompressor.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/ros2src/com_py/com_py/universal_ota_unwrapper.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/ros2src/com_py/com_py/universal_ota_wrapper.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/ros2src/com_py/package.xml +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/ros2src/com_py/resource/com_py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/ros2src/com_py/setup.cfg +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/ros2src/com_py/setup.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/ros2src/com_py/test/test_copyright.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/ros2src/com_py/test/test_flake8.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/ros2src/com_py/test/test_pep257.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/session/content/base/session_plugin_base.yaml +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/session/content/network/up_connectivity.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/session/content/network/wifi_network_analysis_2.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/session/creation/anonymize_bag.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/session/creation/catmux_log_setup.sh +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/session/creation/create_session_yaml.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/session/creation/generate_session_files.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/session/creation/run_session.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/session/creation/run_session_in_external_terminal.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/resources/ws/session/creation/strip_ansi.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/status_eval.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/stream_stats.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/trace_profiles.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/transit.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom/video_quality.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom_dev.egg-info/dependency_links.txt +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom_dev.egg-info/entry_points.txt +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom_dev.egg-info/requires.txt +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom_dev.egg-info/top_level.txt +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/terminology.md +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/tests/contract/test_benched_set_registry.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/tests/contract/test_findings.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/tests/contract/test_generated_topics_have_a_producer.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/tests/contract/test_markdown_links.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/tests/contract/test_ota_source_bundle.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/tests/contract/test_package_metadata.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/tests/contract/test_packaged_resources.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/tests/contract/test_profile_covers_generated_commands.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/tests/contract/test_pytest_policy.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/tests/contract/test_readme_examples.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/tests/contract/test_security_maintenance_config.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/tests/contract/test_session_configuration_doc.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/tests/contract/test_session_template_substitution.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/tests/contract/test_workflow_contracts.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/tests/e2e/conftest.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/tests/e2e/test_anonymize_e2e.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/tests/e2e/test_benchmark_ab.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/tests/e2e/test_benchmark_capacity.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/tests/e2e/test_benchmark_replay.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/tests/e2e/test_parallel_smoke.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/tests/e2e/test_smoke.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/tests/e2e/test_timeline_stepping.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/tests/e2e/test_video_quality_e2e.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/tests/sessions/generate_rmw_matrix.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/tests/sessions/rmw_matrix/1_heartbeat_cyclone-local_zenoh-ros2dds-ota/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/tests/sessions/rmw_matrix/1_heartbeat_cyclone-ota/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/tests/sessions/rmw_matrix/1_heartbeat_cyclone-ota-tuned/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/tests/sessions/rmw_matrix/1_heartbeat_fastdds/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/tests/sessions/rmw_matrix/1_heartbeat_fastdds-default/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/tests/sessions/rmw_matrix/1_heartbeat_zen-endpoints/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/tests/unit/test_anonymize.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/tests/unit/test_bag_ground_truth.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/tests/unit/test_benched_set.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/tests/unit/test_benchmark.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/tests/unit/test_benchmark_delta.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/tests/unit/test_bundle_check.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/tests/unit/test_catmux_pane_logging.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/tests/unit/test_cli.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/tests/unit/test_cli_benchmark.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/tests/unit/test_container_shaping.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/tests/unit/test_deployment.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/tests/unit/test_ffmpeg_flags.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/tests/unit/test_ffmpeg_packet.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/tests/unit/test_field_profiles.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/tests/unit/test_forensics.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/tests/unit/test_geomap.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/tests/unit/test_image_cache.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/tests/unit/test_link_bytes.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/tests/unit/test_link_trace.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/tests/unit/test_netem_dist.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/tests/unit/test_network_preflight.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/tests/unit/test_network_profiles.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/tests/unit/test_network_shaper.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/tests/unit/test_ota_unwrapper.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/tests/unit/test_ota_wrapper.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/tests/unit/test_ota_xml.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/tests/unit/test_plots.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/tests/unit/test_pub_sub_pair_types.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/tests/unit/test_qos_fallback_logging.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/tests/unit/test_relay_optional_parameters.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/tests/unit/test_session_pipeline.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/tests/unit/test_stage_latency.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/tests/unit/test_status_eval.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/tests/unit/test_status_overview.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/tests/unit/test_status_overview_observer.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/tests/unit/test_stream_stats.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/tests/unit/test_trace_profiles.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/tests/unit/test_transit.py +0 -0
- {rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/tests/unit/test_video_quality.py +0 -0
|
@@ -32,6 +32,8 @@ 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 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.
|
|
35
|
+
- [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.
|
|
36
|
+
- [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.
|
|
35
37
|
- [Oversubscription queues — it does not lose until the queue itself dies](oversubscription-queues-not-losses.md) - 16% over an emulated cap climbed one-way delay 340 → 3250 ms across twelve bins with zero loss in every one; the losses arrived only when the queue died, all at once.
|
|
36
38
|
- [Best-effort reordering becomes reader-side loss, independent of history depth](reorder-becomes-reader-loss.md) - under pure delay jitter a Cyclone best-effort reader discards every overtaken sample (57% at 100 Hz under 50+-45 ms), delivery stays strictly monotonic, and depth 50 loses the same as depth 1.
|
|
37
39
|
- [Jitter causes loss while bandwidth shortage builds latency](jitter-loss-bandwidth-latency.md) - 18 KB at 20 Hz separates jitter-induced loss from bandwidth-induced queueing.
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
# Any Transport Element In A Fast DDS Profile Doubles Every Sample On The Wire
|
|
2
|
+
|
|
3
|
+
## Claim
|
|
4
|
+
|
|
5
|
+
A Fast DDS participant profile that carries **any** transport element transmits
|
|
6
|
+
every sample twice. It is not a property of the transport that gets selected:
|
|
7
|
+
`<builtinTransports>DEFAULT</builtinTransports>` asks for exactly the built-in
|
|
8
|
+
set — a semantic no-op — and doubles the wire just as a full custom
|
|
9
|
+
`<userTransports>` descriptor does. Removing the element is the entire fix.
|
|
10
|
+
|
|
11
|
+
Measured against a 960 kbit/s payload, on the profile this repository ships:
|
|
12
|
+
|
|
13
|
+
| participant profile carries | interface tx |
|
|
14
|
+
|---|---|
|
|
15
|
+
| `<userTransports>` + `<useBuiltinTransports>false` (as shipped) | 1741 kbit/s |
|
|
16
|
+
| `<builtinTransports non_blocking="true">UDPv4` | 1741 kbit/s |
|
|
17
|
+
| `<builtinTransports>UDPv4` | 1741 kbit/s |
|
|
18
|
+
| `<builtinTransports>DEFAULT` | 1741 kbit/s |
|
|
19
|
+
| **no transport element** | **1007 kbit/s** |
|
|
20
|
+
|
|
21
|
+
Counted per datagram: **366** to the reader's data locator for **180** published
|
|
22
|
+
samples, against **183** without the element — each carrying a full 11 951 B of
|
|
23
|
+
UDP payload, to the same address and the same port. The reader discards the
|
|
24
|
+
second copy by sequence number, so it is delivered exactly once and costs half
|
|
25
|
+
the link.
|
|
26
|
+
|
|
27
|
+
The consequence for any published wire-volume comparison is direct: a Fast DDS
|
|
28
|
+
row measured with such a profile is a measurement of this defect, not of the
|
|
29
|
+
middleware.
|
|
30
|
+
|
|
31
|
+
## Setup
|
|
32
|
+
|
|
33
|
+
- Host pair / topology: one host, two containers on a private docker bridge
|
|
34
|
+
(172.31.77.0/24), publisher and subscriber in separate containers; and the
|
|
35
|
+
same profile on the host network of a multi-homed machine (38 interfaces:
|
|
36
|
+
docker bridges, a VPN tun, WLAN) for the discovery checks.
|
|
37
|
+
- Session: a two-process rclpy probe, not the session pipeline — one
|
|
38
|
+
`std_msgs/String` topic at 12000 B and 10 Hz, best_effort / KEEP_LAST depth 1,
|
|
39
|
+
publisher started after the subscriber. Bytes are read from
|
|
40
|
+
`/sys/class/net/eth0/statistics/tx_bytes` around the run; datagrams are counted
|
|
41
|
+
from a `tshark` capture with `ip.defragment:FALSE`, so the packet count and the
|
|
42
|
+
interface counter agree.
|
|
43
|
+
- rosotacom SHA: `fastdds_tuned.xml.template` as of this commit, rendered by
|
|
44
|
+
`get_ota_xml.py`. ROS 2 Kilted, Fast DDS 3.2.4, `rmw_fastrtps_cpp` 9.3.4,
|
|
45
|
+
image `ros-communication:latest`.
|
|
46
|
+
- Profile: no shaping for the wire-volume rows — the point is what the stack
|
|
47
|
+
offers, not what a link does with it.
|
|
48
|
+
- Seed policy: deterministic; one run per cell, and the cells that share a
|
|
49
|
+
configuration agree to the byte (4 996 526 B across three different descriptor
|
|
50
|
+
shapes), which is what makes single runs readable here.
|
|
51
|
+
|
|
52
|
+
## Evidence
|
|
53
|
+
|
|
54
|
+
Evidence grade: interface counters plus a packet capture of the same runs, on
|
|
55
|
+
both a synthetic profile and the rendered shipped one.
|
|
56
|
+
|
|
57
|
+
The trigger is the element, not its contents. Four descriptor shapes, all 366
|
|
58
|
+
datagrams for 180 samples: a bare `<transport_descriptor>` with nothing but
|
|
59
|
+
`transport_id` and `type`; the same plus `maxInitialPeersRange`; the same with
|
|
60
|
+
`<useBuiltinTransports>` set to `true` instead of `false`; and the same
|
|
61
|
+
allowlisted to a single interface. The single-interface row also refutes the
|
|
62
|
+
obvious alternative explanation — that the participant sends one copy per bound
|
|
63
|
+
interface.
|
|
64
|
+
|
|
65
|
+
On the rendered `fastdds_tuned.xml`, correcting for the ~40 messages published
|
|
66
|
+
before discovery completes (a Fast DDS writer with no matched reader puts nothing
|
|
67
|
+
on the wire, and this profile takes 3.9–4.2 s to match):
|
|
68
|
+
|
|
69
|
+
| | interface tx | transmitted payload | ratio |
|
|
70
|
+
|---|---|---|---|
|
|
71
|
+
| as shipped | 6516 kB | 3109 kB | **2.10×** |
|
|
72
|
+
| with the element removed | 3270 kB | 3145 kB | **1.04×** |
|
|
73
|
+
|
|
74
|
+
Both delivered 245 of 245, at a sub-millisecond median age. Nothing is traded for
|
|
75
|
+
the halving. For scale, CycloneDDS on the same bench and payload costs 963 kbit/s
|
|
76
|
+
— **1.00×** — so removing the element brings Fast DDS from twice Cyclone's wire
|
|
77
|
+
need to within 4% of it.
|
|
78
|
+
|
|
79
|
+
Two properties the removed descriptor carried were checked rather than assumed,
|
|
80
|
+
on the multi-homed host the profile exists for:
|
|
81
|
+
|
|
82
|
+
- **The same-host path stays open.** 195 of 195 delivered, discovery in 4.13 s,
|
|
83
|
+
across 38 interfaces. The pinned `defaultUnicastLocatorList` /
|
|
84
|
+
`metatrafficUnicastLocatorList` already say what the interface allowlist said.
|
|
85
|
+
- **Discovery survives the lost `maxInitialPeersRange`.** With 12 extra
|
|
86
|
+
participants started first, so the probe processes take high participant
|
|
87
|
+
indices: 195 of 195, discovery in 4.24 s, unchanged.
|
|
88
|
+
|
|
89
|
+
What is genuinely given up: `<non_blocking_send>true</non_blocking_send>` goes
|
|
90
|
+
with the descriptor, so a full send buffer blocks the writer instead of dropping.
|
|
91
|
+
That is the smaller cost — a blocking send stalls only while the link is behind,
|
|
92
|
+
where the duplicate costs half the link at all times.
|
|
93
|
+
|
|
94
|
+
Verification: automated:
|
|
95
|
+
`pytest tests/unit/test_ota_link_configs.py::test_no_fastdds_profile_names_a_transport`
|
|
96
|
+
guards the deletion in every packaged Fast DDS profile. Manual, for the effect
|
|
97
|
+
itself: two containers on a private bridge, one 12 kB/10 Hz stream, read
|
|
98
|
+
`tx_bytes` around a 30 s run with and without a `<builtinTransports>DEFAULT</builtinTransports>`
|
|
99
|
+
line in the participant profile — the ratio must be 2:1.
|
|
100
|
+
|
|
101
|
+
## Status
|
|
102
|
+
|
|
103
|
+
confirmed, 2026-08-19.
|
|
104
|
+
|
|
105
|
+
## Publication notes
|
|
106
|
+
|
|
107
|
+
This is a Fast DDS 3.2.4 / `rmw_fastrtps_cpp` 9.3.4 behaviour and is worth
|
|
108
|
+
reporting upstream; the `DEFAULT` row is the reproducer to lead with, because it
|
|
109
|
+
removes every question about what the profile was asking for.
|
|
110
|
+
|
|
111
|
+
It retires the "Fast DDS's lower loss is bought with bandwidth" reading of this
|
|
112
|
+
project's wire-volume table: roughly half of the excess over CycloneDDS was this,
|
|
113
|
+
and the remainder is still unattributed. Pair with
|
|
114
|
+
[lifespan-is-enforced-by-one-reader-and-not-the-other.md](lifespan-is-enforced-by-one-reader-and-not-the-other.md)
|
|
115
|
+
— together they account for both columns on which Fast DDS looked like a
|
|
116
|
+
different kind of stack: it costs about what Cyclone costs, and it delivers less
|
|
117
|
+
because it refuses to deliver stale.
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# Lifespan Is Enforced By One DDS Reader And Not The Other
|
|
2
|
+
|
|
3
|
+
## Claim
|
|
4
|
+
|
|
5
|
+
Under identical oversubscription the two DDS stacks queue identically — 472 and
|
|
6
|
+
433 delivered of ~490 offered, at medians of 1146 ms and 1220 ms. The stacks
|
|
7
|
+
diverge only when `lifespan` is switched on, and then completely: CycloneDDS is
|
|
8
|
+
unchanged (472 delivered, 1143 → 1146 ms, **9.1%** of samples inside the 0.7 s
|
|
9
|
+
bound they were published with), while Fast DDS drops from 433 delivered to
|
|
10
|
+
**4**, at a 344 ms median, and **never delivers a sample older than 570 ms**.
|
|
11
|
+
|
|
12
|
+
`rmw_cyclonedds` does not enforce lifespan at the reader; Fast DDS does. Neither
|
|
13
|
+
enforcement shortens the delay — the backlog is below DDS and unrecallable
|
|
14
|
+
either way. What lifespan decides is whether a late sample is **shown or
|
|
15
|
+
suppressed**, and for an operator picture those are different failures: 7.9 Hz of
|
|
16
|
+
video more than a second old, against 0.07 Hz of video that is current.
|
|
17
|
+
|
|
18
|
+
The corollary matters for reading any oversubscription result: **Fast DDS's
|
|
19
|
+
apparent collapse under a cap is not a transport failure.** With the policy off
|
|
20
|
+
it carries the same load as CycloneDDS. The missing messages are its reader
|
|
21
|
+
discarding what arrived too late.
|
|
22
|
+
|
|
23
|
+
## Setup
|
|
24
|
+
|
|
25
|
+
- Host pair / topology: one host, two containers on a private docker bridge
|
|
26
|
+
(172.31.77.0/24), publisher and subscriber in separate containers. Single host
|
|
27
|
+
on purpose: both sides read the same `CLOCK_REALTIME`, so a sample's age is
|
|
28
|
+
measured without a clock-offset term.
|
|
29
|
+
- Session: a two-process rclpy probe, not the session pipeline — one
|
|
30
|
+
`std_msgs/String` topic at 12000 B and 10 Hz (960 kbit/s payload), QoS
|
|
31
|
+
best_effort / KEEP_LAST depth 1, publisher started after the subscriber so
|
|
32
|
+
discovery is not inside the measurement. The payload carries its own sequence
|
|
33
|
+
number and publish stamp.
|
|
34
|
+
- rosotacom SHA: not involved; ROS 2 Kilted, Fast DDS 3.2.4 /
|
|
35
|
+
`rmw_fastrtps_cpp` 9.3.4, CycloneDDS via `rmw_cyclonedds_cpp`, image
|
|
36
|
+
`ros-communication:latest`.
|
|
37
|
+
- Profile: `tc qdisc add dev eth0 root tbf rate 800kbit burst 64kb latency
|
|
38
|
+
2000ms` on the publisher container's egress — 20% below the offered payload,
|
|
39
|
+
with a 2 s buffer, i.e. a deliberate standing queue. 60 s per run.
|
|
40
|
+
- Both middlewares configured with explicit unicast discovery (the bridge
|
|
41
|
+
carries unicast but not the DDS discovery multicast), so neither runs on
|
|
42
|
+
defaults.
|
|
43
|
+
- Seed policy: no stochastic netem elements (rate only); one run per cell,
|
|
44
|
+
reported as the four-cell A/B rather than as a distribution.
|
|
45
|
+
|
|
46
|
+
## Evidence
|
|
47
|
+
|
|
48
|
+
Evidence grade: single-host container runs, per-sample age computed from a
|
|
49
|
+
publish stamp inside the payload against one clock, sequence numbers giving loss
|
|
50
|
+
independently of the age.
|
|
51
|
+
|
|
52
|
+
| middleware | lifespan | delivered | age p50 | age p95 | age max | inside 0.7 s |
|
|
53
|
+
|---|---|---|---|---|---|---|
|
|
54
|
+
| CycloneDDS | 0.7 s | 472 | 1146 ms | 1449 ms | 1533 ms | **9.1%** |
|
|
55
|
+
| CycloneDDS | 86400 s (off) | 472 | 1143 ms | 1449 ms | 1533 ms | — |
|
|
56
|
+
| Fast DDS | 0.7 s | **4** | **344 ms** | 570 ms | **570 ms** | **100%** |
|
|
57
|
+
| Fast DDS | 86400 s (off) | **433** | 1220 ms | 1459 ms | 1557 ms | — |
|
|
58
|
+
|
|
59
|
+
Three readings:
|
|
60
|
+
|
|
61
|
+
1. **The two stacks queue the same.** With the policy off, 472 against 433 and
|
|
62
|
+
1143 ms against 1220 ms. Interface accounting agrees: 811 and 812 kbit/s, both
|
|
63
|
+
pinned to the 800 kbit/s cap. Whatever separates them under `lifespan: 0.7` is
|
|
64
|
+
not capacity and not the transport.
|
|
65
|
+
2. **CycloneDDS's A/B is a null result, and that is the finding.** 472/472,
|
|
66
|
+
1146/1143 ms — turning the policy off changes nothing measurable, because the
|
|
67
|
+
policy was doing nothing. Only 9.1% of what it delivers is inside the bound it
|
|
68
|
+
was published with.
|
|
69
|
+
3. **Fast DDS's A/B is the opposite.** 4 against 433, and the max age under the
|
|
70
|
+
policy is 570 ms — below 700 ms, not approximately below it. The samples that
|
|
71
|
+
vanish are the ones the shaper delayed past their lifespan.
|
|
72
|
+
|
|
73
|
+
The same pair of runs also shows the delay is a queueing discipline rather than a
|
|
74
|
+
property of the path: replacing `tbf` with `htb` + `fq_codel` at the same
|
|
75
|
+
800 kbit/s takes CycloneDDS from 472 delivered at 1146 ms to 8 delivered at
|
|
76
|
+
**124 ms**, with 100% inside the lifespan. An AQM converts staleness into loss;
|
|
77
|
+
it does not create capacity.
|
|
78
|
+
|
|
79
|
+
Verification: manual: two containers on a private bridge, `tbf` as above on the
|
|
80
|
+
publisher's egress, one 12 kB/10 Hz best_effort depth-1 stream, run once with
|
|
81
|
+
`lifespan: 0.7` and once with it effectively off, for each RMW. The Cyclone pair
|
|
82
|
+
must be indistinguishable and the Fast DDS pair must differ by two orders of
|
|
83
|
+
magnitude in delivered count, with the `lifespan: 0.7` arm's maximum age below
|
|
84
|
+
the lifespan.
|
|
85
|
+
|
|
86
|
+
## Status
|
|
87
|
+
|
|
88
|
+
confirmed, 2026-08-19.
|
|
89
|
+
|
|
90
|
+
## Publication notes
|
|
91
|
+
|
|
92
|
+
This corrects, from the reader side, the conclusion drawn in the operator
|
|
93
|
+
harness's middleware comparison that lifespan is "indistinguishable for both DDS
|
|
94
|
+
stacks" — that A/B's Fast DDS arm ran against a zero-byte profile. It is the
|
|
95
|
+
enforcement half of
|
|
96
|
+
[oversubscription-queues-not-losses.md](oversubscription-queues-not-losses.md):
|
|
97
|
+
that finding shows the excess becomes delay rather than loss, this one shows what
|
|
98
|
+
each reader then does with the delayed sample.
|
|
99
|
+
|
|
100
|
+
For papers, the useful framing is that "loss" and "delivered" are not
|
|
101
|
+
middleware-comparable numbers unless the lifespan enforcement is stated with
|
|
102
|
+
them. A table that puts Fast DDS's 4 next to CycloneDDS's 472 without that column
|
|
103
|
+
reads as a transport difference and is not one.
|
|
104
|
+
|
|
105
|
+
Practical consequence: neither behaviour is usable at 20% oversubscription, so
|
|
106
|
+
this is a choice about how to fail, not a fix. The fix is below DDS (offer fewer
|
|
107
|
+
bytes than the link carries) or above it (receiver-side age gating that can skip
|
|
108
|
+
rather than render).
|
|
@@ -2912,6 +2912,66 @@ def _ota_load_check(plan: OtaSmokePlan, *, dry_run: bool) -> None:
|
|
|
2912
2912
|
print(f"+ {peer.name}: {summary}")
|
|
2913
2913
|
|
|
2914
2914
|
|
|
2915
|
+
_REACH_ATTEMPTS = 3
|
|
2916
|
+
_REACH_BACKOFF_SECONDS = 2.0
|
|
2917
|
+
_REACH_TIMEOUT_SECONDS = 20.0
|
|
2918
|
+
|
|
2919
|
+
|
|
2920
|
+
def _ota_reach_check(peer: OtaSmokePeer, *, dry_run: bool) -> None:
|
|
2921
|
+
"""Open the control channel to a peer, retrying a transport that flaked.
|
|
2922
|
+
|
|
2923
|
+
This is the only preflight step that retries, and the reason is the probe
|
|
2924
|
+
itself: the remote command is ``true``. It cannot fail. Every non-zero exit
|
|
2925
|
+
and every timeout here is therefore the transport — an ssh handshake that
|
|
2926
|
+
timed out because the peer was loaded, a link that had not come up yet —
|
|
2927
|
+
and never a condition on the machine that a second look would paper over.
|
|
2928
|
+
|
|
2929
|
+
The checks after this one deliberately do not retry. A container that is
|
|
2930
|
+
already running is still running a moment later, and a peer somebody else is
|
|
2931
|
+
saturating is still saturated; retrying those would convert a real refusal
|
|
2932
|
+
into a delayed one. Retrying is right where the answer is stateless and the
|
|
2933
|
+
failure is transient, and that is here alone.
|
|
2934
|
+
|
|
2935
|
+
Each attempt is printed. A run that needed three tries to reach a peer was
|
|
2936
|
+
taken under conditions worth knowing about, so the artefact says so rather
|
|
2937
|
+
than reporting a clean first-try connection.
|
|
2938
|
+
"""
|
|
2939
|
+
if dry_run:
|
|
2940
|
+
_ota_run(peer, "true", label=f"{peer.name}: reachable", dry_run=True, batch=True)
|
|
2941
|
+
return
|
|
2942
|
+
|
|
2943
|
+
last_detail = ""
|
|
2944
|
+
for attempt in range(1, _REACH_ATTEMPTS + 1):
|
|
2945
|
+
suffix = "" if attempt == 1 else f" (attempt {attempt} of {_REACH_ATTEMPTS})"
|
|
2946
|
+
try:
|
|
2947
|
+
result = _ota_run(
|
|
2948
|
+
peer,
|
|
2949
|
+
"true",
|
|
2950
|
+
label=f"{peer.name}: reachable{suffix}",
|
|
2951
|
+
batch=True,
|
|
2952
|
+
check=False,
|
|
2953
|
+
timeout=_REACH_TIMEOUT_SECONDS,
|
|
2954
|
+
)
|
|
2955
|
+
except subprocess.TimeoutExpired:
|
|
2956
|
+
last_detail = f"no answer within {_REACH_TIMEOUT_SECONDS:.0f}s"
|
|
2957
|
+
else:
|
|
2958
|
+
if result.returncode == 0:
|
|
2959
|
+
if attempt > 1:
|
|
2960
|
+
print(
|
|
2961
|
+
f"! {peer.name}: reachable on attempt {attempt} of {_REACH_ATTEMPTS} — the transport was flaky"
|
|
2962
|
+
)
|
|
2963
|
+
return
|
|
2964
|
+
last_detail = ((result.stdout or "") + (result.stderr or "")).strip() or f"exit code {result.returncode}"
|
|
2965
|
+
if attempt < _REACH_ATTEMPTS:
|
|
2966
|
+
print(f"! {peer.name}: not reachable ({last_detail}); retrying")
|
|
2967
|
+
time.sleep(_REACH_BACKOFF_SECONDS * attempt)
|
|
2968
|
+
|
|
2969
|
+
raise RuntimeError(
|
|
2970
|
+
f"{peer.name}: not reachable via {_ota_peer_target(peer)} after "
|
|
2971
|
+
f"{_REACH_ATTEMPTS} attempts.\nLast failure: {last_detail}"
|
|
2972
|
+
)
|
|
2973
|
+
|
|
2974
|
+
|
|
2915
2975
|
def _ota_preflight(
|
|
2916
2976
|
plan: OtaSmokePlan,
|
|
2917
2977
|
*,
|
|
@@ -2928,7 +2988,7 @@ def _ota_preflight(
|
|
|
2928
2988
|
sudo_passwords = sudo_passwords or {}
|
|
2929
2989
|
for peer in plan.peers.values():
|
|
2930
2990
|
if _ota_peer_is_remote(peer):
|
|
2931
|
-
|
|
2991
|
+
_ota_reach_check(peer, dry_run=dry_run)
|
|
2932
2992
|
required = ["python3", "docker", "tar"]
|
|
2933
2993
|
if require_tmux:
|
|
2934
2994
|
required.append("tmux")
|
|
@@ -26,44 +26,6 @@
|
|
|
26
26
|
-->
|
|
27
27
|
<dds xmlns="http://www.eprosima.com/XMLSchemas/fastRTPS_Profiles">
|
|
28
28
|
<profiles>
|
|
29
|
-
<transport_descriptors>
|
|
30
|
-
<transport_descriptor>
|
|
31
|
-
<transport_id>rosotacom_ota_udp</transport_id>
|
|
32
|
-
<type>UDPv4</type>
|
|
33
|
-
|
|
34
|
-
<sendBufferSize>1048576</sendBufferSize>
|
|
35
|
-
<receiveBufferSize>4194304</receiveBufferSize>
|
|
36
|
-
|
|
37
|
-
<!-- Drop rather than block when the socket buffer is full: on a shaped
|
|
38
|
-
uplink the blocking default turns a link-layer backlog into
|
|
39
|
-
application-level latency. -->
|
|
40
|
-
<non_blocking_send>true</non_blocking_send>
|
|
41
|
-
|
|
42
|
-
<!-- An initial peer given without a port makes Fast DDS probe
|
|
43
|
-
participant indices 0..range on that address. The default is 4, and
|
|
44
|
-
an OTA domain carrying a domain bridge plus the IN and OUT splits
|
|
45
|
-
can hand out a higher index, so whichever process starts late is
|
|
46
|
-
never found. CycloneDDS probes 10; this matches it. -->
|
|
47
|
-
<maxInitialPeersRange>10</maxInitialPeersRange>
|
|
48
|
-
|
|
49
|
-
<!-- Two addresses, both load-bearing. #host_ip is the OTA address, and
|
|
50
|
-
pinning it is what keeps a multi-homed VPN host from announcing a
|
|
51
|
-
locator the peer cannot route to. 127.0.0.1 is the same-host half:
|
|
52
|
-
with a split OTA domain the stock `domain_bridge` process sits on
|
|
53
|
-
that domain too and speaks whatever RMW the local side uses, so
|
|
54
|
-
this participant has to be able to discover a peer on its own
|
|
55
|
-
machine. An allowlist of the OTA address alone takes the loopback
|
|
56
|
-
path away and the bridge and the OTA processes never see each
|
|
57
|
-
other — a failure that reads as a dead link and is not one. -->
|
|
58
|
-
<interfaces>
|
|
59
|
-
<allowlist>
|
|
60
|
-
<interface name="127.0.0.1" netmask_filter="OFF"/>
|
|
61
|
-
<interface name="#host_ip" netmask_filter="OFF"/>
|
|
62
|
-
</allowlist>
|
|
63
|
-
</interfaces>
|
|
64
|
-
</transport_descriptor>
|
|
65
|
-
</transport_descriptors>
|
|
66
|
-
|
|
67
29
|
<participant profile_name="rosotacom_fastdds_tuned" is_default_profile="true">
|
|
68
30
|
<rtps>
|
|
69
31
|
<defaultUnicastLocatorList>
|
|
@@ -128,10 +90,46 @@
|
|
|
128
90
|
</initialPeersList>
|
|
129
91
|
</builtin>
|
|
130
92
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
93
|
+
<!-- No transport element here, deliberately, and this is load-bearing.
|
|
94
|
+
|
|
95
|
+
Measured on a two-container bench (2026-08-19, ROS 2 Kilted, Fast
|
|
96
|
+
DDS 3.2.4, rmw_fastrtps_cpp 9.3.4): a participant profile that
|
|
97
|
+
carries *any* transport element transmits every sample twice.
|
|
98
|
+
|
|
99
|
+
<userTransports> + <useBuiltinTransports>false 1741 kbit/s
|
|
100
|
+
<builtinTransports non_blocking="true">UDPv4 1741 kbit/s
|
|
101
|
+
<builtinTransports>UDPv4 1741 kbit/s
|
|
102
|
+
<builtinTransports>DEFAULT 1741 kbit/s
|
|
103
|
+
no transport element at all 1007 kbit/s
|
|
104
|
+
|
|
105
|
+
against a 960 kbit/s payload. The DEFAULT row is what settles it:
|
|
106
|
+
that selection is a no-op — it asks for exactly the built-in set —
|
|
107
|
+
and it still doubles. Counted per datagram, 366 to the reader's data
|
|
108
|
+
locator for 180 published samples against 183 without the element,
|
|
109
|
+
each carrying a full 11 951 B of UDP payload to the same address and
|
|
110
|
+
port. The reader discards the second copy by sequence number, so it
|
|
111
|
+
buys nothing and costs half the link.
|
|
112
|
+
|
|
113
|
+
What removing it gives up, named rather than hidden:
|
|
114
|
+
* shared memory is enabled again. It is unused between machines,
|
|
115
|
+
and between processes on one host it is faster than the loopback
|
|
116
|
+
path this profile also names. fastdds_local.xml records that SHM
|
|
117
|
+
was measured and is not the cause of the local-domain failure.
|
|
118
|
+
* <non_blocking_send>true</non_blocking_send> is gone with the
|
|
119
|
+
descriptor, so a full send buffer blocks instead of dropping.
|
|
120
|
+
That is the smaller cost: a blocking send stalls the writer for
|
|
121
|
+
as long as the link is behind, where the duplicate costs half the
|
|
122
|
+
link all the time.
|
|
123
|
+
* maxInitialPeersRange falls back to 4 from 10, and the interface
|
|
124
|
+
allowlist is gone. The locator lists above already pin what this
|
|
125
|
+
participant announces, which is what the allowlist was for. -->
|
|
126
|
+
|
|
127
|
+
<!-- What the removed descriptor's sendBufferSize/receiveBufferSize were.
|
|
128
|
+
These are participant-level and asymmetric on purpose: the receive
|
|
129
|
+
side absorbs a burst that arrives after a stall, the send side
|
|
130
|
+
should not hold one. -->
|
|
131
|
+
<sendSocketBufferSize>1048576</sendSocketBufferSize>
|
|
132
|
+
<listenSocketBufferSize>4194304</listenSocketBufferSize>
|
|
135
133
|
</rtps>
|
|
136
134
|
</participant>
|
|
137
135
|
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<dds xmlns="http://www.eprosima.com/XMLSchemas/fastRTPS_Profiles">
|
|
3
|
+
<profiles>
|
|
4
|
+
<participant profile_name="rosotacom_fastdds_unicast" is_default_profile="true">
|
|
5
|
+
<rtps>
|
|
6
|
+
<defaultUnicastLocatorList>
|
|
7
|
+
<locator>
|
|
8
|
+
<udpv4>
|
|
9
|
+
<address>#host_ip</address>
|
|
10
|
+
<port>0</port>
|
|
11
|
+
</udpv4>
|
|
12
|
+
</locator>
|
|
13
|
+
</defaultUnicastLocatorList>
|
|
14
|
+
|
|
15
|
+
<builtin>
|
|
16
|
+
<metatrafficUnicastLocatorList>
|
|
17
|
+
<locator>
|
|
18
|
+
<udpv4>
|
|
19
|
+
<address>#host_ip</address>
|
|
20
|
+
<port>0</port>
|
|
21
|
+
</udpv4>
|
|
22
|
+
</locator>
|
|
23
|
+
</metatrafficUnicastLocatorList>
|
|
24
|
+
|
|
25
|
+
<initialPeersList>
|
|
26
|
+
<locator>
|
|
27
|
+
<udpv4>
|
|
28
|
+
<address>#host_ip</address>
|
|
29
|
+
<port>0</port>
|
|
30
|
+
</udpv4>
|
|
31
|
+
</locator>
|
|
32
|
+
<!--peer-block--><locator>
|
|
33
|
+
<udpv4>
|
|
34
|
+
<address>#peer</address>
|
|
35
|
+
<port>0</port>
|
|
36
|
+
</udpv4>
|
|
37
|
+
</locator><!--/peer-block-->
|
|
38
|
+
</initialPeersList>
|
|
39
|
+
</builtin>
|
|
40
|
+
|
|
41
|
+
<!-- No transport element here, deliberately, and this is load-bearing.
|
|
42
|
+
|
|
43
|
+
Measured on a two-container bench (2026-08-19, ROS 2 Kilted, Fast
|
|
44
|
+
DDS 3.2.4, rmw_fastrtps_cpp 9.3.4): a participant profile that
|
|
45
|
+
carries *any* transport element transmits every sample twice.
|
|
46
|
+
|
|
47
|
+
<userTransports> + <useBuiltinTransports>false 1741 kbit/s
|
|
48
|
+
<builtinTransports non_blocking="true">UDPv4 1741 kbit/s
|
|
49
|
+
<builtinTransports>UDPv4 1741 kbit/s
|
|
50
|
+
<builtinTransports>DEFAULT 1741 kbit/s
|
|
51
|
+
no transport element at all 1007 kbit/s
|
|
52
|
+
|
|
53
|
+
against a 960 kbit/s payload. The DEFAULT row is what settles it:
|
|
54
|
+
that selection is a no-op — it asks for exactly the built-in set —
|
|
55
|
+
and it still doubles. Counted per datagram, 366 to the reader's data
|
|
56
|
+
locator for 180 published samples against 183 without the element,
|
|
57
|
+
each carrying a full 11 951 B of UDP payload to the same address and
|
|
58
|
+
port. The reader discards the second copy by sequence number, so it
|
|
59
|
+
buys nothing and costs half the link.
|
|
60
|
+
|
|
61
|
+
What removing it gives up, named rather than hidden:
|
|
62
|
+
* shared memory is enabled again. It is unused between machines,
|
|
63
|
+
and between processes on one host it is faster than the loopback
|
|
64
|
+
path this profile also names. fastdds_local.xml records that SHM
|
|
65
|
+
was measured and is not the cause of the local-domain failure.
|
|
66
|
+
* <non_blocking_send>true</non_blocking_send> is gone with the
|
|
67
|
+
descriptor, so a full send buffer blocks instead of dropping.
|
|
68
|
+
That is the smaller cost: a blocking send stalls the writer for
|
|
69
|
+
as long as the link is behind, where the duplicate costs half the
|
|
70
|
+
link all the time.
|
|
71
|
+
* maxInitialPeersRange falls back to 4 from 10, and the interface
|
|
72
|
+
allowlist is gone. The locator lists above already pin what this
|
|
73
|
+
participant announces, which is what the allowlist was for. -->
|
|
74
|
+
</rtps>
|
|
75
|
+
</participant>
|
|
76
|
+
|
|
77
|
+
<data_writer profile_name="rosotacom_fastdds_writer" is_default_profile="true">
|
|
78
|
+
<qos>
|
|
79
|
+
<data_sharing>
|
|
80
|
+
<kind>OFF</kind>
|
|
81
|
+
</data_sharing>
|
|
82
|
+
</qos>
|
|
83
|
+
</data_writer>
|
|
84
|
+
|
|
85
|
+
<data_reader profile_name="rosotacom_fastdds_reader" is_default_profile="true">
|
|
86
|
+
<qos>
|
|
87
|
+
<data_sharing>
|
|
88
|
+
<kind>OFF</kind>
|
|
89
|
+
</data_sharing>
|
|
90
|
+
</qos>
|
|
91
|
+
</data_reader>
|
|
92
|
+
</profiles>
|
|
93
|
+
</dds>
|
|
@@ -32,7 +32,10 @@ class PacerConfig:
|
|
|
32
32
|
adaptive: bool = True
|
|
33
33
|
percentile: float = 0.95 # of (arrival - stamp), window-local
|
|
34
34
|
margin_ms: float = 40.0 # headroom above the tracked percentile
|
|
35
|
-
|
|
35
|
+
#: Samples (~40 s at 10 Hz). Bounds both the tracked percentile and the
|
|
36
|
+
#: delay floor, so how fast the schedule re-anchors after the path changes
|
|
37
|
+
#: is this number: a longer window is steadier and slower to recover.
|
|
38
|
+
window: int = 400
|
|
36
39
|
|
|
37
40
|
def __post_init__(self) -> None:
|
|
38
41
|
if not 0.0 < self.percentile < 1.0:
|
|
@@ -72,8 +75,18 @@ class PlayoutSchedule:
|
|
|
72
75
|
"""
|
|
73
76
|
d = arrival_s - stamp_s
|
|
74
77
|
self._d.append(d)
|
|
75
|
-
|
|
76
|
-
|
|
78
|
+
# The minimum over the *window*, not over all time. An all-time floor
|
|
79
|
+
# can only fall, so any upward shift in `arrival - stamp` -- a clock
|
|
80
|
+
# step, an NTP correction, a route change, a looping replay -- leaves
|
|
81
|
+
# every later message past `stamp + floor + budget`, and the pacer
|
|
82
|
+
# degrades to a pass-through it can never come back from. Found on the
|
|
83
|
+
# fleet e2e, where a bag loop moved the delay by the bag's length and
|
|
84
|
+
# the centre's camera ran unpaced for the rest of the run with every
|
|
85
|
+
# panel healthy. Windowed, the same shift re-anchors within one window.
|
|
86
|
+
#
|
|
87
|
+
# O(window) per message: 400 floats at 10 Hz. A monotonic deque would
|
|
88
|
+
# make it O(1) and is not worth the machinery at these rates.
|
|
89
|
+
self._d_floor = min(self._d)
|
|
77
90
|
release = stamp_s + self._d_floor + self.budget_ms / 1000.0
|
|
78
91
|
if release < arrival_s: # already late: pass through immediately
|
|
79
92
|
release = arrival_s
|
|
@@ -61,6 +61,7 @@ docs/release.md
|
|
|
61
61
|
docs/testing.md
|
|
62
62
|
docs/work-items.md
|
|
63
63
|
docs/findings/README.md
|
|
64
|
+
docs/findings/a-transport-element-doubles-every-fastdds-sample.md
|
|
64
65
|
docs/findings/cyclone-spdp-discovery-bursts.md
|
|
65
66
|
docs/findings/delay-alone-no-loss.md
|
|
66
67
|
docs/findings/fastdds-datagram-cap-drops-large-samples.md
|
|
@@ -68,6 +69,7 @@ docs/findings/graph-derived-types-block-a-non-graph-transport.md
|
|
|
68
69
|
docs/findings/head-of-line-irregularity.md
|
|
69
70
|
docs/findings/jitter-loss-bandwidth-latency.md
|
|
70
71
|
docs/findings/keyframe-loss-kills-the-next-deltas.md
|
|
72
|
+
docs/findings/lifespan-is-enforced-by-one-reader-and-not-the-other.md
|
|
71
73
|
docs/findings/lighter-message-loss.md
|
|
72
74
|
docs/findings/oversubscription-queues-not-losses.md
|
|
73
75
|
docs/findings/reorder-becomes-reader-loss.md
|
{rosotacom_dev-2.5.dev57 → rosotacom_dev-2.5.dev60}/src/rosotacom_dev.egg-info/scm_file_list.json
RENAMED
|
@@ -46,6 +46,7 @@
|
|
|
46
46
|
"docs/ci.md",
|
|
47
47
|
"docs/ffmpeg-keyframes.md",
|
|
48
48
|
"docs/findings/README.md",
|
|
49
|
+
"docs/findings/a-transport-element-doubles-every-fastdds-sample.md",
|
|
49
50
|
"docs/findings/cyclone-spdp-discovery-bursts.md",
|
|
50
51
|
"docs/findings/delay-alone-no-loss.md",
|
|
51
52
|
"docs/findings/fastdds-datagram-cap-drops-large-samples.md",
|
|
@@ -53,6 +54,7 @@
|
|
|
53
54
|
"docs/findings/head-of-line-irregularity.md",
|
|
54
55
|
"docs/findings/jitter-loss-bandwidth-latency.md",
|
|
55
56
|
"docs/findings/keyframe-loss-kills-the-next-deltas.md",
|
|
57
|
+
"docs/findings/lifespan-is-enforced-by-one-reader-and-not-the-other.md",
|
|
56
58
|
"docs/findings/lighter-message-loss.md",
|
|
57
59
|
"docs/findings/oversubscription-queues-not-losses.md",
|
|
58
60
|
"docs/findings/reorder-becomes-reader-loss.md",
|