-
Notifications
You must be signed in to change notification settings - Fork 1
feat(turtlebot3): Complete demo with manifest discovery, fault management and GUI as default #17
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
…ment and GUI as default Major improvements to TurtleBot3 integration demo: Core Features: - Add manifest-based entity discovery (SOVD hierarchy: Areas→Components→Apps→Functions) - Implement fault management via diagnostic_bridge + fault_manager - Add SQLite storage for persistent fault tracking - Support conditional headless/GUI Gazebo modes Docker & Launch: - Fix Dockerfile: add ros2_medkit_fault_manager, fault_reporter, diagnostic_bridge packages - Add SQLite dependencies (sqlite3, libsqlite3-dev) - Update launch file: conditional Gazebo launch based on headless argument - Change default mode from headless to GUI for better UX - Add HEADLESS environment variable support in docker-compose.yml Manifest & Configuration: - Add turtlebot3_manifest.yaml defining complete entity hierarchy - Configure 4 areas: robot, navigation, diagnostics, bridge - Define 6 components: turtlebot3-base, lidar-sensor, nav2-stack, gateway, fault-manager, diagnostic-bridge-unit - Define 11 apps with ROS node bindings and dependencies - Define 3 functions: autonomous-navigation, robot-control, fault-management Shell Scripts: - Fix all app IDs: underscore format → hyphen format (bt_navigator → bt-navigator, etc.) - Add check-entities.sh: explore SOVD entity hierarchy - Add check-faults.sh: view active faults - Add inject-nav-failure.sh: trigger unreachable goal scenario - Add inject-localization-failure.sh: reset AMCL with high uncertainty - Add inject-controller-failure.sh: set restrictive velocity limits - Add inject-collision.sh: navigate toward obstacles - Add restore-normal.sh: restore defaults and clear faults - Update send-nav-goal.sh: use SOVD API instead of docker exec Documentation: - Completely rewrite TurtleBot3 demo README with: * Clear GUI vs headless mode instructions * SOVD entity hierarchy explanation * Fault management architecture diagram * Fault injection scenarios table * Complete REST API examples for all endpoints * Scripts reference table Testing: - All scripts verified working with GATEWAY_URL=http://172.19.0.2:8080 - Navigation goals successfully executed via SOVD API - Fault injection scenarios tested - 23 components discovered, 0 initial faults confirmed - GUI and headless modes both tested and working
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR significantly enhances the TurtleBot3 integration demo by adding complete SOVD-compliant entity discovery, fault management capabilities, and improved Docker deployment options with both GUI and headless Gazebo modes.
Changes:
- Implemented manifest-based entity discovery with complete SOVD hierarchy (Areas → Components → Apps → Functions)
- Added fault management system with diagnostic_bridge for legacy /diagnostics topic support and persistent SQLite storage
- Introduced conditional Gazebo launch modes (GUI/headless) with default GUI mode for better user experience
- Created comprehensive fault injection scripts and monitoring tools for testing fault scenarios
- Updated all documentation with REST API examples, entity hierarchy explanations, and fault management architecture
Reviewed changes
Copilot reviewed 16 out of 16 changed files in this pull request and generated 9 comments.
Show a summary per file
| File | Description |
|---|---|
| send-nav-goal.sh | Migrated from docker exec to SOVD API for navigation goals, added robust validation and error handling |
| run-demo.sh | Added --headless flag with environment variable support for conditional Gazebo modes |
| restore-normal.sh | New script to restore default parameters and clear all faults after testing scenarios |
| inject-nav-failure.sh | New fault injection script for unreachable navigation goals |
| inject-localization-failure.sh | New fault injection script triggering AMCL uncertainty via global relocalization |
| inject-controller-failure.sh | New fault injection script setting restrictive velocity limits |
| inject-collision.sh | New fault injection script navigating toward obstacles |
| check-faults.sh | New script to query and display active faults from gateway |
| check-entities.sh | New script to explore complete SOVD entity hierarchy |
| demo.launch.py | Added conditional headless/GUI Gazebo launch, fault_manager and diagnostic_bridge nodes, manifest path configuration |
| turtlebot3_manifest.yaml | New complete SOVD manifest defining 4 areas, 6 components, 11 apps, and 3 functions |
| medkit_params.yaml | Updated with hybrid discovery mode, DELETE method in CORS, and manifest configuration |
| docker-compose.yml | Added HEADLESS environment variable support, switched to pre-built sovd_web_ui image |
| Dockerfile | Added SQLite dependencies and ros2_medkit fault management packages |
| README.md (root) | Expanded overview with SOVD capabilities, added both demo quick starts, included API examples |
| README.md (turtlebot3) | Complete rewrite with GUI/headless instructions, entity hierarchy documentation, fault injection scenarios, comprehensive API reference |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
|
||
| # Stop the robot | ||
| curl -X POST http://localhost:8080/api/v1/topics/publish \ | ||
| curl -X PUT http://localhost:8080/api/v1/apps/turtlebot3_node/data/cmd_vel \ |
Copilot
AI
Jan 29, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The app ID used in the API endpoints is incorrect. The manifest defines the app ID as "turtlebot3-node" (with hyphen), but the documentation uses "turtlebot3_node" (with underscore). This inconsistency will cause API calls to fail.
All references to "apps/turtlebot3_node" should be changed to "apps/turtlebot3-node" to match the manifest definition in config/turtlebot3_manifest.yaml line 83.
| exit 1 | ||
| fi | ||
| echo "✓ Gateway is healthy" | ||
|
|
Copilot
AI
Jan 29, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing dependency check for 'jq'. This script uses jq extensively throughout (lines 34, 37, 40, 43, 47, 56) but doesn't verify it's installed. If jq is not available, the script will fail with unclear error messages.
Add a check similar to the one in send-nav-goal.sh lines 19-22 to verify jq is installed before proceeding.
| # Check for jq dependency | |
| if ! command -v jq >/dev/null 2>&1; then | |
| echo "❌ 'jq' is required but not installed." | |
| echo " Please install jq (e.g., 'sudo apt-get install jq') and retry." | |
| exit 1 | |
| fi |
| echo "❌ Gateway not available at ${GATEWAY_URL}" | ||
| exit 1 | ||
| fi | ||
|
|
Copilot
AI
Jan 29, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing dependency check for 'jq'. This script uses jq on lines 21, 22, and 51 but doesn't verify it's installed. If jq is not available, the script will fail with unclear error messages.
Add a check similar to the one in send-nav-goal.sh lines 19-22 to verify jq is installed before proceeding.
| # Check jq dependency | |
| if ! command -v jq > /dev/null 2>&1; then | |
| echo "❌ Missing dependency: 'jq' is required but not installed." | |
| echo " Please install jq (https://stedolan.github.io/jq/) and try again." | |
| exit 1 | |
| fi |
| depends_on: | ||
| - turtlebot3-demo |
Copilot
AI
Jan 29, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The sovd-web-ui service declares a dependency on "turtlebot3-demo", but when users run with the nvidia profile (docker compose --profile nvidia up), only the "turtlebot3-demo-nvidia" service will start. This means sovd-web-ui won't start in nvidia mode because its dependency won't be satisfied.
Consider either:
- Removing the depends_on clause (the web UI can retry connecting)
- Creating a conditional dependency that works with both service variants
- Using a shared service name with profiles
The simplest fix is to remove the depends_on clause since the web UI can handle the gateway not being immediately available.
| depends_on: | |
| - turtlebot3-demo |
| # Send velocity command (moves robot forward) | ||
| curl -X POST http://localhost:8080/api/v1/topics/publish \ | ||
| # Send velocity command using Apps data endpoint (moves robot forward) | ||
| curl -X PUT http://localhost:8080/api/v1/apps/turtlebot3_node/data/cmd_vel \ |
Copilot
AI
Jan 29, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The app ID used in the API endpoints is incorrect. The manifest defines the app ID as "turtlebot3-node" (with hyphen), but the documentation uses "turtlebot3_node" (with underscore). This inconsistency will cause API calls to fail.
All references to "apps/turtlebot3_node" should be changed to "apps/turtlebot3-node" to match the manifest definition in config/turtlebot3_manifest.yaml line 83.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Copilot seems to be right here :)
| curl http://localhost:8080/api/v1/apps/turtlebot3_node/data/scan | jq '{ | ||
| angle_min: .angle_min, | ||
| angle_max: .angle_max, | ||
| sample_ranges: .ranges[:5] | ||
| }' | ||
|
|
||
| # Get odometry data | ||
| curl http://localhost:8080/api/v1/apps/turtlebot3_node/data/odom | jq '{ | ||
| position: .pose.pose.position, | ||
| orientation: .pose.pose.orientation | ||
| }' | ||
|
|
||
| # List all data topics for an app | ||
| curl http://localhost:8080/api/v1/apps/turtlebot3_node/data | jq |
Copilot
AI
Jan 29, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The app ID used in the API endpoint is incorrect. The manifest defines the app ID as "turtlebot3-node" (with hyphen), but the documentation uses "turtlebot3_node" (with underscore). This inconsistency will cause API calls to fail.
Change "apps/turtlebot3_node" to "apps/turtlebot3-node" to match the manifest definition.
| curl http://localhost:8080/api/v1/apps/turtlebot3_node/data/scan | jq '{ | |
| angle_min: .angle_min, | |
| angle_max: .angle_max, | |
| sample_ranges: .ranges[:5] | |
| }' | |
| # Get odometry data | |
| curl http://localhost:8080/api/v1/apps/turtlebot3_node/data/odom | jq '{ | |
| position: .pose.pose.position, | |
| orientation: .pose.pose.orientation | |
| }' | |
| # List all data topics for an app | |
| curl http://localhost:8080/api/v1/apps/turtlebot3_node/data | jq | |
| curl http://localhost:8080/api/v1/apps/turtlebot3-node/data/scan | jq '{ | |
| angle_min: .angle_min, | |
| angle_max: .angle_max, | |
| sample_ranges: .ranges[:5] | |
| }' | |
| # Get odometry data | |
| curl http://localhost:8080/api/v1/apps/turtlebot3-node/data/odom | jq '{ | |
| position: .pose.pose.position, | |
| orientation: .pose.pose.orientation | |
| }' | |
| # List all data topics for an app | |
| curl http://localhost:8080/api/v1/apps/turtlebot3-node/data | jq |
| #!/bin/bash | ||
| # Check current faults from ros2_medkit gateway | ||
| # Faults are collected from Nav2/TurtleBot3 via diagnostic_bridge | ||
|
|
||
| GATEWAY_URL="${GATEWAY_URL:-http://localhost:8080}" | ||
| API_BASE="${GATEWAY_URL}/api/v1" | ||
|
|
||
| echo "🔍 Checking faults from ros2_medkit gateway..." | ||
| echo "" | ||
|
|
||
| # Wait for gateway | ||
| echo "Checking gateway health..." | ||
| if ! curl -sf "${API_BASE}/health" > /dev/null 2>&1; then | ||
| echo "❌ Gateway not available at ${GATEWAY_URL}" | ||
| echo " Start with: ./run-demo.sh" | ||
| exit 1 | ||
| fi | ||
| echo "✓ Gateway is healthy" | ||
| echo "" | ||
|
|
||
| # Get all faults | ||
| echo "📋 Active Faults:" | ||
| FAULTS=$(curl -s "${API_BASE}/faults") | ||
|
|
||
| # Check if there are any faults | ||
| FAULT_COUNT=$(echo "$FAULTS" | jq '.items | length') |
Copilot
AI
Jan 29, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing dependency check for 'jq'. This script uses jq extensively but doesn't verify it's installed before attempting to use it. If jq is not available, the script will fail with unclear error messages.
Add a check similar to the one in send-nav-goal.sh lines 19-22 to verify jq is installed before proceeding.
| from launch.conditions import IfCondition, UnlessCondition | ||
| from launch.launch_description_sources import PythonLaunchDescriptionSource | ||
| from launch.substitutions import LaunchConfiguration | ||
| from launch.substitutions import LaunchConfiguration, PythonExpression |
Copilot
AI
Jan 29, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unused import. The PythonExpression class is imported but never used in the launch file. This should be removed to keep the imports clean.
| from launch.substitutions import LaunchConfiguration, PythonExpression | |
| from launch.substitutions import LaunchConfiguration |
| # Publish to topic (see examples above) | ||
| curl -X POST http://localhost:8080/api/v1/topics/publish ... | ||
| # Clear a specific fault | ||
| curl -X DELETE http://localhost:8080/api/v1/apps/diagnostic_bridge/faults/TURTLEBOT3_NODE |
Copilot
AI
Jan 29, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The app ID used in the API endpoint is incorrect. The manifest defines the app ID as "diagnostic-bridge" (with hyphen at line 177 of turtlebot3_manifest.yaml), but the documentation uses "diagnostic_bridge" (with underscore). This inconsistency will cause API calls to fail.
Change "apps/diagnostic_bridge" to "apps/diagnostic-bridge" to match the manifest definition.
| curl -X DELETE http://localhost:8080/api/v1/apps/diagnostic_bridge/faults/TURTLEBOT3_NODE | |
| curl -X DELETE http://localhost:8080/api/v1/apps/diagnostic-bridge/faults/TURTLEBOT3_NODE |
| mv ros2_medkit/src/ros2_medkit_gateway \ | ||
| ros2_medkit/src/ros2_medkit_msgs \ | ||
| ros2_medkit/src/ros2_medkit_serialization \ | ||
| ros2_medkit/src/ros2_medkit_fault_manager \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
since we're cloning from the main branch with --depth 1, builds might break if the upstream repo changes. Maybe worth pinning to a specific commit or tag for reproducibility?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We’re cloning these packages only because they haven’t been deployed to the ROS Index yet.
For now, I suggest we leave this as-is and open a follow-up issue to replace all git clone/mv steps for ros2_medkit packages with a simple rosdep install driven by package.xml.
| launch_arguments={"use_sim_time": use_sim_time}.items(), | ||
| condition=UnlessCondition(headless), | ||
| ), | ||
| # Spawn TurtleBot3 robot (both modes) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment says "Spawn TurtleBot3 robot (both modes)" but looking at the condition on line 109, it only spawns in headless mode.
| } | ||
| }') | ||
|
|
||
| echo "$RESPONSE" | jq '.' 2>/dev/null || echo "$RESPONSE" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This might blow up if the gateway returns an error message instead of JSON - jq will just fail silently. Maybe add a quick check before piping to jq?
| curl -s -X PUT "${API_BASE}/apps/velocity-smoother/configurations/max_velocity" \ | ||
| -H "Content-Type: application/json" \ | ||
| -d '{"value": [0.26, 0.0, 1.0]}' > /dev/null 2>&1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see all the curl errors are going to /dev/null here - makes for clean output but could be tricky to debug if something goes wrong. Maybe keep stderr visible or log to a file?
| # Send velocity command (moves robot forward) | ||
| curl -X POST http://localhost:8080/api/v1/topics/publish \ | ||
| # Send velocity command using Apps data endpoint (moves robot forward) | ||
| curl -X PUT http://localhost:8080/api/v1/apps/turtlebot3_node/data/cmd_vel \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Copilot seems to be right here :)
| ), | ||
| # Launch ros2_medkit fault_manager in root namespace | ||
| # Aggregates faults from all nodes via ReportFault service | ||
| Node( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The launch file uses ros2_medkit_fault_manager and ros2_medkit_diagnostic_bridge packages, but they're not listed in package.xml exec_depend. It works in Docker because everything's built together, but for completeness you might want to add
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
also can we put a real email/name in package.xml instead of demo@example.com?
|
|
||
| echo_step "5. Sample Data (LiDAR Scan)" | ||
| echo "Getting latest LiDAR scan from TurtleBot3..." | ||
| curl -s "${API_BASE}/apps/turtlebot3-node/data/scan" 2>/dev/null | jq '{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
check-entities.sh uses the correct manifest ID:
curl -s "${API_BASE}/apps/turtlebot3-node/data/scan"
But README.md:156 uses:
curl http://localhost:8080/api/v1/apps/turtlebot3_node/data/scan
One of these won't work 😅
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Copilot reviewed 16 out of 16 changed files in this pull request and generated 8 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| echo "✓ Gateway is healthy" | ||
|
|
||
| echo_step "1. Areas (Namespace Groupings)" | ||
| curl -s "${API_BASE}/areas" | jq '.items[] | {id: .id, name: .name, description: .description}' |
Copilot
AI
Jan 29, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The script uses jq extensively for parsing JSON responses (lines 34, 37, 40, 43, 47, 56, 62-64) but does not check if jq is installed. If jq is not available, the script will fail with cryptic errors. Consider adding a check for required dependencies at the beginning of the script.
| } | ||
| }') | ||
|
|
||
| echo "$RESPONSE" | jq '.' 2>/dev/null || echo "$RESPONSE" |
Copilot
AI
Jan 29, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The script uses jq for parsing JSON responses (line 34) but does not check if jq is installed. If jq is not available, the script will fail with a cryptic error. Consider adding a check for required dependencies at the beginning of the script.
| os.path.join(ros_gz_sim_dir, "launch", "gz_sim.launch.py") | ||
| ), | ||
| launch_arguments={ | ||
| "gz_args": ["-r -s -v2 ", world_file], |
Copilot
AI
Jan 29, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The gz_args list construction ["-r -s -v2 ", world_file] will concatenate the flag string with the world file path, potentially resulting in improper spacing. This could work but is fragile. Consider using separate list items for clarity: ["-r", "-s", "-v2", world_file].
| "gz_args": ["-r -s -v2 ", world_file], | |
| "gz_args": ["-r", "-s", "-v2", world_file], |
|
|
||
| # Stop the robot | ||
| curl -X POST http://localhost:8080/api/v1/topics/publish \ | ||
| curl -X PUT http://localhost:8080/api/v1/apps/turtlebot3_node/data/cmd_vel \ |
Copilot
AI
Jan 29, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The app ID should be "turtlebot3-node" (with hyphens) to match the manifest definition, not "turtlebot3_node" (with underscores).
| echo "✓ Normal operation restored!" | ||
| echo "" | ||
| echo "Current fault status:" | ||
| curl -s "${API_BASE}/faults" | jq '.items | length' | xargs -I {} echo " Active faults: {}" |
Copilot
AI
Jan 29, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The script uses jq for parsing JSON responses (line 51) but does not check if jq is installed. If jq is not available, the script will fail with a cryptic error. Consider adding a check similar to send-nav-goal.sh that validates the presence of required dependencies.
| } | ||
| }') | ||
|
|
||
| echo "$RESPONSE" | jq '.' 2>/dev/null || echo "$RESPONSE" |
Copilot
AI
Jan 29, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The script uses jq for parsing JSON responses (line 35) but does not check if jq is installed. If jq is not available, the script will fail with a cryptic error. Consider adding a check for required dependencies at the beginning of the script.
| # Spawn TurtleBot3 robot (both modes) | ||
| IncludeLaunchDescription( | ||
| PythonLaunchDescriptionSource( | ||
| os.path.join(turtlebot3_gazebo_dir, "launch", "spawn_turtlebot3.launch.py") | ||
| ), | ||
| launch_arguments={"x_pose": x_pose, "y_pose": y_pose}.items(), | ||
| condition=IfCondition(headless), |
Copilot
AI
Jan 29, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment says "Spawn TurtleBot3 robot (both modes)" but the code only spawns in headless mode (condition=IfCondition(headless)). This is actually correct since turtlebot3_world.launch.py already spawns the robot in GUI mode, but the comment is misleading. Consider updating the comment to clarify that spawning only happens explicitly in headless mode, as GUI mode already includes it.
| # Publish to topic (see examples above) | ||
| curl -X POST http://localhost:8080/api/v1/topics/publish ... | ||
| # Clear a specific fault | ||
| curl -X DELETE http://localhost:8080/api/v1/apps/diagnostic_bridge/faults/TURTLEBOT3_NODE |
Copilot
AI
Jan 29, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The app ID should be "diagnostic-bridge" (with hyphens) to match the manifest definition, not "diagnostic_bridge" (with underscores).
Description
Major improvements to TurtleBot3 integration demo:
Core Features:
Docker & Launch:
Manifest & Configuration:
Shell Scripts:
Documentation:
Testing:
Related Issue
closes #9
Checklist