19. 话题和服务名称到DDS的映射

本文介绍了提议的ROS话题和服务名称与DDS话题和服务名称之间的映射。

作者:威廉·伍德尔(William Woodall)

撰写日期:2016-10

最后修改:2018-06

19.1 背景

在提出ROS 2话题和服务名称的限制以及到底层DDS话题的映射提议之前,本文首先会总结ROS 1和DDS的现有名称命名指导方针与限制。

19.1.1 ROS 1中的名称

在ROS 1中,话题和服务名称命名指导方针都包含在“ROS 名称”之下,并具有以下限制:

来自 wiki.ros.org/Names

一个有效的名称具有以下特征:

* 首个字符是字母字符 ([a-z|A-Z])、波浪号 (~) 或正斜杠 (/)

* 后续字符可以是字母数字 ([0-9|a-z|A-Z])、下划线 (_) 或正斜杠 (/)

例外:基本名称(后文会介绍)不能包含正斜杠 (/) 或波浪线 (~)。

19.1.2 DDS的话题名称

在DDS中,话题名称受到以下这些限制:

来自DDS 1.4规范或RTI文档

TOPICNAME – 话题名称是话题的标识符,且定义为一系列任意字符 'a', ..., 'z', 'A', ..., 'Z', '0', .. ., '9', '_' 但不能以数字开头。

*注:DDS规范有一个已知的错字,即该规范说允许“-”字符,而RTI文档正确地将“_”列为允许的字符。

此外,DDS(或更准确地说是底层RTPS协议)对话题名称有256个字符的硬性限制,因此另一个目标就是尽量减少从ROS映射到DDS名称时使用的额外字符数。有关详细信息,请参阅“实时发布-订阅协议(RTPS)DDS互操作网络协议规范”表9.12。

19.2 ROS 2话题和服务名称限制

在本节中,将会概要列出对ROS 2话题和服务名称提出的限制,并在合适的情况下列出其理由。

为方便起见,这里总结了ROS 2中话题和服务名称的所有规则:

● 不能为空

● 可能包含字母数字字符 ([0-9|a-z|A-Z])、下划线 (_) 或正斜杠 (/)

● 可以使用平衡花括号 ({}) 以用于替换

● 可以以波浪号 (~) 开头,即私有命名空间替换字符

● 不得以数字字符 ([0-9]) 开头

● 不得以正斜杠 (/) 结尾

● 不得包含任何数量的重复正斜杠 (/)

● 不得包含任何数量的重复下划线 (_)

● 必须用正斜杠 (/) 将波浪号 (~) 与名称的其余部分分开,即可以是~/foo而不能是~foo

● 使用时必须是平衡的花括号 ({}),即可以是{sub}/foo而不能是{sub/foo 或/foo}

替换的内容,即平衡花括号 ({}) 内的字符串,遵循与名称非常相似的规则。替换的内容:

● 不能为空

● 可能包含字母数字字符 ([0-9|a-z|A-Z]) 和下划线 (_)

● 不得以数字字符 ([0-9]) 开头

19.2.1 完全限定名称(Fully Qualified Names)

话题和服务名称规则允许一些方便的语法,在某些情况下需要额外的上下文来扩展为完全限定名称,然后再扩展为DDS等效名称。例如,如下面几节中更详细描述的那样,名称可能是相对的(例如foo与绝对/foo),它们可能包含私有命名空间替换字符(~),或者包含在花括号({})句法中的任意替换字符串。通过上下文,这些特性中的每一个都可以扩展为一些简单的字符串以形成完全限定名称。完全限定名称具有下列额外限制:

● 必须以正斜杠(/)开头,即它们必须是绝对的

● 不得包含波浪号(~)或花括号({})

请注意,扩展的替换必须产生一个有效的名称并符合上一节中所述的名称限制。无效替换的一个示例就是用一个数值替换{sub}的名称 {sub}/foo,这样会导致该话题名称以数字字符开头。

19.2.2 统一资源定位符(URL)

此外,话题和服务名称可以用统一资源定位符(URL)格式表示,以进一步消除资源名称的歧义。话题名称前面可以有rostopic://模式前缀,而服务名称前面可以有rosservice://模式前缀。例如,绝对名称/foo也可以用rostopic:///foo表示为话题,或用rosservice:///foo表示为服务。请注意三个正斜杠(/),它与​​file://模式的风格相似。相对名称foo/bar可以用rostopic://foo/bar表示为话题。

19.2.3 ROS 2名称示例

例如,这些是有效的名称:

foo abc123 _foo Foo BAR
~ foo/bar ~/foo {foo}_bar foo/{ping}/bar
foo/_bar foo_/bar foo_ rosservice:///foo rostopic://foo/bar

而这些则是无效的名称:

123abc 123 foo bar ` ` foo//bar
/~ ~foo foo~ foo~/bar foo/~bar
foo/~/bar foo/ foo__bar

这是一些有效的完全限定名称:

/foo /bar/baz rostopic:///ping /_private/thing /public_namespace/_private/thing

19.2.4 命名空间

话题和服务名称:

● 可以使用正斜杠(/)作为分隔符将其拆分成多个令牌(tokens)

○ 有关令牌的更多详细信息,请参阅“名称令牌”一节

● 不得以正斜杠(/)结尾

最后一个令牌是话题或服务的基本名称,而前面的所有令牌构成了话题或服务的命名空间。

例如,话题名称/foo/bar/baz是命名空间/foo/bar中具有基本名称baz的话题或服务组成。在另一个示例中,名称/foo可拆分成一个令牌,因此它由/命名空间(根命名空间)中具有基本名称foo的话题或服务组成。

话题和服务名称:

● 可以指定为绝对或相对名称

● 如果名称是绝对的,则必须以正斜杠(/)开头

绝对名称以正斜杠(/)开头并且不考虑命名空间,即绝对名称可以被视为“全局”名称。相对名称不以正斜杠(/)开头,并且会考虑到创建它们的节点的命名空间。

相对名称会被添加到创建它们的节点的命名空间中。例如,如果将节点放入命名空间/ping/pong中并且话题或服务名称为foo/bar,那么绝对名称将会是/ping/pong/foo/bar。但是,如果话题或服务名称是/foo/bar,则绝对名称仍将是/foo/bar,它会忽略节点的命名空间。

19.2.5 名称令牌

“名称令牌”是命名空间分隔符之间的字符串,例如话题或服务/foo/bar/baz的名称令牌是foo、bar和baz。

话题和服务的名称令牌:

● 不能为空,例如名称//bar是不允许的

○ 理由:这会消除意外//的连接机会,因此需要将//变为/

● 可以使用字母数字字符([0-9|a-z|A-Z])、下划线(_)和/或平衡花括号({})

● 不得以数字字符([0-9])开头

● 可以是一个波浪号(~)

19.2.6 私有命名空间替换字符

特殊的单字符令牌~将会替换为一个命名空间片段,该片段是节点命名空间和节点名称的连接。例如,命名空间/foo中的节点node1会导致~被/foo/node1替换。另一个示例就是,命名空间foo/bar中的节点node1将会导致~被替换为foo/bar/node1。如果有私有命名空间替换字符的话,则必须用在非完全限定名称的开头。下表列出了一些示例扩展:

输入名称 节点:my_node 命名空间:无 节点:my_node 命名空间:/my_ns
ping /ping /my_ns/ping
/ping /ping /ping
~ /my_node /my_ns/my_node
~/ping /my_node/ping /my_ns/my_node/ping

请注意,私有命名空间替换字符会使名称成为绝对名称,因此不会第二次添加命名空间。

19.2.7 替换(Substitutions)

花括号语法 ({substitution_name}) 可用于非完全限定名称中,以将有用的上下文信息替换到该名称中。本文未设置替换关键字(名称)集合,一些合理的示例可能是:{node}扩展到当前节点名称,或者{ns} 扩展到当前节点的命名空间。

在扩展私有命名空间替换字符之后扩展替换。因此,替换可能不包含私有命名空间替换字符,即~。例如,给定名称{private}foo和一个名为{private}的、会扩展为~/_的替换,这样将会出现错误提示,因为~/_ 会将名称扩展为/my_ns/~/_foo,而在扩展名称内不允许有~。

替换是在一次传递中进行扩展的,因此替换不应扩展为包含替换其本身。例如,给定名称/foo/{bar_baz},其中{bar_baz}扩展为{bar}/baz,而{bar}则扩展为bar,这样最终会得到无效的名称/foo/{bar}/baz,而不是您可能期望的/foo/bar/baz 。

替换也不允许嵌套,即替换名称中不得包含其他替换。这是由上面提及的替换名称只能包含字母数字和下划线(_)这一规则隐式强制执行的。例如,给定名称/foo/{{bar}_baz} 将会导致出错,因为符号{和}不允许在替换名称中使用,而替换名称{bar}_baz确实包含这两个符号。

19.2.8 隐藏的话题或服务名称

包含以下划线(_)开头的任何名称令牌(命名空间或话题或服务名称)的任何话题或服务名称都将会被视为是隐藏的,除非明确请求访问它们,否则各种工具可能都不会显示这类名称。

19.3 ROS 2话题和服务名称到DDS概念的映射

ROS话题和服务名称限制比DDS话题名称允许更多类型的字符,因为ROS还允许使用正斜杠(/)、波浪号(~)和平衡花括号({})。在将ROS话题或服务名称转换为DDS概念的过程中,必须对这些符号进行替换或删除这些符号。由于ROS 2话题和服务名称会被扩展为完全限定名称,因此任何平衡括号({})替换和波浪号(~)都将会被扩展。此外,任何与URL相关的语法,例如rostopic://前缀,将会在解析后被删除。以前DDS话题名称中不允许使用正斜杠(/),现在该限制已被解除(参见omg.org网站上的议题),因此ROS话题名称首先以ROS特定命名空间前缀(如下所述)作为前缀,然后再直接映射到DDS 话题名称。

19.3.1 ROS的特定命名空间前缀

为了易于区分各个ROS话题,由ROS创建的所有DDS话题都应自动以类似于/rX的命名空间作为其前缀,其中X是单个字符,用于表示该话题所属的ROS子系统。例如,一个名为/foo的普通话题会转换为DDS话题rt/foo,这是将rt隐式添加到ROS话题命名空间的结果,该ROS话题位于根命名空间/中且具有基本名称foo。另一个示例就是名为/left/image_raw的话题会转换为DDS话题rt/left/image_raw,这是将rt隐式添加到ROS话题命名空间的结果,该ROS话题位于命名空间/left中且具有基本名称image_raw。

对于使用话题来实现服务(Services)的系统(如OpenSplice),可以使用不同的子系统字符:rq表示请求话题,而rr表示响应话题。在显式处理服务的系统上,我们考虑使用一个单独的前缀,如rs。

下面是一个未穷举完全的命名空间前缀列表:

ROS子系统 前缀
ROS 话题(Topics) rt
ROS 服务请求(Service Request) rq
ROS 服务响应(Service Response) rr
ROS 服务(Service) rs
ROS 参数(Parameter) rp
ROS 动作(Action) ra

虽然所有规划的前缀都由两个字符组成,即rX,但任何位于第一个命名空间分隔符(即/)之前的字符都可以被认为是前缀的组成部分。该标准保留使用最多8个字符作为前缀的权利,以防将来需要额外的前缀空间。

19.3.2 ROS名称到DDS概念的映射示例

下表中列出了如何将完全限定的ROS名称映射拆解到DDS概念的一些示例:

ROS名称 DDS话题
/foo rt/foo
rostopic:///foo/bar rt/foo/bar
/robot1/camera_left/image_raw rt/robot1/camera_left/image_raw

19.3.3 ROS话题和服务名称长度限制

DDS话题名称的长度不得超过256个字符。因此,ROS话题名称(包括命名空间层次结构、话题基本名称和任何ros的特定前缀)的长度不得超过256个字符,因为该名称会直接映射成DDS话题名。

(1)中间件RTI Connext的注意事项

在使用Connext测试我们的实现时,在话题名称长度方面遇到了一些额外的限制。也就是说,例如,服务名称的长度比ROS话题名称的长度会有更严格的限制。RTI Connext实现的服务名称会以服务响应话题的DDS参与者的GUID值作为后缀。而且还会创建一个内容过滤话题(其名称长度最多为256个字符),该话题是从加了后缀的服务名称映射过来的。因此,在链接到rmw_connext_c或rmw_connext_cpp时,服务名称不能超过185个字符,包括命名空间层次结构和ros 的任何特定前缀。

19.3.4 与非ROS话题通信

由于所有ROS话题在转换为DDS话题名称时都带有前缀,因此无法订阅不遵循相同命名模式的现有DDS话题。例如,如果一个现有的DDS程序正在话题image上发布消息(并使用与ROS消息类型等效的DDS消息类型),则ROS程序无法订阅该话题,这是由于ROS的特定隐式命名空间造成的名称改动。因此,为了让ROS程序与DDS “本地”话题名称进行互操作,API应该提供一种跳过ROS特定前缀的方法。

在API中有一种选择,即使用qos_profile中的一个布尔型变量Avoid_ros_namespace_convention,可以将该变量值设置为false以使用ROS前缀,而将其设置为true则不会使用ROS命名空间前缀。

例如:

ROS名称 avoid_ros_namespace_conventions DDS话题
rostopic://image false rt/image
rostopic://image true image

(1)替代方案(想法)

请注意,下面的替代方案并不是本提议的组成部分,而只是解决与DDS “本地”话题通信问题的可能方案。另一种选择就是在模式(schema)名称中添加一些标记,例如:

ROS名称 DDS话题
rostopic://image rt/image
rostopic+exact://image image
rostopic+exact://camera_left/image camera_left/image
rostopic+exact:///camera_left/image camera_left/image

19.4 与ROS 1的比较和对比

为了支持映射到限制性稍强的DDS话题名称规则,这些规则在某些方面比ROS 1的规则更具限制性。为了方便或移除ROS 1中存在的混淆点,还提议了一些其它改变。在ROS 2中,话题和服务名称与ROS 1的不同之处在于:

● 必须用正斜杠(/)将波浪号(~)与名称的其余部分分开

○ 这样做是为了避免~foo在文件系统路径中的工作方式与在ROS名称中使用时的工作方式不一致。

● 可能包含用平衡花括号({})分隔的替换

○ 这是波浪号(~)背后思想的更通用扩展。

● 有长度限制

○ 这是由DDS话题名称长度限制造成的。

● 可以通过在其中一个命名空间中使用前导下划线(_)将其指示为“隐藏”

○ 这用于隐藏常见但不经常检查的话题和服务。

19.5 顾虑/替代方案

这一节列出了对本提议设计的顾虑和考虑过的替代方案。

19.5.1 替代的命名规则和命名规则相关顾虑

有一些曾经建议过但随后被拒绝了的话题和服务名称命名规则替代方案。

(1)更通用的私有命名空间替换字符

目前波浪号(~)私有命名空间替换字符只能用在名称的开头,但也曾经建议该替换字符可以放在名称中的任何位置,且可以就地替换。

由于解释起来很复杂,并且与波浪号(~)在Unix机器上的文件系统路径中使用时的行为不同,因此该命名规则被拒绝了。此外,很难证明该命名规则的存在是合理的,因为所有建议的用例都有很明显的人造痕迹。而且其行为方式也与ROS 1中的工作方式不同,这是该替代方案的另一个负面因素。

(2)替换语法的替代方案

在选用普通的平衡花括号语法({})之前,针对替换语法曾经建议过如下一些替代方案:

● %{sub}

● ${sub}

● $sub

考虑过的最严肃替代方案是${sub}和$sub的“bash风格”语法。$sub风格语法的缺点是难以处理并且无法表达某些类型的连接。${sub}是一个强有力的候选者,但最终被拒绝,因为它会与在shell脚本中的使用相冲突。例如,您可以想象一个运行节点并重映射话题名称的shell脚本会包含这些替换符号,但需要对这些替换符号进行转义以防止bash本身尝试扩展它们。平衡花括号{}语法避免了这个问题,而且还易于解析。

平衡花括号{}语法会与Python的字符串替换发生冲突,但由于这是一个显式操作(与总是隐式发生的shell替换不同),所以问题不大。

(3)替换相关的顾虑

本文没有规定各个具体实现应该支持什么替换。这样做是为了避免阻碍本文在需要就所需替换字符集达成一致方面取得进展。然而,这只是在拖延问题。为了使替换有用,所有处理话题和服务名称的具体实现都需要支持它们。

这种妥协是为了当在替换语法上完成更多工作时,希望不需要更改名称语法,而是关注要支持哪些替换语法以及该支持是否是可选的。

19.5.2 ROS到DDS映射的替代方案

对ROS ->DDS的翻译映射的替代方案和顾虑进行了如下讨论。

(1)使用DDS分区的替代方案

以前,在DDS话题名称中不允许使用正斜杠(/),因此提出了一种策略,该策略使用DDS分区来解决ROS名称中存在的正斜杠 (/)。主要思路是将ROS名称分成“命名空间”和“基本名称”,然后将去掉前导和尾部正斜杠(/)的命名空间放入单个DDS分区条目中,并将剩余的基本名称放入DDS话题名称。这样就解决了这个问题,因为根据定义,ROS名称中的基本名称不会包含任何正斜杠(/),因此DDS话题名称中不再会有任何不允许的字符。DDS分区会包含ROS名称的命名空间,包括构成命名空间且不在命名空间开头或结尾的任何正斜杠(/)。这是可以接受的,因为与以前的DDS话题不同,DDS分区允许包含正斜杠(/),而现在DDS话题名称也允许正斜杠(/)。

DDS分区会被实现为DDS::Publisher和DDS::Subscriber的QoS设置中的一个字符串数组,且该字符串数组没有层次结构或顺序,分区数组中的每个条目直接与DDS话题组合,且它们不会被顺次组合。如果某个发布者有两个分区条目,例如具有基本名称为 baz的foo和bar,则这相当于在这些话题上有两个不同的发布者:/foo/baz和/bar/baz。因此,本提议仅使用该分区数组中的一个字符串来组成ROS名称的整个命名空间。

您可以在RTI的文档中查阅有关DDS分区的更多信息:

 PARTITION_QosPolicy

权衡(与使用包含命名空间的完整ROS名称相比):

● 将ROS名称拆分为“命名空间”和“基本名称”,并将完整的命名空间放入一个为其他用途而设计的字段中似乎是不正确的。

● 一般来说,建议将分区作为备选项,而这个替代方案建议对所有ROS名称使用分区。

● 在此议题中报告了主要的顾虑,即两个具有相同基本名称的话题,尽管它们具有不同的命名空间和不同的类型,仍会引起问题。例如:话题A 的类型为Image,名称为/camera/data;而话题B的类型为Imu,名称为/imu/data。话题A和话题B的基本名称都是data,会产生如这个议题中所述的错误。

● 诸如DDS-XRCE等较新的标准可能根本没有分区。

● 在后一种策略中使用完整的ROS名称会导致对基本名称的长度限制更严格,因为DDS话题名称会包含ROS前缀、命名空间以及基本名称,该名称不应超过DDS 话题名称最大长度为256个字符的限制。

理由:

● 由于DDS供应商决定允许在DDS话题名称中使用正斜杠(/),使用完整的ROS名称似乎比使用分区更简单、更直观。

(2)替换命名空间分隔符的替代方案

之前的一个提议是用DDS话题名称中允许的字符替换命名空间分隔符即正斜杠(/),然后只使用DDS话题名称来表示完整的ROS名称。例如,在最简单的情况下,话题/foo/bar/baz可能会变成__foo__bar__baz,其中正斜杠(/)被替换为双下划线(__),而在ROS话题和服务名称中不允许使用双下划线(__)。

权衡(与使用DDS分区相比):

● 具有更严格的长度限制,因为这样只会受到DDS话题名称的限制,而不会受益于进入到DDS分区的 ROS话题名称部分。

● 对正斜杠(/)的替换必须超过一个字符,因为所有可用字符已经被允许在ROS名称和DDS话题名称中使用,因此每个命名空间会使话题名称长度进一步受到限制。

● 具体实现要求对字符串进行替换并在随后进行验证,这相对比较复杂。

理由:

● DDS分区提议优于此替代方案,因为DDS分区方案允许更长的ROS总体名称且更易于实现,即将字符串拆分为基本名称和命名空间比用双下划线(__)替换正斜杠(/)然后重新进行长度限制测试更简单。

(3)用大写字母替换的替代方案

这是在上一小节“替换命名空间分隔符的替代方案”中所述替代方案的情形下提出的另一个替代方案。由于在从ROS话题名称转换到DDS时正斜杠(/)被双下划线(__)替换,因此每增加一个命名空间都会使256个字符限制的名称长度再失去两个字符。一个提议的替代方案就是添加一个约束,即ROS话题名称不能使用大写字母,这样就可以用大写字母替代正斜杠(/)。

权衡:

● 每个命名空间少使用一个字符,并且更容易计算ROS话题或服务名称的最大长度。

● 不让用户在其名称中使用大写字母,这是一种限制,且对于向后兼容ROS 1的话题和服务来说可能是一个问题。

理由:

● 相对于获得的额外好处来说,不让用户使用大写字母限制太严格了。

(4)带单个下划线的ROS前缀替代方案

这是在上一小节“替换命名空间分隔符的替代方案”中所述替代方案的情形下提出的另一个变体替代方案。这个替代方案的不同之处仅在于它在前缀中使用单个下划线,即rt_而不是rt__(或者rt + 前导/)。

权衡:

● 少用一个字符

● 与其他正斜杠(/)替换不太一致

理由:

● 略微倾向于更一致的替代方案。

(5)受限前缀替代方案

这是在上一小节“替换命名空间分隔符的替代方案”中所述替代方案的情形下提出的另一个变体替代方案。

这个替代方案将:

● 不给话题添加前缀

● 可以选择为其他类型的“实现细节话题”添加前缀

权衡:

● 让ROS订阅DDS创建的话题会更加容易

○ 例如DDS发布者发布的话题image,在ROS中只要使用image就可以进行订阅

○ 但是,类型仍需要相同

○ 在当前的提议中,ROS话题image将会变成rt__image,因此DDS话题需要遵循ROS话题转换方案才能与ROS组件进行互操作

● 难以将ROS创建的DDS话题与一般的DDS话题区分开来

● 服务仍需要区别对待

○ 例如,服务/foo需要如foo_Request和foo_Reply这样的两个话题

理由:

● 略微倾向于更易于区分ROS创建的话题和DDS创建的话题的方案,而不是更易于连接到现有DDS话题的方案。连接到DDS话题可以通过在订阅或发布到某个实现话题名称的“别名”时有一个可选项(如sub->alias_to_explicit_topic('dds_topic'))来实现。而且,将ROS创建的话题与其他DDS话题区分开的解决办法被认为比允许用户为其发布者和订阅指定具体的DDS话题名称的建议解决方案更复杂。

(6)后缀替代方案

这是在上一小节“替换命名空间分隔符的替代方案”中所述替代方案的情形下提出的另一个变体替代方案。

这个替代方案将:

● 不给话题添加前缀

● 将前缀重构为后缀,即rX<topic> -> <topic>_rX_

○ 用户定义的名称将会是唯一的,因为用户定义的名称不能有尾随下划线(_)

权衡:

● 使用DDS工具列出话题时更难以区分开ROS创建的DDS话题和一般或内置的DDS话题,因为话题不是按ROS特定前缀排序的

● 如果DDS供应商再次为服务名称添加后缀(例如在Connext的 请求-响应实现中),则可能也难以与用户的话题名称区分开来

○ 例如,服务/foo可能会成为两个话题:foo_s_Request和foo_s_Reply,且用户也可能会创建名为/foo_s_Request的话题。

○ 这也同样适用于RMW实现可能会对话题名称添加后缀的任何其他类似转换。

理由:

由于与前缀解决方案相比缺乏优势,因此没有选择这个后缀替代方案,而是选择了前缀解决方案。而且,通常需要多使用一个字符来表达(rt对比_rt_;除非您还删除了隐式的首个命名空间/,则是rt__对比_rt_),并且在DDS实现处理请求-响应(带后缀)时可能存在歧义问题。

(7)受限后缀替代方案

这是在上一小节“替换命名空间分隔符的替代方案”中所述替代方案的情形下提出的另一个变体替代方案。

除了下面这一个不同点外,此替代方案与“后缀替代方案”完全相同:

● 话题根本没有后缀或前缀

权衡:

● 与“后缀替代方案”具有相同的权衡

● 但也更容易让ROS订阅DDS创建的话题

○ 例如,DDS发布者发布的话题image,在ROS中只要使用image就可以进行订阅

○ 类型需要相同

○ 在当前提议中,ROS话题image将会变成rt__image,因此DDS话题需要遵循我们的命名模式才能与ROS组件进行互操作

理由:

尽管此替代方案具有后缀替代方案和受限前缀替代方案的好处,但受限前缀替代方案的理由仍然适用于此替代方案。

*英语原文网址:design.ros2.org/article