警告

您正在阅读的 ROS 2 文档版本已达到 EOL(生命周期结束),不再受官方支持。如果您想了解最新信息,请访问 Jazzy.

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

ROS 1 - 节点与小节点

在 ROS 1 中,您可以将代码写成 ROS 节点 或作为 ROS 小节点.ROS 1 节点被编译成可执行文件。而 ROS 1 小节点则编译成共享库,然后由容器进程在运行时加载。

ROS 2 - 统一应用程序接口

在 ROS 2 中,推荐的代码书写方式与节点小程序类似,我们称之为 组件.这样就很容易在现有代码中添加通用概念,如 生命周期.ROS 2 避免了不同应用程序接口的最大缺点,因为这两种方法在 ROS 2 中使用相同的应用程序接口。

备注

使用类似节点的 "编写自己的主程序 "的方式也是可行的,但在一般情况下并不推荐使用。

将流程布局作为一个部署时间决策,用户可以在两者之间做出选择:

  • 在独立进程中运行多个节点,具有进程/故障隔离以及更容易调试单个节点的优点,而且

  • 在单个进程中运行多个节点,开销更低,通信效率更高(见 流程内交流).

此外 玫瑰2 启动 可用于通过专门的启动操作自动执行这些操作。

编写组件

由于组件只内置在共享库中,因此它没有 主要 函数(见 Talker 源代码).组件通常是 rclcpp::Node.由于它不受线程控制,因此不应在构造函数中执行任何长时间运行或阻塞的任务。相反,它可以使用定时器获取定期通知。此外,它还可以创建发布者、订阅者、服务器和客户端。

让这样的类成为组件的一个重要方面是,该类使用软件包中的宏来注册自己。 rclcpp_components (见源代码最后一行)。这样,在运行进程中加载组件库时,就可以发现该组件--它就像一个入口点。

此外,一旦创建了一个组件,它就必须在索引中注册,才能被工具发现。

add_library(对话者组件 共享
   src/talker_component.cpp)
rclcpp_components_register_nodes(对话者组件 "composition::Talker";)
# 若要在同一共享库中注册多个组件,可多次调用
# rclcpp_components_register_nodes(talker_component "composition::Talker2")

备注

为了让 component_container 能够找到所需的组件,它必须从已获取相应工作区的 shell 中执行或启动。

使用组件

"(《世界人权宣言》) 构成 软件包包含几种不同的组件使用方法。最常见的有三种:

  1. 启动一个 (通用容器流程) 并调用 ROS 服务 加载节点 容器提供的组件。然后,ROS 服务将加载由传递的软件包名称和库名称指定的组件,并在运行进程中开始执行。你也可以使用一个 命令行工具 使用传入的命令行参数调用 ROS 服务

  2. 创建一个 自定义执行 包含编译时已知的多个节点。这种方法要求每个组件都有一个头文件(在第一种情况下,严格来说并不需要)。

  3. 创建启动文件并使用 玫瑰2 启动 来创建一个已加载多个组件的容器进程。

运行演示

这些演示使用的可执行文件来自 rclcpp_components, ros2component构成 软件包,并可使用以下命令运行。

了解可用组件

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

$ 玫瑰2 组成部分 类型构成
  构成::谈话者
  composition::Listener
  组成::服务器
  composition::Client

使用 ROS 服务 (1.) 与发布者和订阅者进行运行时组合

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

玫瑰2 运行 rclcpp_components 组件容器

通过 玫瑰2 命令行工具:

$ 玫瑰2 组成部分 list /ComponentManager

在第二个外壳中(见 话匣子 源代码)。该命令将返回已加载组件的唯一 ID 和节点名称。

$ 玫瑰2 组成部分 负荷 /ComponentManager 构成 composition::Talker Loaded 组成部分 1  '/ComponentManager'; 集装箱 网站 作为 '/talker';

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

第二个 shell 中的另一条命令(见 听众 源代码):

$ 玫瑰2 组成部分 负荷 /ComponentManager 构成 已加载 composition::Listener 组成部分 2  '/ComponentManager'; 集装箱 网站 作为 '/listener';

"(《世界人权宣言》) 玫瑰2 命令行实用程序现在可以用来检查容器的状态:

$ 玫瑰2 组成部分 list /ComponentManager
   1  /对话者
   2  /听众

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

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

服务器和客户端的例子非常相似。

第一个外壳

玫瑰2 运行 rclcpp_components 组件容器

在第二个外壳中(见 服务器客户 源代码):

玫瑰2 组成部分 负荷 /ComponentManager 构成 composition::Server ros2 组成部分 负荷 /ComponentManager 构成 composition::Client

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

使用 ROS 服务进行编译时合成 (2.)

该演示表明,可以重复使用相同的共享库来编译运行多个组件的单个可执行文件。该可执行文件包含上述所有四个组件:通话器和监听器以及服务器和客户端。

在 shell 调用中(见 源代码):

玫瑰2 运行 构成 手动合成

这应该会显示来自交谈者和倾听者以及服务器和客户端这两对人的重复信息。

备注

手动组成的组件不会反映在 玫瑰2 组成部分 清单 命令行工具输出。

使用 dlopen 进行运行时合成

本演示介绍了 1.的替代方法,即创建一个通用容器进程,明确传递要加载的库,而不使用 ROS 接口。进程将打开每个库,并为库中的每个 "rclcpp::Node "类创建一个实例 源代码).

玫瑰2 运行 构成 dlopen_composition `玫瑰2  词头 构成`/lib/libtalker_component.so `玫瑰2  词头 构成`/lib/liblistener_component.so

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

备注

dlopen 组件不会反映在 玫瑰2 组成部分 清单 命令行工具输出。

使用发射行动进行合成

虽然命令行工具对调试和诊断组件配置很有用,但同时启动一组组件往往更方便。为了自动执行这一操作,我们可以使用 玫瑰2 启动.

玫瑰2 启动 构成 composition_demo.launch.py

高级主题

在了解了组件的基本操作之后,我们可以讨论一些更高级的话题。

卸载组件

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

玫瑰2 运行 rclcpp_components 组件容器

通过 玫瑰2 命令行工具:

$ 玫瑰2 组成部分 list /ComponentManager

在第二个外壳中(见 话匣子 源代码)。该命令将返回已加载组件的唯一 ID 和节点名称。

$ 玫瑰2 组成部分 负荷 /ComponentManager 构成 composition::Talker Loaded 组成部分 1  '/ComponentManager'; 集装箱 网站 作为 '/talker';
$ 玫瑰2 组成部分 负荷 /ComponentManager 构成 已加载 composition::Listener 组成部分 2  '/ComponentManager'; 集装箱 网站 作为 '/listener';

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

$ 玫瑰2 组成部分 卸载 /ComponentManager 1 2
已卸载 组成部分 1  '/ComponentManager'; 卸载的集装箱 组成部分 2  '/ComponentManager'; 集装箱

在第一个 shell 中,验证通话者和监听者的重复信息是否已经停止。

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

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

玫瑰2 运行 rclcpp_components 组件容器 --ros-args -r __节点:=我的容器 -r __ns:=/ns

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

玫瑰2 组成部分 负荷 /ns/MyContainer 构成 composition::Listener

备注

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

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

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

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

玫瑰2 运行 rclcpp_components 组件容器

如何重新映射名称和命名空间的一些示例:

# 重新映射节点名称
玫瑰2 组成部分 负荷 /ComponentManager 构成 构成::谈话者 --节点名 Talker2
# 重新映射命名空间
玫瑰2 组成部分 负荷 /ComponentManager 构成 构成::谈话者 --节点名称空间 /ns
# 重新映射两者
玫瑰2 组成部分 负荷 /ComponentManager 构成 构成::谈话者 --节点名 talker3 --节点名称空间 /ns2

相应的条目出现在 玫瑰2 组成部分 清单:

$ 玫瑰2 组成部分 list /ComponentManager
   1  /talker2
   2  /ns/talker
   3  /ns2/talker3

备注

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