背景信息
了解《关于组合的概念》,并了解如何编写可组合节点的信息《编写可组合节点》。
先决条件
本教程使用rclcpp_components、ros2component、composition和image_tools包中的可执行文件。如果你按照对应平台的安装说明进行操作,这些应该已经安装好了。
运行Demo
发现可用组件
要查看工作空间中已注册并可用的组件,请在终端中执行以下命令:
ros2 component types
终端将返回所有可用组件的列表:
(... 其他包的组件列表)
composition
composition::Talker
composition::Listener
composition::NodeLikeListener
composition::Server
composition::Client
(... 其他包的组件列表)
使用 ROS 服务进行运行时组合(发布者和订阅者)
在第一个终端中,启动组件容器:
ros2 run rclcpp_components component_container
打开第二个终端,使用ros2命令行工具验证容器是否正在运行:
ros2 component list
你应该会看到组件的名称:
/ComponentManager
在第二个终端中加载talker组件(查看talker 源代码 github.com/ros2/demos/…
ros2 component load /ComponentManager composition composition::Talker
该命令将返回已加载组件的唯一 ID 以及节点名称:
Loaded component 1 into '/ComponentManager' container node as '/talker'
此时,第一个终端应该会显示组件已加载的消息,以及重复的消息发布信息。
在第二个终端中运行另一个命令,加载listener组件(查看 listener 源代码 github.com/ros2/demos/…
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
此时,第一个终端应该会显示每次接收到消息时的重复输出。
使用 ROS 服务进行运行时组合(服务端和客户端)
服务端和客户端的示例与上述示例非常相似。
服务端源代码: github.com/ros2/demos/…
客户端源代码: github.com/ros2/demos/…)
在第一个终端中输入:
ros2 run rclcpp_components component_container
然后在第二个终端中输入:
ros2 component load /ComponentManager composition composition::Server
ros2 component load /ComponentManager composition composition::Client
在这种情况下,客户端向服务端发送请求,服务端处理请求并返回响应,客户端打印接收到的响应。
编译时组合(硬编码节点)
这个Demo展示了共享库可以在不使用 ROS 接口的情况下,被重新用于编译一个运行了多个组件的单个可执行文件。该可执行文件包含上述的所有四个组件:talker、listener、server和client,这些组件在主函数中进行了硬编码。具体可查看源代码 github.com/ros2/demos/…
在终端中调用:
ros2 run composition manual_composition
这应该会显示talker和listener以及server和client这两对节点的不断重复的消息。
注意事项
手动组合的组件不会在ros2 component list命令行工具的输出中显示。
使用 dlopen 进行运行时组合
这里展示了一种运行时组合的替代方法,即创建一个通用的容器进程,并在不使用 ROS 接口的情况下显式地传递要加载的库。该进程将打开每个库,并在库中创建每个rclcpp::Node类的一个实例(源代码 github.com/ros2/demos/…
ros2 run composition dlopen_composition `ros2 pkg prefix composition`/lib/libtalker_component.so `ros2 pkg prefix composition`/lib/liblistener_component.so
此时,终端应该会显示每次发送和接收消息的不断重复的消息。
注意事项
使用dlopen组合的组件同样不会在ros2 component list命令行工具的输出中显示。
使用启动动作进行组合
虽然命令行工具对于调试和诊断组件配置很有用,但是通常同时启动一组组件会更方便。为了自动化这个操作,我们可以使用启动文件:
ros2 launch composition composition_demo_launch.py
组合进阶
现在我们已经了解了组件的基本操作,接下来可以讨论一些更高级的主题。
组件容器类型
有几种不同选项的组件容器类型。你可以根据自己的需求选择最合适的组件容器类型。
component_container(无可用选项/参数)
ros2 run rclcpp_components component_container
component_container_mt,使用由 4 个线程组成的MultiThreadedExecutor。可以使用thread_num参数选项指定MultiThreadedExecutor中的线程数。
ros2 run rclcpp_components component_container_mt --ros-args -p thread_num:=4
component_container_isolated,为每个组件使用MultiThreadedExecutor。--use_multi_threaded_executor参数指定为每个组件使用的执行器类型为MultiThreadedExecutor。
ros2 run rclcpp_components component_container_isolated --use_multi_threaded_executor
卸载组件
在第一个终端中,启动组件容器:
ros2 run rclcpp_components component_container
使用ros2命令行工具验证容器是否正在运行:
ros2 component list
你应该会看到组件的名称:
/ComponentManager
在第二个终端中,像之前一样加载talker和listener组件:
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
在第一个终端中,验证talker和listener的重复消息是否已经停止。
重映射容器名称和命名空间
可以通过标准命令行参数重映射组件管理器的名称和命名空间:
ros2 run rclcpp_components component_container --ros-args -r __node:=MyContainer -r __ns:=/ns
在第二个终端中,可以使用更新后的容器名称加载组件:
ros2 component load /ns/MyContainer composition composition::Listener
注意事项
容器的命名空间重映射不会影响已加载的组件。
重映射组件名称和命名空间
可以通过load命令的参数调整组件的名称和命名空间。
在第一个终端中,启动组件容器:
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 component load命令行支持在节点构造时向其传递任意参数。可以按如下方式使用此功能:
ros2 component load /ComponentManager image_tools image_tools::Cam2Image -p burger_mode:=true
向组件传递额外参数
ros2 component load命令行支持向组件管理器传递特定选项,以便在构造节点时使用。
以下示例展示了如何使用额外参数use_intra_process_comms和forward_global_arguments:
ros2 component load /ComponentManager composition composition::Talker -e use_intra_process_comms:=true -e forward_global_arguments:=false
支持以下额外参数:
| 参数 | 类型 | 默认值 | 描述 |
|---|---|---|---|
| forward_global_arguments | 布尔值 | true | 加载组件节点时应用全局参数。 |
| use_intra_process_comms | 布尔值 | false | 启用组件节点中的进程内通信。 |
可组合节点作为共享库
如果要将可组合节点从软件包导出为共享库,并在链接时组合的软件包中使用该节点,请将代码添加到 CMake 文件中,该文件将导入下游软件包中的实际目标
然后安装生成的文件并导出该文件。
可以在此处查看一个实际示例: ROS Discourse - Ament 共享库的最佳实践 (answers.ros.org/question/30…)
组合非节点派生组件
在 ROS2 中,组件允许更有效地使用系统资源,并提供了一个强大的功能,使你能够创建不依赖于特定节点的可重用功能。
使用组件的一个优点是,它们允许你将非节点派生的功能创建为独立的可执行文件或共享库,并在需要时加载到 ROS 系统中。
要创建一个非节点派生的组件,请遵循以下准则:
- 实现一个接受
const rclcpp::NodeOptions&作为参数的构造函数。 - 实现
get_node_base_interface()方法,该方法应返回一个NodeBaseInterface::SharedPtr。你可以用构造函数创建的节点的get_node_base_interface()方法来提供此接口。
以下是一个非节点派生的组件示例,它监听一个 ROS topic: node_like_listener_component (github.com/ros2/demos/…
有关这个主题的更多信息,你可以参考这个讨论: github.com/ros2/rclcpp…
关注【智践行】,发送 【机器人】 获得机器人经典学习资料