Skip to content
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

Migrate to ros2dds bridge #37

Merged
merged 4 commits into from
Dec 26, 2024
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
60 changes: 48 additions & 12 deletions nexus_integration_tests/config/zenoh/nexus_network_config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,68 @@
# Use 'client' when there is an available Zenoh router, otherwise
# use 'peer' for a distributed system.
mode: peer
# When true, discovery info is forwarded to the remote plugins/bridges
forward_discovery: false
# When true, activates a REST API used to administer Zenoh Bridge configurations
enable_rest_api: true
# Additional endpoints to allow, these could be endpoints not defined in REDF but are necessary for lifecycle transitions
add_allowed_endpoints: ["/list_workcells", "/.*/workcell_state", "/.*/is_task_doable", "/.*/request", "/.*/queue_task", "/.*/remove_pending_task", "/register_workcell", "/register_transporter", ".*/available", ".*/transport", "/estop", "/.*/pause", "/.*/get_state", "/.*/change_state", "/.*/signal"]

system_orchestrators:
- ros_namespace: system_orchestrator # ROS Namespace of the endpoints
- namespace: system_orchestrator # ROS Namespace of the endpoints
# ROS Domain ID
domain_id: 14
domain_id: 0
# Listening TCP Address of Zenoh bridge
tcp_listen: ["0.0.0.0:7447"]
# HTTP Port for the REST API
rest_api_http_port: 8000
allow:
publishers: []
# TODO(luca) check if we need estop
subscribers: ["/estop", "/.*/workcell_state"]
service_servers: ["/list_workcells", "/register_workcell", "/register_transporter"]
# TODO(luca) check if transporter needs available endpoint
service_clients: ["/.*/queue_task", "/.*/remove_pending_task", "/.*/pause", "/.*/signal", "/.*/get_state", "/.*/change_state", "/.*/is_task_doable"]
action_servers: []
# TODO(luca) check if we really need transporter client
Comment on lines +21 to +24
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any idea if these TODOs are still valid?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The demo / integration test works well but the configuration of these endpoints depends on where nodes are ran / how complete we want this config file.
The main crux is that in this specific implementation the system orchestrator and the transporter node run in the same domain ID so technically it is not necessary to allow all the transporter interfaces through Zenoh.
On the other hand, if we want to have this file be kind of a template that would also allow external transporters to connect to the system orchestrator we would need to add their interfaces here.

For the estop I'm just not 100% sure how it is supposed to work, since it seems it is a global topic do we just halt the whole system as soon as one workcell decides to estop? That sounds a bit dangerous so I left a note here.

I'm erring on the side of "make this a template" at least until a proper redf integration for generation of config files is not done and permissively allow all the interfaces we might need but what do you think?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the estop I'm just not 100% sure how it is supposed to work, since it seems it is a global topic do we just halt the whole system as soon as one workcell decides to estop? That sounds a bit dangerous so I left a note here.

Yeah we halt processes across all workcells if the estop is triggered. This was a requirement.

action_clients: ["/.*/request", "/.*/transport"]
queries_timeout:
default: 600.0


workcell_orchestrators:
- ros_namespace: workcell_1
domain_id: 15
- namespace: workcell_1
domain_id: 1
tcp_connect: ["0.0.0.0:7447"]
rest_api_http_port: 8001
- ros_namespace: workcell_2
domain_id: 16
allow:
publishers: ["/workcell_1/workcell_state"]
subscribers: []
service_servers: ["/workcell_1/is_task_doable", "/workcell_1/queue_task", "/workcell_1/remove_pending_task", "/workcell_1/get_state", "/workcell_1/change_state", "/workcell_1/signal", "/workcell_1/pause"]
service_clients: ["/register_workcell"]
action_servers: ["/workcell_1/request"]
action_clients: []
queries_timeout:
default: 600.0
- namespace: workcell_2
domain_id: 2
tcp_connect: ["0.0.0.0:7447"]
rest_api_http_port: 8002
- ros_namespace: workcell_3
domain_id: 17
allow:
publishers: ["/workcell_2/workcell_state"]
subscribers: []
service_servers: ["/workcell_2/is_task_doable", "/workcell_2/queue_task", "/workcell_2/remove_pending_task", "/workcell_2/get_state", "/workcell_2/change_state", "/workcell_2/signal", "/workcell_2/pause"]
service_clients: ["/register_workcell"]
action_servers: ["/workcell_2/request"]
action_clients: []
queries_timeout:
default: 600.0
- namespace: workcell_3
domain_id: 3
tcp_connect: ["0.0.0.0:7447"]
rest_api_http_port: 8003
allow:
publishers: ["workcell_3/workcell_state"]
subscribers: []
service_servers: ["workcell_3/is_task_doable", "workcell_3/queue_task", "workcell_3/remove_pending_task", "workcell_3/get_state", "workcell_3/change_state"]
service_clients: ["/register_workcell"]
action_servers: ["workcell_3/request"]
action_clients: []
queries_timeout:
default: 600.0
2 changes: 1 addition & 1 deletion nexus_integration_tests/launch/zenoh_bridge.launch.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ def launch_setup(context, *args, **kwargs):

cmd = [
ExecutableInPackage(
executable="zenoh_bridge_dds",
executable="zenoh_bridge_ros2dds",
package="nexus_zenoh_bridge_dds_vendor",
),
"--config",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,7 @@ def __init__(

# Set global variables
self.enable_rest_api = self.nexus_net_cfg["enable_rest_api"]
self.add_allowed_endpoints = self.nexus_net_cfg[
"add_allowed_endpoints"]
self.bridge_mode = self.nexus_net_cfg["mode"]
self.forward_discovery = self.nexus_net_cfg["forward_discovery"]

self.zenoh_cfg_file_extension = "json5"

Expand Down Expand Up @@ -146,11 +143,11 @@ def zenoh_cfg(

zenoh_dict = {
"plugins": {
"dds": {
"ros2dds": {
"domain": orchestrator["domain_id"],
"group_member_id": orchestrator["ros_namespace"],
"forward_discovery": self.forward_discovery,
"allow": allowed_endpoints,
"namespace": orchestrator["namespace"],
"allow": orchestrator["allow"],
"queries_timeout": orchestrator["queries_timeout"],
},
},
"mode": self.bridge_mode,
Expand Down Expand Up @@ -180,7 +177,7 @@ def generate_zenoh_config(self, output_dir):
orchestrators_zenoh_cfg = []

allowed_endpoints = self.generate_allowed_endpoints(
self.redf_cfg, self.add_allowed_endpoints)
self.redf_cfg)

# Generate system orchestrator zenoh dictionary
for orchestrator in nexus_net_cfg["system_orchestrators"]:
Expand Down Expand Up @@ -212,18 +209,17 @@ def generate_zenoh_config(self, output_dir):
for zenoh_cfg in orchestrators_zenoh_cfg:
write_filepath = os.path.join(
output_dir,
zenoh_cfg["plugins"]["dds"]["group_member_id"]
zenoh_cfg["plugins"]["ros2dds"]["namespace"]
+ "."
+ self.zenoh_cfg_file_extension,
)
# This has been removed in Zenoh 1.0.0
del zenoh_cfg["plugins"]["dds"]["group_member_id"]
del zenoh_cfg["plugins"]["ros2dds"]["namespace"]
self.write_to_json(write_filepath, zenoh_cfg)
print(f"Generated Zenoh configuration at {write_filepath}")

def generate_allowed_endpoints(self,
redf_cfg,
add_allowed_endpoints):
redf_cfg
):
"""
Generate allowed endpoints string from REDF configuration.

Expand All @@ -234,8 +230,6 @@ def generate_allowed_endpoints(self,
----------
redf_cfg : dict
REDF Configuration dictionary
add_allowed_endpoints : array
Additional endpoints allowed

Returns
-------
Expand All @@ -253,8 +247,6 @@ def generate_allowed_endpoints(self,
elif endpoint.get("service_name"):
allowed_endpoints.append(endpoint["service_name"])

allowed_endpoints.extend(add_allowed_endpoints)

allowed_endpoints_str = ""
for endpoint_str in allowed_endpoints:
# Searches for namespace defined in curly braces in REDF endpoints.
Expand Down
73 changes: 54 additions & 19 deletions nexus_network_configuration/schemas/nexus_network_schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,7 @@
"type": "object",
"required": [
"mode",
"forward_discovery",
"enable_rest_api",
"add_allowed_endpoints",
"system_orchestrators",
"workcell_orchestrators"
],
Expand All @@ -18,18 +16,10 @@
"type": "string",
"enum": ["peer", "client"]
},
"forward_discovery": {
"description": "When true, discovery info is forwarded to the remote plugins/bridges",
"type": "boolean"
},
"enable_rest_api":{
"description": "When true, activates a REST API used to administer Zenoh Bridge configurations",
"type": "boolean"
},
"add_allowed_endpoints":{
"description": "Additional endpoints to allow, these could be endpoints not defined in REDF but are necessary for lifecycle transitions",
"type": "array"
},
"system_orchestrators": {
"type": "array",
"items": { "$ref": "#/$defs/system_orchestrator_unit"}
Expand All @@ -41,12 +31,45 @@
},

"$defs": {
"queries_timeout": {
"description": "Timeout parameters for Zenoh queries",
"type": "object",
"properties": {
"default": {
"type": "number"
}
}
},
"allow": {
"description": "Additional endpoints to allow, these could be endpoints not defined in REDF but are necessary for lifecycle transitions",
"type": "object",
"properties": {
"subscribers": {
"type": "array"
},
"publishers": {
"type": "array"
},
"service_servers": {
"type": "array"
},
"service_clients": {
"type": "array"
},
"action_servers": {
"type": "array"
},
"action_clients": {
"type": "array"
}
}
},
"system_orchestrator_unit": {
"type": "object",
"required": ["ros_namespace", "domain_id", "tcp_listen"],
"required": ["namespace", "domain_id", "tcp_listen"],
"properties": {
"ros_namespace":{
"$ref": "#/$defs/ros_namespace"
"namespace":{
"$ref": "#/$defs/namespace"
},
"domain_id":{
"$ref": "#/$defs/domain_id"
Expand All @@ -56,15 +79,21 @@
},
"rest_api_http_port":{
"$ref": "#/$defs/rest_api_http_port"
},
"allow":{
"$ref": "#/$defs/allow"
},
"queries_timeout":{
"$ref": "#/$defs/queries_timeout"
}
}
},
"workcell_orchestrator_unit": {
"type": "object",
"required": ["ros_namespace", "domain_id", "tcp_connect"],
"required": ["namespace", "domain_id", "tcp_connect"],
"properties": {
"ros_namespace":{
"$ref": "#/$defs/ros_namespace"
"namespace":{
"$ref": "#/$defs/namespace"
},
"domain_id":{
"$ref": "#/$defs/domain_id"
Expand All @@ -74,18 +103,24 @@
},
"rest_api_http_port":{
"$ref": "#/$defs/rest_api_http_port"
},
"allow":{
"$ref": "#/$defs/allow"
},
"queries_timeout":{
"$ref": "#/$defs/queries_timeout"
}
}
},
"ros_namespace":{
"namespace":{
"description": "ROS Namespace of the endpoints",
"type": "string"
},
"domain_id":{
"description": "ROS Domain ID",
"type": "integer",
"minimum": 0,
"maxmimum": 232
"maximum": 232
},
"tcp_connect":{
"description": "TCP Address of system orchestrator Zenoh bridge",
Expand All @@ -99,7 +134,7 @@
"description": "HTTP Port for the REST API",
"type": "integer",
"minimum": 0,
"maxmimum": 65535
"maximum": 65535
}
}
}
6 changes: 3 additions & 3 deletions nexus_zenoh_bridge_dds_vendor/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@ find_package(ament_cmake REQUIRED)
find_package(ament_cmake_vendor_package REQUIRED)

ament_vendor(zeno_bridge_dds_vendor
VCS_URL https://github.com/eclipse-zenoh/zenoh-plugin-dds.git
VCS_VERSION 1.0.2
VCS_URL https://github.com/eclipse-zenoh/zenoh-plugin-ros2dds.git
VCS_VERSION 1.0.3
)

# TODO(sloretz) make a nice way to get this path from ament_vendor
set(INSTALL_DIR "${CMAKE_CURRENT_BINARY_DIR}/zeno_bridge_dds_vendor-prefix/install")
install(
DIRECTORY "${INSTALL_DIR}/lib/zenoh_bridge_dds/"
DIRECTORY "${INSTALL_DIR}/lib/zenoh_bridge_ros2dds/"
DESTINATION "lib/${PROJECT_NAME}"
USE_SOURCE_PERMISSIONS
)
Expand Down
Loading