feat: multi-ECU aggregation demo with static peer and mDNS discovery#56
feat: multi-ECU aggregation demo with static peer and mDNS discovery#56
Conversation
Perception ECU: lidar_driver, camera_driver, point_cloud_filter, object_detector Planning ECU: path_planner, behavior_planner, task_scheduler Actuation ECU: motor_controller, joint_driver, gripper_controller All nodes follow sensor_diagnostics pattern with parameter-based fault injection and /diagnostics publishing.
3x params (perception/planning/actuation with gateway + fault_manager config) 3x manifests (robot-alpha parent component, 3 sub-components, 3 cross-ECU functions) 2x domain_bridge (planning bridges /perception/detections, actuation bridges /planning/commands)
Each launch file starts ECU-specific nodes + gateway + fault_manager + diagnostic_bridge. Planning and actuation include domain_bridge for cross-domain topic bridging.
Single image (ros:jazzy-ros-base), ECU_LAUNCH env var selects launch file. 3 ECU services with isolated ROS_DOMAIN_ID (10/20/30) + web UI.
Host-side: run-demo, stop-demo, 4 inject scripts, restore-normal Container: Scripts API auto-discovery per ECU component (inject + restore)
Gateway runs in /diagnostics namespace, not /perception|planning|actuation. Params were under wrong top-level key, causing gateway to use defaults (127.0.0.1, runtime_only, aggregation disabled).
…nodes - Actuation ECU needs aggregation.enabled=true for mDNS announce to work (the aggregation subsystem must be active for announce/discover flags) - Changed unmanifested_nodes from warn to hide in all 3 manifests to filter infrastructure nodes (diagnostic_bridge, fault_manager, etc.)
…es ignore - Added medkit-gateway, medkit-fault-manager, medkit-diagnostic-bridge as manifest apps on each ECU sub-component - Changed unmanifested_nodes from hide to ignore (correct enum value) - Gateway infra nodes now appear per-ECU instead of polluting as orphans
There was a problem hiding this comment.
Pull request overview
Adds a new headless Docker-based demo (demos/multi_ecu_aggregation/) that showcases ros2_medkit multi-instance peer aggregation across three simulated ECUs (perception/planning/actuation), including static peer configuration, mDNS discovery, DDS isolation via ROS_DOMAIN_ID, domain bridging, and fault-injection scripts.
Changes:
- Introduces a new ROS 2 package (
multi_ecu_demo) with simulated Perception/Planning/Actuation nodes that publish data and/diagnostics. - Adds Docker + Compose orchestration and host/container scripts for running the demo and injecting/restoring faults.
- Adds gateway configs/manifests and domain_bridge configs to demonstrate cross-ECU aggregation and topic bridging.
Reviewed changes
Copilot reviewed 45 out of 46 changed files in this pull request and generated 16 comments.
Show a summary per file
| File | Description |
|---|---|
| demos/multi_ecu_aggregation/stop-demo.sh | Stops the demo stack with optional cleanup flags. |
| demos/multi_ecu_aggregation/src/planning/task_scheduler.cpp | Planning ECU task-state publisher + diagnostics + fault injection. |
| demos/multi_ecu_aggregation/src/planning/path_planner.cpp | Planning ECU path generator reacting to detections + diagnostics. |
| demos/multi_ecu_aggregation/src/planning/behavior_planner.cpp | Planning ECU command generator from planned path + diagnostics. |
| demos/multi_ecu_aggregation/src/perception/point_cloud_filter.cpp | Perception ECU LaserScan→PointCloud2 converter/filter + diagnostics. |
| demos/multi_ecu_aggregation/src/perception/object_detector.cpp | Perception ECU fake detector driven by timer + point cloud freshness tracking. |
| demos/multi_ecu_aggregation/src/perception/lidar_driver.cpp | Perception ECU simulated LaserScan publisher + fault injection. |
| demos/multi_ecu_aggregation/src/perception/camera_driver.cpp | Perception ECU simulated Image publisher + fault injection. |
| demos/multi_ecu_aggregation/src/actuation/motor_controller.cpp | Actuation ECU Twist→JointState publisher + diagnostics + fault injection. |
| demos/multi_ecu_aggregation/src/actuation/joint_driver.cpp | Actuation ECU JointState integrator publishing joint_state + diagnostics. |
| demos/multi_ecu_aggregation/src/actuation/gripper_controller.cpp | Actuation ECU Twist→gripper JointState + diagnostics + fault injection. |
| demos/multi_ecu_aggregation/run-demo.sh | Builds/starts the demo stack with optional update/no-cache/attached mode. |
| demos/multi_ecu_aggregation/restore-normal.sh | Host-side helper to call “restore-normal” scripts on all ECUs via Scripts API. |
| demos/multi_ecu_aggregation/README.md | Full demo documentation: architecture, discovery, APIs, scripts, troubleshooting. |
| demos/multi_ecu_aggregation/package.xml | Declares the multi_ecu_demo ROS 2 package and dependencies. |
| demos/multi_ecu_aggregation/launch/planning.launch.py | Launches Planning ECU nodes + gateway + fault_manager + bridge. |
| demos/multi_ecu_aggregation/launch/perception.launch.py | Launches Perception ECU nodes + gateway (aggregation enabled) + fault_manager. |
| demos/multi_ecu_aggregation/launch/actuation.launch.py | Launches Actuation ECU nodes + gateway (mDNS announce) + fault_manager + bridge. |
| demos/multi_ecu_aggregation/inject-sensor-failure.sh | Host script to trigger perception ECU fault injection via Scripts API. |
| demos/multi_ecu_aggregation/inject-planning-delay.sh | Host script to trigger planning ECU delay injection via Scripts API. |
| demos/multi_ecu_aggregation/inject-gripper-jam.sh | Host script to trigger actuation ECU gripper jam via Scripts API. |
| demos/multi_ecu_aggregation/inject-cascade-failure.sh | Host script to trigger a multi-ECU fault scenario via Scripts API. |
| demos/multi_ecu_aggregation/Dockerfile | Builds a self-contained demo image (ROS 2 + ros2_medkit + demo package). |
| demos/multi_ecu_aggregation/docker-compose.yml | Defines 3 ECU services + web UI on a shared bridge network. |
| demos/multi_ecu_aggregation/container_scripts/planning-ecu/restore-normal/script.bash | In-container restore script (planning). |
| demos/multi_ecu_aggregation/container_scripts/planning-ecu/restore-normal/metadata.json | Scripts API metadata (planning restore). |
| demos/multi_ecu_aggregation/container_scripts/planning-ecu/inject-planning-delay/script.bash | In-container injection script (planning delay). |
| demos/multi_ecu_aggregation/container_scripts/planning-ecu/inject-planning-delay/metadata.json | Scripts API metadata (planning delay). |
| demos/multi_ecu_aggregation/container_scripts/perception-ecu/restore-normal/script.bash | In-container restore script (perception). |
| demos/multi_ecu_aggregation/container_scripts/perception-ecu/restore-normal/metadata.json | Scripts API metadata (perception restore). |
| demos/multi_ecu_aggregation/container_scripts/perception-ecu/inject-sensor-failure/script.bash | In-container injection script (lidar failure). |
| demos/multi_ecu_aggregation/container_scripts/perception-ecu/inject-sensor-failure/metadata.json | Scripts API metadata (lidar failure). |
| demos/multi_ecu_aggregation/container_scripts/actuation-ecu/restore-normal/script.bash | In-container restore script (actuation). |
| demos/multi_ecu_aggregation/container_scripts/actuation-ecu/restore-normal/metadata.json | Scripts API metadata (actuation restore). |
| demos/multi_ecu_aggregation/container_scripts/actuation-ecu/inject-gripper-jam/script.bash | In-container injection script (gripper jam). |
| demos/multi_ecu_aggregation/container_scripts/actuation-ecu/inject-gripper-jam/metadata.json | Scripts API metadata (gripper jam). |
| demos/multi_ecu_aggregation/config/planning_params.yaml | Planning ECU gateway/node/fault_manager params. |
| demos/multi_ecu_aggregation/config/planning_manifest.yaml | Planning ECU SOVD manifest (components/apps/functions). |
| demos/multi_ecu_aggregation/config/perception_params.yaml | Perception ECU gateway params (aggregation + discover + static peer URL). |
| demos/multi_ecu_aggregation/config/perception_manifest.yaml | Perception ECU SOVD manifest. |
| demos/multi_ecu_aggregation/config/domain_bridge/planning_bridge.yaml | Domain bridge config: detections 10→20. |
| demos/multi_ecu_aggregation/config/domain_bridge/actuation_bridge.yaml | Domain bridge config: commands 20→30. |
| demos/multi_ecu_aggregation/config/actuation_params.yaml | Actuation ECU gateway/node/fault_manager params (mDNS announce). |
| demos/multi_ecu_aggregation/config/actuation_manifest.yaml | Actuation ECU SOVD manifest. |
| demos/multi_ecu_aggregation/CMakeLists.txt | Builds/installs all demo nodes and launch/config resources. |
| .gitignore | Adds an ignore entry under the demo launch directory. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
demos/multi_ecu_aggregation/container_scripts/perception-ecu/restore-normal/script.bash
Show resolved
Hide resolved
demos/multi_ecu_aggregation/container_scripts/perception-ecu/inject-sensor-failure/script.bash
Show resolved
Hide resolved
demos/multi_ecu_aggregation/container_scripts/planning-ecu/restore-normal/script.bash
Show resolved
Hide resolved
demos/multi_ecu_aggregation/container_scripts/planning-ecu/inject-planning-delay/script.bash
Show resolved
Hide resolved
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 45 out of 46 changed files in this pull request and generated 6 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…creation - Add shellcheck source=/dev/null directives to all container scripts - Add shellcheck disable=SC2086 for remaining COMPOSE_CMD usages - Fix clock type mismatch in object_detector (RCL_ROS_TIME -> RCL_SYSTEM_TIME) - Fix config comment in actuation_params.yaml (aggregation is enabled) - Recreate wall timer on rate parameter change in all demo nodes, consistent with the pattern already used in object_detector
…r and joint_driver
…gs dep for path_planner
…demo Code quality: - Fix copyright headers to SPDX format in all 10 source files - Fix namespace inconsistency: actuation files now use multi_ecu_demo - Add blocking sleep comments in path_planner and point_cloud_filter - Fix inject-cascade-failure.sh header comment (wrong parameters) - Use error counter pattern in inject-cascade-failure.sh Infrastructure: - Add check-demo.sh readiness script (polls health, shows entity counts) - Add smoke test (tests/smoke_test_multi_ecu.sh) using smoke_lib.sh - Add CI profile services to docker-compose.yml (headless, no web UI) - Add build-and-test-multi-ecu job to CI workflow - Share Docker image across ECU services (multi-ecu-demo:local) UX/correctness: - Add fault-clearing curl calls to all 3 restore scripts - Add gateway reachability check to host-side injection scripts - Use demo-specific container_name for web UI (multi_ecu_web_ui) - Quote ECU_LAUNCH in Dockerfile CMD - Update top-level README with new demo entry
…s in smoke test - Replace hyphens with underscores in domain_bridge YAML node names (ROS 2 node names only allow alphanumerics and underscores) - Make peer ECU component checks non-fatal in smoke test since component aggregation depends on gateway version
ECU components (perception-ecu, planning-ecu, actuation-ecu) have parent_component_id=robot-alpha, so they appear under /components/robot-alpha/subcomponents, not /components.
Description
New headless Docker demo showcasing multi-instance peer aggregation from ros2_medkit#327. Three containers simulate three ECUs of a robotics system (perception/planning/actuation), each running its own gateway + fault_manager. Perception ECU acts as the primary aggregator.
Key features demonstrated:
robot-alphawith 3 sub-components (one per ECU)Verified with:
Related Issue
Depends on ros2_medkit#327 (feat/entity-model-and-aggregation branch)
Before merge
ROS2_MEDKIT_REFin Dockerfile fromfeat/entity-model-and-aggregationtomainafter ros2_medkit#327 is mergedChecklist