Interfaces¶
Interface Configuration Guide¶
VYRA uses JSON configuration files to define ROS2 interfaces (services, topics, and actions) for modules. These configuration files are located in src/<module_name>_interfaces/config/ and automatically generate the corresponding ROS2 message types and service endpoints.
Overview¶
Each module requires interface definitions for:
Services/Callables: ROS2 services for synchronous request-response communication
Topics/Speakers: ROS2 topics for asynchronous publish-subscribe communication
Actions/Jobs: ROS2 actions for long-running tasks with feedback (future feature)
File Structure¶
Interface configuration files are JSON arrays containing interface definitions:
src/
└── <module_name>_interfaces/
└── config/
├── module_core_meta.json # Core services (required)
├── module_state_meta.json # State management services
├── module_custom_meta.json # Module-specific interfaces
└── ...
Each JSON file contains an array of interface definitions that share common characteristics.
Services/Callables¶
Services provide synchronous request-response communication between modules. They are defined with the callable type.
Structure¶
Field |
Required |
Description |
|---|---|---|
|
Yes |
Array containing |
|
Yes |
Must be |
|
Yes |
Python method name (snake_case) |
|
Yes |
Human-readable name for UI |
|
Yes |
Detailed description of the service |
|
Yes |
ROS2 service type name (ends with |
|
Yes |
Security level required (1-5) |
|
Yes |
Array of input parameters |
|
Yes |
Array of return values |
|
No |
UI display configuration |
Parameter/Return Structure¶
Each parameter and return value has:
Field |
Required |
Description |
|---|---|---|
|
Yes |
Parameter name (snake_case) |
|
Yes |
ROS2 data type (e.g., |
|
Yes |
Human-readable name |
|
Yes |
Parameter description |
Example: Service Definition¶
{
"tags": ["ros2_srv"],
"type": "callable",
"functionname": "set_parameter",
"displayname": "Set Parameter",
"description": "Set a configuration parameter in the system",
"filetype": "VBASESetParam.srv",
"access_level": 3,
"params": [
{
"name": "key",
"datatype": "string",
"displayname": "Parameter Key",
"description": "The key of the parameter to set"
},
{
"name": "value",
"datatype": "string",
"displayname": "Parameter Value",
"description": "The value to set for the parameter"
}
],
"returns": [
{
"name": "success",
"datatype": "bool",
"displayname": "Success",
"description": "True if parameter was set successfully"
},
{
"name": "message",
"datatype": "string",
"displayname": "Message",
"description": "Status message or error description"
}
],
"displaystyle": {
"visible": true,
"published": false
}
}
Implementation¶
After defining the service in JSON, implement it in your application:
from vyra_base.com import remote_service
from vyra_base.security import security_required, SecurityLevel
class Application(OperationalStateMachine):
@remote_service()
@security_required(security_level=SecurityLevel.EXTENDED_AUTH)
def set_parameter(self, request=None, response=None):
"""
Implementation matching the interface definition.
Access level 3 (EXTENDED_AUTH) required.
"""
try:
self.entity.parameters[request.key] = request.value
response.success = True
response.message = f"Parameter '{request.key}' set successfully"
except Exception as e:
response.success = False
response.message = str(e)
return response
Topics/Speakers¶
Topics provide asynchronous publish-subscribe communication. Publishers send messages without waiting for responses, and multiple subscribers can listen to the same topic.
Structure¶
Field |
Required |
Description |
|---|---|---|
|
Yes |
Array containing |
|
Yes |
Must be |
|
Yes |
Topic name (snake_case) |
|
Yes |
Human-readable name |
|
Yes |
Topic purpose description |
|
Yes |
ROS2 message type name (ends with |
|
No |
Publishing frequency in Hz (default: 10.0) |
|
Yes |
Array of message fields |
|
No |
UI display configuration |
Example: Topic Definition¶
{
"tags": ["ros2_topic"],
"type": "speaker",
"functionname": "status_updates",
"displayname": "Status Updates",
"description": "Publishes module status updates periodically",
"filetype": "ModuleStatus.msg",
"frequency": 1.0,
"params": [
{
"name": "module_name",
"datatype": "string",
"displayname": "Module Name",
"description": "Name of the module"
},
{
"name": "state",
"datatype": "string",
"displayname": "State",
"description": "Current operational state"
},
{
"name": "cpu_usage",
"datatype": "float32",
"displayname": "CPU Usage",
"description": "CPU usage percentage"
},
{
"name": "timestamp",
"datatype": "builtin_interfaces/Time",
"displayname": "Timestamp",
"description": "Time of status update"
}
],
"displaystyle": {
"visible": true,
"published": true
}
}
Implementation¶
from vyra_base.com.datalayer.speaker import VyraSpeaker
from vyra_base.com.datalayer.interface_factory import create_vyra_speaker
class Application(OperationalStateMachine):
def __init__(self, entity, *args, **kwargs):
super().__init__(entity.unified_state_machine)
self.entity = entity
# Create speaker from interface definition
self.status_speaker = create_vyra_speaker(
node=entity.node,
name="status_updates",
msg_type=ModuleStatus,
frequency=1.0
)
async def publish_status(self):
"""Publish status update."""
msg = ModuleStatus()
msg.module_name = self.entity.module_entry.name
msg.state = self.entity.state_machine.operational_state.name
msg.cpu_usage = self.get_cpu_usage()
msg.timestamp = self.entity.node.get_clock().now().to_msg()
self.status_speaker.publish(msg)
Actions/Jobs¶
Actions provide long-running operations with feedback. They are useful for tasks that take time to complete and need to report progress.
Note
Action support is planned for future releases. Current implementation uses simplified job pattern.
Structure¶
Field |
Required |
Description |
|---|---|---|
|
Yes |
Array containing |
|
Yes |
Must be |
|
Yes |
Action name (snake_case) |
|
Yes |
Human-readable name |
|
Yes |
Action purpose description |
|
Yes |
ROS2 action type name (ends with |
|
Yes |
Security level required (1-5) |
|
Yes |
Array of goal parameters |
|
Yes |
Array of result fields |
|
Yes |
Array of feedback fields |
|
No |
UI display configuration |
Example: Action Definition¶
{
"tags": ["ros2_action"],
"type": "job",
"functionname": "execute_task",
"displayname": "Execute Task",
"description": "Execute a long-running task with progress feedback",
"filetype": "ExecuteTask.action",
"access_level": 3,
"goal": [
{
"name": "task_id",
"datatype": "string",
"displayname": "Task ID",
"description": "Unique identifier for the task"
},
{
"name": "parameters",
"datatype": "string",
"displayname": "Parameters",
"description": "JSON-encoded task parameters"
}
],
"result": [
{
"name": "success",
"datatype": "bool",
"displayname": "Success",
"description": "True if task completed successfully"
},
{
"name": "result_data",
"datatype": "string",
"displayname": "Result Data",
"description": "JSON-encoded result data"
}
],
"feedback": [
{
"name": "progress",
"datatype": "float32",
"displayname": "Progress",
"description": "Completion percentage (0.0-100.0)"
},
{
"name": "status_message",
"datatype": "string",
"displayname": "Status Message",
"description": "Current operation status"
}
],
"displaystyle": {
"visible": true,
"published": false
}
}
Implementation (Simplified)¶
from vyra_base.com.datalayer.job import VyraJob
from vyra_base.com.datalayer.interface_factory import create_vyra_job
class Application(OperationalStateMachine):
@remote_service()
@security_required(security_level=SecurityLevel.EXTENDED_AUTH)
async def execute_task(self, request=None, response=None):
"""
Execute long-running task.
In full action implementation, this would return action handle.
"""
task_id = request.task_id
# Create job for async execution
job = create_vyra_job(
name=f"task_{task_id}",
callback=self._execute_task_impl,
args=(task_id, request.parameters)
)
response.success = True
response.message = f"Task {task_id} started"
return response
async def _execute_task_impl(self, task_id, parameters):
"""Internal task implementation with progress updates."""
for progress in range(0, 101, 10):
await asyncio.sleep(0.5)
# Publish feedback (simplified)
self.entity.publish_news(
f"Task {task_id}: {progress}% complete"
)
return {"success": True, "result": "Task completed"}
Common Data Types¶
ROS2 Standard Types¶
Type |
Description |
|---|---|
|
Boolean (true/false) |
|
Signed integers |
|
Unsigned integers |
|
Floating point numbers |
|
UTF-8 string |
|
Raw byte data |
|
Unbounded array (e.g., |
|
Fixed-size array (e.g., |
Common ROS2 Message Types¶
Type |
Description |
|---|---|
|
ROS timestamp (seconds + nanoseconds) |
|
Time duration |
|
Message header with timestamp and frame_id |
|
3D point (x, y, z) |
|
Position and orientation |
|
UUID (16 bytes) |
Access Levels¶
Every interface must specify an access_level (1-5) that determines which modules can call it:
Level |
Name |
Description |
|---|---|---|
1 |
NONE |
Public access, no authentication required |
2 |
BASIC_AUTH |
Module ID verification required |
3 |
EXTENDED_AUTH |
Module ID + password authentication |
4 |
HMAC |
HMAC-SHA256 message integrity check |
5 |
DIGITAL_SIGNATURE |
Certificate-based PKI authentication |
See Security Framework for detailed security documentation.
Best Practices¶
Naming Conventions¶
Function names: Use
snake_case(e.g.,set_parameter,get_status)Display names: Use Title Case (e.g.,
"Set Parameter","Get Status")File types: Use PascalCase with suffix (e.g.,
VBASESetParam.srv,ModuleStatus.msg)Parameter names: Use
snake_case
Organization¶
Group related interfaces: Put core services in
*_core_meta.json, state management in*_state_meta.jsonConsistent naming: Use module prefix for custom types (e.g.,
V2MMSetConfig.srvfor v2_modulemanager)Access levels: Start with level 2 (BASIC_AUTH) as minimum for non-public services
Documentation: Provide clear descriptions for all interfaces and parameters
Interface Versioning¶
When modifying existing interfaces:
Non-breaking changes: Add optional parameters at the end
Breaking changes: Create new interface with version suffix (e.g.,
SetParamV2.srv)Deprecation: Mark old interfaces as deprecated in description
Migration: Provide migration guide in module documentation
Example: Complete Module Interfaces¶
Complete example for a module with multiple interface types:
[
{
"tags": ["ros2_srv"],
"type": "callable",
"functionname": "get_info",
"displayname": "Get Module Info",
"description": "Retrieve module information and capabilities",
"filetype": "GetInfo.srv",
"access_level": 1,
"params": [],
"returns": [
{
"name": "module_name",
"datatype": "string",
"displayname": "Module Name"
},
{
"name": "version",
"datatype": "string",
"displayname": "Version"
},
{
"name": "capabilities",
"datatype": "string[]",
"displayname": "Capabilities"
}
]
},
{
"tags": ["ros2_topic"],
"type": "speaker",
"functionname": "heartbeat",
"displayname": "Heartbeat",
"description": "Module alive signal",
"filetype": "Heartbeat.msg",
"frequency": 1.0,
"params": [
{
"name": "timestamp",
"datatype": "builtin_interfaces/Time"
},
{
"name": "sequence",
"datatype": "uint64"
}
]
},
{
"tags": ["ros2_srv"],
"type": "callable",
"functionname": "emergency_stop",
"displayname": "Emergency Stop",
"description": "Immediately halt all operations",
"filetype": "EmergencyStop.srv",
"access_level": 5,
"params": [
{
"name": "reason",
"datatype": "string",
"displayname": "Reason"
}
],
"returns": [
{
"name": "success",
"datatype": "bool"
}
]
}
]
See Also¶
Security Framework: Security framework and access control
COM API Overview: Communication overview
VyraEntity - The Core: Entity initialization and interface registration