一、命名规则
ROS中的节点、参数、话题和服务统称为计算图源,其命名方式采用灵活的分层结构,便于在复杂的系统中集成和复用。以下是一些命名的示例:
/foo
/stanford/robot/name
/mq/node1
一个有效的命名应该具备以下特点:
1)首字符必须是字母([a-z|A-Z])、波浪线(~)或者左斜杠(/)。
2)后续字符可以是字母或数字([0-9|a-z|A-Z])、下划线(_)或者左斜杠(/)。
二、名称空间
计算图源命名是ROS封装的一种重要机制。每个资源都定义在一个名称空间内,该名称空间内还可以创建更多资源。但是处于不同名称空间内的资源不仅可以在所处名称空间内使用,还可以在全局范围内访问。这种命名机制可以有效避免不同名称空间内的命名冲突。
ROS提供以下几种设置名称空间的方法:
- 1)通过编码设置命令参数。调用
ros::init()
的ROS程序会接收名为__ns
的命令行参数,可以为程序设置默认的名称空间,如下:
std::map<std::string, std::string> map;
map["__ns"] = "namespace";
ros::init(map, "namespace_learning");
- 2)在launch文件中设置。在launch文件中可通过设置
ns
参数来确定默认名称空间:
<node pkg="package_name " type="file_name" name="node_name" ns="space_name" />
- 3)命令行中,使用
rosrun
命令参数__ns:=/xxx
来指定名称空间:
rosrun package_name file_name __ns:=/new_namespace
- 4)使用环境变量设置。也可以在执行ROS程序的终端中设置默认名称空间的环境变量:
export ROS_NAMESPACE=default-namespace
三、名称解析
计算图源的名称可以分为以下四种,
- 1)基础(base)名称,例如:name。
- 2)全局(global)名称,例如:/global/name。
- 3)相对(relative)名称,例如:relative/name。
- 4)私有(private)名称,例如:~private/name。
基础名称: 用来描述资源本身,可以看作相对名称的一个子类,上述示例中的name就是一个基础名称。
全局名称: 首字符是左斜杠(/)的名称,由左斜杠分开一系列名称空间,示例中的名称空间为 global。全局名称之所以称为全局,是因为它的解析度最高,可以在全局范围内直接访问。
但是在系统中全局名称越少越好,因为过多的全局名称会直接影响功能包的可移植性。
相对名称: 全局名称需要列出所有名称空间,在名称空间繁多的复杂系统中使用较为不便,所以可以使用相对名称代替。相对名称由ROS提供默认的名称空间,不需要带有开头的左斜杠。
例如在默认名称空间 /relative
内使用相对名称 name
,解析到全局名称为 /relative/name
。
相比全局名称,相对名称具备良好的移植性,用户可以直接将一个相对命名的节点移植到其他名称空间内,有效防止命名冲突。
私有名称: 是一个节点内部私有的资源名称,只会在节点内部使用。私有名称以波浪线 ~
开始,与相对名称一样,其并不包含本身所在的名称空间,需要ROS为其解析;但不同的是,私有名称并不使用当前默认名称空间,而是用节点的全局名称作为名称空间。
例如有一个节点的全局名称是 /sim1/pubvel
,其中的私有名称 ~max_vel
解析成全局名称即为 /sim1/pubvel/max_vel
。
总结命名解析方式如下表:
节点 | 名称空间 | 相对名称 | 全局名称 | 私有名称 |
---|---|---|---|---|
/node1 | / | bar -> /bar | /bar -> /bar | ~bar -> /node1/bar |
/mq/node2 | /mq | bar -> /mq/bar | /bar -> /bar | ~bar -> /mq/node2/bar |
/mq/node3 | /mq | foo/bar -> /mq/foo/bar | /foo/bar -> /foo/bar | ~foo/bar -> /mq/node3/foo/bar |
四、节点名称重映射
所有ROS节点内的资源名称都可以在节点启动时进行重映射。ROS这一强大的特性甚至可以支持我们同时打开多个相同的节点,而不会发生命名冲突。
与名称空间类似,ROS也为名称的设置提供了几种方法:
-
1)编码方式。
- C++实现
// 指定重映射名称 std::map<std::string, std::string> map; map["__name"] = "new_name"; ros::init(map, "namespace_learning"); // 随机重映射名称,会在原有名称后面加时间戳 ros::init(argc, argv, "namespace_learning", ros::init_options::AnonymousName);
- Python实现
rospy.init_node("namespace_learning", anonymous=True)
-
2)
rosrun
命令行在节点启动时可以使用如下方式重映射命名:
rosrun package_name file_name __name:=new_node_name 或 注意该方法不止会重映射节点名称,如有old_name名称的topic或service,也会被重映射 rosrun package_name file_name old_name:=new_node_name
-
3)在launch文件中设置
在launch文件中可通过设置
name
参数来设置节点名称:<node pkg="package_name" type="file_name" name="new_node_name" />
五、话题/服务名称重映射
对于话题和服务,通过编码只能设置名称,不能对名称重映射。
上文提到过,通过 rosrun
可以对话题和服务名称重映射:
rosrun package_name node_name old_name:=new_node_name
通过 launch 文件也可以对话题和服务名称重映射:
<node pkg="package_name" type="file_name" name="node_name">
<remap from="old_name" to="new_name" />
</node>
注意,同一节点中,如果有相同名字的话题和服务,以上方法会同时对他们的名称重映射。