ROS2入门教程-Composition简介
ROS2入门教程-Composition简介
说明:
- 介绍ros2 Composition
ROS 1 - 节点与 Nodelets
- 在 ROS 1 中,您可以将代码编写为 ROS 节点或 ROS nodelet。 ROS 1 节点被编译成可执行文件。
- 另一方面,ROS 1 nodelet 被编译成一个共享库,然后在运行时由容器进程加载。
ROS 2 - 统一 API
- 在 ROS 2 中,推荐的编写代码的方式类似于 nodelet——我们称之为组件。
- 这使得向现有代码添加通用概念变得容易,例如生命周期。
- ROS 2 避免了不同 API 的最大缺点,因为两种方法在 ROS 2 中使用相同的 API。
统一API的好处:
- 在单独的进程中运行多个节点,具有进程/故障隔离的好处以及更容易调试单个节点
- 在单个进程中运行多个节点,具有更低的开销和更有效的通信(请参阅进程内通信)。
- 此外,ros2 launch启动可用于通过专门的启动操作自动执行这些操作。
编写组件
由于组件仅内置在共享库中,因此它没有 main 函数(参见 Talker 源代码)。
组件通常是 rclcpp::Node 的子类。 由于它不受线程控制,因此不应在其构造函数中执行任何长时间运行或阻塞的任务。
相反,它可以使用计时器来获得定期通知。
此外,它还可以创建发布者、订阅者、服务器和客户端。
使这样的类成为组件的一个重要方面是该类使用包 rclcpp_components 中的宏注册自己(参见源代码中的最后一行)。
add_library(talker_component SHARED
src/talker_component.cpp)
rclcpp_components_register_nodes(talker_component "composition::Talker")
# To register multiple components in the same shared library, use multiple calls
# rclcpp_components_register_nodes(talker_component "composition::Talker2")
- 这使得组件在其库被加载到正在运行的进程中时可被发现 - 它充当一种入口点。
- 此外,一旦创建了组件,就必须使用索引注册它才能被工具发现。
- 为了使 component_container 能够找到所需的组件,它必须从提供了相应工作空间的 shell 执行或启动。
使用组件
- 组合包包含一些关于如何使用组件的不同方法。
- 最常见的三种是:
- 1.启动一个(通用容器进程)并调用容器提供的 ROS 服务 load_node。 然后,ROS 服务将加载由传递的包名和库名指定的组件,并开始在正在运行的进程中执行它。 除了以编程方式调用 ROS 服务,您还可以使用命令行工具通过传递的命令行参数调用 ROS 服务
- 2.创建包含多个在编译时已知的节点的自定义可执行文件。 这种方法要求每个组件都有一个头文件(第一种情况并不严格需要)。
- 3.创建一个launch文件,使用ros2 launch创建一个加载了多个组件的容器进程。
演示
- 使用来自 rclcpp_components、ros2component 和组合包的可执行文件,并且可以使用以下命令运行。
- 发现可用组件
- 要查看工作区中已注册和可用的组件,请在 shell 中执行以下命令:
ros2 component types
- 终端将返回所有可用组件的列表:
(... components of other packages here)
composition
composition::Talker
composition::Listener
composition::Server
composition::Client
使用具有发布者和订阅者的 ROS 服务的运行时组合
- 在第一个 shell 中,启动组件容器:
ros2 run rclcpp_components component_container
- 打开第二个 shell 并通过 ros2 命令行工具验证容器是否正在运行:
ros2 component list
- 您应该会看到组件的名称:
/ComponentManager
- 在第二个 shell 中加载talker 组件(参见talker 源代码):
ros2 component load /ComponentManager composition composition::Talker
- 该命令将返回加载组件的唯一 ID 以及节点名称:
Loaded component 1 into '/ComponentManager' container node as '/talker'
现在第一个 shell 应该显示一个组件已加载的消息以及用于发布消息的重复消息。
在第二个 shell 中运行另一个命令以加载侦听器组件(请参阅侦听器源代码):
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
ros2 component load /ComponentManager composition composition::Server
ros2 component load /ComponentManager composition composition::Client
- 在这种情况下,客户端向服务器发送请求,服务器处理请求并回复响应,客户端打印收到的响应。
使用 ROS 服务的编译时组合
- 该演示表明,可以重用相同的共享库来编译运行多个组件的单个可执行文件。
- 可执行文件包含上面的所有四个组件:talker 和 listener 以及 server 和 client。
- 在 shell 调用中(参见源代码):
ros2 run composition manual_composition
- 这应该显示来自talker和listener 以及server 和client的重复消息。
- 手动编写的组件不会反映在 ros2 组件列表命令行工具输出中。
使用 dlopen的运行时组合
该演示通过创建通用容器进程并显式传递要加载的库而不使用 ROS 接口,提供了运行时组合的替代方案。
该过程将打开每个库并在库源代码中为每个“rclcpp::Node”类创建一个实例)。
现在,shell 应该为每个talker和listener的消息显示重复的输出。
dlopen-composed 组件不会反映在 ros2 组件列表命令行工具输出中。
ros2 run composition dlopen_composition
ros2 pkg prefix composition
/lib/libtalker_component.soros2 pkg prefix composition
/lib/liblistener_component.so
使用launch启动的组合
- 虽然命令行工具对于调试和诊断组件配置很有用,但同时启动一组组件通常更方便。 要自动执行此操作,我们可以使用 ros2 启动中的功能。
ros2 launch composition composition_demo.launch.py
- 现在我们已经了解了组件的基本操作,我们可以讨论一些更高级的主题。
卸载组件
- 在第一个 shell 中,启动组件容器:
ros2 run rclcpp_components component_container
- 通过 ros2 命令行工具验证容器是否正在运行:
ros2 component list
- 您应该会看到组件的名称:
/ComponentManager
- 在第二个 shell 中(参见talker 源代码)。
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
- 容器的命名空间重新映射不会影响加载的组件。
重新映射组件名称和命名空间
组件名称和命名空间可以通过加载命令的参数进行调整。
在第一个 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
- 容器的命名空间重新映射不会影响加载的组件。
将参数值传递给组件
- ros2 组件加载命令行支持在构建节点时将任意参数传递给节点。
- 此功能可按如下方式使用:
ros2 component load /ComponentManager image_tools image_tools::Cam2Image -p burger_mode:=true
- 将附加参数传递给组件
- ros2 组件加载命令行支持将特定选项传递给组件管理器,以便在构建节点时使用。
- 到目前为止,唯一受支持的命令行选项是使用进程内通信来实例化节点。
- 此功能可按如下方式使用:
ros2 component load /ComponentManager composition composition::Talker -e use_intra_process_comms:=true
作为共享库的可组合节点
- 如果要将可组合节点作为共享库从包中导出并在另一个执行链接时组合的包中使用该节点
- 请将代码添加到 CMake 文件中,该文件会在下游包中导入实际目标。
- 然后安装生成的文件并导出生成的文件。
- 一个实际的例子可以在这里看到:ROS Discourse - Ament best practice for sharing library
获取最新文章: 扫一扫右上角的二维码加入“创客智造”公众号