Skip to content

Commit

Permalink
Support bridge namespaces (#225)
Browse files Browse the repository at this point in the history
  • Loading branch information
aaronchongth authored Feb 26, 2025
1 parent b933733 commit 3d90897
Show file tree
Hide file tree
Showing 7 changed files with 42 additions and 24 deletions.
28 changes: 17 additions & 11 deletions DEFAULT_CONFIG.json5
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,18 @@
// ros_hostname: "hostname",

////
//// ros_name: A bridge node's name for ROS1, the default is "ros1_to_zenoh_bridge"
//// ros_name: A bridge node's name for ROS1, the default is "ros1_to_zenoh_bridge"
////
// ros_name: "ros1_to_zenoh_bridge",

////
//// with_rosmaster: An option wether the bridge should run it's own rosmaster process, the default is "false"
//// bridge_namespace: A bridge's namespace in terms of zenoh keys, the default is "*", the wildcard namespace.
//// The generated zenoh keys will be in the form of {data_type}/{md5}/{bridge_namespace}/{topic}.
////
// bridge_namespace: "*",

////
//// with_rosmaster: An option wether the bridge should run it's own rosmaster process, the default is "false"
////
// with_rosmaster: "false",

Expand Down Expand Up @@ -59,13 +65,13 @@
//// - ROS1 doesn't allow multiple services on the same topic
//// Due to this, client's bridging works differently compared to pub\sub bridging:
//// - lazy bridging mode is not available as there is no way to discover local ROS1 clients
//// - client bridging is disabled by default, as it may brake the local ROS1 system if it intends to have client and service interacting on the same topic
//// - client bridging is disabled by default, as it may break the local ROS1 system if it intends to have client and service interacting on the same topic
//// In order to use client bridging, you have two options:
//// - globally select auto bridging mode (with caution!) with this option
//// - bridge specific topics using 'client_topic_custom_bridging_mode' option (with a little bit less caution!)"#
// client_bridging_mode: "disabled",

////
////
//// subscriber_topic_custom_bridging_mode: A JSON Map describing custom bridging modes for particular topics.
//// Custom bridging mode overrides the global one.
//// Format: {"topic1":"mode", "topic2":"mode"}
Expand All @@ -76,7 +82,7 @@
//// The default is empty
// subscriber_topic_custom_bridging_mode: ""

////
////
//// publisher_topic_custom_bridging_mode: A JSON Map describing custom bridging modes for particular topics.
//// Custom bridging mode overrides the global one.
//// Format: {"topic1":"mode", "topic2":"mode"}
Expand All @@ -87,7 +93,7 @@
//// The default is empty
// publisher_topic_custom_bridging_mode: ""

////
////
//// service_topic_custom_bridging_mode: A JSON Map describing custom bridging modes for particular topics.
//// Custom bridging mode overrides the global one.
//// Format: {"topic1":"mode", "topic2":"mode"}
Expand All @@ -98,7 +104,7 @@
//// The default is empty
// service_topic_custom_bridging_mode: ""

////
////
//// client_topic_custom_bridging_mode: A JSON Map describing custom bridging modes for particular topics.
//// Custom bridging mode overrides the global one.
//// Format: {"topic1":"mode", "topic2":"mode"}
Expand All @@ -120,19 +126,19 @@
// ros_master_polling_interval: "100ms",

////
//// This plugin uses Tokio (https://tokio.rs/) for asynchronous programming.
//// This plugin uses Tokio (https://tokio.rs/) for asynchronous programming.
//// When running as a plugin within a Zenoh router, the plugin creates its own Runtime managing 2 pools of threads:
//// - worker threads for non-blocking tasks. Those threads are spawn at Runtime creation.
//// - blocking threads for blocking tasks (e.g. I/O). Those threads are spawn when needed.
//// For more details see https://github.com/tokio-rs/tokio/discussions/3858#discussioncomment-869878
//// When running as a standalone bridge the Zenoh Session's Runtime is used and can be configured via the
//// `ZENOH_RUNTIME` environment variable. See https://docs.rs/zenoh-runtime/latest/zenoh_runtime/enum.ZRuntime.html
////

//// work_thread_num: The number of worker thread in the asynchronous runtime will use. (default: 2)
//// Only for a plugin, no effect on a bridge.
// work_thread_num: 2,

//// max_block_thread_num: The number of blocking thread in the asynchronous runtime will use. (default: 50)
//// Only for a plugin, no effect on a bridge.
// max_block_thread_num: 50,
Expand Down Expand Up @@ -176,7 +182,7 @@

////
//// Which endpoints to listen on. E.g. tcp/localhost:7447.
//// By configuring the endpoints, it is possible to tell zenoh which are the endpoints that other routers,
//// By configuring the endpoints, it is possible to tell zenoh which are the endpoints that other routers,
//// peers, or client can use to establish a zenoh session.
////
listen: {
Expand Down
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<img src="https://raw.githubusercontent.com/eclipse-zenoh/zenoh/main/zenoh-dragon.png" height="150">

<!---
<!---
[![CI](https://github.com/eclipse-zenoh/zenoh-plugin-ros1/workflows/Rust/badge.svg)](https://github.com/eclipse-zenoh/zenoh-plugin-ros1/actions?query=workflow%3ARust)
--->
[![Discussion](https://img.shields.io/badge/discussion-on%20github-blue)](https://github.com/eclipse-zenoh/roadmap/discussions)
Expand Down Expand Up @@ -36,17 +36,17 @@ To install the latest release of either the ROS1 plugin for the Zenoh router, ei

### Manual installation (all platforms)

All release packages can be downloaded from:
All release packages can be downloaded from:

- [https://download.eclipse.org/zenoh/zenoh-plugin-ros1/latest/](https://download.eclipse.org/zenoh/zenoh-plugin-ros1/latest/)

Each subdirectory has the name of the Rust target. See the platforms each target corresponds to on [https://doc.rust-lang.org/stable/rustc/platform-support.html](https://doc.rust-lang.org/stable/rustc/platform-support.html)

Choose your platform and download:

- the `zenoh-plugin-ros1-<version>-<platform>.zip` file for the plugin.
- the `zenoh-plugin-ros1-<version>-<platform>.zip` file for the plugin.
Then unzip it in the same directory than `zenohd` or to any directory where it can find the plugin library (e.g. /usr/lib)
- the `zenoh-bridge-ros1-<version>-<platform>.zip` file for the standalone executable.
- the `zenoh-bridge-ros1-<version>-<platform>.zip` file for the standalone executable.
Then unzip it where you want, and run the extracted `zenoh-bridge-ros1` binary.

### Linux Debian
Expand Down Expand Up @@ -104,7 +104,7 @@ The **`zenoh-bridge-ros1`** standalone executable is also available as a [Docker
- `docker pull eclipse/zenoh-bridge-ros1:latest` for the latest release
- `docker pull eclipse/zenoh-bridge-ros1:main` for the main branch version (nightly build)

Usage: **`docker run --init --net host eclipse/zenoh-bridge-ros1`**
Usage: **`docker run --init --net host eclipse/zenoh-bridge-ros1`**
It supports the same command line arguments than the `zenoh-bridge-ros1` (see below or check with `-h` argument).

## A quick test with built-in examples
Expand All @@ -115,7 +115,7 @@ If you want to run examples or tests, you need to install ROS1:
sudo apt install -y ros-base
```

There is a set of example utilities illustarating bridge in operation.
There is a set of example utilities illustrating bridge in operation.
Here is a description on how to configure the following schema:

```raw
Expand Down
7 changes: 5 additions & 2 deletions zenoh-bridge-ros1/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,9 @@ r#"--ros_name=[String] 'A bridge node's name for ROS1, the default is "ros1_to
r#"--ros_namespace=[String] 'A bridge's namespace in terms of ROS1, the default is empty'"#
))
.arg(Arg::from_usage(
r#"--bridge_namespace=[String] 'A bridge's namespace in terms of zenoh keys, the default is "*", the wildcard namespace'"#
))
.arg(Arg::from_usage(
r#"--with_rosmaster=[bool] 'Start rosmaster with the bridge, the default is "false"'"#
))
.arg(Arg::from_usage(
Expand Down Expand Up @@ -134,7 +137,7 @@ r#"--client_bridging_mode=[String] \
- ROS1 doesn't allow multiple services on the same topic
Due to this, client's bridging works differently compared to pub\sub bridging:
- lazy bridging mode is not available as there is no way to discover local ROS1 clients
- client bridging is disabled by default, as it may brake the local ROS1 system if it intends to have client and service interacting on the same topic
- client bridging is disabled by default, as it may break the local ROS1 system if it intends to have client and service interacting on the same topic
In order to use client bridging, you have two options:
- globally select auto bridging mode (with caution!) with this option
- bridge specific topics using 'client_topic_custom_bridging_mode' option (with a little bit less caution!)"#
Expand Down Expand Up @@ -283,7 +286,7 @@ async fn main() {
plugins_mgr.declare_static_plugin::<zenoh_plugin_rest::RestPlugin, &str>("ros1", true);
}

// declare ROS2DDS plugin
// declare ROS 1 plugin
plugins_mgr.declare_static_plugin::<zenoh_plugin_ros1::Ros1Plugin, &str>("ros1", true);

// create a zenoh Runtime.
Expand Down
1 change: 0 additions & 1 deletion zenoh-plugin-ros1/src/ros_to_zenoh_bridge/discovery.rs
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,6 @@ impl RemoteResources {
let md5 = discovery.md5().to_string();

let resource_class = discovery.resource_class().to_string();
//let bridge_namespace = discovery.bridge_namespace().ok_or("No bridge_namespace present!")?.to_string();
let topic = discovery.topic().ok_or("No topic present!")?;

let ros1_topic = make_topic(datatype, &md5, topic);
Expand Down
5 changes: 5 additions & 0 deletions zenoh-plugin-ros1/src/ros_to_zenoh_bridge/environment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,10 @@ impl Environment {
return Entry::new("ROS_NAMESPACE", namespace());
}

pub fn bridge_namespace() -> Entry<'static, String> {
return Entry::new("BRIDGE_NAMESPACE", "*".to_string());
}

pub fn with_rosmaster() -> Entry<'static, bool> {
return Entry::new("WITH_ROSMASTER", false);
}
Expand Down Expand Up @@ -192,6 +196,7 @@ impl Environment {
Self::ros_hostname(),
Self::ros_name(),
Self::ros_namespace(),
Self::bridge_namespace(),
Self::subscriber_bridging_mode().into(),
Self::publisher_bridging_mode().into(),
Self::service_bridging_mode().into(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ where

let local_resources = Arc::new(LocalResources::new(
"*".to_string(),
"*".to_string(),
Environment::bridge_namespace().get(),
session.clone(),
));

Expand All @@ -108,7 +108,11 @@ async fn make_remote_resources_discovery<'a>(
) -> RemoteResources {
let bridges2 = bridges.clone();

let builder = RemoteResourcesBuilder::new("*".to_string(), "*".to_string(), session);
let builder = RemoteResourcesBuilder::new(
"*".to_string(),
Environment::bridge_namespace().get(),
session,
);
builder
.on_discovered(move |b_type, topic| {
let bridges = bridges.clone();
Expand Down
5 changes: 3 additions & 2 deletions zenoh-plugin-ros1/src/ros_to_zenoh_bridge/topic_utilities.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ use zenoh::key_expr::{
keyexpr, OwnedKeyExpr,
};

use super::topic_descriptor::TopicDescriptor;
use super::{environment::Environment, topic_descriptor::TopicDescriptor};

kedefine!(
pub ros_mapping_format: "${data_type:*}/${md5:*}/${topic:**}",
pub ros_mapping_format: "${data_type:*}/${md5:*}/${bridge_ns:*}/${topic:**}",
);

pub fn make_topic_key(topic: &TopicDescriptor) -> &str {
Expand All @@ -31,6 +31,7 @@ pub fn make_zenoh_key(topic: &TopicDescriptor) -> OwnedKeyExpr {
let mut formatter = ros_mapping_format::formatter();
keformat!(
formatter,
bridge_ns = Environment::bridge_namespace().get(),
data_type = hex::encode(topic.datatype.as_bytes()),
md5 = topic.md5.clone(),
topic = make_topic_key(topic)
Expand Down

0 comments on commit 3d90897

Please sign in to comment.