ROS2编程基础课程–Component

  • 2019 年 10 月 5 日
  • 筆記

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

本文链接:https://blog.csdn.net/ZhangRelay/article/details/100773710

Composing multiple nodes in a single process

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

ROS 1 – Nodes vs. Nodelets ROS 1 -节点与Nodelets

In ROS 1 you can write your code either as a ROS node or as a ROS nodelet. ROS 1 nodes are compiled into executables. ROS 1 nodelets on the other hand are compiled into a shared library which is then loaded at runtime by a container process.

在ROS 1,无论是作为一个ROS节点或作为ROS nodelet都可以通过代码实现。ROS 1节点被编译成可执行文件。另一方面,ROS 1 nodelets被编译成共享库,然后由容器进程在运行时加载。

ROS 2 – Unified API ROS 2 – 统一API

In ROS 2 the recommended way of writing your code is similar to a nodelet – we call it a Component. This makes is easy to add common concepts to existing code, like a life cycle. The biggest drawback of different APIs is avoided in ROS 2 since both approaches use the same API in ROS 2.

在ROS 2中,编写代码的推荐方法类似于nodelet – 我们称之为Component。这样可以很容易地将常见概念添加到现有代码中,例如生命周期。ROS 2中避免了不同API的最大缺点,因为这两种方法在ROS 2中使用相同的API。

Note 注意

It is still possible to use the node-like style of “writing your own main” but for the common case it is not recommended.

仍然可以使用类似节点的“编写自定义main”样式,但对于常见情况,不推荐使用。

By making the process layout a deploy-time decision the user can choose between:

通过使流程布局成为部署时决策,用户可以选择:

  • running multiple nodes in separate processes with the benefits of process/fault isolation as well as easier debugging of individual nodes and

在单独的进程中运行多个节点,具有进程/故障隔离的好处,以及更容易调试单个节点和

  • running multiple nodes in a single process with the lower overhead and optionally more efficient communication (see Intra Process Communication).

在单个进程中运行多个节点,具有较低的开销和可选的更高效的通信(请参考进程内通信)。

Additionally ros2 launch can be used to automate these actions through specialized launch actions.

此外,ros2 launch还可用于通过专门的启动操作自动执行这些操作。

Writing a Component 编写组件

Since a component is only built into a shared library it doesn’t have a main function (see Talker source code). A component is commonly a subclass of rclcpp::Node. Since it is not in control of the thread it shouldn’t perform any long running or blocking tasks in its constructor. Instead it can use timers to get periodic notification. Additionally it can create publishers, subscribers, servers, and clients.

由于组件仅编译在共享库中,因此它没有main函数(请参考Talker源代码)。组件通常是子类rclcpp::Node。由于它不受线程控制,因此不应在其构造函数中执行任何长时间运行或阻塞任务。相反,它可以使用计时器来获得定期通知。此外,它还可以创建发布器,订阅器,服务器和客户端。

An important aspect of making such a class a component is that the class registers itself using macros from the package rclcpp_components (see the last line in the source code). This makes the component discoverable when its library is being loaded into a running process – it acts as kind of an entry point.

将这样的类作为组件的一个重要方面是类使用rclcpp_components包中的宏来注册自己(参考源代码中的最后一行)。这使得组件在将其库加载到正在运行的进程时可被发现 – 它充当入口点。

Additionally, once a component is created, it must be registered with the index to be discoverable by the tooling.

此外,一旦创建了组件,就必须将其注册到工具可以发现的索引。

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")

Note 注意

In order for the component_container to be able to find desired components, it must be executed or launched from a shell that has sourced the corresponding workspace.

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

Using Components 使用组件

The composition package contains a couple of different approaches on how to use components. The three most common ones are:

组合包中包含了一些关于如何使用的组件不同的方法。最常见的三种是:

  • Start a (generic container process) and call the ROS service load_node offered by the container. The ROS service will then load the component specified by the passed package name and library name and start executing it within the running process. Instead of calling the ROS service programmatically you can also use a command line tool to invoke the ROS service with the passed command line arguments

启动(通用容器进程)并调用容器提供的ROS服务load_node。然后,ROS服务将加载由传递的包名和库名 指定的组件,并在运行的进程中开始执行它。您不必以编程方式调用ROS服务,也可以使用命令行工具使用 传递的命令行参数调用ROS服务

  • Create a custom executable containing multiple nodes which are known at compile time. This approach requires that each component has a header file (which is not strictly needed for the first case).

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

  • Create a launch file and use ros2 launch to create a container process with multiple components loaded.

创建启动文件并用ros2 launch创建加载了多个组件的容器进程。

Run the demos 运行演示

The demos use executables from rclcpp_components, ros2component, and composition packages, and can be run with the following commands.

演示使用来自rclcpp_componentsros2componentcomposition包的可执行文件,并且可以使用以下命令运行。

Discover available components 发现可用的组件

To see what components are registered and available in the workspace, execute the following in a shell:

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

$ ros2 component types

composition

composition::Talker

composition::Listener

composition::Server

composition::Client

Run-time composition using ROS services (1.) with a publisher and subscriber

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

In the first shell, start the component container:

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

ros2 run rclcpp_components component_container

Verify that the container is running via ros2 command line tools:

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

$ ros2 component list

/ComponentManager

In the second shell (see talker source code). The command will return the unique ID of the loaded component as well as the node name.

在第二个shell中(参考talker源代码)。该命令将返回已加载组件的唯一ID以及节点名称。

$ ros2 component load /ComponentManager composition composition::Talker

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

Now the first shell should show a message that the component was loaded as well as repeated message for publishing a message.

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

Another command in the second shell (see listener source code):

第二个shell中的另一个命令(参考监听器源代码):

$ ros2 component load /ComponentManager composition composition::Listener

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

The ros2 command line utility can now be used to inspect the state of the container:

该ros2命令行实用程序现在可以用于检查容器的状态:

$ ros2 component list

/ComponentManager

1 /talker

2 /listener

Now the first shell should show repeated output for each received message.

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

Run-time composition using ROS services (1.) with a server and client

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

The example with a server and a client is very similar. 服务器和客户端的示例非常相似。

In the first shell: 在第一个shell中:

ros2 run rclcpp_components component_container

In the second shell (see server and client source code): 在第二个shell中(请参考服务器客户端源代码):

ros2 component load /ComponentManager composition composition::Server

ros2 component load /ComponentManager composition composition::Client

In this case the client sends a request to the server, the server processes the request and replies with a response, and the client prints the received response.

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

Compile-time composition using ROS services (2.)

使用ROS服务编译时组成(2.)

This demos shows that the same shared libraries can be reused to compile a single executable running multiple components. The executable contains all four components from above: talker and listener as well as server and client.

此演示显示可以重用相同的共享库来编译运行多个组件的单个可执行文件。可执行文件包含上面的所有四个组件:talker和listener以及服务器和客户端。

In the shell call (see source code):

在shell调用中(参考源代码):

ros2 run composition manual_composition

This should show repeated messages from both pairs, the talker and the listener as well as the server and the client.

这应该显示来自两个对,发布器和听众以及服务器和客户端的重复消息。

Note 注意

Manually-composed components will not be reflected in the ros2 component list command line tool output. 手动编写的组件不会反映在ros2 component list命令行工具输出中。

Run-time composition using dlopen 使用dlopen运行时组合

This demo presents an alternative to 1. by creating a generic container process and explicitly passing the libraries to load without using ROS interfaces. The process will open each library and create one instance of each “rclcpp::Node” class in the library source code).

此演示提供了1的替代方法,通过创建通用容器进程并显式传递库而不使用ROS接口。该过程将打开每个库并在库源代码中创建每个“rclcpp :: Node”类的一个实例。

Linux In the shell call: Linux在shell中调用:

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

OSX In the shell call:

OSX在shell中调用:

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

Windows In cmd.exe call

Windows在cmd.exe中调用

ros2 pkg prefix composition

to get the path to where composition is installed. Then call

获取安装组合的路径。然后调用:

ros2 run composition dlopen_composition <path_to_composition_install>bintalker_component.dll <path_to_composition_install>binlistener_component.dll

Now the shell should show repeated output for each sent and received message.

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

Note 注意

dlopen-composed components will not be reflected in the ros2 component list command line tool output.

dlopen组成的组件不会反映在命令行ros2 component list工具输出中。

Composition using launch actions

使用launch启动行动的组合

While the command line tools are useful for debugging and diagnosing component configurations, it is frequently more convenient to start a set of components at the same time. To automate this action, we can use the functionality in ros2 launch.

虽然命令行工具对于调试和诊断组件配置很有用,但同时启动一组组件通常更方便。要自动执行此操作,可以使用ros2 launch功能。

ros2 launch composition composition_demo.launch.py

Advanced Topics 高级主题

Now that we have seen the basic operation of components, we can discuss a few more advanced topics.

现在已经看到了组件的基本操作,我们可以讨论一些更高级的主题。

Unloading components 卸载组件

In the first shell, start the component container: 在第一个shell中,启动组件容器:

ros2 run rclcpp_components component_container

Verify that the container is running via ros2 command line tools: 通过ros2命令行工具验证容器是否正在运行:

$ ros2 component list

/ComponentManager

In the second shell (see talker source code). The command will return the unique ID of the loaded component as well as the node name.

在第二个shell中(参考talker源代码)。该命令将返回已加载组件的唯一ID以及节点名称。

$ ros2 component load /ComponentManager composition composition::Talker

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

$ ros2 component load /ComponentManager composition composition::Listener

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

Use the unique ID to unload the node from the component container.

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

$ ros2 component unload /ComponentManager 1 2

Unloaded component 1 from '/ComponentManager' container

Unloaded component 2 from '/ComponentManager' container

In the first shell, verify that the repeated messages from talker and listener have stopped.

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

Remapping container name and namespace

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

The component manager name and namespace can be remapped via standard command line arguments:

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

ros2 run rclcpp_components component_container __node:=MyContainer __ns:=/ns

In a second shell, components can be loaded by using the updated container name:

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

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

Note 注意

Namespace remappings of the container do not affect loaded components.

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

Remap component names and namespaces

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

Component names and namespaces may be adjusted via arguments to the load command.

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

In the first shell, start the component container:

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

ros2 run rclcpp_components component_container

Some examples of how to remap names and namespaces:

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

# Remap node name

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

# Remap namespace

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

# Remap both

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

The corresponding entries appear in ros2 component list:

ros2 component list相应的条目显示在:

$ ros2 component list

/ComponentManager

1 /talker2

2 /ns/talker

3 /ns2/talker3

Note 注意

Namespace remappings of the container do not affect loaded components.

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