ros2_medkit_gateway
===================
This section contains design documentation for the ros2_medkit_gateway project.
Architecture
------------
The following diagram shows the relationships between the main components of the gateway.
.. plantuml::
:caption: ROS 2 Medkit Gateway Class Architecture
@startuml ros2_medkit_gateway_architecture
skinparam linetype ortho
skinparam classAttributeIconSize 0
title ROS 2 Medkit Gateway - Class Architecture
package "ROS 2 Framework" {
class "rclcpp::Node" {
+get_node_names()
+get_topic_names_and_types()
+get_service_names_and_types()
}
}
package "ros2_medkit_gateway" {
class GatewayNode {
+ get_entity_cache(): EntityCache
+ get_data_access_manager(): DataAccessManager*
+ get_operation_manager(): OperationManager*
+ get_discovery_manager(): DiscoveryManager*
+ get_configuration_manager(): ConfigurationManager*
}
class DiscoveryManager {
+ discover_areas(): vector
+ discover_components(): vector
+ discover_services(): vector
+ discover_actions(): vector
+ find_service_for_component(): optional
+ find_action_for_component(): optional
}
class OperationManager {
+ call_service(): ServiceCallResult
+ call_component_service(): ServiceCallResult
+ send_action_goal(): ActionSendGoalResult
+ send_component_action_goal(): ActionSendGoalResult
+ cancel_action_goal(): ActionCancelResult
+ get_tracked_goal(): optional
+ get_latest_goal_for_action(): optional
+ cleanup_old_goals(): void
+ is_valid_uuid_hex(): bool {static}
+ is_service_type(): bool {static}
+ is_action_type(): bool {static}
}
class RESTServer {
+ start(): void
+ stop(): void
}
class DataAccessManager {
+ get_topic_sample_with_fallback(): json
+ get_component_data_with_fallback(): json
+ publish_to_topic(): json
+ get_topic_sample_native(): json
+ get_component_data_native(): json
}
class ConfigurationManager {
+ list_parameters(): ParameterResult
+ get_parameter(): ParameterResult
+ set_parameter(): ParameterResult
}
class NativeTopicSampler {
+ discover_all_topics(): vector
+ discover_topics(): vector
+ sample_topic(): TopicSampleResult
+ sample_topics_parallel(): vector
}
class ROS2CLIWrapper {
+ exec(): string
+ is_command_available(): bool
+ escape_shell_arg(): string {static}
}
class OutputParser {
+ parse_yaml(): json
+ yaml_to_json(): json {static}
}
class Area {
+ id: string
+ namespace_path: string
+ type: string
+ to_json(): json
}
class Component {
+ id: string
+ namespace_path: string
+ fqn: string
+ type: string
+ area: string
+ services: vector
+ actions: vector
+ to_json(): json
}
class ServiceInfo {
+ full_path: string
+ name: string
+ type: string
}
class ActionInfo {
+ full_path: string
+ name: string
+ type: string
}
class EntityCache {
+ areas: vector
+ components: vector
+ last_update: time_point
}
}
package "External Libraries" {
class "httplib::Server" as HTTPLibServer
class "nlohmann::json" as JSON
}
' Relationships
' Inheritance
GatewayNode -up-|> "rclcpp::Node" : extends
' Composition (Gateway owns these)
GatewayNode *-down-> DiscoveryManager : owns
GatewayNode *-down-> RESTServer : owns
GatewayNode *-down-> DataAccessManager : owns
GatewayNode *-down-> OperationManager : owns
GatewayNode *-down-> ConfigurationManager : owns
GatewayNode *-down-> EntityCache : owns
' Discovery Manager uses Node interface
DiscoveryManager --> "rclcpp::Node" : uses
' REST Server references Gateway, DataAccessManager, OperationManager, and ConfigurationManager
RESTServer --> GatewayNode : uses
RESTServer --> DataAccessManager : uses
RESTServer --> OperationManager : uses
RESTServer --> ConfigurationManager : uses
' OperationManager uses DiscoveryManager and CLI
OperationManager --> DiscoveryManager : uses
OperationManager *--> ROS2CLIWrapper : owns
' DataAccessManager owns utility classes
DataAccessManager *--> ROS2CLIWrapper : owns (publishing)
DataAccessManager *--> OutputParser : owns
DataAccessManager *--> NativeTopicSampler : owns
' NativeTopicSampler uses Node interface
NativeTopicSampler --> "rclcpp::Node" : uses
' ConfigurationManager uses Node interface for parameter clients
ConfigurationManager --> "rclcpp::Node" : uses
' Entity Cache aggregates entities
EntityCache o-right-> Area : contains many
EntityCache o-right-> Component : contains many
' Component contains operations
Component o--> ServiceInfo : contains many
Component o--> ActionInfo : contains many
' Discovery produces entities
DiscoveryManager ..> Area : creates
DiscoveryManager ..> Component : creates
DiscoveryManager ..> ServiceInfo : creates
DiscoveryManager ..> ActionInfo : creates
' REST Server uses HTTP library
RESTServer *--> HTTPLibServer : owns
' Models use JSON for serialization
Area ..> JSON : serializes to
Component ..> JSON : serializes to
@enduml
Main Components
---------------
1. **GatewayNode** - The main ROS 2 node that orchestrates the system
- Extends ``rclcpp::Node``
- Manages periodic discovery and cache refresh
- Runs the REST server in a separate thread
- Provides thread-safe access to the entity cache
- Manages periodic cleanup of old action goals (60s interval)
2. **DiscoveryManager** - Discovers ROS 2 entities and maps them to the SOVD hierarchy
- Discovers Areas from node namespaces
- Discovers Components from nodes, topics, and services
- Discovers Services and Actions using native rclcpp APIs
- Attaches operations (services/actions) to their parent components
- Uses O(n+m) algorithm with hash maps for efficient service/action attachment
3. **OperationManager** - Executes ROS 2 operations (services and actions)
- Calls ROS 2 services synchronously via ``ros2 service call`` CLI
- Sends action goals via ``ros2 action send_goal`` CLI (3s timeout for acceptance)
- Tracks active action goals with status, feedback, and timestamps
- Subscribes to ``/_action/status`` topics for real-time goal status updates
- Supports goal cancellation via ``ros2 action cancel`` CLI
- Automatically cleans up completed goals older than 5 minutes
4. **RESTServer** - Provides the HTTP/REST API
- Discovery endpoints: ``/health``, ``/``, ``/areas``, ``/components``, ``/areas/{area_id}/components``
- Data endpoints: ``/components/{component_id}/data``, ``/components/{component_id}/data/{topic_name}``
- Operations endpoints: ``POST .../operations/{op}`` (execute), ``GET .../operations/{op}/status`` (status), ``DELETE .../operations/{op}`` (cancel)
- Configurations endpoints: ``GET/PUT .../configurations``, ``GET/PUT .../configurations/{param}``
- Retrieves cached entities from the GatewayNode
- Uses DataAccessManager for runtime topic data access
- Uses OperationManager for service/action execution
- Uses ConfigurationManager for parameter CRUD operations
- Runs on configurable host and port with CORS support
5. **ConfigurationManager** - Manages ROS 2 node parameters
- Lists all parameters for a node via ``rclcpp::SyncParametersClient``
- Gets/sets individual parameter values with type conversion
- Provides parameter descriptors (description, constraints, read-only flag)
- Caches parameter clients per node for efficiency
- Converts between JSON and ROS 2 parameter types automatically
6. **DataAccessManager** - Reads runtime data from ROS 2 topics
- Uses native rclcpp APIs for fast topic discovery and sampling
- Checks publisher counts before sampling to skip idle topics instantly
- Returns metadata (type, schema) for topics without publishers
- Falls back to ROS 2 CLI only for publishing (``ros2 topic pub``)
- Returns topic data as JSON with metadata (topic name, timestamp, type info)
- Parallel topic sampling with configurable concurrency limit (``max_parallel_topic_samples``, default: 10)
7. **NativeTopicSampler** - Fast topic sampling using native rclcpp APIs
- Discovers topics via ``node->get_topic_names_and_types()``
- Checks ``count_publishers()`` before sampling to skip idle topics
- Returns metadata instantly for topics without publishers (no CLI timeout)
- Significantly improves UX when robot has many idle topics
8. **ROS2CLIWrapper** - Executes ROS 2 CLI commands safely
- Used for publishing (``ros2 topic pub``), service calls, and action operations
- Wraps ``popen()`` with RAII for exception safety during command execution
- Checks command exit status to detect failures
- Prevents command injection with shell argument escaping
- Validates command availability before execution
9. **OutputParser** - Converts ROS 2 CLI output to JSON
- Parses YAML output from ``ros2 topic echo`` and ``ros2 service call``
- Preserves type information (bool → int → double → string precedence)
- Handles multi-document YAML streams correctly
- Converts ROS message structures to nested JSON objects
- Provides static ``yaml_to_json()`` utility for reuse
10. **Data Models** - Entity representations
- ``Area`` - Physical or logical domain
- ``Component`` - Hardware or software component with attached operations
- ``ServiceInfo`` - Service metadata (path, name, type)
- ``ActionInfo`` - Action metadata (path, name, type)
- ``EntityCache`` - Thread-safe cache of discovered entities