rosotacom-dev 2.5.dev41__tar.gz → 2.5.dev47__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.dev41 → rosotacom_dev-2.5.dev47}/PKG-INFO +1 -1
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/docs/ffmpeg-keyframes.md +24 -5
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/docs/findings/README.md +1 -0
- rosotacom_dev-2.5.dev47/docs/findings/reorder-becomes-reader-loss.md +69 -0
- rosotacom_dev-2.5.dev47/docs/findings/repro/reorder_drop_repro.py +170 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/docs/forensics-report.md +16 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/docs/rfcs/0004-network-profiles.md +44 -7
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/session-configuration.md +21 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/cli_benchmark.py +24 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/forensics.py +143 -24
- rosotacom_dev-2.5.dev47/src/rosotacom/netem_dist.py +104 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/network_profiles.py +162 -17
- rosotacom_dev-2.5.dev47/src/rosotacom/resources/examples/dist/field-20260817.dist +513 -0
- rosotacom_dev-2.5.dev47/src/rosotacom/resources/examples/profiles.yaml +171 -0
- rosotacom_dev-2.5.dev47/src/rosotacom/resources/ws/ros2src/com_py/com_py/ffmpeg_flags.py +58 -0
- rosotacom_dev-2.5.dev47/src/rosotacom/resources/ws/ros2src/com_py/com_py/playout_pacer.py +100 -0
- rosotacom_dev-2.5.dev47/src/rosotacom/resources/ws/ros2src/com_py/com_py/playout_pacer_core.py +83 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/ros2src/com_py/com_py/status_overview.py +8 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/ros2src/com_py/com_py/status_overview_core.py +35 -30
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/ros2src/com_py/setup.py +1 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/stream_stats.py +8 -1
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom_dev.egg-info/PKG-INFO +1 -1
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom_dev.egg-info/SOURCES.txt +11 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom_dev.egg-info/scm_file_list.json +11 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom_dev.egg-info/scm_version.json +2 -2
- rosotacom_dev-2.5.dev47/tests/unit/test_ffmpeg_flags.py +130 -0
- rosotacom_dev-2.5.dev47/tests/unit/test_field_profiles.py +51 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/tests/unit/test_forensics.py +153 -0
- rosotacom_dev-2.5.dev47/tests/unit/test_netem_dist.py +62 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/tests/unit/test_network_profiles.py +87 -0
- rosotacom_dev-2.5.dev47/tests/unit/test_playout_pacer.py +81 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/tests/unit/test_status_overview.py +27 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/tests/unit/test_status_overview_observer.py +106 -5
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/tests/unit/test_stream_stats.py +12 -0
- rosotacom_dev-2.5.dev41/src/rosotacom/resources/examples/profiles.yaml +0 -85
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/.devcontainer/devcontainer.json.template +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/.devcontainer/re_generate_devcontainer_json.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/.github/CODEOWNERS +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/.github/ISSUE_TEMPLATE/documentation-audit.md +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/.github/ISSUE_TEMPLATE/implementation-cleanup.md +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/.github/ISSUE_TEMPLATE/quality-workflow.md +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/.github/ISSUE_TEMPLATE/redesign.md +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/.github/ISSUE_TEMPLATE/release-process.md +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/.github/ISSUE_TEMPLATE/repository-diagnosis.md +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/.github/ISSUE_TEMPLATE/test-ci-audit.md +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/.github/ISSUE_TEMPLATE/work-item.md +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/.github/actions/setup-just/action.yml +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/.github/dependabot.yml +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/.github/workflows/benchmark-calibrate.yml +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/.github/workflows/benchmark-gate.yml +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/.github/workflows/dev-release.yml +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/.github/workflows/image-scan.yml +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/.github/workflows/nightly-e2e.yml +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/.github/workflows/pr-lightweight.yml +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/.github/workflows/pr-merge-gate.yml +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/.github/workflows/release.yml +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/.pre-commit-config.yaml +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/AGENTS.md +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/CONCURRENCY.md +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/CONTRIBUTING.md +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/DEVELOPMENT_PRINCIPLES.md +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/LICENSE.txt +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/MANIFEST.in +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/README.md +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/budgets.jsonl +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/calibration/README.md +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/calibration/capacity-size-tight-cyclone.json +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/calibration/probe-loss-gop-tight-cyclone.json +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/calibration/probe-loss-nominal-cyclone.json +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/calibration/probe-loss-tight-cyclone.json +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/calibration/probe-loss-tight-fastdds.json +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/calibration/probe-loss-tight-zenoh.json +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/codecov.yml +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/deployment-configuration.md +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/docs/benchmark-ab.md +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/docs/benchmark-bag-as-load.md +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/docs/ci.md +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/docs/findings/cyclone-spdp-discovery-bursts.md +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/docs/findings/delay-alone-no-loss.md +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/docs/findings/head-of-line-irregularity.md +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/docs/findings/jitter-loss-bandwidth-latency.md +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/docs/findings/lighter-message-loss.md +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/docs/findings/zero-loss-boundaries-18kb-20hz.md +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/docs/geo-link-map.md +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/docs/github-repository-settings.md +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/docs/link-bandwidth.md +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/docs/link-trace.md +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/docs/owner-runbook.md +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/docs/performance-bands.md +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/docs/playbooks/README.md +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/docs/quality-model.md +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/docs/release-notes/TEMPLATE.md +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/docs/release-notes/v2.1.md +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/docs/release-notes/v2.2.md +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/docs/release-notes/v2.3.md +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/docs/release-notes/v2.4.md +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/docs/release.md +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/docs/rfcs/0001-expectation-driven-test-suite.md +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/docs/rfcs/0002-expectation-concepts.md +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/docs/rfcs/0003-metric-backbone.md +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/docs/rfcs/0005-benchmark-genres-and-ci.md +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/docs/rfcs/0006-dynamic-qos.md +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/docs/rfcs/0007-regression-gate.md +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/docs/rfcs/README.md +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/docs/testing.md +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/docs/work-items.md +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/install.sh +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/justfile +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/media/control_center.png +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/media/echo_test.png +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/media/forensics-report-example.png +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/media/host.png +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/media/vehicle.png +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/pyproject.toml +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/requirements.txt +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/rosotacom.yaml +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/setup.cfg +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/__init__.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/__main__.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/anonymize.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/bag_ground_truth.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/benched_set.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/benchmark.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/benchmark_delta.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/bundle_check.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/cli.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/deployment.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/ffmpeg_packet.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/geomap.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/image_cache.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/network_shaper.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/plots.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/py.typed +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/benched-set.yaml +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/examples/.gitignore +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/examples/README.md +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/examples/__init__.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/examples/bags/8_drop_reference/metadata.yaml +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/examples/deployment.example.yaml +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/examples/ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/examples/rosotacom.yaml +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/examples/scenarios/2_native_chatter/scenario-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/examples/scripts/1_heartbeat/run_machine_a.sh +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/examples/scripts/1_heartbeat/run_machine_b.sh +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_a/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_a/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_a/run_external.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_a/wait_for_echo_topic.sh +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_b/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_b/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_b/run_external.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_a/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_a/external_session.yaml +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_a/foxglove.json +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_a/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_a/run_external.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_b/costmap_1second/costmap_1second_0.mcap +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_b/costmap_1second/metadata.yaml +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_b/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_b/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_b/run_external.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_a/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_a/external_session.yaml +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_a/foxglove.json +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_a/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_a/run_external.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_b/costmap_1second/costmap_1second_0.mcap +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_b/costmap_1second/metadata.yaml +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_b/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_b/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_b/run_external.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_a/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_a/external_session.yaml +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_a/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_a/run_external.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_b/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_b/external_session.yaml +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_b/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_b/run_external.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_a/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_a/external_session.yaml +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_a/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_a/run_external.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_b/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_b/external_session.yaml +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_b/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_b/run_external.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/examples/sessions/10_restamp/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/examples/sessions/11_trickle/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/examples/sessions/12_content_integrity/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/examples/sessions/13_link_latency/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/examples/sessions/14_remote_assist_anonymized/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/examples/sessions/15_remote_assist_anonymized_costmap/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/examples/sessions/16_remote_assist_anonymized_camera/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/examples/sessions/17_synthetic_camera_quality/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/examples/sessions/1_heartbeat/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/examples/sessions/1_heartbeat_status/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/examples/sessions/2_native_chatter/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/examples/sessions/3_comp_occ_grid/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/examples/sessions/4_comp_occ_grid_zen/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/examples/sessions/5_sized_payload/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/examples/sessions/6_sized_payload_zen/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/examples/sessions/7_latched_static/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/examples/sessions/8_drop/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/examples/sessions/9_throttle/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/examples/sessions/bench_1_1_capacity/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/examples/sessions/bench_1_2_load_sweep/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/examples/sessions/bench_1_3_ramp/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/examples/sessions/bench_1_4_recovery/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/examples/sessions/bench_1_5_camera/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ros2docker.json.example +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/.vscode/c_cpp_properties.json +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/.vscode/settings.json +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_easy_mode.xml.template +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_initial_peer_list.xml.template +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_v2.xml.template +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_v3.xml.template +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_v4.xml.template +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_v5.xml.template +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/ota_configs/create_zenoh_json5.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/ota_configs/cyclonedds_local_participants.xml.template +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/ota_configs/cyclonedds_minimal.xml.template +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/ota_configs/cyclonedds_tuned.xml.template +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/ota_configs/fastdds_unicast.xml.template +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/ota_configs/get_ota_xml.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/ota_configs/utils.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/ota_configs/zenoh.json5.template +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/ros2src/.gitkeep +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/ros2src/com_cpp/CMakeLists.txt +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/ros2src/com_cpp/COLCON_IGNORE +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/ros2src/com_cpp/LICENSE.txt +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/ros2src/com_cpp/package.xml +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/ros2src/com_cpp/src/hz_monitor.cpp +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/ros2src/com_cpp/src/universal_compressor.cpp +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/ros2src/com_cpp/src/universal_decompressor.cpp +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/ros2src/com_msgs/CMakeLists.txt +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/ros2src/com_msgs/LICENSE.txt +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/ros2src/com_msgs/msg/CompressedData.msg +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/ros2src/com_msgs/msg/EchoHeartbeat.msg +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/ros2src/com_msgs/msg/OtaStamped.msg +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/ros2src/com_msgs/msg/SizedPayload.msg +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/ros2src/com_msgs/package.xml +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/ros2src/com_py/LICENSE.txt +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/ros2src/com_py/com_py/__init__.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/ros2src/com_py/com_py/base_bridge_relay.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/ros2src/com_py/com_py/bridge_in.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/ros2src/com_py/com_py/bridge_out.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/ros2src/com_py/com_py/heartbeat_echo.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/ros2src/com_py/com_py/hz_monitor.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/ros2src/com_py/com_py/image_bandwidth_reducer.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/ros2src/com_py/com_py/image_pixel_capper.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/ros2src/com_py/com_py/lanelet_saver.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/ros2src/com_py/com_py/latch_relay.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/costmap_remapper.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/marker_remapper.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/speed_test.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/tf_remapper.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/traffic_monitor.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/wifi_network_analysis_1.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/ros2src/com_py/com_py/link_bytes.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/ros2src/com_py/com_py/link_trace.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/ros2src/com_py/com_py/local_global_frame_bridge.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/ros2src/com_py/com_py/localization_map_split_reduce_saver.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/ros2src/com_py/com_py/msg_transform.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/ros2src/com_py/com_py/pair_management.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/ros2src/com_py/com_py/pub_sub_pair.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/ros2src/com_py/com_py/qos.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/ros2src/com_py/com_py/relay_in.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/ros2src/com_py/com_py/relay_out.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/ros2src/com_py/com_py/restamp.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/ros2src/com_py/com_py/sized_publisher.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/ros2src/com_py/com_py/stage_latency.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/ros2src/com_py/com_py/stage_latency_core.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/ros2src/com_py/com_py/tf_map_to_cart_saver.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/ros2src/com_py/com_py/topic_monitor.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/ros2src/com_py/com_py/topic_resolution.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/ros2src/com_py/com_py/trickle.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/ros2src/com_py/com_py/universal_compressor.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/ros2src/com_py/com_py/universal_decompressor.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/ros2src/com_py/com_py/universal_ota_unwrapper.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/ros2src/com_py/com_py/universal_ota_wrapper.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/ros2src/com_py/package.xml +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/ros2src/com_py/resource/com_py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/ros2src/com_py/setup.cfg +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/ros2src/com_py/test/test_copyright.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/ros2src/com_py/test/test_flake8.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/ros2src/com_py/test/test_pep257.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/session/content/base/session_plugin_base.yaml +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/session/content/network/up_connectivity.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/session/content/network/wifi_network_analysis_2.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/session/creation/anonymize_bag.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/session/creation/catmux_log_setup.sh +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/session/creation/create_session_yaml.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/session/creation/generate_session_files.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/session/creation/run_session.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/session/creation/run_session_in_external_terminal.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/resources/ws/session/creation/strip_ansi.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/status_eval.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/trace_profiles.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/transit.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom/video_quality.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom_dev.egg-info/dependency_links.txt +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom_dev.egg-info/entry_points.txt +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom_dev.egg-info/requires.txt +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/src/rosotacom_dev.egg-info/top_level.txt +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/terminology.md +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/tests/contract/test_benched_set_registry.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/tests/contract/test_findings.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/tests/contract/test_markdown_links.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/tests/contract/test_ota_source_bundle.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/tests/contract/test_package_metadata.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/tests/contract/test_packaged_resources.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/tests/contract/test_profile_covers_generated_commands.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/tests/contract/test_pytest_policy.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/tests/contract/test_readme_examples.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/tests/contract/test_security_maintenance_config.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/tests/contract/test_session_configuration_doc.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/tests/contract/test_session_template_substitution.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/tests/contract/test_workflow_contracts.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/tests/e2e/conftest.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/tests/e2e/test_anonymize_e2e.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/tests/e2e/test_benchmark_ab.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/tests/e2e/test_benchmark_capacity.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/tests/e2e/test_benchmark_replay.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/tests/e2e/test_parallel_smoke.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/tests/e2e/test_smoke.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/tests/e2e/test_timeline_stepping.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/tests/e2e/test_video_quality_e2e.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/tests/sessions/generate_rmw_matrix.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/tests/sessions/rmw_matrix/1_heartbeat_cyclone-local_zenoh-ros2dds-ota/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/tests/sessions/rmw_matrix/1_heartbeat_cyclone-ota/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/tests/sessions/rmw_matrix/1_heartbeat_cyclone-ota-tuned/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/tests/sessions/rmw_matrix/1_heartbeat_fastdds/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/tests/sessions/rmw_matrix/1_heartbeat_zen-endpoints/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/tests/unit/test_anonymize.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/tests/unit/test_bag_ground_truth.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/tests/unit/test_benched_set.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/tests/unit/test_benchmark.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/tests/unit/test_benchmark_delta.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/tests/unit/test_bundle_check.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/tests/unit/test_catmux_pane_logging.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/tests/unit/test_cli.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/tests/unit/test_cli_benchmark.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/tests/unit/test_concurrency.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/tests/unit/test_deployment.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/tests/unit/test_ffmpeg_packet.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/tests/unit/test_geomap.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/tests/unit/test_image_cache.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/tests/unit/test_link_bytes.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/tests/unit/test_link_trace.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/tests/unit/test_network_shaper.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/tests/unit/test_ota_unwrapper.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/tests/unit/test_ota_wrapper.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/tests/unit/test_ota_xml.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/tests/unit/test_plots.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/tests/unit/test_qos_fallback_logging.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/tests/unit/test_relay_optional_parameters.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/tests/unit/test_session_pipeline.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/tests/unit/test_stage_latency.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/tests/unit/test_status_eval.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/tests/unit/test_trace_profiles.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/tests/unit/test_transit.py +0 -0
- {rosotacom_dev-2.5.dev41 → rosotacom_dev-2.5.dev47}/tests/unit/test_video_quality.py +0 -0
|
@@ -45,6 +45,18 @@ Grouping a stream into GOPs is then just splitting at keyframes. Note the
|
|
|
45
45
|
encoder may emit keyframes *early* (scene cuts), so GOPs can be shorter than
|
|
46
46
|
`gop_size` — assert spacing `<= gop_size`, not `== gop_size`.
|
|
47
47
|
|
|
48
|
+
## Transit records carry the flag
|
|
49
|
+
|
|
50
|
+
The receiving status overview applies the same parse live: when an inbound
|
|
51
|
+
`OtaStamped` envelope's `msg_type` names an FFMPEGPacket, it walks the wrapped
|
|
52
|
+
CDR bytes to `flags` (`com_py/ffmpeg_flags.py`, a dependency-free mirror of the
|
|
53
|
+
host parser) and writes `keyframe: true/false` on every delivered RFC 0003
|
|
54
|
+
transit row in `events.jsonl`. Synthesized lost rows have no payload and carry
|
|
55
|
+
no such field; a payload the walk cannot parse simply omits it. Downstream,
|
|
56
|
+
`rosotacom report` annotates a stream from these real flags whenever they cover
|
|
57
|
+
more than 90% of its delivered rows (provenance `ffmpeg_flags (transit
|
|
58
|
+
records)`), and only recordings without the field fall back to size bimodality.
|
|
59
|
+
|
|
48
60
|
## Automated stream-stage stats
|
|
49
61
|
|
|
50
62
|
`rosotacom stream-stats` applies the same packet parser and GOP grouping to
|
|
@@ -69,8 +81,9 @@ Inputs are explicit and repeatable:
|
|
|
69
81
|
rosbag2 storage backends fall back to `rosbag2_py` in a ROS environment.
|
|
70
82
|
- `--events LABEL=PATH:/topic` reads delivered RFC 0003 transit rows from
|
|
71
83
|
`events.jsonl`, using receiver-side `t_com_in` timestamps and `size_bytes`.
|
|
72
|
-
|
|
73
|
-
|
|
84
|
+
Rows carrying the per-message `keyframe` field annotate GOPs from the real
|
|
85
|
+
flags; older recordings without it use the documented size-bimodality
|
|
86
|
+
fallback when the keyframe share looks like a real GOP.
|
|
74
87
|
|
|
75
88
|
The Markdown output starts with the comparison table:
|
|
76
89
|
|
|
@@ -105,9 +118,9 @@ averages 43,723 B, while positions 1-4 average 3,738 B, 4,512 B, 4,834 B, and
|
|
|
105
118
|
|
|
106
119
|
## Fallback: size bimodality
|
|
107
120
|
|
|
108
|
-
If `flags` is unavailable (foreign recordings,
|
|
109
|
-
|
|
110
|
-
classes: delta frames dominate the stream (a GOP of N contributes N−1), so
|
|
121
|
+
If `flags` is unavailable (foreign recordings, bags anonymized before flag
|
|
122
|
+
preservation existed, or `events.jsonl` written before transit rows carried
|
|
123
|
+
`keyframe`), the size distribution still separates the two classes: delta frames dominate the stream (a GOP of N contributes N−1), so
|
|
111
124
|
the median frame size sits on the delta mode, while keyframes are typically
|
|
112
125
|
5–100× larger. `rosotacom.ffmpeg_packet.keyframes_by_size` marks frames
|
|
113
126
|
above `3 × median` as keyframes. This misclassifies only when delta frames
|
|
@@ -119,6 +132,12 @@ scene at a very low bitrate) — prefer `flags` whenever present.
|
|
|
119
132
|
- `tests/unit/test_ffmpeg_packet.py` — CDR parsing (alignment across
|
|
120
133
|
odd-length strings), flag semantics, and the size fallback on a synthetic
|
|
121
134
|
GOP pattern.
|
|
135
|
+
- `tests/unit/test_ffmpeg_flags.py` — the receiver-side keyframe-bit walk in
|
|
136
|
+
`com_py/ffmpeg_flags.py`: agreement with the host parser on hand-built
|
|
137
|
+
packets, and `None` (never an exception) on truncated or foreign bytes.
|
|
138
|
+
- `tests/unit/test_forensics.py` — `rosotacom report` prefers transit-row
|
|
139
|
+
`keyframe` flags over size bimodality, and falls back below the coverage
|
|
140
|
+
gate.
|
|
122
141
|
- `tests/unit/test_stream_stats.py` — exact stream statistics, per-GOP-position
|
|
123
142
|
tables from hand-built CDR packets, events-row source loading, comparison
|
|
124
143
|
table shape, and CLI output writing.
|
|
@@ -28,6 +28,7 @@ living verification hook.
|
|
|
28
28
|
|
|
29
29
|
## Findings
|
|
30
30
|
|
|
31
|
+
- [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.
|
|
31
32
|
- [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.
|
|
32
33
|
- [Lighter alternating messages can lose more than steady messages](lighter-message-loss.md) - a 1x18KB+1x0KB pattern lost under a tight emulated profile while the steady 18 KB comparison did not.
|
|
33
34
|
- [Delay alone was not the loss boundary for the 18 KB at 20 Hz probe](delay-alone-no-loss.md) - pure delay profiles showed no material loss, and the 300 ms delay-only probe delivered all messages.
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# Best-Effort Reordering Becomes Reader-Side Loss, Independent Of History Depth
|
|
2
|
+
|
|
3
|
+
## Claim
|
|
4
|
+
|
|
5
|
+
Under delay jitter large enough to reorder packets — with ZERO configured
|
|
6
|
+
loss — a CycloneDDS best-effort reader discards every overtaken sample to
|
|
7
|
+
preserve per-writer order: delivery is strictly monotonic, the discarded
|
|
8
|
+
samples count as loss, and subscription history depth does not recover any of
|
|
9
|
+
it (the drop happens in the reader proxy, before history). Variance is
|
|
10
|
+
therefore a loss mechanism of its own, and it is the one QoS depth cannot
|
|
11
|
+
help against — unlike bundled-publication overwrite, where depth does help.
|
|
12
|
+
|
|
13
|
+
## Setup
|
|
14
|
+
|
|
15
|
+
- Host pair / topology: two Docker containers on one machine (the repository's
|
|
16
|
+
communication image; any image with `rclpy`, `rmw_cyclonedds_cpp` and `tc`
|
|
17
|
+
works), unicast Cyclone peers (`AllowMulticast=false`, static IPs), one
|
|
18
|
+
`std_msgs/Int64` stream at 100 Hz, publisher history depth 10, best-effort;
|
|
19
|
+
the receiver subscribes the SAME topic twice: depth 1 and depth 50. netem on
|
|
20
|
+
the publisher's egress only, delay+jitter, no loss, no rate limit.
|
|
21
|
+
- rosotacom SHA: measured at `3227daf`; re-runs record theirs.
|
|
22
|
+
- Profile: inline netem args (`delay 50ms 45ms` and `delay 50ms 20ms`), not a
|
|
23
|
+
packaged profile — the experiment is below rosotacom, at the RMW layer.
|
|
24
|
+
- Seed policy: seedless single runs (`n=1` per jitter level); the effect size
|
|
25
|
+
(tens of percent) dwarfs run-to-run noise.
|
|
26
|
+
|
|
27
|
+
## Evidence
|
|
28
|
+
|
|
29
|
+
Evidence grade: scripted container reproduction, committed next to this file.
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
python3 docs/findings/repro/reorder_drop_repro.py orchestrate --rate 100 --duration 40
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
2026-08-18 run (4000 messages sent per scenario, zero configured loss):
|
|
36
|
+
|
|
37
|
+
| netem | depth 1 delivered | depth 50 delivered | inversions | loss of span |
|
|
38
|
+
|---|---|---|---|---|
|
|
39
|
+
| `delay 50ms 45ms` | 1709 | 1727 | 0 | **57%** |
|
|
40
|
+
| `delay 50ms 20ms` | 2626 | 2659 | 0 | **34%** |
|
|
41
|
+
|
|
42
|
+
Three readings, one per column group: delivery is strictly monotonic (zero
|
|
43
|
+
inversions in every subscription), depth 50 loses the same as depth 1 (the
|
|
44
|
+
0.5–1 pp difference is executor noise, not recovery), and the loss tracks the
|
|
45
|
+
overtake probability — at 100 Hz the inter-message gap is 10 ms, so jitter
|
|
46
|
+
±45 ms makes "the next message arrives first" the common case.
|
|
47
|
+
|
|
48
|
+
Field context (2026-08-17 CCNG drive): the operational 10 Hz streams have a
|
|
49
|
+
100 ms gap against ~18 ms steady jitter, so this channel is minor there
|
|
50
|
+
(neighbour-delay overtake proxy: 9.6% around steady losses vs 6.0% baseline).
|
|
51
|
+
It grows quadratically relevant as rates rise or jitter grows — any stream
|
|
52
|
+
whose inter-message gap approaches the link's jitter pays it.
|
|
53
|
+
|
|
54
|
+
Verification: manual: run the command above from a source checkout with
|
|
55
|
+
Docker (build the image via the packaged `ros2docker.json.example` or pass
|
|
56
|
+
`--image`); the script prints and writes `out/reorder_results.json`.
|
|
57
|
+
|
|
58
|
+
## Status
|
|
59
|
+
|
|
60
|
+
confirmed, 2026-08-18.
|
|
61
|
+
|
|
62
|
+
## Publication notes
|
|
63
|
+
|
|
64
|
+
This is the mechanism behind the jitter side of
|
|
65
|
+
[jitter-loss-bandwidth-latency.md](jitter-loss-bandwidth-latency.md): the
|
|
66
|
+
jitter boundary is not radio noise but the reader's monotonicity rule. For
|
|
67
|
+
papers: plot delivered share vs jitter/gap ratio, and state explicitly that
|
|
68
|
+
history depth is not a mitigation here — pacing (larger gaps), FEC, or
|
|
69
|
+
reliable QoS are.
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Does jitter-induced reordering become LOSS at a CycloneDDS best-effort
|
|
3
|
+
reader, and does history depth help?
|
|
4
|
+
|
|
5
|
+
Two containers (rcd image, cyclone RMW). Publisher shapes its egress with
|
|
6
|
+
pure delay+jitter (NO configured loss, no rate limit). Receiver subscribes
|
|
7
|
+
the same topic twice: depth 1 and depth 50.
|
|
8
|
+
|
|
9
|
+
Discriminates two mechanisms:
|
|
10
|
+
- loss seen by depth-50 sub = reader-proxy drop of overtaken samples
|
|
11
|
+
(depth cannot help) (or nothing, if cyclone delivers OOO)
|
|
12
|
+
- extra loss of depth-1 sub = history overwrite from arrival bunching
|
|
13
|
+
(depth DOES help)
|
|
14
|
+
- delivered inversions = out-of-order delivery (would mean no drop)
|
|
15
|
+
|
|
16
|
+
Modes: orchestrate (host) | pub | sub (in container).
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
import argparse
|
|
20
|
+
import json
|
|
21
|
+
import subprocess
|
|
22
|
+
import sys
|
|
23
|
+
import time
|
|
24
|
+
from pathlib import Path
|
|
25
|
+
|
|
26
|
+
IMG = "ros-communication:latest" # any image with rclpy + rmw_cyclonedds + tc (--image overrides)
|
|
27
|
+
NET = "claude_reorder_net"
|
|
28
|
+
TOPIC = "/reorder_probe"
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def mode_pub(args):
|
|
32
|
+
import rclpy
|
|
33
|
+
from rclpy.node import Node
|
|
34
|
+
from rclpy.qos import HistoryPolicy, QoSProfile, ReliabilityPolicy
|
|
35
|
+
from std_msgs.msg import Int64
|
|
36
|
+
|
|
37
|
+
rclpy.init()
|
|
38
|
+
node = Node("reorder_pub")
|
|
39
|
+
qos = QoSProfile(reliability=ReliabilityPolicy.BEST_EFFORT, history=HistoryPolicy.KEEP_LAST, depth=10)
|
|
40
|
+
pub = node.create_publisher(Int64, TOPIC, qos)
|
|
41
|
+
time.sleep(5.0) # discovery
|
|
42
|
+
n = int(args.rate * args.duration)
|
|
43
|
+
period = 1.0 / args.rate
|
|
44
|
+
t0 = time.monotonic()
|
|
45
|
+
for i in range(n):
|
|
46
|
+
while time.monotonic() < t0 + i * period:
|
|
47
|
+
time.sleep(0.0005)
|
|
48
|
+
m = Int64()
|
|
49
|
+
m.data = i
|
|
50
|
+
pub.publish(m)
|
|
51
|
+
time.sleep(3.0)
|
|
52
|
+
print(f"published {n}")
|
|
53
|
+
node.destroy_node()
|
|
54
|
+
rclpy.shutdown()
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def mode_sub(args):
|
|
58
|
+
import rclpy
|
|
59
|
+
from rclpy.node import Node
|
|
60
|
+
from rclpy.qos import HistoryPolicy, QoSProfile, ReliabilityPolicy
|
|
61
|
+
from std_msgs.msg import Int64
|
|
62
|
+
|
|
63
|
+
rclpy.init()
|
|
64
|
+
node = Node("reorder_sub")
|
|
65
|
+
got = {1: [], 50: []}
|
|
66
|
+
|
|
67
|
+
def make_cb(depth):
|
|
68
|
+
def cb(msg):
|
|
69
|
+
got[depth].append(msg.data)
|
|
70
|
+
|
|
71
|
+
return cb
|
|
72
|
+
|
|
73
|
+
subs = []
|
|
74
|
+
for depth in (1, 50):
|
|
75
|
+
qos = QoSProfile(reliability=ReliabilityPolicy.BEST_EFFORT, history=HistoryPolicy.KEEP_LAST, depth=depth)
|
|
76
|
+
subs.append(node.create_subscription(Int64, TOPIC, make_cb(depth), qos))
|
|
77
|
+
t_end = time.monotonic() + args.duration + 20
|
|
78
|
+
while time.monotonic() < t_end:
|
|
79
|
+
rclpy.spin_once(node, timeout_sec=0.05)
|
|
80
|
+
out = {}
|
|
81
|
+
for depth, seqs in got.items():
|
|
82
|
+
inv = sum(1 for a, b in zip(seqs, seqs[1:], strict=False) if b < a)
|
|
83
|
+
out[f"depth{depth}"] = {
|
|
84
|
+
"received": len(seqs),
|
|
85
|
+
"unique": len(set(seqs)),
|
|
86
|
+
"inversions": inv,
|
|
87
|
+
"first": seqs[0] if seqs else None,
|
|
88
|
+
"last": max(seqs) if seqs else None,
|
|
89
|
+
}
|
|
90
|
+
Path(args.out).write_text(json.dumps(out, indent=2))
|
|
91
|
+
print(json.dumps(out))
|
|
92
|
+
node.destroy_node()
|
|
93
|
+
rclpy.shutdown()
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def run(cmd):
|
|
97
|
+
r = subprocess.run(cmd, shell=True, capture_output=True, text=True)
|
|
98
|
+
if r.returncode != 0:
|
|
99
|
+
raise RuntimeError(f"{cmd}\n{r.stderr or r.stdout}")
|
|
100
|
+
return r.stdout
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def mode_orchestrate(args):
|
|
104
|
+
global IMG
|
|
105
|
+
IMG = args.image
|
|
106
|
+
me = Path(__file__).resolve()
|
|
107
|
+
outdir = me.parent / "out"
|
|
108
|
+
scenarios = [
|
|
109
|
+
("jitter45", "tc qdisc replace dev eth0 root netem delay 50ms 45ms"),
|
|
110
|
+
("jitter20", "tc qdisc replace dev eth0 root netem delay 50ms 20ms"),
|
|
111
|
+
]
|
|
112
|
+
ip_sub, ip_pub = "10.97.0.2", "10.97.0.3"
|
|
113
|
+
ddsuri = (
|
|
114
|
+
"<CycloneDDS><Domain><General><AllowMulticast>false</AllowMulticast>"
|
|
115
|
+
'</General><Discovery><Peers><Peer address=\\"' + ip_sub + '\\"/>'
|
|
116
|
+
'<Peer address=\\"' + ip_pub + '\\"/></Peers>'
|
|
117
|
+
"<ParticipantIndex>auto</ParticipantIndex></Discovery></Domain></CycloneDDS>"
|
|
118
|
+
)
|
|
119
|
+
subprocess.run(f"docker network rm {NET}", shell=True, capture_output=True)
|
|
120
|
+
run(f"docker network create --subnet 10.97.0.0/24 {NET}")
|
|
121
|
+
results = {}
|
|
122
|
+
try:
|
|
123
|
+
for name, netem in scenarios:
|
|
124
|
+
subprocess.run("docker rm -f claude_reorder_pub claude_reorder_sub", shell=True, capture_output=True)
|
|
125
|
+
env = f'-e RMW_IMPLEMENTATION=rmw_cyclonedds_cpp -e ROS_DOMAIN_ID=77 -e CYCLONEDDS_URI="{ddsuri}"'
|
|
126
|
+
run(
|
|
127
|
+
f"docker run -d --name claude_reorder_sub --network {NET} --ip {ip_sub} {env} "
|
|
128
|
+
f"-v {me.parent}:/w -v {outdir}:/out {IMG} bash -lc "
|
|
129
|
+
f"'python3 /w/{me.name} sub --duration {args.duration} "
|
|
130
|
+
f"--out /out/reorder_{name}.json'"
|
|
131
|
+
)
|
|
132
|
+
time.sleep(2)
|
|
133
|
+
run(
|
|
134
|
+
f"docker run -d --name claude_reorder_pub --network {NET} --ip {ip_pub} "
|
|
135
|
+
f"--cap-add NET_ADMIN {env} -v {me.parent}:/w {IMG} bash -lc "
|
|
136
|
+
f"'{netem} && python3 /w/{me.name} pub --rate {args.rate} "
|
|
137
|
+
f"--duration {args.duration}'"
|
|
138
|
+
)
|
|
139
|
+
run("docker wait claude_reorder_pub")
|
|
140
|
+
run("docker wait claude_reorder_sub")
|
|
141
|
+
data = json.loads((outdir / f"reorder_{name}.json").read_text())
|
|
142
|
+
sent = int(args.rate * args.duration)
|
|
143
|
+
for d in ("depth1", "depth50"):
|
|
144
|
+
span = (data[d]["last"] or 0) - (data[d]["first"] or 0) + 1
|
|
145
|
+
data[d]["loss_pct_of_span"] = round(100 * (1 - data[d]["unique"] / max(span, 1)), 2)
|
|
146
|
+
data["sent"] = sent
|
|
147
|
+
results[name] = data
|
|
148
|
+
print(f"== {name}: {json.dumps(data)}")
|
|
149
|
+
finally:
|
|
150
|
+
subprocess.run("docker rm -f claude_reorder_pub claude_reorder_sub", shell=True, capture_output=True)
|
|
151
|
+
subprocess.run(f"docker network rm {NET}", shell=True, capture_output=True)
|
|
152
|
+
(outdir / "reorder_results.json").write_text(json.dumps(results, indent=2))
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def main():
|
|
156
|
+
ap = argparse.ArgumentParser()
|
|
157
|
+
sub = ap.add_subparsers(dest="mode", required=True)
|
|
158
|
+
for m in ("orchestrate", "pub", "sub"):
|
|
159
|
+
p = sub.add_parser(m)
|
|
160
|
+
p.add_argument("--rate", type=float, default=100.0)
|
|
161
|
+
p.add_argument("--duration", type=float, default=40.0)
|
|
162
|
+
p.add_argument("--image", default=IMG)
|
|
163
|
+
if m == "sub":
|
|
164
|
+
p.add_argument("--out", required=True)
|
|
165
|
+
args = ap.parse_args()
|
|
166
|
+
{"pub": mode_pub, "sub": mode_sub, "orchestrate": mode_orchestrate}[args.mode](args)
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
if __name__ == "__main__":
|
|
170
|
+
sys.exit(main() or 0)
|
|
@@ -77,6 +77,22 @@ missing tail after the last record is not judged either — without a sender-sid
|
|
|
77
77
|
end marker it is indistinguishable from a normal shutdown (RFC 0003, honest
|
|
78
78
|
limits).
|
|
79
79
|
|
|
80
|
+
A receiver-only view also cannot tell a broken link from a source that simply
|
|
81
|
+
stopped publishing — on the 2026-08-17 CCNG drive, "0 Hz collapses" on the
|
|
82
|
+
planner visualization were the source pausing during manual interventions while
|
|
83
|
+
the link delivered everything offered. When the instance also contains the
|
|
84
|
+
sending peer's own transit records for a stream (`direction: outbound`, stage
|
|
85
|
+
`com_out`), the report bins their `t_wrap` stamps into a per-bin **offered**
|
|
86
|
+
rate on the same publish timeline and each collapse event names its culprit in
|
|
87
|
+
`details.cause`: `source` when every collapsed bin was offered below the same
|
|
88
|
+
threshold — the collapse is fully explained by the source, and the markdown
|
|
89
|
+
line reads "source paused" (0 Hz offered) or "source slowed"; `link` when at
|
|
90
|
+
least one collapsed bin was offered at/above threshold and the link still
|
|
91
|
+
delivered below it; `unknown` without sender-side records. `min_offered_hz` /
|
|
92
|
+
`max_offered_hz` accompany the verdict. Sender-side rows feed only the offered
|
|
93
|
+
rate — they never enter the delivered view, where the cross-peer join would
|
|
94
|
+
upgrade receiver-inferred lost rows to delivered.
|
|
95
|
+
|
|
80
96
|
Events across streams and kinds are grouped into **incidents** when their
|
|
81
97
|
windows touch (merge gap defaults to one bin): one degradation moment, several
|
|
82
98
|
lenses on it.
|
|
@@ -91,11 +91,24 @@ profiles:
|
|
|
91
91
|
- { for: 40s, uplink: { rate: 2.5mbit, delay: 90ms, loss: 1% } }
|
|
92
92
|
```
|
|
93
93
|
|
|
94
|
-
- **static** — constant `{rate, delay, jitter, distribution,
|
|
95
|
-
loss_correlation, reorder, duplicate, seed}` per
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
94
|
+
- **static** — constant `{rate, delay, jitter, distribution, distribution_file,
|
|
95
|
+
loss, loss_correlation, loss_gemodel, reorder, duplicate, seed}` per
|
|
96
|
+
direction. Two loss models, mutually exclusive per direction:
|
|
97
|
+
`loss` (+ optional `loss_correlation`) is netem's independent/correlated
|
|
98
|
+
per-packet loss; `loss_gemodel: {p, r, loss_bad, loss_good}` is the
|
|
99
|
+
Gilbert–Elliott state model (`tc netem loss gemodel`), the vocabulary a real
|
|
100
|
+
cellular link needs — rare transitions into a short intense bad state
|
|
101
|
+
(`p`/`r` per packet) with distinct loss probabilities inside (`loss_bad`)
|
|
102
|
+
and outside (`loss_good`) of it. The 2026-08-17 CCNG field fit is the
|
|
103
|
+
reference: `p 0.12%, r 2.9%, loss_bad 2.7%, loss_good 0.098%` reproduces
|
|
104
|
+
113 ms bad states every ~2.8 s. `distribution` accepts the iproute2
|
|
105
|
+
builtins (`normal|pareto|paretonormal`) or a custom table name whose
|
|
106
|
+
`distribution_file` (a `.dist` built by `python -m rosotacom.netem_dist`
|
|
107
|
+
from measured delay samples) the runner installs into the shaping netns as
|
|
108
|
+
`/usr/lib/tc/<name>.dist` — because a field link's delay is
|
|
109
|
+
lognormal-tailed and `normal` under-tails p99 by ~2x. `seed` maps to
|
|
110
|
+
`tc netem seed SEED` when supported, making the generated random
|
|
111
|
+
delay/loss draw replayable.
|
|
99
112
|
- **timeline** — an ordered list of `{ for: <dur>, <static-params> | outage }`
|
|
100
113
|
segments. A recovery benchmark (RFC 0005) *is* a timeline profile; `outage` is
|
|
101
114
|
the step whose recovery is measured.
|
|
@@ -189,8 +202,11 @@ RFC 0002's `calibrate` / `--suggest` machinery, **per profile**:
|
|
|
189
202
|
the fluctuation `netem` does not reproduce by default. Emulation buys
|
|
190
203
|
**reproducibility, not truth** — rung 4 (real cellular) calibrates the
|
|
191
204
|
*shape* of the emulated profile; the profile then gives repeatable gating.
|
|
192
|
-
- **Bursty loss needs the state model.** Default `netem loss` is independent;
|
|
193
|
-
`
|
|
205
|
+
- **Bursty loss needs the state model.** Default `netem loss` is independent; the
|
|
206
|
+
2-arg `loss p% corr%` cannot express short-bad/long-good either. `loss_gemodel`
|
|
207
|
+
carries the Gilbert–Elliott parameters directly (see the schema section); fit
|
|
208
|
+
`p`/`r` from the measured bad/good run lengths (per packet) and the two loss
|
|
209
|
+
probabilities from the loss rate inside/outside bad states.
|
|
194
210
|
- **Outage semantics are a choice.** `netem loss 100%` keeps the interface up (DDS
|
|
195
211
|
endpoints survive, recovery is "catch up") vs link-down (forces RMW
|
|
196
212
|
re-discovery, a harsher recovery). They test different recoveries — see Open
|
|
@@ -215,6 +231,12 @@ risk — a stuck `qdisc` silently corrupts every later result on the machine.
|
|
|
215
231
|
`profiles.yaml` referenced from `rosotacom.yaml`), and resolve selection via
|
|
216
232
|
`--profile <name>` / `shared.profile` / `none` (`resolve_profile_selection`,
|
|
217
233
|
`cli._resolve_active_profile`).
|
|
234
|
+
- [x] Extend the loss/delay vocabulary to what field links actually need
|
|
235
|
+
(issue #278): `loss_gemodel` (Gilbert–Elliott state loss, exclusive with
|
|
236
|
+
`loss`) and custom delay-distribution tables (`distribution` beyond the
|
|
237
|
+
builtins + `distribution_file`, generated from measured samples by
|
|
238
|
+
`rosotacom.netem_dist`, installed into the shaping netns by the lab runner
|
|
239
|
+
before arming).
|
|
218
240
|
- [x] Arm a named static profile on the OTA-interface egress with fail-safe
|
|
219
241
|
teardown (revert on stop, on error, and via a safety max-duration watchdog);
|
|
220
242
|
target the data interface only, never the SSH/control interface
|
|
@@ -268,6 +290,21 @@ off during implementation). Notes whether automation is feasible; privileged
|
|
|
268
290
|
for a given profile/direction (rate/delay/jitter/loss/correlation → `tbf`+`netem`
|
|
269
291
|
string), without touching a real interface (`test_shaping_commands_*`,
|
|
270
292
|
`test_netem_arg_ordering_is_valid`). Done.
|
|
293
|
+
- [x] **Gilbert–Elliott loss (`loss_gemodel`)** — host unit tests on the schema
|
|
294
|
+
(required/unknown keys, exclusivity against `loss`) and on the argv (all four
|
|
295
|
+
probabilities always emitted): `test_gemodel_parse_and_exclusivity`,
|
|
296
|
+
`test_gemodel_argv_emits_all_four_probabilities`. The *statistical* fidelity of
|
|
297
|
+
the emitted process (bad-run length, in-state loss rates) stays a bench check
|
|
298
|
+
against a field fit — the 2026-08-17 CCNG fragment replay is the reference.
|
|
299
|
+
- [x] **Custom delay-distribution tables** — host unit tests: a non-builtin
|
|
300
|
+
`distribution` requires `distribution_file` and resolves relative to the
|
|
301
|
+
profiles file (`test_custom_distribution_requires_a_file_and_builtin_does_not`,
|
|
302
|
+
`test_load_profiles_file_resolves_distribution_files_and_lists_installs`);
|
|
303
|
+
table generation is normalized, monotonic, tail-preserving
|
|
304
|
+
(`test_netem_dist.py`). The lab runner installs required tables into the
|
|
305
|
+
shaping netns before arming (`required_dist_installs` consumed in
|
|
306
|
+
`cli_benchmark`); that a netem referencing the installed name actually loads
|
|
307
|
+
it is part of the same bench check as arming itself.
|
|
271
308
|
- [~] **Fail-safe teardown** (revert on stop, on error, on safety max-duration; the
|
|
272
309
|
idempotent `tc qdisc del … root` always runs; data-interface-only, never the
|
|
273
310
|
SSH/control interface) — host unit test on the teardown/targeting logic done
|
|
@@ -568,6 +568,27 @@ number being reported.
|
|
|
568
568
|
- `bit_rate` (int)
|
|
569
569
|
- `encoder_av_options` (string)
|
|
570
570
|
|
|
571
|
+
#### Receiver-side playout pacing (manual node)
|
|
572
|
+
|
|
573
|
+
A receiver that hands every packet to the decoder the moment it arrives turns
|
|
574
|
+
network delay jitter into display stutter. `com_py playout_pacer` re-times a
|
|
575
|
+
received packet stream to `stamp + budget` (budget adaptive above the fastest
|
|
576
|
+
observed path, clock-offset-proof; late packets pass through immediately, order
|
|
577
|
+
always preserved — the decoder chain sees every packet):
|
|
578
|
+
|
|
579
|
+
```bash
|
|
580
|
+
ros2 run com_py playout_pacer --ros-args \
|
|
581
|
+
-p topic:=/cam/image/compressed/drop1of2/ffmpeg \
|
|
582
|
+
-p target_ms:=350.0 -p adaptive:=true
|
|
583
|
+
```
|
|
584
|
+
|
|
585
|
+
It republishes on `<topic>/paced` plus `.../paced/budget_ms` and
|
|
586
|
+
`.../paced/queue_depth` debug topics; point the reverse republish (or any
|
|
587
|
+
decoder) at the paced name. On the 2026-08-17 CCNG field trace this removes
|
|
588
|
+
~95 % of delay-caused >200 ms display gaps at ~100 ms median added age
|
|
589
|
+
(adaptive mode). Declarative wiring as a `transport.playout` block is tracked
|
|
590
|
+
in issue #284.
|
|
591
|
+
|
|
571
592
|
`type: foxglove` supports (CompressedVideo):
|
|
572
593
|
- `gop_size` (int)
|
|
573
594
|
- `bit_rate` (int)
|
|
@@ -5514,6 +5514,30 @@ def _make_live_run_point(args: argparse.Namespace, session_name: str) -> RunPoin
|
|
|
5514
5514
|
|
|
5515
5515
|
# 3. Arm the network shapers (after discovery is complete)
|
|
5516
5516
|
if profile_obj is not None:
|
|
5517
|
+
from .network_profiles import required_dist_installs
|
|
5518
|
+
|
|
5519
|
+
dist_installs = required_dist_installs(profile_obj)
|
|
5520
|
+
if dist_installs:
|
|
5521
|
+
# Custom delay-distribution tables must exist inside the
|
|
5522
|
+
# shaping netns before netem references them by name.
|
|
5523
|
+
for dist_container in (a_container, b_container):
|
|
5524
|
+
if not dist_container:
|
|
5525
|
+
continue
|
|
5526
|
+
for table_name, file_path in dist_installs:
|
|
5527
|
+
dist_target = f"/usr/lib/tc/{table_name}.dist"
|
|
5528
|
+
for install_cmd in (
|
|
5529
|
+
["docker", "exec", "-u", "root", dist_container, "mkdir", "-p", "/usr/lib/tc"],
|
|
5530
|
+
["docker", "cp", file_path, f"{dist_container}:{dist_target}"],
|
|
5531
|
+
):
|
|
5532
|
+
res = subprocess.run(install_cmd, capture_output=True, text=True, check=False)
|
|
5533
|
+
if res.returncode != 0:
|
|
5534
|
+
raise RuntimeError(
|
|
5535
|
+
f"failed to install netem distribution table {table_name!r} in "
|
|
5536
|
+
f"{dist_container}: {' '.join(install_cmd)} -> {res.stderr or res.stdout}"
|
|
5537
|
+
)
|
|
5538
|
+
print(
|
|
5539
|
+
f" netem distribution {table_name!r} installed in {dist_container}: {dist_target}"
|
|
5540
|
+
)
|
|
5517
5541
|
if profile_obj.is_timeline:
|
|
5518
5542
|
# Peer A shapes uplink (egress to B)
|
|
5519
5543
|
shaper_a = ProfileShaper("eth0", make_container_runner(a_container))
|