系列文章目录
文章目录
- 系列文章目录
- preface
- **对象与数据结构**
- ● Publish-Subscriber模块
- ● RTPS模块
- **配置Attributes**
- Discovery
- 传输控制
- 前言
- 0、安装
- cmake安装相关
- 源码安装:
- - A `foonathan_memory_vendor`
- - C `fastcdr`
- - D `tinyxml2`
- - E `asio`
- - F `openssl`
- - G `fastrtps`
- 一、C++ publisher、subscriber应用
- 什么是DDS
- DCPS概念模型
- RTPS
- C++ 发布者订阅者应用
- 总结
preface
fast dds官方文档缺乏对DDS整体的介绍,一上来就介绍各种细节,DDS的整体设计意图和用法隐匿与各种细节中,很容易让人一头雾水,不知其所云。该文章对DDS有一个整体的介绍,方便快速了解其概念。
https://www.eprosima.com/docs/fast-rtps/1.9.3/html/index.html
DDS全称是Data Distribution Service,这是一套通信协议和API标准,它提供了以数据为中心的连接服务,基于发布者-订阅者模型。这是一套中间件,它提供介于操作系统和应用程序之间的功能,使得组件之间可以互相通信。并且提供了低延迟,高可靠的通信以及可扩展的架构。
DDS本身是一套标准。由Object Management Group(简称OMG)维护。
OMG是一个开放性的非营利技术标准联盟,由许多大型IT公司组成:包括IBM,Apple Computer,Sun Microsystems等。
但OMG仅仅负责制定标准,而标准的实现则由其他服务提供商完成。
目前DDS的提供商包括下面这些:
- Vortex OpenSplice
- eProsima Fast RTPS
- Hamersham
- Company Summary Kongsberg Gallium
- MilSOFT
- Object Computing OpenDDS
- Remedy IT
- RTI
- Twin Oaks Computing, Inc.
DDS与RTPS
在DDS规范中,有两个描述标准的基本文档:
- DDS Specification:描述了以数据为中心的发布-订阅模型。该规范定义了API和通信语义(行为和服务质量),使消息从消息生产者有效地传递到匹配的消费者。DDS规范的目的可以概括为:“能够在正确的时间将正确的信息高效,可靠地传递到正确的位置”。
- DDSI-RTPS:描述了RTPS(Real Time Publish Subscribe Protocol)协议。该协议通过UDP等不可靠的传输,实现最大努力(Best-Effort)和可靠的发布-订阅通信。RTPS是DDS实现的标准协议,它的目的和范围是确保基于不同DDS供应商的应用程序可以实现互操作。
Fast-RTPS 介绍
Fast-RTPS是eprosima对于RTPS的C++实现,这是一个免费开源软件,遵循Apache License 2.0。
eProsima Fast RTPS在性能,功能和对最新版本RTPS标准(RTPS 2.2)的遵守方面均处于领先地位。
Fast-RTPS具有以下优点:
- 对于实时应用程序来说,可以在Best-Effort和可靠通信两种策略上进行配置。
- 即插即用的连接性,使得网络的所有成员自动发现其他新的成员。
- 模块化和可扩展性允许网络中设备不断增长。
- 可配置的网络行为和可互换的传输层:为每个部署选择最佳协议和系统输入/输出通道组合。
- 两个API层:一个简单易用的发布者-订阅者层和一个提供对RTPS协议内部更好控制的Writer-Reader层。
Fast-RTPS提供了两个层次的API:
- Publisher-Subscriber层:RTPS上的简化抽象。
- Writer-Reader层:对于RTPS端点的直接控制。
对象与数据结构
下面是Fast-RTPS实现中的核心结构。
● Publish-Subscriber模块
RTPS标准的高层类型。
- Domain:用来创建,管理和销毁Participants。
- Participant:包括Publisher和Subscriber,并管理它们的配置。
- ParticipantAttributes:创建Participant的配置参数。
- ParticipantListener:可以让开发者实现Participant的回调函数。
- Publisher:在Topic上发布数据的对象。
- PublisherAttributes:创建Publisher的配置参数。
- PublisherListener:可以让开发者实现Publisher的回调函数。
- Subscriber:在Topic上接受数据的对象。
- SubscriberAttributes:创建Subscriber的配置参数。
- SubscriberListener:可以让开发者实现Subscriber的回调函数。
● RTPS模块
RTPS的底层模型。包含下面几个子模块:
- RTPS Common
- CacheChange_t:描述Topic上的变更,存储在历史Cache中。
- Data:Cache变化的负载。
- Message:RTPS消息。
- Header:RTPS协议的头信息。
- Sub-Message Header:标识RTPS的订阅消息。
- MessageReceiver:反序列化和处理接受到的RTPS消息。
- RTPSMessageCreator:构建RTPS消息。
- RTPS Domain
- RTPSDomain:用来创建,管理和销毁底层的RTPSParticipants。
- RTPSParticipant:包括Writer和Reader。
- RTPS Reader
- RTPSReader:读者的基类。
- ReaderAttributes:包含RTPS读者的配置参数。
- ReaderHistory:存储Topic变化的历史数据。
- ReaderListener:读者的回调类型。
- RTPS Writer
- RTPSWriter:写者的基类。
- WriterAttributes:包含RTPS写者的配置参数。
- WriterHistory:存储写者的历史数据。
配置Attributes
上面的数据结构中看到了许多Attributes后缀的类名。这些类包含了对协议或者对象的配置参数,很多特性都需要设置这些属性来完成。
这些类的定义基本都位于下面三个文件夹中:
https://github.com/eProsima/Fast-DDS
- include/fastrtps/attributes
- include/fastrtps/rtps/attributes
- include/fastdds/rtps/attributes
Fast RTPS支持非常多的配置参数,并且参数的结构常常是嵌套的。
通过代码去配置这些参数会产生很多啰嗦的代码,而且最大的问题在于:每次更改配置参数都需要重新编译。这个问题并非Fast RTPS才有,只要包含大量配置参数的软件都会这样的问题。通常的解决方法就是:提供文本格式的配置文件的方式来配置参数。因此对于Fast-RTPS来说,除了支持通过代码配置参数,它也支持通过XML文件的方式来进行配置。
Fast-RTPS支持的配置项,以及这些配置项说明和默认值都可以到这个链接中查看:XML profiles。
Discovery
作为DDS的实现,Fast-RTPS提供了Publisher和Subscriber自动发现和匹配的功能。在实现上,这分为两个步骤来完成:
- Participant Discovery Phase (PDP):在这个阶段,参与者互相通知彼此的存在。为了达到这个目的,每个参与者需要定时发送公告消息。公告消息通过约定的多播地址和端口发送(根据domain计算得到)。
- Endpoint Discovery Phase (EDP):在这个阶段,Publisher和Subscriber互相确认。为此,参与者使用在PDP期间建立的通信通道,彼此共享有关其发布者和订阅者的信息。 该信息包含了Topic和数据类型。为了使两个端点匹配,它们的Topic和数据类型必须一致。 一旦发布者和订阅者匹配,他们就发送/接收数据了。
这两个阶段对应了两个独立的协议:
- Simple Participant Discovery Protocol:指定参与者如何在网络中发现彼此。
- Simple Endpoint Discovery Protocol:定义了已经互相发现的参与者交换信息的协议。
Fast-RTPS提供了四种发现机制:
- Simple:这是默认机制。它在PDP和EDP阶段均使用RTPS标准,因此可与任何其他DDS和RTPS实现兼容。
- Static:此机制在PDP阶段使用Simple Participant Discovery Protocol。如果所有发布者和订阅者的地址以及端口和主题信息是事先知道的,则允许跳过EDP阶段。
- Discovery Server: 这种发现机制使用集中式发现结构,由服务器充当发现机制的Hub。
- Manual:此机制仅与RTPSDomain层兼容。它禁用了PDP阶段,使用户可以使用其选择的任何外部元信息通道手动匹配和取消匹配RTPS参与者,读者和写者。
不同的发现机制具有一些共同的配置:
名称 | 描述 | 默认值 |
---|---|---|
Ignore Participant flags | 在必要的时候,可以选择忽略一些参与者。 | |
例如:另一台主机上的,另一个进程的或者同一个进程的。 | NO_FILTER | |
Lease Duration | 指定远程参与者在多少时间内认为本地参与者还活着。 | 20s |
Announcement Period | 指定参与者的PDP公告消息的周期。 | 3s |
more details: https://fast-dds.docs.eprosima.com/en/latest/fastdds/discovery/discovery.html
传输控制
ast-RTPS实现了可插拔的传输架构,这意味着每一个参与者可以随时加入和退出。
在传输上,Fast-RTPS支持以下五种传输方式:
UDPv4
UDPv6
TCPv4
TCPv6
SHM(Shared Memory
默认的,当Participant创建时,会自动的配置两个传输通道:
SHM:用来与同一个机器上的参与者通信。
UDPv4:同来与跨机器的参与者通信。
开发者可以改变这个默认行为,通过C++接口或者XML配置文件都可以。
SHM要求所有参与者位于同一个系统上,它是借助了操作系统提供的共享内存机制实现。共享内存的好处是:支持大数据传输,减少了数据拷贝,并且也减少系统负载。因此通常情况下,使用SHM会获得更好的性能。使用SHM时,可以配置共享内存的大小。
网络通信包含了非常多的参数需要配置,例如:Buffer大小,端口号,超时时间等等。框架本身为参数设置了默认值,大部分情况下开发者不用调整它们。但是知道这些默认值是什么,在一些情况下可能会对分析问题有所帮助。
与UDP不同,TCP传输是面向连接的,因此,Fast-RTPS必须在发送RTPS消息之前建立TCP连接。TCP传输可以具有两种行为:充当TCP服务器或充当TCP客户端。服务器打开一个TCP端口以侦听传入的连接,然后客户端尝试连接到服务器。服务器和客户端的概念独立于RTPS概念,例如:Publisher,Subscriber,Reader或Writer。它们中的任何一个都可以用作TCP服务器或TCP客户端,因为这些实体仅用于建立TCP连接,而RTPS协议可以在该TCP连接上工作。
如果要使用TCP传输,开发者需要做更多的配置。
前言
eProsima Fast DDS是DDS规范的C++实现,DDS是由OMG定义的一种协议。eProsima Fast DDS 库提供应用程序编程接口 (API) 和通信协议 部署 以数据为中心的发布者-订阅者 (DCPS) 模型,旨在建立高效可靠的信息在实时系统之间分配。eProsima Fast DDS 在资源处理方面具有可预测性、可扩展性、灵活性和高效性。 为了满足这些要求,它利用了类型化接口和多对多的铰链 分布式网络范式,巧妙地允许将通信的发布者和订阅者端分开。eProsima Fast DDS 包括:
- DDS API实现
- Fast DDS-Gen,一种用于桥接类型化接口与中间件的生成工具 实现
- 底层RTPS有限协议实现
DDS采用的通信模式是多对多的单向数据交换,其中应用 生成数据,将其发布到属于使用数据的应用程序的订阅者的本地缓存。 信息流由QOS策略管理,QOS由交换数据的实体建立。DDS通讯只能发生在DDS Domain内,不能夸Domain。
RTPS Wire Protocol
在传输层之上的协议,传输层可以是TCP/UDP/IP
0、安装
https://www.eprosima.com/index.php/downloads-all
https://fast-dds.docs.eprosima.com/en/latest/index.html
cmake安装相关
宏 | 做用 | 用法 | 备注 |
---|---|---|---|
CMAKE_INSTALL_PREFIX | 指定make intall安装路径 | cmake … -DCMAKE_INSTALL_PREFIX=<path/to/install> | |
CMAKE_C_COMPILER | 指定C编译器 | set(CMAKE_C_COMPILER </path/gcc> | 在project之前 |
CMAKE_CXX_COMPILER | 指定C++编译器 | set(CMAKE_CXX_COMPILER </path/g++> | 在project之前 |
指定全局编译选项 | add_compile_options(-O2 -g) |
include
源码安装:
- A
foonathan_memory_vendor
, an STL compatible C++ memory allocator library. - B
fastdds_gen
, a Java application that generates source code using the data types defined in an IDL file. - C
fastcdr
, a C++ library that serializes according to the standard CDR serialization mechanism. - D
tinyxml2
- E
asio
- F
openssl
- G
fastrtps
, the core library of eProsima Fast DDS library.
最终目标是安装:https://github.com/eProsima/Fast-DDS
在thirdparty目录下也有第三方依赖
- A foonathan_memory_vendor
https://github.com/eProsima/foonathan_memory_vendor
编译该项目时需要下载:https://github.com/foonathan/memory.git。将该项目手动下载并修改foonathan_memory_vendor的CMakeLists.txt文件中的:
externalproject_add(foo_mem-ext
GIT_REPOSITORY https://github.com/foonathan/memory.git
GIT_TAG v0.7-3
TIMEOUT 600
# Avoid the update (git pull) and so the recompilation of foonathan_memory library each time.
UPDATE_COMMAND ""
CMAKE_ARGS
-DFOONATHAN_MEMORY_BUILD_EXAMPLES=${BUILD_MEMORY_EXAMPLES}
-DFOONATHAN_MEMORY_BUILD_TESTS=${BUILD_MEMORY_TESTS}
-DFOONATHAN_MEMORY_BUILD_TOOLS=${BUILD_MEMORY_TOOLS}
-DCMAKE_INSTALL_PREFIX=${CMAKE_CURRENT_BINARY_DIR}/foo_mem_ext_prj_install
${extra_cmake_args}
-Wno-dev
${PATCH_COMMAND_STR}
)
修改为:
externalproject_add(foo_mem-ext
SOURCE_DIR <dir/memory-main>
# Avoid the update (git pull) and so the recompilation of foonathan_memory library each time.
UPDATE_COMMAND ""
CMAKE_ARGS
-DFOONATHAN_MEMORY_BUILD_EXAMPLES=${BUILD_MEMORY_EXAMPLES}
-DFOONATHAN_MEMORY_BUILD_TESTS=${BUILD_MEMORY_TESTS}
-DFOONATHAN_MEMORY_BUILD_TOOLS=${BUILD_MEMORY_TOOLS}
-DCMAKE_INSTALL_PREFIX=${CMAKE_CURRENT_BINARY_DIR}/foo_mem_ext_prj_install
${extra_cmake_args}
-Wno-dev
${PATCH_COMMAND_STR}
)
编译命令:
mkdir build && cd build
cmake .. -DCMAKE_INSTALL_PREFIX=<path/to/install>
make -j8
make install
- C fastcdr
https://github.com/eProsima/Fast-CDR
编译命令:
mkdir build && cd build
cmake .. -DCMAKE_INSTALL_PREFIX=<path/to/install>
make -j8
make install
- D tinyxml2
https://github.com/leethomason/tinyxml2
编译命令:
mkdir build && cd build
cmake .. -DCMAKE_INSTALL_PREFIX=<path/to/install>
make -j8
make install
- E asio
Asio是一个用于网络和低级I/O编程的跨平台C++库,它使用现代C++方法为开发人员提供了一个一致的异步模型。
asio只有头文件,不需要编译
https://think-async.com/Asio/
https://think-async.com/Asio/Repository.html
https://github.com/chriskohlhoff/asio/
- F openssl
https://github.com/janbar/openssl-cmake
如果需要动态库则需要将crypto/CMakeLists.txt的add_library(crypto ${LIBSRC} ${OBJECTS_SRC})添加SHARED
;ssl/CMakeLists.txt的add_library(ssl ${LIBSRC})添加SHARED
编译命令:
mkdir build && cd build
cmake .. -DCMAKE_INSTALL_PREFIX=<path/to/install>
make -j8
make install
- G fastrtps
libfastrtps.so是最后一个库,安装完后fastdds就可以使用了。
https://github.com/eProsima/Fast-DDS
在其thirdparty目录下有一些第三方库,部分文件在编译时cmake会自动找到,下面解决编译时报错等问题。
修改CMakeLists.txt,添加include_directories(openssl/include/path asio/include/path)
大约在249行,在eprosima_find_package(fastcdr REQUIRED)之前添加cmake package搜罗路径:
# 将fastcdr, tinyxml2, foonathan_memory的位置添加进find_package的搜罗路径
set(CMAKE_PREFIX_PATH "<installpath/lib/cmake/fastcdr>;<lib/cmake/tinyxml2>;<lib/foonathan_memory/cmake>")
# 根据上面编译时的路径,编译fastrtps是应该找到对应的cmake package了
另外,Asio和Boost.Asio是可同时存在的,虽然它们功能一样但namespace和宏名等有差异,因此是不冲突的,modules/FindAsio.cmake文件line:35中使用的是ASIO_VERSION,boost.asio的宏为BOOST_ASIO_VERSION
由于openssl在安装后没有cmake文件,因此不能通过find_package找到openssl。需要在编译时指定动态库:在target_link_libraries中添加库文件的绝对路径即可
<fastdds_root_dir>/cpp/CMakeLists.txt:line:460后添加target_link_directories(${PROJECT_NAME} PUBLIC <openssl/lib_dir>)
; line:517添加<xx/lib/libssl.so> <xx/lib/libcrypto.so>
注释掉关于OpenSSL的行
编译命令:
mkdir build && cd build
cmake .. -DCMAKE_INSTALL_PREFIX=<path/to/install>
make -j8
make install
一、C++ publisher、subscriber应用
什么是DDS
Data Distribution Service(DDS)是一个以数据为中心的通讯协议,它用于进程之间的通讯。它描述了通讯APIs和通讯双方的通讯语义。
Since it is a Data-Centric Publish Subscribe (DCPS) model, 三个关键点:
- 发布实体:生成数据并定义其格式、属性等
- 接收实体:数据接接收方
- 配置实体:定义信息类型,作为topics传输,创建publishersubscriber和QOS属性,确保实体的正确表现
DDS 使用 QoS 来定义 DDS 实体的行为特征。QoS 由单独的 QoS 策略组成
DCPS概念模型
在DCPS模型中,为通信应用系统的开发定义了四个基本要素。
- 发布者。它是 DCPS 实体,负责创建和配置它实现的 DataWriter。 DataWriter 是负责消息实际发布的实体。 每个主题都将有一个分配的主题,在该主题下发布消息。
- 订阅者。 它是DCPS实体,负责接收在其订阅的主题下发布的数据。 它提供一个或多个 DataReader 对象,这些对象负责传达新数据的可用性 到应用程序。
- 主题。 它是绑定发布者和订阅者的实体。 它在 DDS 域中是唯一的。 通过 TopicDescription,它允许出版物和订阅的数据类型的统一性。
- 域
RTPS
RPTS 协议,开发为 支持DDS应用,是一个发布-订阅通信中间件 通过尽力而为的传输,例如 UDP/IP。此外,Fast DDS 还支持 TCP 和 共享内存 (SHM) 传输。
它旨在支持单播和组播通信。
在 RTPS 的顶部,继承自 DDS,可以找到域,它定义了一个单独的通信平面。 多个域可以独立地同时共存。 域包含任意数量的 RTPSParticipants,即能够发送和接收数据的元素。 为此,RTPSParticipants 使用其终结点:
RTPSWriter:能够发送数据的端点。
RTPSReader:能够接收数据的端点。
C++ 发布者订阅者应用
DDS是以数据为中心的通讯中间件,它实现了DCPS模型。该模型基于发布者、订阅者模式。这些实体通过主题进行通信,主题是绑定两个 DDS 实体的元素。发布者在主题下产生信息,订阅者通过相同的主题接收信息。
- 创建应用程序空间
- 依赖库
Fast DDS 和 Fast CDR
如果是二进制安装,头文件在/usr/include/fastrtps/
和/usr/include/fastcdr/
;库文件在/usr/lib/
- 配置CMake工程
cmake_minimum_required(VERSION 3.20)
project(DDSHelloWorld)
# Find requirements
if(NOT fastcdr_FOUND)
find_package(fastcdr 2 REQUIRED)
endif()
if(NOT fastrtps_FOUND)
find_package(fastrtps 2.12 REQUIRED)
endif()
# Set C++11
include(CheckCXXCompilerFlag)
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_COMPILER_IS_CLANG OR
CMAKE_CXX_COMPILER_ID MATCHES "Clang")
check_cxx_compiler_flag(-std=c++11 SUPPORTS_CXX11)
if(SUPPORTS_CXX11)
add_compile_options(-std=c++11)
else()
message(FATAL_ERROR "Compiler doesn't support C++11")
endif()
endif()
message(STATUS "Configuring HelloWorld publisher/subscriber example...")
file(GLOB DDS_HELLOWORLD_SOURCES_CXX "src/*.cxx")
- build the topic data type
eProsima Fast DDS-Gen是一个生成源码的Java应用,它使用Interface Description Language(IDL)文件定义的数据类型。它有两个功能:- 为topic生成C++定义
- 用topic数据生成功能案例
cd src && touch HelloWorld.idl
HelloWorld.idl文件中定义的 topic C++定义
struct HelloWorld
{
unsigned long index;
string message;
};
然后通过eProsima Fast DDS-Gen工具生成C++11代码:
<path/to/Fast DDS-Gen>/scripts/fastddsgen HelloWorld.idl
这将生成:
总结
https://fast-dds.docs.eprosima.com/en/latest/02-formalia/titlepage.html
https://paul.pub/dds-and-fastrtps/