Type Specific Interfaces
一直以来,API的某些部分必然特定于所交换的消息类型,例如发布消息或订阅主题,因此需要为每个消息类型生成代码。下图布局了从用户定义的rosidl文件(如.msg文件)到用户和系统用于执行特定类型功能的特定类型代码的路径:
图:“静态”类型支持生成的流程图,从rosidl文件到面向用户的代码。
图的右侧显示了.msg文件是如何直接传递给特定语言的代码生成器的,例如rosidl_generator_cpp或rosidl_generator_py。这些生成器负责创建用户将包含(或导入)的代码,并用作.msg文件中定义的消息的内存表示。例如,考虑消息std_msgs/String,用户可能会在C++中使用此文件,并使用语句#include<std_msgs/msg/String.hpp>,或者在Python中使用std_msgs.msg-import String中的语句。这些语句之所以有效,是因为这些特定于语言(但与中间件无关)的生成器包生成了文件。
另外,.msg文件用于为每个类型生成类型支持代码。在这种情况下,类型支持意味着:特定于给定类型并由系统用于执行给定类型的特定任务的元数据或函数。对给定消息的类型支持可能包括消息中每个字段的名称和类型列表。它还可能包含对代码的引用,这些代码可以执行该类型的特定任务,例如发布消息。
Static Type Support
当类型支持引用代码来执行特定消息类型的特定功能时,该代码有时需要执行特定于中间件的工作。例如,考虑特定于类型的发布函数,当使用“vendor a”时,该函数需要调用“vendor B”的某些API,但当使用“vendor B”时,它需要调用“VendorB”的API。为了允许使用特定于中间件供应商的代码,用户定义的.msg文件可能会导致生成特定于供应商的代码。通过类型支持抽象,该特定于供应商代码仍然对用户隐藏,这类似于“Private Implementation”(或Pimpl)模式的工作方式。
Static Type Support with DDS
对于基于DDS的中间件供应商,特别是那些基于OMG IDL文件(.IDL文件)生成代码的供应商,用户定义的rosidl文件(.msg文件)将转换为等效的OMG IDL文件(.id1文件)。从这些OMG IDL文件中,创建特定于供应商的代码,然后在特定于类型的函数中使用,这些函数由给定类型的类型支持引用。上图在左侧显示了这一点,其中.msg文件由rosidl_dds包使用以生成.idl文件,然后将这些.idl文件提供给特定于语言和特定于dds供应商的类型支持生成包。
例如,考虑Fast DDS实现,它有一个名为rosidl_typesupport_fastrtps_cpp的包。这个包负责生成代码来处理诸如将C++消息对象转换为要在网络上写入的串行八位字节缓冲区之类的事情。这个代码虽然特定于Fast DDS,但由于类型支持代码中的抽象,仍然没有向用户公开。
Dynamic Type Support
实现类型支持的另一种方法是为发布到主题之类的事情提供通用函数,而不是为每个消息类型生成函数的版本。为了实现这一点,这个通用函数需要一些关于正在发布的消息类型的元信息,比如字段名和类型在消息类型中出现的顺序列表。然后,要发布消息,您需要调用一个通用发布函数,并传递一个要发布的消息以及一个包含有关消息类型的必要元数据的结构。这被称为“动态”类型支持,而“静态”类型支持需要为每个类型生成函数的版本。
图:“动态”类型支持生成的流程图,从rosidl文件到面向用户的代码。
上图显示了从用户定义的rosidl文件到生成的面向用户的代码的流程。它与静态类型支持的图表非常相似,不同之处仅在于如何生成类型支持(由图表的左侧表示)。在动态类型支持中,.msg文件直接转换为面向用户的代码。
此代码也是中间件无关的,因为它只包含有关消息的元信息。实际完成工作的函数,例如发布到主题,是消息类型的通用函数,将对中间件特定的API进行任何必要的调用。请注意,与静态类型支持中的情况不同,这种方法具有用于每种语言的中间件无关的包,例如rosidl_typesupport_introspection_c和rosidl_ypesupport_intropection_cpp,而不是提供类型支持代码的特定于dds供应商的包。包名称的内省部分指的是使用为消息类型生成的元数据内省任何消息实例的能力。这是允许“发布到主题”等函数的通用实现的基本功能。
这种方法的优点是,所有生成的代码都与中间件无关,这意味着它可以被不同的中间件实现重用,只要它们允许动态类型支持。它还导致生成的代码更少,从而减少了编译时间和代码大小。
然而,动态类型支持要求底层中间件支持类似形式的动态类型支持。在DDS的情况下,DDS XTypes标准允许使用元信息而不是生成的代码发布消息。为了支持动态类型支持,底层中间件中需要DDSXTypes或类似的东西。此外,这种类型支持方法通常比静态类型支持方法慢。静态类型支持中的特定类型生成的代码可以写得更高效,因为它不需要迭代消息类型的元数据来执行序列化等操作。
参考
rosidl