在单个进程中组合多个节点

目标: 将多个节点组合成一个进程。

教程级别: 中级

时间: 20 分钟

背景

请参阅 概念文章

有关如何编写可组合节点的信息,请参阅 本教程

先决条件

本教程使用 rclcpp_componentsros2componentcompositionimage_tools 包中的可执行文件。如果您已按照适用于您平台的 安装说明 进行操作,则这些应该已经安装。

运行演示

发现可用组件

要查看工作区中已注册且可用的组件,请在 shell 中执行以下操作:

ros2 component types

终端将返回所有可用组件的列表:

(... components of other packages here)
composition
  composition::Talker
  composition::Listener
  composition::NodeLikeListener
  composition::Server
  composition::Client
(... components of other packages here)

使用带有发布者和订阅者的 ROS 服务进行运行时组合

在第一个 shell 中,启动组件容器:

ros2 run rclcpp_components component_container

打开第二个shell并通过“ros2”命令行工具验证容器是否正在运行:

ros2 component list

您应该看到该组件的名称:

/ComponentManager

在第二个 shell 中加载 talker 组件 (see talker source code):

ros2 component load /ComponentManager composition composition::Talker

该命令将返回已加载组件的唯一 ID 以及节点名称:

Loaded component 1 into '/ComponentManager' container node as '/talker'

现在第一个 shell 应该显示组件已加载的消息以及发布消息的重复消息。

在第二个 shell 中运行另一个命令来加载侦听器组件(参见 listener 源代码):

ros2 component load /ComponentManager composition composition::Listener

终端将返回:

Loaded component 2 into '/ComponentManager' container node as '/listener'

现在可以使用“ros2”命令行实用程序来检查容器的状态:

ros2 component list

您将看到以下结果:

/ComponentManager
   1  /talker
   2  /listener

现在,第一个 shell 应该显示每个收到的消息的重复输出。

使用 ROS 服务与服务器和客户端进行运行时组合

带有服务器和客户端的示例非常相似。

在第一个 shell 中:

ros2 run rclcpp_components component_container

在第二个 shell 中 (see server and client source code):

ros2 component load /ComponentManager composition composition::Server
ros2 component load /ComponentManager composition composition::Client

在这种情况下,客户端向服务器发送请求,服务器处理该请求并回复响应,客户端打印收到的响应。

使用硬编码节点进行编译时组合

此演示表明,可以重复使用相同的共享库来编译运行多个组件的单个可执行文件,而无需使用 ROS 接口。 可执行文件包含上述所有四个组件:talker 和 listener 以及服务器和客户端,它们在主函数中被硬编码。

在 shell 中调用 (see source code):

ros2 run composition manual_composition

这应该显示来自两对、讲话者和听众以及服务器和客户端的重复消息。

Note

手动组成的组件不会反映在“ros2 组件列表”命令行工具输出中。

使用 dlopen 进行运行时组合

此演示通过创建通用容器进程并明确传递要加载的库(不使用 ROS 接口)来介绍运行时组合的替代方案。 该进程将打开每个库并在库中为每个“rclcpp::Node”类创建一个实例(源代码)。

ros2 run composition dlopen_composition `ros2 pkg prefix composition`/lib/libtalker_component.so `ros2 pkg prefix composition`/lib/liblistener_component.so

现在 shell 应该显示每个发送和接收消息的重复输出。

Note

dlopen-composed 组件不会反映在“ros2 组件列表”命令行工具输出中。

使用启动操作进行组合

虽然命令行工具对于调试和诊断组件配置很有用,但同时启动一组组件通常更方便。 为了自动执行此操作,我们可以使用`启动文件<https://github.com/ros2/demos/blob/rolling/composition/launch/composition_demo.launch.py​​>`__:

ros2 launch composition composition_demo.launch.py

高级主题

现在我们已经了解了组件的基本操作,我们可以讨论几个更高级的主题。

卸载组件

在第一个 shell 中,启动组件容器:

ros2 run rclcpp_components component_container

通过“ros2”命令行工具验证容器是否正在运行:

ros2 component list

您应该看到该组件的名称:

/ComponentManager

在第二个 shell 中,像之前一样加载说话者和监听者:

ros2 component load /ComponentManager composition composition::Talker
ros2 component load /ComponentManager composition composition::Listener

使用唯一ID从组件容器中卸载节点。

ros2 component unload /ComponentManager 1 2

终端应该返回:

Unloaded component 1 from '/ComponentManager' container
Unloaded component 2 from '/ComponentManager' container

在第一个 shell 中,验证来自 talker 和 listener 的重复消息是否已停止。

重新映射容器名称和命名空间

可以通过标准命令行参数重新映射组件管理器名称和命名空间:

ros2 run rclcpp_components component_container --ros-args -r __node:=MyContainer -r __ns:=/ns

在第二个 shell 中,可以使用更新后的容器名称加载组件:

ros2 component load /ns/MyContainer composition composition::Listener

Note

容器的命名空间重新映射不会影响已加载的组件。

重新映射组件名称和命名空间

组件名称和命名空间可以通过 load 命令的参数进行调整。

在第一个 shell 中,启动组件容器:

ros2 run rclcpp_components component_container

以下是一些如何重新映射名称和命名空间的示例。

重新映射节点名称:

ros2 component load /ComponentManager composition composition::Talker --node-name talker2

重新映射命名空间:

ros2 component load /ComponentManager composition composition::Talker --node-namespace /ns

重新映射两者:

ros2 component load /ComponentManager composition composition::Talker --node-name talker3 --node-namespace /ns2

现在使用“ros2”命令行实用程序:

ros2 component list

您应该在控制台中看到相应的条目:

/ComponentManager
   1  /talker2
   2  /ns/talker
   3  /ns2/talker3

Note

容器的命名空间重新映射不会影响已加载的组件。

将参数值传递给组件

“ros2 component load”命令行支持在构建节点时向其传递任意参数。 此功能可按如下方式使用:

ros2 component load /ComponentManager image_tools image_tools::Cam2Image -p burger_mode:=true

将附加参数传递给组件

ros2 component load 命令行支持将特定选项传递给组件管理器以供构建节点时使用。 到目前为止,唯一支持的命令行选项是使用进程内通信实例化节点。 此功能可以按如下方式使用:

ros2 component load /ComponentManager composition composition::Talker -e use_intra_process_comms:=true

可组合节点作为共享库

如果您想要从包中将可组合节点导出为共享库,并在执行链接时组合的另一个包中使用该节点,请将代码添加到 CMake 文件中,该文件将导入下游包中的实际目标。

然后安装生成的文件并导出生成的文件。

此处可以看到一个实际示例:ROS Discourse - Ament 共享库的最佳实践

组合非节点派生组件

在 ROS 2 中,组件允许更有效地使用系统资源,并提供强大的功能,使您能够创建不与特定节点绑定的可重用功能。

使用组件的一个优点是,它们允许您将非节点派生功能创建为独立的可执行文件或共享库,可以根据需要加载到 ROS 系统中。

要创建非从节点派生的组件,请遵循以下准则:

  1. 实现以 const rclcpp::NodeOptions& 作为其参数的构造函数。

  2. 实现 get_node_base_interface() 方法,该方法应返回 NodeBaseInterface::SharedPtr。您可以使用在构造函数中创建的节点的 get_node_base_interface() 方法来提供此接口。

以下是非从节点派生的组件的示例,它监听 ROS 主题:node_like_listener_component

有关该主题的更多信息,您可以参考此`讨论<https://github.com/ros2/rclcpp/issues/2110#issuecomment-1454228192>`__。