目录
我们承担ROS,FastDDS,C++,cmake等技术的项目开发和专业培训,质量有保证,如有需要请私信联系。
每个RTPS实体和DDS实体是一对一对应的。HistoryCache充当了DDS Entities和RTPS Entities之间的接口。比如说,DDS DataWriter的写操作会添加一个CacheChange到RTPS Writer的HistoryCache中,RTPS Writer随后将CacheChange发送给所有匹配的RTPS Readers,然后由RTPS Reader通知DDS DataReader新的CacheChange到达。
概览
RTPS中的各实体和类
Class | Purpose |
---|---|
Entity | 所有RTPS Entities的基类。RTPS Entity代表了网络中其他Etities能够看到的,所以RTPS Entity有一个GUID,并且可以在RTPS 消息中引用这个guid |
Endpoint | RTPS Entity的子类,可以作为通讯端点的对象,即既可以发出RTPS消息,也可以接收RTPS消息的对象。 |
Participant | 所有RTPS实体的容器,这些实体共享相同的属性,并位于同一个地址空间中。 |
Writer | RTPS Endpoint的子类,CacheChanges.消息的源端 |
Reader | RTPS Endpoint的子类,CacheChanges.消息的接收端 |
HistoryCache | 用于存储和管理一系列data对象的changes。并不需要保留所有历史changes记录,而只需要保留那些对于当前和未来的RTPS Reader端点所需要的changes。所需的部分历史记录取决于DDS(数据分发服务)的QoS(服务质量)以及与匹配的Reader(读取器)端点的通信状态。在RTPS协议中,QoS策略可以用于指定数据守护进程服务如何处理数据。例如,它可以设置数据是否需要在传输过程中进行加密,是否需要对未传送的数据进行排队等。通信状态则可以反映读取器端点与写入器端点之间的连接状态,比如是否正常通信,是否存在延迟等。因此,所需的部分历史记录会根据这些因素进行动态调整;Reader端只需要保留一部分的历史记录,这些记录是所有匹配的Writer端点对数据对象变更的叠加,而并不需要维护全部的历史记录。这部分历史记录的大小和规则取决于DDS的服务质量需求和与Writer端点的通信状态。 |
CacheChange | 代表着对数据对象所做的单个变更。这包括数据对象的创建、修改和删除。 |
Data | 用户数据 |
RTPS实体和类的属性类型:
Attribute type | Purpose |
---|---|
GUID_t | 唯一标识系统中的每个RTPS实体,必须用16个字节,保留值:GUID_UNKNOWN |
GuidPrefix_t | 用于guid中的prefix,同属于一个participant的每个entities的guid的有相同的prefix,必须使用12个字节表示,保留值GUIDPREFIX_UNKNOWN |
EntityId_t | 用于guid中的suffix,participant的中不同entities具有不同的entity_id,必须使用4个字节,保留值:ENTITYID_UNKNOWN |
SequenceNumber_t | sequence number,用64位表示,保留值:SEQUENCENUMBER_UNKNOWN |
Locator_t | 用于发送到RTPS 对端的地址信息结构,包括三部分:1. 一个区分器:一个唯一的标识符,用于指定传输协议的类型(例如,TCP、UDP等)。这个区分器使用4字节(32比特)进行编码;2. 地址,用16个字节; 3. 端口,用4个字节表示,以下值保留:LOCATOR_INVALID,LOCATOR_KIND_INVALID, LOCATOR_KIND_RESERVED, LOCATOR_KIND_UDPv4, LOCATOR_KIND_UDPv6, LOCATOR_ADDRESS_INVALID, LOCATOR_PORT_INVALID |
TopicKind_t | 用于区分是否一个topic定义了一些字段作为key,这个key用于识别topic中的数据实例;RTPS协议中有两种主题种类:NO_KEY和WITH_KEY。NO_KEY表示主题没有定义键,相当于所有主题实例都是唯一的,不需要关键字段来区分。而WITH_KEY表示主题定义了一些字段作为键,这些键字段将用于识别和区分主题内的不同数据实例。 |
ChangeKind_t | 用来区别对数据对象所做的不同种类的变更。这些变更包括对数据本身的改动,或者对数据对象的实例状态的改动。简单来说,这个概念被用来描述或者记录数据对象在时间线上的变化。例如,你可能想知道一个数据对象是被添加、删除、修改,还是下线了,这些信息都可以由"ChangeKind_t"枚举类型来标识,并通过RTPS协议传给订阅者。包含以下值:ALIVE, ALIVE_FILTERED, NOT_ALIVE_DISPOSED, NOT_ALIVE_UNREGISTERED |
ReliabilityKind_t | 用于描述通信的可靠状态,包括:BEST_EFFORT, RELIABLE. |
InstanceHandle_t | 代表数据对象身份的类型。在RTPS协议中,一个数据对象的身份(也就是指数据对象的唯一标识)是由一个特定类型来表示的。这个类型用于在RTPS协议中表示和追踪数据对象,使得数据对象的值的变化能够被有效地监测和沟通。这就意味着,这个特定类型的数据实质上就是数据对象的唯一ID,用来标志、标识一个特定的数据对象,确保信息传输的过程中,接收方可以确切知道每个接收到的变化值应该关联到哪个数据对象上。 |
ProtocolVersion_t | RTPS protocol版本 |
VendorId_t | 实现RTPS协议的供应商 |
RTPS Entities属性
RTPS Eitities的一部分属性是通过DDS的Qos映射来的;一些属性(或者说参数)可以进行调整,以便适应特定的传输环境和部署情况。通过调整这些参数,可以改变协议的行为,使之适合当前的网络环境和应用需求;除了上面的属性之外,RTPS协议还有一些其他的属性,它们不是用来调节协议的行为的,而是用来记录或者表示RTPS实体(例如某个特定的数据对象)当前的状态的。这些状态信息对于理解和跟踪协议的运行过程是很重要的,但它们不影响协议的基本行为。
主要实体类的属性配置UML类图
HistoryCache
HistoryCache用于连接DDS和RTPS,在读端和写端有不同的作用。
读端,包含了所有匹配的RTPSWriter端发送的部分数据。部分是因为,没有必要保持所有变更的完整历史。相反,我们需要的是历史的一个子集,这个子集必须能够满足RTPS协议的行为需求和相关DDS实体的QoS需求。定义这个子集的规则 由RTPS协议规定,既取决于通信协议的状态,也取决于相关DDS实体的QoS。
HistoryCache属性:
attribute | type | meaning | relation to DDS |
---|---|---|---|
changes | CacheChange[*] | HistoryCache中包含的CacheChanges的容器 | History / DataReaderHistory / DataWriterHistory |
HistoryCache操作:
P 9.2.2 24页
- new:创建一个新的RTPS HistoryCache,并初始化一个空的changes的list
- add_change:将一个新的CacheChange添加到HistoryCache中,这个操作只有在没有足够的资源将变更添加到历史缓存时才会失败。这是DDS服务实现的责任,需要以与DDS实体的 RESOURCE_LIMITS QoS一致的方式配置历史缓存,并按照DDS规范的指定方式向DDS用户传播任何错误。
- remove_change:将CacheChange对象从HistoryCache中移除
- get_seq_num_min:获取HistoryCache中CacheChange对象的
CacheChange::sequenceNumber
的最小值 - get_seq_num_max:获取HistoryCache中CacheChange对象的
CacheChange::sequenceNumber
的最大值
CacheChange
属性 | 类型 | 含义 | 与DDS的关联 | 对应到Fast DDS中的成员 |
---|---|---|---|---|
kind | ChangeKind_t | ChangeKind_t 类型 | DDS instance state kind | kind |
writerGuid | GUID_t | RTPS Writer的GUID_t | writerGUID | |
instanceHandle | InstanceHandle_t | 数据实例 | In DDS, the value of the fields labeled as ‘key’ within the data uniquely identify each data- object. | instanceHandle |
sequenceNumber | SequenceNumber_t | RTPS Writer使用Sequence number唯一标识一个change. | sequenceNumber | |
data_value | Data | CacheChange是用来追踪数据对象状态变化的。每个CacheChange都有一个与之关联的数据值。这个数据值描述了与变化相关的具体数据内容。但这句话同时也指出,根据CacheChange的种类,可能并没有与之关联的数据。也就是说,并非所有的CacheChange都会改变数据或有新的数据,有些CacheChange只是表示一种状态变化,比如从‘未修改’变为‘已修改’,但并没有具体的修改内容。 | serializedPayload :SerializedPayload_t | |
inlineQos | ParameterList | Contains QoS that may affect the interpretation of the CacheChange::data_value. | DDS-specific information which affects the data. | inline_qos:SerializedPayload_t |
RTPS Entity
RTPS Entity是所有RTPS实体类的基类。实体属性如下:
attribute | type | meaning | relation to DDS |
---|---|---|---|
guid | GUID_t | 在DDS domain中全局且唯一标识RTPS 实体 |
GUID是一个tuple,tuple <prefix, entityId>
包含一个GuidPrefix_t prefix
和一个EntityId_t entityId
字段 | 类型 | 含义 |
---|---|---|
prefix | GuidPrefix_t | 在Domain中唯一标识了Participant |
entityId | EntityId_t | 在Participant中唯一标识了Entity |
- GUIDs of RTPS Participants:每个Participant都有一个GUID:
<prefix, ENTITYID_PARTICIPANT>
,其中ENTITYID_PARTICIPANT是一个常量,依赖平台的定义,prefix的实现只要保证唯一性即可。 - GUID 为
<participantPrefix, ENTITYID_PARTICIPANT>
的Participant中的RTPS Endpoints的GUID 为<participantPrefix, entityId>
,其中entityId在这个participant中是唯一的:- 同一Participant中的Endpoints的GUID有相同的prefix.
- 只要知道了Endpoint中的GUID,包含该endpoint的Participant的GUID也就知道了
- 任何端点的GUID都可以从它所属的participant的GUID和它的entity ID中推导出来。每个RTPS实体的实体ID的选择取决于PSM。
- DDS定义了Publisher和Subscriber实体,这两个实体定义的GUID符合这里的描述;
RTPS Participant
对应于DDS DomainParticipant
TODO 8.2.5 P28
属性 | 类型 | 含义 | 与DDS的关联 | Fast DDS对应的字段 |
---|---|---|---|---|
defaultUnicastLocatorList | Locator_t[*] | 默认单播的locators(transport, address, port) | ||
defaultMulticastLocatorList | Locator_t[*] | 默认多播的locators | ||
protocolVersion | ProtocolVersion_t | RTPS协议版本 | ||
vendorId | VendorId_t | 供应商id |
RTPS EndPoint
RTPS Endpoint代表了从RTPS协议的角度来看可能的通信端点。有两种RTPS endpoint实体:Writer和Reader。
RTPS Endpoint属性有以下:
attribute | type | meaning | relation to DDS |
---|---|---|---|
unicastLocatorList | Locator_t[*] | 用于给endpoint发送消息的unicast locators(transport,address,port的组合),这个列表可能是空的 | |
multicastLocatorList | Locator_t[*] | 用于给endpoint发送消息的unicast locators(transport,address,port的组合),这个列表可能是空的 | |
reliabilityLevel | ReliabilityKind_t | Endpoint.支持的reliability | RELIABILITY QoS的kind |
topicKind | TopicKind_t | 表示是否支持实例生命周期管理操作 | 由与DDS topic关联的Data-type定义,表明与rtps endpoint关联的datatype是否定义了一些包含dds key的字段 |
RTPS Writer
所有的RTPS Writer属于RTPS Group,用于向已经匹配的RTPS Readers发送CacheChange
RTPS Reader
所有的RTPS Reader属于RTPS Group。用于接收已经匹配的Writer消息。
和DDS Entities的关联
HistoryCache建立了DDS Entities和RTPS Entities之间的关联。但是RTPS协议并未规定DDS如何和HistoryCache交互,只规定了如何从RTPS writer的HistoryCache中传输CacheChange到每个匹配的RTPS reader的HistoryCache。
DDS DataWriter
DDS DataWriter添加CacheChange到与它关联的RTPS Writer的HistoryCache中。所以HistoryCache中保存了写入的CacheChange,具体保存多少由DDS的DataWriter的Qos(如HISTORY 和 RESOURCE_LIMITS)决定。
默认情况下,所有HistoryCache中的CacheChange都会被发送到与其匹配的远端readers中。
CacheChange没有被发送到远端Readers中有两个原因:
- DDS DataWriter 从HistoryCache移除了,所以不再有效
- 被认为是与Reader无关
DDS DataWriter从HistoryCache中移除CacheChange的原因有以下几点:
- History Qos中设置了限制数量
- LIFESPAN Qos中设置了sample的生命周期
- 使用reliable通信时,当所有接收到该CacheChange的readders都已经确认,且仍然是active和alive的时,这个CacheChange才会被删除。
并非所有的更改都对每个匹配的远端readers都有关,如TIME_BASED_FILTER Qos,或使用DDS 内容过滤topic,是否一次change具有相关性必须根据每个reader的情况来判断。在可能的情况下,通过在writer端进行过滤,可能能优化带宽或CPU使用。换句话说,只有被认为与特定reader有关的change才会被发送,从而节约资源使用。是否能优化带宽和/或CPU使用取决于实现是否跟踪每个单独的远程reader以及适用于该reader的QoS和过滤器。reader本身总是会过滤的。这意味着如果系统以一种方式实现,使得它能够记住针对每个reader的特定设置和过滤,那就可以在writer端进行优化过滤,而不是全部依赖reader端的过滤。
根据写writer存储的reader的特定信息,DDS_FILTER(reader端过滤change)可能不会进行任何操作。对于基于内容的过滤,RTPS规范允许在每次变更时发送信息,列出已经应用于change的过滤器,以及通过了哪些过滤器。如果有这些信息,那么reader可以在不调用DDS_FILTER的情况下过滤change。这种方法通过在writer端一次过滤样本,而不是在每个reader端过滤,节省了CPU周期。
Transition | state | event | next state |
---|---|---|---|
T1 | initial | new DDS DataWriter | alive |
T2 | alive | DataWriter::write | alive |
T3 | alive | DataWriter::dispose | alive |
T4 | alive | DataWriter::unregister | alive |
T5 | alive | delete DDS DataWriter | final |
DDS DataReader
DatReader从RTPSReader的HistoryCache中获取数据,存储在HistoryCache中的数据由Qos决定(HISTORY,RESOURCE_LIMITS)。
每个匹配的writer都将尝试将其HistoryCache中的所有相关samples传输到reader的HistoryCache中。在DDS DataReader上通过read或take调用获取HistoryCache中的数据。返回给用户的change是通过所有reader的特定filter的HistoryCacahe中的change。
实现可能能够在writer一侧执行大部分过滤。在这种情况下,samples要么从未发送(因此不存在于reader的HistoryCache中),要么包含了应用了哪些过滤器及其相应结果的信息(基于content-based的过滤)
DataReader可以根据Qos如TIME_BASED_FILTER从HistoryCache中移除changes,
Transition | state | event | next state |
---|---|---|---|
T1 | initial | new DDS DataReader | alive |
T2 | alive | DDS DataReader::read | alive |
T3 | alive | DDS DataReader::take | alive |
T4 | alive | delete DDS DataReader | final |