Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ to complete mobile robot integration:
Both demos support:

- REST API access via SOVD protocol
- Web UI for visualization ([sovd_web_ui](https://github.com/selfpatch/sovd_web_ui))
- Web UI for visualization ([ros2_medkit_web_ui](https://github.com/selfpatch/ros2_medkit_web_ui))
- Fault injection and monitoring
- Docker deployment for easy setup

Expand Down Expand Up @@ -189,7 +189,7 @@ CI runs all 3 demos in parallel - each job builds the Docker image, starts the c
## Related Projects

- [ros2_medkit](https://github.com/selfpatch/ros2_medkit) — Core diagnostics library with SOVD-compliant gateway
- [sovd_web_ui](https://github.com/selfpatch/sovd_web_ui) — Web-based visualization and control interface
- [ros2_medkit_web_ui](https://github.com/selfpatch/ros2_medkit_web_ui) — Web-based visualization and control interface
- [ros2_medkit_mcp](https://github.com/selfpatch/ros2_medkit_mcp) — MCP server for LLM integration
- [ros2_medkit documentation](https://selfpatch.github.io/ros2_medkit/) — Full documentation and API reference

Expand Down
10 changes: 8 additions & 2 deletions demos/moveit_pick_place/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ RUN apt-get update && apt-get install -y \
libcpp-httplib-dev \
ros-jazzy-rosbag2-storage-mcap \
ros-jazzy-foxglove-bridge \
libsystemd-dev \
sqlite3 libsqlite3-dev git curl \
&& rm -rf /var/lib/apt/lists/*

Expand All @@ -41,13 +42,18 @@ RUN mkdir -p /var/lib/ros2_medkit/rosbags
ARG ROS2_MEDKIT_REF=main
WORKDIR ${COLCON_WS}/src
RUN git clone --depth 1 --branch ${ROS2_MEDKIT_REF} https://github.com/selfpatch/ros2_medkit.git && \
mv ros2_medkit/src/ros2_medkit_cmake . && \
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 \
ros2_medkit/src/ros2_medkit_fault_reporter \
ros2_medkit/src/ros2_medkit_diagnostic_bridge \
ros2_medkit/src/ros2_medkit_cmake . && \
ros2_medkit/src/ros2_medkit_diagnostic_bridge . && \
mv ros2_medkit/src/ros2_medkit_plugins/ros2_medkit_graph_provider . && \
mv ros2_medkit/src/ros2_medkit_discovery_plugins/ros2_medkit_beacon_common . && \
mv ros2_medkit/src/ros2_medkit_discovery_plugins/ros2_medkit_topic_beacon . && \
mv ros2_medkit/src/ros2_medkit_discovery_plugins/ros2_medkit_param_beacon . && \
mv ros2_medkit/src/ros2_medkit_discovery_plugins/ros2_medkit_linux_introspection . && \
rm -rf ros2_medkit

# Copy demo package from local context
Expand Down
6 changes: 3 additions & 3 deletions demos/moveit_pick_place/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ That's it! The script will:
1. Build the Docker image (first run: ~15-20 min, ~7 GB)
2. Set up X11 forwarding for Gazebo GUI
3. Launch Panda robot in factory world + MoveIt 2 + ros2_medkit gateway
4. Launch sovd_web_ui at http://localhost:3000
4. Launch ros2_medkit_web_ui at http://localhost:3000

**REST API:** http://localhost:8080/api/v1/
**Web UI:** http://localhost:3000/
Expand Down Expand Up @@ -120,7 +120,7 @@ docker exec -it moveit_medkit_demo bash # Shell into container
┌─────────────┼─────────────┐
│ │ │
sovd_web_ui curl/httpie MCP Server
ros2_medkit_web_ui curl/httpie MCP Server
:3000 (LLM tools)
```

Expand Down Expand Up @@ -300,7 +300,7 @@ curl http://localhost:8080/api/v1/faults | jq '.items[] | {fault_code, severity_

## Web UI

The sovd_web_ui container starts automatically at **http://localhost:3000**.
The ros2_medkit_web_ui container starts automatically at **http://localhost:3000**.

Connect it to the gateway at `http://localhost:8080` to browse:
- Entity tree (Areas → Components → Apps)
Expand Down
3 changes: 3 additions & 0 deletions demos/moveit_pick_place/config/medkit_params.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ diagnostics:
runtime:
create_synthetic_components: false # Manifest defines components

# Plugin configuration (set by launch file when .so paths are resolved)
plugins: [""]

# Fault Manager configuration (runs in root namespace)
fault_manager:
ros__parameters:
Expand Down
8 changes: 4 additions & 4 deletions demos/moveit_pick_place/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,9 @@ services:
source /root/demo_ws/install/setup.bash &&
ros2 launch moveit_medkit_demo demo.launch.py headless:=true"

# SOVD Web UI pre-built from GHCR
sovd-web-ui:
image: ghcr.io/selfpatch/sovd_web_ui:latest
container_name: sovd_web_ui
# Web UI - pre-built from GHCR
medkit-web-ui:
image: ghcr.io/selfpatch/ros2_medkit_web_ui:latest
container_name: ros2_medkit_web_ui
ports:
- "3000:80"
32 changes: 32 additions & 0 deletions demos/moveit_pick_place/launch/demo.launch.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@

import os

from ament_index_python.packages import get_package_prefix
from ament_index_python.packages import get_package_share_directory
from ament_index_python.packages import PackageNotFoundError
from launch import LaunchDescription
from launch.actions import (
DeclareLaunchArgument,
Expand All @@ -24,6 +26,18 @@
from launch_ros.actions import Node


def _resolve_plugin_path(package_name, lib_name):
"""Resolve a gateway plugin .so path, returning empty string if not found."""
try:
prefix = get_package_prefix(package_name)
path = os.path.join(prefix, 'lib', package_name, f'lib{lib_name}.so')
if os.path.isfile(path):
return path
except PackageNotFoundError:
pass
return ''


def generate_launch_description():
# Get package share directories
demo_pkg_dir = get_package_share_directory("moveit_medkit_demo")
Expand All @@ -35,6 +49,23 @@ def generate_launch_description():
medkit_params_file = os.path.join(demo_pkg_dir, "config", "medkit_params.yaml")
manifest_file = os.path.join(demo_pkg_dir, "config", "panda_manifest.yaml")

# Resolve plugin paths
graph_provider_path = _resolve_plugin_path(
'ros2_medkit_graph_provider', 'ros2_medkit_graph_provider_plugin')
procfs_plugin_path = _resolve_plugin_path(
'ros2_medkit_linux_introspection', 'procfs_introspection')

# Build plugin overrides - only include plugins that were found
plugin_overrides = {}
active_plugins = []
if graph_provider_path:
active_plugins.append('graph_provider')
plugin_overrides['plugins.graph_provider.path'] = graph_provider_path
if procfs_plugin_path:
active_plugins.append('procfs_introspection')
plugin_overrides['plugins.procfs_introspection.path'] = procfs_plugin_path
plugin_overrides['plugins'] = active_plugins

# Launch configuration variables
use_sim_time = LaunchConfiguration("use_sim_time", default="False")
headless = LaunchConfiguration("headless", default="False")
Expand Down Expand Up @@ -128,6 +159,7 @@ def generate_launch_description():
"use_sim_time": use_sim_time,
"discovery.manifest_path": manifest_file,
},
plugin_overrides,
],
),
# === Foxglove Bridge (WebSocket on port 8765) ===
Expand Down
32 changes: 32 additions & 0 deletions demos/moveit_pick_place/launch/demo_gazebo.launch.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@

import xacro
import yaml
from ament_index_python.packages import get_package_prefix
from ament_index_python.packages import get_package_share_directory
from ament_index_python.packages import PackageNotFoundError
from launch import LaunchDescription
from launch.actions import (
DeclareLaunchArgument,
Expand All @@ -36,6 +38,18 @@
from launch_ros.substitutions import FindPackageShare


def _resolve_plugin_path(package_name, lib_name):
"""Resolve a gateway plugin .so path, returning empty string if not found."""
try:
prefix = get_package_prefix(package_name)
path = os.path.join(prefix, 'lib', package_name, f'lib{lib_name}.so')
if os.path.isfile(path):
return path
except PackageNotFoundError:
pass
return ''


def generate_launch_description():
# ── Package directories ──────────────────────────────────────────
demo_pkg_dir = get_package_share_directory("moveit_medkit_demo")
Expand All @@ -54,6 +68,23 @@ def generate_launch_description():
demo_pkg_dir, "config", "panda_manifest.yaml"
)

# Resolve plugin paths
graph_provider_path = _resolve_plugin_path(
'ros2_medkit_graph_provider', 'ros2_medkit_graph_provider_plugin')
procfs_plugin_path = _resolve_plugin_path(
'ros2_medkit_linux_introspection', 'procfs_introspection')

# Build plugin overrides - only include plugins that were found
plugin_overrides = {}
active_plugins = []
if graph_provider_path:
active_plugins.append('graph_provider')
plugin_overrides['plugins.graph_provider.path'] = graph_provider_path
if procfs_plugin_path:
active_plugins.append('procfs_introspection')
plugin_overrides['plugins.procfs_introspection.path'] = procfs_plugin_path
plugin_overrides['plugins'] = active_plugins

# Factory world file path
factory_world = os.path.join(
demo_pkg_dir, "worlds", "factory.sdf"
Expand Down Expand Up @@ -472,6 +503,7 @@ def generate_launch_description():
"use_sim_time": True,
"discovery.manifest_path": manifest_file,
},
plugin_overrides,
],
),
# ═════════════════════════════════════════════════════════
Expand Down
13 changes: 10 additions & 3 deletions demos/sensor_diagnostics/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -16,23 +16,30 @@ RUN apt-get update && apt-get install -y \
python3-requests \
nlohmann-json3-dev \
libcpp-httplib-dev \
libsystemd-dev \
sqlite3 \
libsqlite3-dev \
git \
curl \
jq \
&& rm -rf /var/lib/apt/lists/*

# Clone ros2_medkit from GitHub (gateway + dependencies)
# Clone ros2_medkit from GitHub (gateway + dependencies + plugins)
ARG ROS2_MEDKIT_REF=main
WORKDIR ${COLCON_WS}/src
RUN git clone --depth 1 https://github.com/selfpatch/ros2_medkit.git && \
RUN git clone --depth 1 --branch ${ROS2_MEDKIT_REF} https://github.com/selfpatch/ros2_medkit.git && \
mv ros2_medkit/src/ros2_medkit_cmake . && \
mv ros2_medkit/src/ros2_medkit_gateway . && \
mv ros2_medkit/src/ros2_medkit_serialization . && \
mv ros2_medkit/src/ros2_medkit_msgs . && \
mv ros2_medkit/src/ros2_medkit_fault_manager . && \
mv ros2_medkit/src/ros2_medkit_fault_reporter . && \
mv ros2_medkit/src/ros2_medkit_diagnostic_bridge . && \
mv ros2_medkit/src/ros2_medkit_cmake . && \
mv ros2_medkit/src/ros2_medkit_plugins/ros2_medkit_graph_provider . && \
mv ros2_medkit/src/ros2_medkit_discovery_plugins/ros2_medkit_beacon_common . && \
mv ros2_medkit/src/ros2_medkit_discovery_plugins/ros2_medkit_topic_beacon . && \
mv ros2_medkit/src/ros2_medkit_discovery_plugins/ros2_medkit_param_beacon . && \
mv ros2_medkit/src/ros2_medkit_discovery_plugins/ros2_medkit_linux_introspection . && \
rm -rf ros2_medkit

# Copy demo package
Expand Down
3 changes: 3 additions & 0 deletions demos/sensor_diagnostics/config/medkit_params.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ diagnostics:
runtime:
create_synthetic_components: false # Manifest defines components

# Plugin configuration (set by launch file when .so paths are resolved)
plugins: [""]

# Fault Manager configuration (runs in root namespace)
fault_manager:
ros__parameters:
Expand Down
6 changes: 3 additions & 3 deletions demos/sensor_diagnostics/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ services:
ros2 launch sensor_diagnostics_demo demo.launch.py"

# Web UI for visualization (optional)
sovd-web-ui:
image: ghcr.io/selfpatch/sovd_web_ui:latest
container_name: sovd_web_ui
medkit-web-ui:
image: ghcr.io/selfpatch/ros2_medkit_web_ui:latest
container_name: ros2_medkit_web_ui
ports:
- "3000:80"
depends_on:
Expand Down
32 changes: 32 additions & 0 deletions demos/sensor_diagnostics/launch/demo.launch.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,27 @@

import os

from ament_index_python.packages import get_package_prefix
from ament_index_python.packages import get_package_share_directory
from ament_index_python.packages import PackageNotFoundError
from launch import LaunchDescription
from launch.actions import DeclareLaunchArgument
from launch.substitutions import LaunchConfiguration
from launch_ros.actions import Node


def _resolve_plugin_path(package_name, lib_name):
"""Resolve a gateway plugin .so path, returning empty string if not found."""
try:
prefix = get_package_prefix(package_name)
path = os.path.join(prefix, 'lib', package_name, f'lib{lib_name}.so')
if os.path.isfile(path):
return path
except PackageNotFoundError:
pass
return ''


def generate_launch_description():
# Get package directory
pkg_dir = get_package_share_directory("sensor_diagnostics_demo")
Expand All @@ -36,6 +50,23 @@ def generate_launch_description():
sensor_params_file = os.path.join(pkg_dir, "config", "sensor_params.yaml")
manifest_file = os.path.join(pkg_dir, "config", "sensor_manifest.yaml")

# Resolve plugin paths
graph_provider_path = _resolve_plugin_path(
'ros2_medkit_graph_provider', 'ros2_medkit_graph_provider_plugin')
procfs_plugin_path = _resolve_plugin_path(
'ros2_medkit_linux_introspection', 'procfs_introspection')

# Build plugin overrides - only include plugins that were found
plugin_overrides = {}
active_plugins = []
if graph_provider_path:
active_plugins.append('graph_provider')
plugin_overrides['plugins.graph_provider.path'] = graph_provider_path
if procfs_plugin_path:
active_plugins.append('procfs_introspection')
plugin_overrides['plugins.procfs_introspection.path'] = procfs_plugin_path
plugin_overrides['plugins'] = active_plugins

# Launch arguments
use_sim_time = LaunchConfiguration("use_sim_time", default="false")

Expand Down Expand Up @@ -120,6 +151,7 @@ def generate_launch_description():
medkit_params_file,
{"use_sim_time": use_sim_time},
{"discovery.manifest_path": manifest_file},
plugin_overrides,
],
),
# ===== Fault Manager (at root namespace) =====
Expand Down
15 changes: 11 additions & 4 deletions demos/turtlebot3_integration/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -37,22 +37,29 @@ RUN apt-get update && apt-get install -y \
python3-requests \
nlohmann-json3-dev \
libcpp-httplib-dev \
libsystemd-dev \
sqlite3 \
libsqlite3-dev \
git \
curl \
&& rm -rf /var/lib/apt/lists/*

# Clone ros2_medkit from GitHub
# Clone ros2_medkit from GitHub (gateway + dependencies + plugins)
ARG ROS2_MEDKIT_REF=main
WORKDIR ${COLCON_WS}/src
RUN git clone --depth 1 https://github.com/selfpatch/ros2_medkit.git && \
RUN git clone --depth 1 --branch ${ROS2_MEDKIT_REF} https://github.com/selfpatch/ros2_medkit.git && \
mv ros2_medkit/src/ros2_medkit_cmake . && \
mv ros2_medkit/src/ros2_medkit_gateway . && \
mv ros2_medkit/src/ros2_medkit_msgs . && \
mv ros2_medkit/src/ros2_medkit_serialization . && \
mv ros2_medkit/src/ros2_medkit_fault_manager . && \
mv ros2_medkit/src/ros2_medkit_fault_reporter . && \
mv ros2_medkit/src/ros2_medkit_diagnostic_bridge . && \
mv ros2_medkit/src/ros2_medkit_cmake . && \
mv ros2_medkit/src/ros2_medkit_plugins/ros2_medkit_graph_provider . && \
mv ros2_medkit/src/ros2_medkit_discovery_plugins/ros2_medkit_beacon_common . && \
mv ros2_medkit/src/ros2_medkit_discovery_plugins/ros2_medkit_topic_beacon . && \
mv ros2_medkit/src/ros2_medkit_discovery_plugins/ros2_medkit_param_beacon . && \
mv ros2_medkit/src/ros2_medkit_discovery_plugins/ros2_medkit_linux_introspection . && \
rm -rf ros2_medkit

# Copy demo package from local context (this repo)
Expand All @@ -66,7 +73,7 @@ WORKDIR ${COLCON_WS}
RUN bash -c "source /opt/ros/jazzy/setup.bash && \
rosdep update && \
rosdep install --from-paths src --ignore-src -r -y && \
colcon build --symlink-install"
colcon build --symlink-install --cmake-args -DBUILD_TESTING=OFF"

# Setup environment
RUN echo "source /opt/ros/jazzy/setup.bash" >> ~/.bashrc && \
Expand Down
Loading
Loading