ROS 1 - Node和Nodelets
在ROS 1中,我们可以将代码写在node(节点)或nodelet中。
ROS 1 node将被编译为可执行文件。
ROS 1的nodelet将被编译为共享库,并在运行时由容器进程加载。
ROS 2 - 统一API
在ROS 2中,推荐的代码编写方式较为接近nodelet —— 在ROS 2中我们称之为组件。这使得向现有代码中添加例如生命周期等的公共概念变得容易。
在ROS 2中避免了不同API的最大缺点,因为不同的方法在ROS 2中都会导向使用相同的API。
注意
仍可以使用节点风格的“编写自己的main函数”,但在ROS 2中属于不推荐的范畴。
我们的发布流程构成将会影响部署,因此用户可以在以下两种情况中进行选择:
- 在独立的进程中运行多个节点,好处是能够具备进程/故障隔离,并且我们将更容易调试单个节点
- 在单个进程中运行多个节点,这可以获得更低的开销和更有效的通信(参见进程内部通信)
另外,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中执行或启动。
使用组件
ROS 2的composition包提供了一系列不同的组件使用方法。
最常用的三种如下:
- 启动一个(generic container process)并调用容器所提供的ROS服务load_node。
然后ROS服务将加载组件(通过包名和库名加以指定)并在正在运行的进程中加以执行。
除了通过编写代码的方式调用ROS服务,您还可以使用命令行工具进行调用。 - 创建一个编译时移植的包含多个节点的自定义可执行文件。这种方法要求每个组件都有一个头文件(第一种情况并不严格需要此头文件)。
- 创建一个启动文件,并使用
ros2 launch
来创建一个加载了多个组件的容器进程。