ROS2-011-通信机制补完:节点重名
简介
在 ROS2 中,不同的节点可以有相同的节点名称,比如你可以启动多个节点的名称都是 turtlesim 的 turtlesim_node 节点。
虽然节点重名是被 允许 的,但是开发者应该 主动避免 这种情况,因为节点重名可能会导致操作上的混淆。
仍以启动了多个 turtlesim_node 节点为例,当使用 计算图(rqt_graph) 查看节点运行状态时,由于这些节点的名称一致,它们在计算图上会被显示为同一个节点,而实际上是有多个节点。并且节点名称也会和话题名称、服务名称、动作名称、参数等多种变量产生关联,届时也可能会导致通信逻辑上的混乱。
那么在 ROS2 中,我们应该如何避免节点重名呢?
解决策略
通常为了避免重名问题,一般有两种常用策略:
- 命名空间,即给节点的名称添加一个前缀,这个前缀可以有多级,一般格式为:/xxx/yyy/zzz
- 名称重映射,给节点起一个别名;
实现途径
1. 使用 ros2 run 设置节点名称
①. 设置命名空间
语法如下:
ros2 run <包名> <节点名> --ros-args --remap __ns:=<命名空间>
例如:
ros2 run turtlesim turtlesim_node --ros-args --remap __ns:=/t1
在终端中运行该指令后,使用 ros2 node list
查看节点信息时会显示包含以下结果的信息:
/t1/turtlesim
②. 设置名称重映射
语法如下:
ros2 run <包名> <节点名> --ros-args --remap __name:=<重映射名>
或者:
ros2 run <包名> <节点名> --ros-args --remap __node:=<重映射名>
例如(以 __name
为例):
ros2 run turtlesim turtlesim_node --ros-args --remap __name:=ts1
在终端中运行该指令后,使用 ros2 node list
查看节点信息时会显示包含以下结果的信息:
/ts1
③. 同时设置命名空间与名称重映射
就把上述两个指令相结合即可。语法如下:
ros2 run <包名> <节点名> --ros-args --remap __ns:=<命名空间> --remap __name:=<重映射名>
例如:
ros2 run turtlesim turtlesim_node --ros-args --remap __ns:=/t1 --remap __name:=ts1
在终端中运行该指令后,使用 ros2 node list
查看节点信息时会显示包含以下结果的信息:
/t1/ts1
2. 使用 launch 文件设置节点名称
launch 文件 可以使用 Python
、XML
或者 YAML
三种语言编写,这三种实现方式都可以用于设置命名空间与名称重映射。
使用之前……
在使用 launch
文件时,记得在 CMakeLists.txt
内 install
相关位置添加
install(DIRECTORY launch DESTINATION share/${PROJECT_NAME})
当然,以下的 launch
文件针对的是 C++
节点的相关配置信息,若希望针对 Python
节点进行相关配置,请参照之后的launch文件说明
①. 使用 Python 编写 launch 文件以设置命名空间与名称重映射(推荐)
使用 Python
编写 launch 文件时,可以通过 Python
类 launch_ros.actions.Node
来创建被启动的节点对象,在该对象的构造函数中提供了 name
和 namespace
两个参数来设置节点的 名称 与 命名空间。使用示例如下:
from launch import LaunchDesciption
from launch_ros.actions import Node
def generate_launch_description():
return LaunchDesciption([
# 设置名称重映射
Node(package="turtlesim", executable="turtlesim_node", name="ts1"),
# 设置命名空间
Node(package="turtlesim", executable="turtlesim_node", namespace="t1"),
# 同时设置命名空间与名称重映射
Node(package="turtlesim", executable="turtlesim_node", namespace="t1", name="ts1")
])
请注意
上述的函数名 必须 是 generate_launch_description
,否则函数无法被 ROS2 识别执行。
②. 使用 XML 编写 launch 文件以设置命名空间与名称重映射
使用 XML
编写 launch 文件时,可以通过 node
内提供的 name
和 namespace
两个参数来设置节点的 名称 与 命名空间。使用示例如下:
<launch>
<!-- 设置名称重映射 -->
<node pkg="turtlesim" exec="turtlesim_node" name="ts1"/>
<!-- 设置命名空间 -->
<node pkg="turtlesim" exec="turtlesim_node" namespace="t1"/>
<!-- 同时设置命名空间与名称重映射 -->
<node pkg="turtlesim" exec="turtlesim_node" namespace="t1" name="ts1"/>
</launch>
③. 使用 YAML 编写 launch 文件以设置命名空间与名称重映射
使用 YAML
编写 launch 文件时,同样可以通过 node
内提供的 name
和 namespace
两个参数来设置节点的 名称 与 命名空间。使用示例如下:
launch:
# 设置名称重映射
- node:
pkg: "turtlesim"
exec: "turtlesim_node"
name: "ts1"
# 设置命名空间
- node:
pkg: "turtlesim"
exec: "turtlesim_node"
namespace: "t1"
# 同时设置命名空间与名称重映射
- node:
pkg: "turtlesim"
exec: "turtlesim_node"
namespace: "t1"
name: "ts1"
3. 使用 编码 设置节点名称
当我们编写节点时,实际上在 rclcpp
和 rclpy
所提供的节点类的构造函数中,分别提供了设置节点名称和命名空间的参数。
①. rclcpp 内的相关 API
在 rclcpp
中节点内的构造函数及其所涵盖的部分参数如下:
Node(const std::string &node_name,
const std::string &namespace_,
const NodeOptions &options = NodeOptions())
其中参数 node_name
可以用于设置名称重映射,namespace_
可以用于设置命名空间。这两个参数可以同时使用。
②. rclpy 内的相关 API
在 rclpy
中节点内的构造函数及其所涵盖的部分参数如下:
Node(node_name, *,
context=None,
cli_args=None,
namespace=None,
use_global_arguments=True,
enable_rosout=True,
start_parameter_services=True,
parameter_overrides=None,
allow_undeclared_parameters=False,
automatically_declare_parameters_from_overrides=False)
其中参数 node_name
可以用于设置名称重映射,namespace
可以用于设置命名空间。这两个参数可以同时使用。
目前已知的情报
在最开始学习的时候,我们通过参数 node_name
对各个节点进行了节点名的设置,因此通过在这里设定参数 node_name
本质上也是在对节点进行命名的重映射。在这里使用的重映射就与前两种实现途径有些许不同,因为是在创建节点的过程中就已经进行了相关定义,而不是在外部运行前才进行重映射或相关的修改。还请注意。