rosotacom-dev 2.5.dev56__tar.gz → 2.5.dev57__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.dev56 → rosotacom_dev-2.5.dev57}/PKG-INFO +1 -1
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/session-configuration.md +29 -2
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/ros2src/com_py/com_py/playout_pacer.py +17 -3
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/ros2src/com_py/com_py/status_overview.py +6 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/ros2src/com_py/com_py/status_overview_core.py +68 -4
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/session/creation/generate_session_files.py +16 -10
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/status_eval.py +11 -2
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom_dev.egg-info/PKG-INFO +1 -1
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom_dev.egg-info/scm_version.json +2 -2
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/tests/contract/test_generated_topics_have_a_producer.py +30 -4
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/tests/unit/test_playout_pacer.py +32 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/tests/unit/test_session_pipeline.py +51 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/tests/unit/test_status_eval.py +41 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/tests/unit/test_status_overview.py +124 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/.devcontainer/devcontainer.json.template +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/.devcontainer/re_generate_devcontainer_json.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/.github/CODEOWNERS +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/.github/ISSUE_TEMPLATE/documentation-audit.md +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/.github/ISSUE_TEMPLATE/implementation-cleanup.md +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/.github/ISSUE_TEMPLATE/quality-workflow.md +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/.github/ISSUE_TEMPLATE/redesign.md +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/.github/ISSUE_TEMPLATE/release-process.md +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/.github/ISSUE_TEMPLATE/repository-diagnosis.md +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/.github/ISSUE_TEMPLATE/test-ci-audit.md +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/.github/ISSUE_TEMPLATE/work-item.md +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/.github/actions/setup-just/action.yml +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/.github/dependabot.yml +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/.github/workflows/benchmark-calibrate.yml +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/.github/workflows/benchmark-gate.yml +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/.github/workflows/dev-release.yml +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/.github/workflows/image-scan.yml +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/.github/workflows/nightly-e2e.yml +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/.github/workflows/pr-lightweight.yml +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/.github/workflows/pr-merge-gate.yml +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/.github/workflows/release.yml +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/.pre-commit-config.yaml +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/AGENTS.md +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/CONCURRENCY.md +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/CONTRIBUTING.md +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/DEVELOPMENT_PRINCIPLES.md +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/LICENSE.txt +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/MANIFEST.in +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/README.md +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/budgets.jsonl +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/calibration/README.md +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/calibration/capacity-size-tight-cyclone.json +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/calibration/probe-loss-gop-tight-cyclone.json +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/calibration/probe-loss-nominal-cyclone.json +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/calibration/probe-loss-tight-cyclone.json +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/calibration/probe-loss-tight-fastdds.json +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/calibration/probe-loss-tight-zenoh.json +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/codecov.yml +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/deployment-configuration.md +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/docs/benchmark-ab.md +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/docs/benchmark-bag-as-load.md +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/docs/ci.md +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/docs/ffmpeg-keyframes.md +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/docs/findings/README.md +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/docs/findings/cyclone-spdp-discovery-bursts.md +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/docs/findings/delay-alone-no-loss.md +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/docs/findings/fastdds-datagram-cap-drops-large-samples.md +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/docs/findings/graph-derived-types-block-a-non-graph-transport.md +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/docs/findings/head-of-line-irregularity.md +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/docs/findings/jitter-loss-bandwidth-latency.md +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/docs/findings/keyframe-loss-kills-the-next-deltas.md +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/docs/findings/lighter-message-loss.md +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/docs/findings/oversubscription-queues-not-losses.md +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/docs/findings/reorder-becomes-reader-loss.md +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/docs/findings/repro/decode_chain_repro.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/docs/findings/repro/reorder_drop_repro.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/docs/findings/sender-rows-make-a-dead-link-look-loss-free.md +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/docs/findings/zero-loss-boundaries-18kb-20hz.md +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/docs/forensics-report.md +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/docs/geo-link-map.md +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/docs/github-repository-settings.md +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/docs/link-bandwidth.md +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/docs/link-trace.md +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/docs/owner-runbook.md +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/docs/performance-bands.md +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/docs/playbooks/README.md +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/docs/quality-model.md +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/docs/release-notes/TEMPLATE.md +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/docs/release-notes/v2.1.md +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/docs/release-notes/v2.2.md +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/docs/release-notes/v2.3.md +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/docs/release-notes/v2.4.md +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/docs/release.md +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/docs/rfcs/0001-expectation-driven-test-suite.md +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/docs/rfcs/0002-expectation-concepts.md +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/docs/rfcs/0003-metric-backbone.md +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/docs/rfcs/0004-network-profiles.md +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/docs/rfcs/0005-benchmark-genres-and-ci.md +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/docs/rfcs/0006-dynamic-qos.md +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/docs/rfcs/0007-regression-gate.md +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/docs/rfcs/README.md +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/docs/testing.md +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/docs/work-items.md +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/install.sh +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/justfile +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/media/control_center.png +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/media/echo_test.png +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/media/forensics-report-example.png +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/media/host.png +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/media/vehicle.png +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/pyproject.toml +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/requirements.txt +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/rosotacom.yaml +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/setup.cfg +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/__init__.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/__main__.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/anonymize.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/bag_ground_truth.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/benched_set.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/benchmark.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/benchmark_delta.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/bundle_check.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/cli.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/cli_benchmark.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/deployment.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/ffmpeg_packet.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/forensics.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/geomap.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/image_cache.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/netem_dist.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/network_preflight.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/network_profiles.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/network_shaper.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/plots.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/py.typed +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/benched-set.yaml +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/examples/.gitignore +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/examples/README.md +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/examples/__init__.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/examples/bags/8_drop_reference/metadata.yaml +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/examples/deployment.example.yaml +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/examples/dist/field-20260817.dist +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/examples/profiles.yaml +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/examples/ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/examples/rosotacom.yaml +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/examples/scenarios/2_native_chatter/scenario-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/examples/scripts/1_heartbeat/run_machine_a.sh +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/examples/scripts/1_heartbeat/run_machine_b.sh +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_a/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_a/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_a/run_external.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_a/wait_for_echo_topic.sh +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_b/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_b/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/examples/scripts/2_native_chatter/machine_b/run_external.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_a/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_a/external_session.yaml +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_a/foxglove.json +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_a/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_a/run_external.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_b/costmap_1second/costmap_1second_0.mcap +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_b/costmap_1second/metadata.yaml +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_b/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_b/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/examples/scripts/3_comp_occ_grid/machine_b/run_external.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_a/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_a/external_session.yaml +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_a/foxglove.json +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_a/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_a/run_external.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_b/costmap_1second/costmap_1second_0.mcap +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_b/costmap_1second/metadata.yaml +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_b/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_b/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/examples/scripts/4_comp_occ_grid_zen/machine_b/run_external.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_a/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_a/external_session.yaml +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_a/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_a/run_external.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_b/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_b/external_session.yaml +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_b/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/examples/scripts/5_sized_payload/machine_b/run_external.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_a/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_a/external_session.yaml +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_a/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_a/run_external.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_b/external.ros2docker.json +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_b/external_session.yaml +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_b/run_communication.sh +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/examples/scripts/6_sized_payload_zen/machine_b/run_external.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/examples/sessions/10_restamp/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/examples/sessions/11_trickle/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/examples/sessions/12_content_integrity/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/examples/sessions/13_link_latency/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/examples/sessions/14_remote_assist_anonymized/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/examples/sessions/15_remote_assist_anonymized_costmap/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/examples/sessions/16_remote_assist_anonymized_camera/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/examples/sessions/17_synthetic_camera_quality/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/examples/sessions/1_heartbeat/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/examples/sessions/1_heartbeat_status/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/examples/sessions/2_native_chatter/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/examples/sessions/3_comp_occ_grid/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/examples/sessions/4_comp_occ_grid_zen/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/examples/sessions/5_sized_payload/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/examples/sessions/6_sized_payload_zen/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/examples/sessions/7_latched_static/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/examples/sessions/8_drop/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/examples/sessions/9_throttle/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/examples/sessions/bench_1_1_capacity/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/examples/sessions/bench_1_2_load_sweep/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/examples/sessions/bench_1_3_ramp/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/examples/sessions/bench_1_4_recovery/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/examples/sessions/bench_1_5_camera/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ros2docker.json.example +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/.vscode/c_cpp_properties.json +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/.vscode/settings.json +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_easy_mode.xml.template +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_initial_peer_list.xml.template +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_v2.xml.template +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_v3.xml.template +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_v4.xml.template +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/ota_configs/archive/fastdds_v5.xml.template +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/ota_configs/create_zenoh_json5.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/ota_configs/cyclonedds_local_participants.xml.template +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/ota_configs/cyclonedds_minimal.xml.template +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/ota_configs/cyclonedds_tuned.xml.template +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/ota_configs/fastdds_easy_mode.xml.template +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/ota_configs/fastdds_local.xml.template +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/ota_configs/fastdds_tuned.xml.template +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/ota_configs/fastdds_unicast.xml.template +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/ota_configs/get_ota_xml.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/ota_configs/utils.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/ota_configs/zenoh.json5.template +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/ros2src/.gitkeep +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/ros2src/com_cpp/CMakeLists.txt +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/ros2src/com_cpp/COLCON_IGNORE +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/ros2src/com_cpp/LICENSE.txt +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/ros2src/com_cpp/package.xml +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/ros2src/com_cpp/src/hz_monitor.cpp +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/ros2src/com_cpp/src/universal_compressor.cpp +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/ros2src/com_cpp/src/universal_decompressor.cpp +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/ros2src/com_msgs/CMakeLists.txt +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/ros2src/com_msgs/LICENSE.txt +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/ros2src/com_msgs/msg/CompressedData.msg +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/ros2src/com_msgs/msg/EchoHeartbeat.msg +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/ros2src/com_msgs/msg/OtaStamped.msg +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/ros2src/com_msgs/msg/SizedPayload.msg +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/ros2src/com_msgs/package.xml +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/ros2src/com_py/LICENSE.txt +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/ros2src/com_py/com_py/__init__.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/ros2src/com_py/com_py/base_bridge_relay.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/ros2src/com_py/com_py/bridge_in.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/ros2src/com_py/com_py/bridge_out.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/ros2src/com_py/com_py/ffmpeg_flags.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/ros2src/com_py/com_py/heartbeat_echo.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/ros2src/com_py/com_py/hz_monitor.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/ros2src/com_py/com_py/image_bandwidth_reducer.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/ros2src/com_py/com_py/image_pixel_capper.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/ros2src/com_py/com_py/lanelet_saver.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/ros2src/com_py/com_py/latch_relay.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/costmap_remapper.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/marker_remapper.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/speed_test.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/tf_remapper.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/traffic_monitor.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/ros2src/com_py/com_py/legacy/wifi_network_analysis_1.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/ros2src/com_py/com_py/link_bytes.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/ros2src/com_py/com_py/link_trace.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/ros2src/com_py/com_py/local_global_frame_bridge.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/ros2src/com_py/com_py/localization_map_split_reduce_saver.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/ros2src/com_py/com_py/msg_transform.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/ros2src/com_py/com_py/pair_management.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/ros2src/com_py/com_py/playout_pacer_core.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/ros2src/com_py/com_py/pub_sub_pair.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/ros2src/com_py/com_py/qos.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/ros2src/com_py/com_py/relay_in.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/ros2src/com_py/com_py/relay_out.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/ros2src/com_py/com_py/restamp.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/ros2src/com_py/com_py/sized_publisher.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/ros2src/com_py/com_py/stage_latency.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/ros2src/com_py/com_py/stage_latency_core.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/ros2src/com_py/com_py/tf_map_to_cart_saver.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/ros2src/com_py/com_py/topic_monitor.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/ros2src/com_py/com_py/topic_resolution.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/ros2src/com_py/com_py/trickle.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/ros2src/com_py/com_py/universal_compressor.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/ros2src/com_py/com_py/universal_decompressor.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/ros2src/com_py/com_py/universal_ota_unwrapper.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/ros2src/com_py/com_py/universal_ota_wrapper.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/ros2src/com_py/package.xml +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/ros2src/com_py/resource/com_py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/ros2src/com_py/setup.cfg +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/ros2src/com_py/setup.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/ros2src/com_py/test/test_copyright.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/ros2src/com_py/test/test_flake8.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/ros2src/com_py/test/test_pep257.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/session/content/base/session_plugin_base.yaml +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/session/content/network/up_connectivity.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/session/content/network/wifi_network_analysis_2.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/session/creation/anonymize_bag.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/session/creation/catmux_log_setup.sh +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/session/creation/create_session_yaml.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/session/creation/run_session.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/session/creation/run_session_in_external_terminal.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/resources/ws/session/creation/strip_ansi.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/stream_stats.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/trace_profiles.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/transit.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom/video_quality.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom_dev.egg-info/SOURCES.txt +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom_dev.egg-info/dependency_links.txt +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom_dev.egg-info/entry_points.txt +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom_dev.egg-info/requires.txt +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom_dev.egg-info/scm_file_list.json +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/src/rosotacom_dev.egg-info/top_level.txt +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/terminology.md +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/tests/contract/test_benched_set_registry.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/tests/contract/test_findings.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/tests/contract/test_markdown_links.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/tests/contract/test_ota_source_bundle.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/tests/contract/test_package_metadata.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/tests/contract/test_packaged_resources.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/tests/contract/test_profile_covers_generated_commands.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/tests/contract/test_pytest_policy.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/tests/contract/test_readme_examples.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/tests/contract/test_security_maintenance_config.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/tests/contract/test_session_configuration_doc.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/tests/contract/test_session_template_substitution.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/tests/contract/test_workflow_contracts.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/tests/e2e/conftest.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/tests/e2e/test_anonymize_e2e.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/tests/e2e/test_benchmark_ab.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/tests/e2e/test_benchmark_capacity.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/tests/e2e/test_benchmark_replay.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/tests/e2e/test_parallel_smoke.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/tests/e2e/test_smoke.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/tests/e2e/test_timeline_stepping.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/tests/e2e/test_video_quality_e2e.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/tests/sessions/generate_rmw_matrix.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/tests/sessions/rmw_matrix/1_heartbeat_cyclone-local_zenoh-ros2dds-ota/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/tests/sessions/rmw_matrix/1_heartbeat_cyclone-ota/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/tests/sessions/rmw_matrix/1_heartbeat_cyclone-ota-tuned/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/tests/sessions/rmw_matrix/1_heartbeat_fastdds/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/tests/sessions/rmw_matrix/1_heartbeat_fastdds-default/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/tests/sessions/rmw_matrix/1_heartbeat_zen-endpoints/session-definition.yaml +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/tests/unit/test_anonymize.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/tests/unit/test_bag_ground_truth.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/tests/unit/test_benched_set.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/tests/unit/test_benchmark.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/tests/unit/test_benchmark_delta.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/tests/unit/test_bundle_check.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/tests/unit/test_catmux_pane_logging.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/tests/unit/test_cli.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/tests/unit/test_cli_benchmark.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/tests/unit/test_concurrency.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/tests/unit/test_container_shaping.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/tests/unit/test_deployment.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/tests/unit/test_ffmpeg_flags.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/tests/unit/test_ffmpeg_packet.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/tests/unit/test_field_profiles.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/tests/unit/test_forensics.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/tests/unit/test_geomap.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/tests/unit/test_image_cache.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/tests/unit/test_link_bytes.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/tests/unit/test_link_trace.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/tests/unit/test_netem_dist.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/tests/unit/test_network_preflight.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/tests/unit/test_network_profiles.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/tests/unit/test_network_shaper.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/tests/unit/test_ota_link_configs.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/tests/unit/test_ota_unwrapper.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/tests/unit/test_ota_wrapper.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/tests/unit/test_ota_xml.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/tests/unit/test_plots.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/tests/unit/test_pub_sub_pair_types.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/tests/unit/test_qos_fallback_logging.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/tests/unit/test_relay_optional_parameters.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/tests/unit/test_stage_latency.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/tests/unit/test_status_overview_observer.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/tests/unit/test_stream_stats.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/tests/unit/test_trace_profiles.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/tests/unit/test_transit.py +0 -0
- {rosotacom_dev-2.5.dev56 → rosotacom_dev-2.5.dev57}/tests/unit/test_video_quality.py +0 -0
|
@@ -720,8 +720,35 @@ ros2 run com_py playout_pacer --ros-args \
|
|
|
720
720
|
-p target_ms:=350.0 -p adaptive:=true
|
|
721
721
|
```
|
|
722
722
|
|
|
723
|
-
It republishes on `<topic>/paced` plus
|
|
724
|
-
`.../paced/queue_depth`
|
|
723
|
+
It republishes on `<topic>/paced` plus three topics next to it:
|
|
724
|
+
`.../paced/budget_ms` and `.../paced/queue_depth` at 1 Hz, and
|
|
725
|
+
`.../paced/hold_ms` with every release, carrying how long *that* message was
|
|
726
|
+
actually held.
|
|
727
|
+
|
|
728
|
+
##### What the status overview does with it
|
|
729
|
+
|
|
730
|
+
A paced stage's age is the link plus a delay this session asked for, and one
|
|
731
|
+
number cannot be judged against a threshold meant for the link. So the
|
|
732
|
+
generator names the pacer's report on the stage it explains
|
|
733
|
+
(`paced_hold_topic` in `pipeline_spec.yaml`), and `status_overview` takes the
|
|
734
|
+
hold back out before classifying:
|
|
735
|
+
|
|
736
|
+
```
|
|
737
|
+
native_in FLOWING .../ffmpeg/compressed 10.0Hz 286ms(link 46+paced 240) ...
|
|
738
|
+
```
|
|
739
|
+
|
|
740
|
+
`latency_ms` stays the age on screen; `link_latency_ms` and `pacing_hold_ms`
|
|
741
|
+
are the split, and the quality verdict uses the former. Without this the
|
|
742
|
+
default 200 ms bad-threshold — set before anything on a link was held on
|
|
743
|
+
purpose — marks every healthy paced stream BAD, which is how an operator learns
|
|
744
|
+
to stop reading the panel.
|
|
745
|
+
|
|
746
|
+
It is the *applied* hold that is subtracted, never the configured budget: a
|
|
747
|
+
message that arrived later than its release time passes straight through, is
|
|
748
|
+
reported as held for 0 ms, and still flags. A budget-based correction would
|
|
749
|
+
credit that message a buffer it never received and quietly stop reporting a slow
|
|
750
|
+
link. Before the pacer has reported at all, nothing is subtracted — neither zero
|
|
751
|
+
nor the budget is a safe guess.
|
|
725
752
|
|
|
726
753
|
`type: foxglove` supports (CompressedVideo):
|
|
727
754
|
- `gop_size` (int)
|
|
@@ -8,7 +8,16 @@ Inserted between the OTA unwrapper and a decoder chain it turns network jitter
|
|
|
8
8
|
into a constant, bounded age instead of visible stutter.
|
|
9
9
|
|
|
10
10
|
Debug topics next to the output: ``.../paced/budget_ms`` (current delay
|
|
11
|
-
budget) and ``.../paced/queue_depth
|
|
11
|
+
budget) and ``.../paced/queue_depth``, both at 1 Hz, and ``.../paced/hold_ms``
|
|
12
|
+
— published with *every* release, carrying how long that message was actually
|
|
13
|
+
held.
|
|
14
|
+
|
|
15
|
+
``hold_ms`` exists so the status overview can tell the link's contribution from
|
|
16
|
+
this node's. Deliberately the applied hold rather than the budget: a message
|
|
17
|
+
that arrived later than its release time passes straight through and is held
|
|
18
|
+
for 0 ms, so a genuinely slow link cannot be credited with a buffer it never
|
|
19
|
+
used. Subtracting the *budget* would do exactly that, and would quietly stop
|
|
20
|
+
reporting the problem it exists to make visible.
|
|
12
21
|
"""
|
|
13
22
|
|
|
14
23
|
from __future__ import annotations
|
|
@@ -62,6 +71,7 @@ class PlayoutPacerNode(Node):
|
|
|
62
71
|
self._pub = self.create_publisher(msg_cls, out_topic, qos)
|
|
63
72
|
self._budget_pub = self.create_publisher(Float64, out_topic + "/budget_ms", 10)
|
|
64
73
|
self._depth_pub = self.create_publisher(Int32, out_topic + "/queue_depth", 10)
|
|
74
|
+
self._hold_pub = self.create_publisher(Float64, out_topic + "/hold_ms", 10)
|
|
65
75
|
self.create_subscription(msg_cls, topic, self._on_message, qos)
|
|
66
76
|
# 2 ms release tick: bounds added jitter to well below frame cadence.
|
|
67
77
|
self.create_timer(0.002, self._release_due)
|
|
@@ -72,12 +82,16 @@ class PlayoutPacerNode(Node):
|
|
|
72
82
|
now = time.time()
|
|
73
83
|
stamp = msg.header.stamp.sec + msg.header.stamp.nanosec * 1e-9
|
|
74
84
|
release = self.schedule.on_message(stamp, now)
|
|
75
|
-
self._queue.append((release, msg))
|
|
85
|
+
self._queue.append((release, msg, now))
|
|
76
86
|
|
|
77
87
|
def _release_due(self) -> None:
|
|
78
88
|
now = time.time()
|
|
79
89
|
while self._queue and self._queue[0][0] <= now:
|
|
80
|
-
self.
|
|
90
|
+
release, msg, arrival = self._queue.popleft()
|
|
91
|
+
self._pub.publish(msg)
|
|
92
|
+
# What this node added, not what it was allowed to add. Clamped
|
|
93
|
+
# because a late message's release time is already in the past.
|
|
94
|
+
self._hold_pub.publish(Float64(data=max(0.0, (release - arrival) * 1000.0)))
|
|
81
95
|
|
|
82
96
|
def _publish_debug(self) -> None:
|
|
83
97
|
self._budget_pub.publish(Float64(data=float(self.schedule.budget_ms)))
|
|
@@ -71,6 +71,7 @@ from com_py.ffmpeg_flags import FFMPEG_PACKET_TYPE, parse_keyframe_flag
|
|
|
71
71
|
from com_py.link_bytes import LinkByteSampler, resolve_link_interface
|
|
72
72
|
from com_py.link_trace import LinkTraceRecorder
|
|
73
73
|
from com_py.status_overview_core import (
|
|
74
|
+
SCALAR_MSG_TYPE,
|
|
74
75
|
STARTUP_GRACE_S,
|
|
75
76
|
ClockOffsetEstimator,
|
|
76
77
|
StageObservation,
|
|
@@ -309,6 +310,11 @@ class StageObserver(Node):
|
|
|
309
310
|
"t_com_out": now_ros_s,
|
|
310
311
|
"keyframe": keyframe,
|
|
311
312
|
}
|
|
313
|
+
elif obs.type_str == SCALAR_MSG_TYPE:
|
|
314
|
+
# Not a stage: a number this node reads to interpret one. The
|
|
315
|
+
# pacing hold arrives here (`.../paced/hold_ms`); it carries no
|
|
316
|
+
# header, so there is no latency to record, only the value.
|
|
317
|
+
obs.last_value = float(msg.data)
|
|
312
318
|
else:
|
|
313
319
|
header = getattr(msg, "header", None)
|
|
314
320
|
stamp = getattr(header, "stamp", None) if header is not None else None
|
|
@@ -61,6 +61,12 @@ GOOD = "GOOD"
|
|
|
61
61
|
DEGRADED = "DEGRADED"
|
|
62
62
|
BAD = "BAD"
|
|
63
63
|
|
|
64
|
+
#: A stage whose age includes a delay this session asked for names the topic on
|
|
65
|
+
#: which the node responsible reports what it actually held. Set by the
|
|
66
|
+
#: generator for a decode that reads a playout pacer's output.
|
|
67
|
+
PACED_HOLD_KEY = "paced_hold_topic"
|
|
68
|
+
SCALAR_MSG_TYPE = "std_msgs/msg/Float64"
|
|
69
|
+
|
|
64
70
|
# Topic-level rollup
|
|
65
71
|
OK = "OK"
|
|
66
72
|
PARTIAL = "PARTIAL"
|
|
@@ -371,6 +377,9 @@ class StageObservation:
|
|
|
371
377
|
last_recv_wall: Optional[float] = None
|
|
372
378
|
last_delay_s: Optional[float] = None
|
|
373
379
|
last_raw_delay_s: Optional[float] = None
|
|
380
|
+
#: Payload of the last message, for the scalar topics this node reads as
|
|
381
|
+
#: numbers rather than observes as stages (the pacing hold).
|
|
382
|
+
last_value: Optional[float] = None
|
|
374
383
|
last_rtt_s: Optional[float] = None
|
|
375
384
|
last_clock_offset_s: Optional[float] = None
|
|
376
385
|
# (t_mono, size_bytes, delay_s_or_None)
|
|
@@ -673,6 +682,21 @@ class StatusAggregator:
|
|
|
673
682
|
self._startup_pending: Optional[Tuple[float, set]] = None
|
|
674
683
|
|
|
675
684
|
# -- observation lookup --
|
|
685
|
+
def _pacing_hold_ms(self, stage: Dict[str, Any]) -> Optional[float]:
|
|
686
|
+
"""How long this session deliberately held the last message of a stage.
|
|
687
|
+
|
|
688
|
+
None whenever the answer is not actually known -- no pacer named, or the
|
|
689
|
+
pacer has not reported yet. Guessing zero would read a paced picture as
|
|
690
|
+
a slow link; guessing the configured budget would do the opposite and
|
|
691
|
+
credit a hold that a late message never received.
|
|
692
|
+
"""
|
|
693
|
+
hold_topic = stage.get(PACED_HOLD_KEY)
|
|
694
|
+
if not hold_topic:
|
|
695
|
+
return None
|
|
696
|
+
observer = self._observers.get("local")
|
|
697
|
+
observation = observer.observations.get(str(hold_topic)) if observer else None
|
|
698
|
+
return None if observation is None else observation.last_value
|
|
699
|
+
|
|
676
700
|
def _obs_for(self, stage: Dict[str, Any]) -> Optional[StageObservation]:
|
|
677
701
|
domain = stage.get("domain", "local")
|
|
678
702
|
observer = self._observers.get(domain) or self._observers.get("local")
|
|
@@ -714,6 +738,9 @@ class StatusAggregator:
|
|
|
714
738
|
"observation": "graph" if obs is not None and obs.graph_only else "payload",
|
|
715
739
|
"inferred_from": None,
|
|
716
740
|
"latched": str((expect or {}).get("mode", "")).strip().lower() == "latched",
|
|
741
|
+
# Split of `latency_ms` for a stage this session delays on purpose.
|
|
742
|
+
"pacing_hold_ms": None,
|
|
743
|
+
"link_latency_ms": None,
|
|
717
744
|
}
|
|
718
745
|
if obs is None:
|
|
719
746
|
return result
|
|
@@ -727,6 +754,10 @@ class StatusAggregator:
|
|
|
727
754
|
result["age_s"] = round(m["age_s"], 3) if m["age_s"] is not None else None
|
|
728
755
|
if m["last_delay_s"] is not None:
|
|
729
756
|
result["latency_ms"] = round(m["last_delay_s"] * 1000.0, 1)
|
|
757
|
+
hold_ms = self._pacing_hold_ms(stage)
|
|
758
|
+
if hold_ms is not None:
|
|
759
|
+
result["pacing_hold_ms"] = round(hold_ms, 1)
|
|
760
|
+
result["link_latency_ms"] = round(max(0.0, result["latency_ms"] - hold_ms), 1)
|
|
730
761
|
if m["last_raw_delay_s"] is not None:
|
|
731
762
|
result["latency_uncorrected_ms"] = round(m["last_raw_delay_s"] * 1000.0, 1)
|
|
732
763
|
if m["last_rtt_s"] is not None:
|
|
@@ -759,7 +790,9 @@ class StatusAggregator:
|
|
|
759
790
|
return result
|
|
760
791
|
|
|
761
792
|
result["state"] = FLOWING
|
|
762
|
-
quality, reason = self._classify_quality(
|
|
793
|
+
quality, reason = self._classify_quality(
|
|
794
|
+
m, expected_hz, expect, pacing_hold_ms=result["pacing_hold_ms"]
|
|
795
|
+
)
|
|
763
796
|
result["quality"] = quality
|
|
764
797
|
result["quality_reason"] = reason
|
|
765
798
|
return result
|
|
@@ -823,7 +856,12 @@ class StatusAggregator:
|
|
|
823
856
|
self._copy_inferred_activity(stage_result, source)
|
|
824
857
|
|
|
825
858
|
def _classify_quality(
|
|
826
|
-
self,
|
|
859
|
+
self,
|
|
860
|
+
m: Dict[str, Any],
|
|
861
|
+
expected_hz: Optional[float],
|
|
862
|
+
expect: Optional[Dict[str, Any]] = None,
|
|
863
|
+
*,
|
|
864
|
+
pacing_hold_ms: Optional[float] = None,
|
|
827
865
|
) -> Tuple[str, Optional[str]]:
|
|
828
866
|
expect = expect or {}
|
|
829
867
|
hz_exp = expect.get("hz") or {}
|
|
@@ -833,8 +871,17 @@ class StatusAggregator:
|
|
|
833
871
|
# Latency: a declared `expect.latency_ms.max` overrides the global bad
|
|
834
872
|
# threshold; the good band stays the default so a tight contract still
|
|
835
873
|
# surfaces a DEGRADED before BAD where it makes sense.
|
|
874
|
+
#
|
|
875
|
+
# A stage the session delays on purpose is judged on what is left after
|
|
876
|
+
# that delay is taken back out. Otherwise a threshold calibrated for a
|
|
877
|
+
# link measures a buffer, which reads as a fault on a healthy stream and
|
|
878
|
+
# teaches an operator to stop believing the panel. The subtracted value
|
|
879
|
+
# is the hold actually applied, so a late message -- which the pacer
|
|
880
|
+
# passes straight through -- is credited nothing and still flags.
|
|
836
881
|
bad_lat = float(lat_exp["max"]) if "max" in lat_exp else self._delay_bad_ms
|
|
837
882
|
delay_ms = (m["last_delay_s"] * 1000.0) if m["last_delay_s"] is not None else None
|
|
883
|
+
if delay_ms is not None and pacing_hold_ms is not None:
|
|
884
|
+
delay_ms = max(0.0, delay_ms - pacing_hold_ms)
|
|
838
885
|
if delay_ms is not None:
|
|
839
886
|
if delay_ms >= bad_lat:
|
|
840
887
|
return BAD, "latency"
|
|
@@ -1142,7 +1189,16 @@ class StatusAggregator:
|
|
|
1142
1189
|
if st["state"] in (FLOWING, STALE):
|
|
1143
1190
|
parts = [f"{st['hz']:.1f}Hz"]
|
|
1144
1191
|
if st["latency_ms"] is not None:
|
|
1145
|
-
|
|
1192
|
+
# A paced stage reads as one big number unless the split
|
|
1193
|
+
# is on the same line: what the link cost, and what this
|
|
1194
|
+
# session chose to add on top of it.
|
|
1195
|
+
if st.get("pacing_hold_ms") is not None:
|
|
1196
|
+
parts.append(
|
|
1197
|
+
f"{st['latency_ms']:.0f}ms"
|
|
1198
|
+
f"(link {st['link_latency_ms']:.0f}+paced {st['pacing_hold_ms']:.0f})"
|
|
1199
|
+
)
|
|
1200
|
+
else:
|
|
1201
|
+
parts.append(f"{st['latency_ms']:.0f}ms")
|
|
1146
1202
|
elif st["latency_uncorrected_ms"] is not None:
|
|
1147
1203
|
parts.append(f"{st['latency_uncorrected_ms']:.0f}ms(raw)")
|
|
1148
1204
|
if st["loss_pct"] is not None:
|
|
@@ -1298,7 +1354,12 @@ class StatusAggregator:
|
|
|
1298
1354
|
|
|
1299
1355
|
|
|
1300
1356
|
def collect_stage_topics(spec: Dict[str, Any]) -> Dict[str, Dict[str, Optional[str]]]:
|
|
1301
|
-
"""Return {domain: {topic: type_hint}} from the pipeline spec.
|
|
1357
|
+
"""Return {domain: {topic: type_hint}} from the pipeline spec.
|
|
1358
|
+
|
|
1359
|
+
Includes the pacing-hold topics a stage names: they are not stages of the
|
|
1360
|
+
link -- nothing is delivered on them -- but the aggregator has to read them
|
|
1361
|
+
to tell this session's deliberate delay from the network's.
|
|
1362
|
+
"""
|
|
1302
1363
|
by_domain: Dict[str, Dict[str, Optional[str]]] = {"local": {}, "ota": {}}
|
|
1303
1364
|
for topic_spec in spec.get("topics", []):
|
|
1304
1365
|
type_hint = topic_spec.get("type")
|
|
@@ -1307,6 +1368,9 @@ def collect_stage_topics(spec: Dict[str, Any]) -> Dict[str, Dict[str, Optional[s
|
|
|
1307
1368
|
by_domain.setdefault(domain, {})
|
|
1308
1369
|
existing = by_domain[domain].get(stage["topic"])
|
|
1309
1370
|
by_domain[domain][stage["topic"]] = existing or stage.get("type") or type_hint
|
|
1371
|
+
hold_topic = stage.get(PACED_HOLD_KEY)
|
|
1372
|
+
if hold_topic:
|
|
1373
|
+
by_domain["local"].setdefault(str(hold_topic), SCALAR_MSG_TYPE)
|
|
1310
1374
|
return by_domain
|
|
1311
1375
|
|
|
1312
1376
|
|
|
@@ -1666,17 +1666,23 @@ def _build_status_pipeline_spec(
|
|
|
1666
1666
|
if postprocessed != final:
|
|
1667
1667
|
native_in_type = base_type
|
|
1668
1668
|
transport = p.get("transport")
|
|
1669
|
+
native_in: Dict[str, Any] = {
|
|
1670
|
+
"stage": "native_in",
|
|
1671
|
+
"topic": _relay_in_local_topic(postprocessed),
|
|
1672
|
+
"type": native_in_type,
|
|
1673
|
+
"domain": "local",
|
|
1674
|
+
"produced_by": "postprocessing",
|
|
1675
|
+
}
|
|
1669
1676
|
if isinstance(transport, TransportSpec) and transport.remote_republish:
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
"
|
|
1677
|
-
"
|
|
1678
|
-
|
|
1679
|
-
)
|
|
1677
|
+
native_in["type"] = REPUBLISH_OUTPUT_TYPES[transport.remote_republish]
|
|
1678
|
+
if transport.playout is not None and playout_republish(transport.playout) != "unpaced":
|
|
1679
|
+
# This stage's age is the link plus a hold this session
|
|
1680
|
+
# asked for. The pacer reports the hold it applied; naming
|
|
1681
|
+
# the topic here is what lets the status separate the two
|
|
1682
|
+
# instead of reading a deliberate buffer as a fault.
|
|
1683
|
+
paced = _relay_in_local_topic(str(p.get("irt_in"))) + "/paced"
|
|
1684
|
+
native_in["paced_hold_topic"] = f"{paced}/hold_ms"
|
|
1685
|
+
stages.append(native_in)
|
|
1680
1686
|
|
|
1681
1687
|
topics.append(
|
|
1682
1688
|
{
|
|
@@ -265,10 +265,19 @@ def _check_expect(
|
|
|
265
265
|
failures.append(f"[{peer}] {base}: latency_ms.stage '{stage_name}' not in pipeline")
|
|
266
266
|
return failures
|
|
267
267
|
lat_stage = named
|
|
268
|
-
|
|
268
|
+
# A stage the session delays on purpose reports the split, and `expect` is
|
|
269
|
+
# about what the *link* delivers -- the buffer is already bounded by the
|
|
270
|
+
# `playout` block that asked for it. The live status classifies on the same
|
|
271
|
+
# number, and the two must not disagree about one contract: that is how a
|
|
272
|
+
# session ends up passing `rosotacom test` while its own panel reads BAD.
|
|
273
|
+
lat = lat_stage.get("link_latency_ms")
|
|
274
|
+
measured = "link latency"
|
|
275
|
+
if lat is None:
|
|
276
|
+
lat = lat_stage.get("latency_ms")
|
|
277
|
+
measured = "latency"
|
|
269
278
|
if "max" in lat_exp and (lat is None or lat > lat_exp["max"]):
|
|
270
279
|
where = f" at '{stage_name}'" if stage_name else ""
|
|
271
|
-
failures.append(f"[{peer}] {base}:
|
|
280
|
+
failures.append(f"[{peer}] {base}: {measured} {lat}ms{where} > expected max {lat_exp['max']}ms")
|
|
272
281
|
|
|
273
282
|
loss_exp = expect.get("loss_pct") or {}
|
|
274
283
|
if "max" in loss_exp:
|
|
@@ -218,7 +218,7 @@ def touches(params: dict, peer_dir: Path) -> Touches:
|
|
|
218
218
|
for index in _slots(params, "pace_{}_topic", limit=4):
|
|
219
219
|
topic = _one(params, f"pace_{index}_topic")
|
|
220
220
|
result.through(str(topic), f"{topic}/paced")
|
|
221
|
-
result.writes.update({f"{topic}/paced/budget_ms", f"{topic}/paced/queue_depth"})
|
|
221
|
+
result.writes.update({f"{topic}/paced/budget_ms", f"{topic}/paced/queue_depth", f"{topic}/paced/hold_ms"})
|
|
222
222
|
|
|
223
223
|
# NOR: relays a prefixed, suffixed name back onto the bare base, so a local
|
|
224
224
|
# consumer (a TF tree) finds the name it expects.
|
|
@@ -245,14 +245,35 @@ def touches(params: dict, peer_dir: Path) -> Touches:
|
|
|
245
245
|
|
|
246
246
|
# Observability: reads only, never republishes.
|
|
247
247
|
result.reads.update(_many(params, "metric_stage_topics"))
|
|
248
|
+
# STAT: the status overview reads the pacing hold a stage names, to tell
|
|
249
|
+
# this session's deliberate delay from the network's. It is configured out
|
|
250
|
+
# of the pipeline spec rather than out of these parameters, but it is a read
|
|
251
|
+
# by a node this peer starts, so it belongs here -- a hold topic no pacer
|
|
252
|
+
# publishes would leave the status silently subtracting nothing.
|
|
253
|
+
result.reads.update(paced_hold_topics(peer_dir))
|
|
248
254
|
|
|
249
255
|
return result
|
|
250
256
|
|
|
251
257
|
|
|
258
|
+
def _spec(peer_dir: Path) -> dict:
|
|
259
|
+
path = peer_dir / "pipeline_spec.yaml"
|
|
260
|
+
if not path.is_file():
|
|
261
|
+
return {}
|
|
262
|
+
return yaml.safe_load(path.read_text(encoding="utf-8")) or {}
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
def _stages(peer_dir: Path) -> Iterator[dict]:
|
|
266
|
+
for topic in _spec(peer_dir).get("topics", []):
|
|
267
|
+
yield from topic.get("stages", [])
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
def paced_hold_topics(peer_dir: Path) -> set[str]:
|
|
271
|
+
return {stage["paced_hold_topic"] for stage in _stages(peer_dir) if stage.get("paced_hold_topic")}
|
|
272
|
+
|
|
273
|
+
|
|
252
274
|
def spec_topics(peer_dir: Path) -> set[str]:
|
|
253
275
|
"""Every topic this peer's pipeline spec models, at any stage."""
|
|
254
|
-
|
|
255
|
-
return {stage["topic"] for topic in spec.get("topics", []) for stage in topic.get("stages", [])}
|
|
276
|
+
return {stage["topic"] for stage in _stages(peer_dir)}
|
|
256
277
|
|
|
257
278
|
|
|
258
279
|
# ---------------------------------------------------------------------------
|
|
@@ -352,7 +373,12 @@ def test_the_composed_names_are_the_ones_the_template_composes() -> None:
|
|
|
352
373
|
# reads that name, and `touches` claims those two writes, so all three have
|
|
353
374
|
# to agree -- they are three files apart and nothing else compares them.
|
|
354
375
|
pacer = PACER_PY.read_text(encoding="utf-8")
|
|
355
|
-
for composed in (
|
|
376
|
+
for composed in (
|
|
377
|
+
'declare_parameter("topic_suffix", "/paced")',
|
|
378
|
+
'+ "/budget_ms"',
|
|
379
|
+
'+ "/queue_depth"',
|
|
380
|
+
'+ "/hold_ms"',
|
|
381
|
+
):
|
|
356
382
|
assert composed in pacer, f"the pacer no longer composes {composed}"
|
|
357
383
|
|
|
358
384
|
|
|
@@ -79,3 +79,35 @@ def test_config_validation() -> None:
|
|
|
79
79
|
PacerConfig(min_ms=500.0, max_ms=100.0)
|
|
80
80
|
with pytest.raises(ValueError):
|
|
81
81
|
PacerConfig(window=3)
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
# The hold the node reports (#301).
|
|
85
|
+
#
|
|
86
|
+
# `.../paced/hold_ms` carries what this node actually added, so the status
|
|
87
|
+
# overview can take it back out of a decoded stage's age and judge what is left
|
|
88
|
+
# -- the link. The node computes `max(0, release - arrival)`; both halves of
|
|
89
|
+
# that clamp are properties of the schedule, so they are asserted here rather
|
|
90
|
+
# than in three lines of publishing glue.
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def _hold_ms(schedule: PlayoutSchedule, stamp: float, arrival: float) -> float:
|
|
94
|
+
"""What the node publishes for a message: the delay it applied, never negative."""
|
|
95
|
+
return max(0.0, (schedule.on_message(stamp, arrival) - arrival) * 1000.0)
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def test_the_reported_hold_is_what_was_added_not_what_was_allowed() -> None:
|
|
99
|
+
schedule = PlayoutSchedule(PacerConfig(adaptive=False, target_ms=200.0))
|
|
100
|
+
# First message sets the floor at its own delay, so it is released at
|
|
101
|
+
# floor + 200 ms and waits exactly the budget.
|
|
102
|
+
assert _hold_ms(schedule, 0.0, 0.030) == pytest.approx(200.0, abs=1.0)
|
|
103
|
+
# One that arrives 150 ms later than the floor has already spent 150 of the
|
|
104
|
+
# budget on the wire and waits only the remainder.
|
|
105
|
+
assert _hold_ms(schedule, 1.0, 1.180) == pytest.approx(50.0, abs=1.0)
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def test_a_late_message_is_reported_as_held_for_nothing() -> None:
|
|
109
|
+
"""The clamp: a pass-through must not be credited with a buffer it skipped."""
|
|
110
|
+
schedule = PlayoutSchedule(PacerConfig(adaptive=False, target_ms=200.0))
|
|
111
|
+
_hold_ms(schedule, 0.0, 0.030)
|
|
112
|
+
|
|
113
|
+
assert _hold_ms(schedule, 1.0, 1.400) == 0.0
|
|
@@ -394,3 +394,54 @@ def test_every_mode_delivers_the_same_topic_name(tmp_path: Path) -> None:
|
|
|
394
394
|
delivered.add(generator._delivered_topic(unpaced_link, unpaced_link["final"]))
|
|
395
395
|
|
|
396
396
|
assert len(delivered) == 1, delivered
|
|
397
|
+
|
|
398
|
+
|
|
399
|
+
# The status has to be told which pacer belongs to which stage (#301).
|
|
400
|
+
#
|
|
401
|
+
# A decoded stage's age is the link plus a hold this session asked for, and the
|
|
402
|
+
# status overview cannot tell them apart by looking at one number. The generator
|
|
403
|
+
# knows both nodes, so it names the pacer's report on the stage it explains --
|
|
404
|
+
# rather than the status guessing from a topic-name convention.
|
|
405
|
+
|
|
406
|
+
|
|
407
|
+
def _native_in(receiver: str) -> dict:
|
|
408
|
+
spec = yaml.safe_load(receiver)
|
|
409
|
+
for topic in spec["topics"]:
|
|
410
|
+
if topic["direction"] == "inbound":
|
|
411
|
+
for stage in topic["stages"]:
|
|
412
|
+
if stage["stage"] == "native_in":
|
|
413
|
+
return stage
|
|
414
|
+
raise AssertionError("no inbound native_in stage")
|
|
415
|
+
|
|
416
|
+
|
|
417
|
+
def _receiver_spec(tmp_path: Path, playout: dict | None) -> str:
|
|
418
|
+
transport: dict = {"type": "ffmpeg", "remote_republish": "compressed"}
|
|
419
|
+
if playout is not None:
|
|
420
|
+
transport["playout"] = playout
|
|
421
|
+
generator.func(
|
|
422
|
+
session_config_obj=_camera_cfg({"transport": transport, "use_ota_wrapper": True}),
|
|
423
|
+
output_dir=str(tmp_path),
|
|
424
|
+
force=True,
|
|
425
|
+
peer_addresses={"a": "127.0.0.1", "b": "127.0.0.2"},
|
|
426
|
+
)
|
|
427
|
+
return (tmp_path / "a" / "pipeline_spec.yaml").read_text(encoding="utf-8")
|
|
428
|
+
|
|
429
|
+
|
|
430
|
+
def test_a_paced_decode_names_the_pacer_that_explains_its_age(tmp_path: Path) -> None:
|
|
431
|
+
stage = _native_in(_receiver_spec(tmp_path, {"adaptive": True, "max_ms": 300}))
|
|
432
|
+
|
|
433
|
+
assert stage["paced_hold_topic"] == "/camera/image/ffmpeg/paced/hold_ms"
|
|
434
|
+
|
|
435
|
+
|
|
436
|
+
def test_an_unpaced_link_names_no_pacer(tmp_path: Path) -> None:
|
|
437
|
+
"""Nothing holds this stream, so nothing may be subtracted from its age."""
|
|
438
|
+
stage = _native_in(_receiver_spec(tmp_path, None))
|
|
439
|
+
|
|
440
|
+
assert "paced_hold_topic" not in stage
|
|
441
|
+
|
|
442
|
+
|
|
443
|
+
def test_a_pacer_kept_off_the_display_path_explains_nothing(tmp_path: Path) -> None:
|
|
444
|
+
"""`republish: unpaced` decodes the arrived stream; its age is all link."""
|
|
445
|
+
stage = _native_in(_receiver_spec(tmp_path, {"adaptive": True, "republish": "unpaced"}))
|
|
446
|
+
|
|
447
|
+
assert "paced_hold_topic" not in stage
|
|
@@ -531,3 +531,44 @@ def test_suggest_profile_band_nests_conditional_keys_under_per_profile() -> None
|
|
|
531
531
|
entry = band["/heartbeat_a"]["per_profile"]["cellular"]
|
|
532
532
|
assert "hz" in entry and "latency_ms" in entry # conditional keys only
|
|
533
533
|
assert "presence" not in entry and "mode" not in entry # invariant stays top-level
|
|
534
|
+
|
|
535
|
+
|
|
536
|
+
# A contract about a stage the session delays on purpose (#301).
|
|
537
|
+
#
|
|
538
|
+
# `status_overview` classifies such a stage on what is left after the pacer's
|
|
539
|
+
# own hold is taken back out. This evaluator has to measure the same thing, or a
|
|
540
|
+
# session passes `rosotacom test` while its own panel reads BAD -- one contract,
|
|
541
|
+
# two answers, which is worse than either answer alone.
|
|
542
|
+
|
|
543
|
+
|
|
544
|
+
def _paced_report(latency_ms: float, link_latency_ms: float | None) -> dict:
|
|
545
|
+
stage = _stage("native_in", 10.0, latency_ms)
|
|
546
|
+
if link_latency_ms is not None:
|
|
547
|
+
stage["link_latency_ms"] = link_latency_ms
|
|
548
|
+
stage["pacing_hold_ms"] = latency_ms - link_latency_ms
|
|
549
|
+
return {"peer": "a", "topics": [_topic("/camera", "inbound", "OK", [stage])]}
|
|
550
|
+
|
|
551
|
+
|
|
552
|
+
def test_a_paced_stage_is_asserted_on_the_link_not_the_buffer() -> None:
|
|
553
|
+
"""286 ms on screen, 46 of them the link's: a 200 ms link contract holds."""
|
|
554
|
+
report = _paced_report(latency_ms=286.0, link_latency_ms=46.0)
|
|
555
|
+
|
|
556
|
+
assert evaluate_report(report, {"/camera": {"latency_ms": {"max": 200}}}) == []
|
|
557
|
+
|
|
558
|
+
|
|
559
|
+
def test_a_slow_link_under_a_pacer_still_fails() -> None:
|
|
560
|
+
report = _paced_report(latency_ms=480.0, link_latency_ms=480.0)
|
|
561
|
+
|
|
562
|
+
failures = evaluate_report(report, {"/camera": {"latency_ms": {"max": 200}}})
|
|
563
|
+
|
|
564
|
+
assert len(failures) == 1
|
|
565
|
+
assert "link latency 480.0ms" in failures[0]
|
|
566
|
+
|
|
567
|
+
|
|
568
|
+
def test_an_unpaced_stage_is_asserted_on_what_it_always_was() -> None:
|
|
569
|
+
report = _paced_report(latency_ms=286.0, link_latency_ms=None)
|
|
570
|
+
|
|
571
|
+
failures = evaluate_report(report, {"/camera": {"latency_ms": {"max": 200}}})
|
|
572
|
+
|
|
573
|
+
assert len(failures) == 1
|
|
574
|
+
assert "latency 286.0ms" in failures[0]
|