9个版本 ()

1.0.0-alpha.62024年8月6日
1.0.0-alpha.52024年7月26日
1.0.0-alpha.2 2024年6月21日
0.11.0 2024年6月4日
0.0.0 2022年12月7日

#2 in 机器人

Download history 163/week @ 2024-04-27 8/week @ 2024-05-04 124/week @ 2024-05-11 27/week @ 2024-05-18 2/week @ 2024-05-25 136/week @ 2024-06-01 12/week @ 2024-06-08 62/week @ 2024-06-15 43/week @ 2024-06-22 2/week @ 2024-06-29 95/week @ 2024-07-06 20/week @ 2024-07-13 49/week @ 2024-07-20 110/week @ 2024-07-27 103/week @ 2024-08-03 9/week @ 2024-08-10

272 每月下载量

EPL-2.0 OR Apache-2.0

195KB
3K SLoC

Discussion Discord License License

Eclipse Zenoh

Eclipse Zenoh:零开销的Pub/Sub、存储/查询和计算。

Zenoh(发音为/zeno/)统一了运动中的数据、静止数据和计算。它在传统pub/sub和地理分布式存储、查询和计算之间巧妙地结合,同时保持了时间效率和空间效率,远超任何主流堆栈。

请访问网站zenoh.io路线图 以获取更多信息。


DDS插件和独立zenoh-bridge-dds

👉 安装最新版本:见下文如何安装它

👉 Docker镜像:见下文如何获取Docker镜像

👉 构建"main"分支:见下文如何构建它

背景

数据分发服务(DDS)是一种以数据为中心的发布/订阅标准。虽然DDS已经存在很长时间,并在各个行业中有着悠久的部署历史,但最近由于机器人操作系统(ROS 2)的采用而引起了广泛关注——在ROS 2节点之间进行通信时使用。

⚠️ 在与ROS 2一起使用时 ⚠️

此插件基于DDS标准,因此可以在一定程度上与ROS 2协同工作。

然而,我们强烈建议ROS 2用户尝试使用新的 zenoh-plugin-ros2dds,这是一个专门用于支持ROS 2与DDS的插件。由于与ROS 2概念的更好集成,此新插件具有以下优点:

  • 更好地集成ROS图(所有ROS主题/服务/动作都可以在桥接器中查看)
  • 更好地支持ROS工具(ros2 CLI,rviz2...)
  • 在桥接器上配置ROS命名空间(而不是在每个ROS节点上)
  • 将服务和动作作为Zenoh可查询对象,比通过DDS的RPC更高效和可扩展
  • 桥接器之间有更多紧凑的发现信息(不会像这样转发所有ros_discovery_info消息)

此DDS Zenoh插件最终将因ROS 2使用而弃用。

插件或桥接器?

此软件有两种构建方式可供选择

  • zenoh-plugin-dds:一个Zenoh插件——一个可以由Zenoh路由器加载的动态库
  • zenoh-bridge-dds:一个独立的可执行文件

本文档中描述的功能和配置适用于两者。这意味着本文档其余部分中,“插件”和“桥接器”这两个词可以互换使用。

如何安装它

要安装Zenoh路由器的最新版本的DDS插件或zenoh-bridge-dds独立可执行文件,您可以按照以下步骤操作:

手动安装(所有平台)

所有发布包都可以从以下位置下载:

每个子目录都包含Rust目标名称。请参阅https://doc.rust-lang.net.cn/stable/rustc/platform-support.html上每个目标对应的平台。

选择您的平台并下载

  • 插件文件zenoh-plugin-dds-<version>-<platform>.zip
    然后将它解压缩到与zenohd相同的目录,或者到任何可以找到插件库的目录(例如/usr/lib)
  • 独立可执行文件文件zenoh-bridge-dds-<version>-<platform>.zip
    然后将它解压缩到您想要的位置,并运行提取的zenoh-bridge-dds二进制文件。

Linux Debian

将Eclipse Zenoh私有存储库添加到源列表

echo "deb [trusted=yes] https://download.eclipse.org/zenoh/debian-repo/ /" | sudo tee -a /etc/apt/sources.list > /dev/null
sudo apt update

然后,您可以

  • 使用以下命令安装插件: sudo apt install zenoh-plugin-dds
  • 使用以下命令安装独立可执行文件: sudo apt install zenoh-bridge-dds

如何构建它

⚠️ 警告 ⚠️ : Zenoh及其生态系统正在积极开发中。当你从git构建时,确保你也从git构建你计划使用的任何其他Zenoh仓库(例如,绑定、插件、后端等)。可能发生的情况是,git中的某些更改与最新的Zenoh打包版本(例如,deb、docker、pip)不兼容。我们在维护Zenoh项目中各个git仓库之间的兼容性上投入了特别多的努力。

⚠️ 警告 ⚠️ : 由于Rust没有稳定的ABI,插件应该使用与zenohd相同的Rust版本进行构建,并且使用与zenoh依赖项相同的版本(或提交号)。否则,在zenohd和库之间的共享类型内存映射中的不兼容性可能导致"SIGSEV"崩溃。

为了构建用于DDS的zenoh桥,您首先需要安装以下依赖项

  • Rust。如果您已经安装了Rust工具链,请确保它已经更新到

    $ rustup update
    
  • 在Linux上,确保已安装llvmclang开发包

    • 在Debian上:sudo apt install llvm-dev libclang-dev
    • 在CentOS或RHEL上:sudo yum install llvm-devel clang-devel
    • 在Alpine上:apk install llvm11-dev clang-dev
  • CMake(用于构建CycloneDDS,它是一个本地依赖项)

一旦这些依赖项就绪,您可以在您的机器上克隆仓库

$ git clone https://github.com/eclipse-zenoh/zenoh-plugin-dds.git
$ cd zenoh-plugin-dds
$ cargo build --release

独立的可执行二进制文件zenoh-bridge-dds和插件共享库(在Linux上为*.so,在Mac OS上为*.dylib,在Windows上为*.dll),它们将被动态加载到zenoh路由器zenohd中,并生成在target/release子目录中。

启用Cyclone DDS共享内存支持

Cyclone DDS共享内存支持由Iceoryx库提供。Iceoryx引入了额外的系统要求,这些要求在此有文档说明。

为了构建支持共享内存的DDS的zenoh桥,必须在构建过程中启用dds_shm可选功能,如下所示

  • 插件库
$ cargo build --release -p zenoh-plugin-dds --features dds_shm
  • 独立可执行二进制文件
$ cargo build --release -p zenoh-bridge-dds --features dds_shm

注意:当启用dds_shm功能时,不需要安装Iceoryx来构建桥接器。Iceoryx将作为cargo构建过程的一部分自动下载、编译并静态链接到zenoh桥接器中。

当zenoh桥配置为使用DDS共享内存(请参阅配置)时,必须运行Iceoryx RouDi守护进程(iox-roudi,以便桥接器能够成功启动。如果未启动,则桥接器将等待一段时间,等待守护进程变得可用,然后超时并终止。

当启用 dds_shm 功能构建 Zenoh 桥接器时,为了方便起见,还会构建 iox-roudi 守护进程。守护进程可以在以下位置找到:target/debug|release/build/cyclors-<hash>/out/iceoryx-build/bin/iox-roudi

有关 Cyclone DDS 中共享内存支持的更多详细信息,请参阅此处

ROS 2 软件包

⚠️ 请考虑使用专为 ROS 2 优化的zenoh-bridge-ros2dds

如果您是 ROS 2 用户,您也可以将 zenoh-bridge-dds 作为运行

rosdep install --from-paths . --ignore-src -r -y
colcon build --packages-select zenoh_bridge_dds --cmake-args -DCMAKE_BUILD_TYPE=Release

rosdep 命令将自动安装构建依赖项 Rustclang

如果您想在 x86 设备上为任何目标交叉编译软件包,可以使用以下命令

rosdep install --from-paths . --ignore-src -r -y
colcon build --packages-select zenoh_bridge_dds --cmake-args -DCMAKE_BUILD_TYPE=Release  --cmake-args -DCROSS_ARCH=<target>

其中 <target> 是目标架构(例如,aarch64-unknown-linux-gnu)。架构列表可以在此处找到。

交叉编译使用 zig 作为链接器。您可以通过此处的说明进行安装。此外,还需要在目标设备上安装 zigbuild 软件包。您可以通过此处的说明进行安装。

Docker 镜像

zenoh-bridge-dds 独立可执行文件也作为适用于 amd64 和 arm64 的 Docker 镜像 提供。要获取它,请执行以下操作:

  • docker pull eclipse/zenoh-bridge-dds:latest 获取最新版本
  • docker pull eclipse/zenoh-bridge-dds:main 获取主分支版本(夜间构建)

⚠️ 但是,请注意,它的使用仅限于 Linux 上的 Docker 和使用 --net host 选项。
原因在于 DDS 使用 UDP 组播,而 Docker 不支持容器与其主机之间的 UDP 组播(请参阅案例 moby/moby#23659moby/libnetwork#2397moby/libnetwork#552)。使其工作的唯一已知方法是使用 --net host 选项,该选项仅支持在 Linux 主机上使用

用法: docker run --init --net host eclipse/zenoh-bridge-dds
它支持与 zenoh-bridge-dds 相同的命令行参数(请参阅下面或使用 -h 参数检查)。


用法

此 Zenoh 插件用于 DDS 的用例多种多样

  • DDS系统与Zenoh系统的集成
  • 借助zenoh-pico实现DDS系统与嵌入式设备的通信
  • 通过Zenoh基础设施(例如一些路由器或桥接器之间的点对点)在各个传输之间桥接不同的DDS系统
  • 使用Zenoh路由器将DDS系统扩展到云
  • 与其他Zenoh插件(MQTT、ROS 2 ...)或存储技术(InfluxDB、RocksDB)集成的任何技术

配置

zenoh-bridge-dds可以通过通过-c参数传递的JSON5文件进行配置。您可以在以下链接中查看此类配置文件的注释示例:DEFAULT_CONFIG.json5

此配置文件中相同的"dds"部分也可以用于Zenoh路由器的配置文件(在其"plugins"部分中)。路由器将在启动时自动尝试加载插件库(zenoh-plugin_dds)并应用其配置。

zenoh-bridge-dds还接受以下参数。如果设置,则每个参数将覆盖配置文件中的类似设置

  • 与Zenoh相关的参数
    • -c, --config <FILE> : 配置文件
    • -m, --mode <MODE> : Zenoh会话模式。默认值:peer 可能的值:peerclient
      有关更多详细信息,请参阅Zenoh文档
    • -l, --listen <LOCATOR> : 此路由器将监听传入会话的定位器。重复此选项以打开多个监听器。定位器示例:tcp/localhost:7447
    • -e, --peer <LOCATOR> : 此路由器将尝试连接到的对等定位器(通常是另一个桥接器或Zenoh路由器)。重复此选项以连接到多个对等点。定位器示例:tcp/<ip-address>:7447
    • --no-multicast-scouting : 禁用允许自动发现Zenoh对等点和路由器的Zenoh侦察协议。
    • -i, --id <hex_string> : Zenoh桥必须使用的标识符(作为十六进制字符串 - 例如:0A0B23...)。警告:此标识符必须在系统中是唯一的! 如果未设置,将使用随机UUIDv4。
    • --rest-http-port <rest-http-port> : 设置REST API的http端口(默认:8000)
  • DDS相关参数
    • -d, --domain <ID> : DDS域ID。默认设置为0,或者如果定义了环境变量"$ROS_DOMAIN_ID"则设置为该变量。

    • --dds-localhost-only : 如果设置,则仅在本机接口(127.0.0.1)上发生DDS发现和流量。默认设置为false,除非定义了环境变量“ROS_LOCALHOST_ONLY=1”。

    • --dds-enable-shm : 如果设置,则配置DDS使用共享内存。此选项有效的前提是桥接程序使用具有“dds_shm”特性的构建。默认设置为false。

    • -f, --fwd-discovery : 设置后,在发现本地DDS实体时,不是创建本地路由,而是将此发现信息转发到远程插件/桥接程序。这些程序将创建路由,包括发现实体的副本。更多详情请点击此处

    • -s, --scope <String> : 当映射到zenoh键时,用作DDS流量作用域的前缀的字符串。

    • -a, --allow <String> : 匹配必须通过zenoh路由的“分区/主题名称”集的正则表达式。默认情况下,允许所有分区和主题。
      如果同时设置了“允许”和“拒绝”,则如果分区和/或主题仅匹配“允许”表达式,则允许其通过。
      重复此选项以配置多个主题表达式。这些表达式通过“|”连接。

      • .*/TopicA将仅允许TopicA路由,无论分区如何。
      • PartitionX/.*将允许所有主题路由,但仅限于PartitionX
      • cmd_vel|rosout将仅允许名称或分区名称中包含cmd_velrosout的主题通过。
    • --deny <String> : 匹配必须不通过zenoh路由的“分区/主题名称”集的正则表达式。默认情况下,不允许任何分区和主题。
      如果同时设置了“允许”和“拒绝”,则如果分区和/或主题仅匹配“允许”表达式,则允许其通过。
      重复此选项以配置多个主题表达式。这些表达式通过“|”连接。

    • --max-frequency <String>... : 指定每个主题通过zenoh的数据路由的最大频率。字符串必须具有格式"regex=float",其中

      • "regex"是一个正则表达式,匹配必须以不高于相关最大频率(与--allow选项语法相同)的速度路由数据的“分区/主题名称”集。
      • "float" 是赫兹频率的最大值;如果发布速率更高,则在路由时会进行降采样。

      (可多次使用)

    • --queries-timeout <Duration>:当桥查询其他远程桥以获取发现信息和为它服务的 TRANSIENT_LOCAL DDS 读者历史数据时使用的超时时间(默认:5.0 秒)。如果查询远程桥超出了超时,一些历史样本可能不会路由到读者,但路由不会被永久阻塞。

    • -w, --generalise-pub <String>:用于泛化 zenoh 发布声明的键表达式列表,从而最小化发现流量(可多次使用)。请参阅此博客获取更多详细信息。

    • -r, --generalise-sub <String>:用于泛化 zenoh 订阅声明的键表达式列表,从而最小化发现流量(可多次使用)。请参阅此博客获取更多详细信息。

管理空间

DDS 的 zenoh 桥提供了一个管理空间,允许浏览已发现的 DDS 实体(及其 QoS),以及已在 DDS 和 zenoh 之间建立的路由。此管理空间可以通过任何 zenoh API 访问,包括您可以在 zenoh-bridge-dds 启动时使用 --rest-http-port 参数激活的 REST API。

从版本 0.11.0-rc.2 开始,zenoh-bridge-dds 使用以 @/<uuid>/dds 为前缀的路径(其中 <uuid> 是桥实例的唯一标识符)来公开此管理空间。然后,信息按这些路径组织

  • @/<uuid>/dds/version:桥版本
  • @/<uuid>/dds/config:桥配置
  • @/<uuid>/dds/participant/<gid>/reader/<gid>/<topic>:在 <topic> 上发现的 DDS 读者
  • @/<uuid>/dds/participant/<gid>/writer/<gid>/<topic>:在 <topic> 上发现的 DDS 读者。
  • @/<uuid>/dds/route/from_dds/<zenoh-resource>:从 DDS 写入者到名为 <zenoh-resource> 的 zenoh 键建立的路径(参见 映射规则)。
  • @/<uuid>/dds/route/to_dds/<zenoh-resource>:从名为 <zenoh-resource> 的 zenoh 键建立的路径(参见 映射规则)。

对于旧版本,请参阅 README.md 的相应版本:[0.10.1-rc](https://github.com/eclipse-zenoh/zenoh-plugin-dds/blob/0.10.1-rc/README.md#admin-space)。

使用 REST API 和 curl 命令行工具对管理空间进行查询的示例(不要忘记使用 --rest-http-port 8000 参数激活 REST API)

  • 列出所有已发现的 DDS 实体
    curl https://127.0.0.1:8000/@/*/dds/participant/**
    
  • 列出所有建立的路径
    curl https://127.0.0.1:8000/@/*/dds/route/**
    
  • 列出主题 cmd_vel 的所有已发现 DDS 实体和建立的路径
    curl https://127.0.0.1:8000/@/*/dds/**/cmd_vel
    

技巧:将结果传递到 jq 命令进行 JSON 美化打印或转换。

架构细节

DDS 用的 zenoh 桥 发现 DDS 系统中的所有 DDS 写入者和读者,并将每个主题 T 上的 DDS 发布作为 Zenoh 关键表达式 T 上的 Zenoh 发布路由。相反,假设已发现主题 T 上的 DDS 读者,它将关键表达式 T 上的每个 Zenoh 发布作为主题 T 上的 DDS 发布路由。

桥不会反序列化从 DDS 写入者接收的作为 SerializedPayload 的 DDS 数据,其表示形式在 DDS-RTPS 规范 §10 中定义。因此,任何 Zenoh 应用程序为桥提供的 DDS 读者发布的有效负载必须具有此格式

 0...2...........8...............16..............24..............32
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 |   representation_identifier   |    representation_options     |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 ~                                                               ~
 ~ ... Bytes of data representation using a format that ...      ~
 ~ ... depends on the RepresentationIdentifier and options ...   ~
 ~                                                               ~
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

其中前 4 个字节(representation_identifier 和 representation_options)通常是 Big Endian 编码的 {0x00, 0x0} 或 Little Endian 编码的 {0x00, 0x01},其余字节是 CDR 编码的数据。

具体来说,无论是作为库还是作为独立的可执行文件,它都执行相同的功能

  • 在默认模式下

    • 它通过标准DDS发现协议(使用UDP多播)发现任何DDS应用程序声明的DDS读取器和写入器
    • 为每个发现的读取器或写入器创建一个镜像DDS写入器或读取器(使用相同的QoS)
    • 将发现的DDS主题和分区映射到zenoh键(见以下映射详情)
    • 它将用户数据从DDS主题转发到相应的zenoh键,反之亦然
    • 它不会将任何DDS发现信息转发到远程网桥
  • 在“转发发现”模式下

    • 每个网桥将通过zenoh将本地DDS发现数据转发到远程网桥(比原始DDS发现流量更紧凑的方式)
    • 每个通过zenoh接收DDS发现数据的网桥将创建DDS读取器或写入器的副本,具有类似的QoS。这些副本将服务于zenoh的路径,并将被ROS2节点发现。
    • 对于ROS 2系统,每个网桥将以比原始发布更少的强度将ros_discovery_info数据(在远程网桥上)转发。接收后,远程网桥将原始实体的GIDs转换为相应副本的GIDs,并在DDS上重新发布ros_discovery_info。然后,每个主机上的ROS 2节点可以发现完整的ROS图。

DDS主题到zenoh键的映射

DDS和zenoh之间的映射相当简单:给定一个没有设置分区QoS的用于主题A的DDS读取器/写入器,则等效的zenoh键将具有相同的名称:A。如果定义了分区QoS P,则等效的zenoh键将命名为P/A

可选地,网桥可以配置一个作用域,该作用域将用作每个zenoh键的前缀。也就是说,对于作用域S,等效的zenoh键将为:

  • S/A,对于没有分区的主题A
  • S/P/A,对于主题A和分区P

将ROS 2名称映射到zenoh键

从ROS 2主题和服务的名称到DDS主题的映射在此处指定。请注意,ROS 2不使用DDS分区。
根据上述映射以及DDS到zenoh的映射,以下是一些从ROS 2名称到zenoh键的映射示例

ROS2名称 DDS主题名称 zenoh键(无作用域) zenoh键(如果作用域=myscope
主题:/rosout rt/rosout rt/rosout myscope/rt/rosout
主题:/turtle1/cmd_vel rt/turtle1/cmd_vel rt/turtle1/cmd_vel myscope/rt/turtle1/cmd_vel
服务:/turtle1/set_pen rq/turtle1/set_penRequest
rr/turtle1/set_penReply
rq/turtle1/set_penRequest
rr/turtle1/set_penReply
myscope/rq/turtle1/set_penRequest
myscope/rr/turtle1/set_penReply
动作:/turtle1/rotate_absolute rq/turtle1/rotate_absolute/_action/send_goalRequest
rr/turtle1/rotate_absolute/_action/send_goalReply
rq/turtle1/rotate_absolute/_action/cancel_goalRequest
rr/turtle1/rotate_absolute/_action/cancel_goalReply
rq/turtle1/rotate_absolute/_action/get_resultRequest
rr/turtle1/rotate_absolute/_action/get_resultReply
rt/turtle1/rotate_absolute/_action/status
rt/turtle1/rotate_absolute/_action/feedback
rq/turtle1/rotate_absolute/_action/send_goalRequest
rr/turtle1/rotate_absolute/_action/send_goalReply
rq/turtle1/rotate_absolute/_action/cancel_goalRequest
rr/turtle1/rotate_absolute/_action/cancel_goalReply
rq/turtle1/rotate_absolute/_action/get_resultRequest
rr/turtle1/rotate_absolute/_action/get_resultReply
rt/turtle1/rotate_absolute/_action/status
rt/turtle1/rotate_absolute/_action/feedback
myscope/rq/turtle1/rotate_absolute/_action/send_goalRequest
myscope/rr/turtle1/rotate_absolute/_action/send_goalReply
myscope/rq/turtle1/rotate_absolute/_action/cancel_goalRequest
myscope/rr/turtle1/rotate_absolute/_action/cancel_goalReply
myscope/rq/turtle1/rotate_absolute/_action/get_resultRequest
myscope/rr/turtle1/rotate_absolute/_action/get_resultReply
myscope/rt/turtle1/rotate_absolute/_action/status
myscope/rt/turtle1/rotate_absolute/_action/feedback
节点turtlesim的所有参数 rq/turtlesim/list_parametersRequest
rr/turtlesim/list_parametersReply
rq/turtlesim/describe_parametersRequest
rr/turtlesim/描述参数回复
rq/turtlesim/获取参数请求
rr/turtlesim/获取参数回复
rr/turtlesim/获取参数类型回复
rq/turtlesim/获取参数类型请求
rq/turtlesim/设置参数请求
rr/turtlesim/设置参数回复
rq/turtlesim/原子设置参数请求
rr/turtlesim/原子设置参数回复
rq/turtlesim/list_parametersRequest
rr/turtlesim/list_parametersReply
rq/turtlesim/describe_parametersRequest
rr/turtlesim/描述参数回复
rq/turtlesim/获取参数请求
rr/turtlesim/获取参数回复
rr/turtlesim/获取参数类型回复
rq/turtlesim/获取参数类型请求
rq/turtlesim/设置参数请求
rr/turtlesim/设置参数回复
rq/turtlesim/原子设置参数请求
rr/turtlesim/原子设置参数回复
myscope/rq/turtlesim/list_parametersRequest
myscope/rr/turtlesim/list_parametersReply
myscope/rq/turtlesim/describe_parametersRequest
myscope/rr/turtlesim/描述参数回复
myscope/rq/turtlesim/获取参数请求
myscope/rr/turtlesim/获取参数回复
myscope/rr/turtlesim/获取参数类型回复
myscope/rq/turtlesim/获取参数类型请求
myscope/rq/turtlesim/设置参数请求
myscope/rr/turtlesim/设置参数回复
myscope/rq/turtlesim/原子设置参数请求
myscope/rr/turtlesim/原子设置参数回复
特定的ROS发现话题 ros发现信息 ros发现信息 myscope/ros发现信息

依赖项

~43–57MB
~1M SLoC