DDS协议 fast-dds 概述
文章目录
Fast-RTPS 安装(只是参考哦)
我的资料包:https://download.csdn.net/download/qq_41816308/88123590
也可自行官网下载
mkdir DDS
cd DDS/
tar -zxvf eProsima_Fast-DDS-v2.7.1-Linux.tgz.tgz
sudo ./install.sh
cd src/
cd fastrtps/
mkdir build
cd build/
vim ../CMakeLists.txt
cmake -DCOMPILE_EXAMPLES=ON ..
make -j8
cd examples/
cd cpp/
cd dds/
cd HelloWorldExample
ls
./DDSHelloWorldExample publisher
./DDSHelloWorldExample subscriber
//使用fastddsgen自动生成代码
/work/dds/src/fastddsgen/scripts/fastddsgen -example CMake Fantest.idl
Fast-RTPS 介绍
Fast-RTPS 是 eprosima 对于 RTPS 的 C++ 实现,这是一个免费开源软件,遵循 Apache License 2.0。
eProsima Fast RTPS 在性能、功能和最新版本(RTPS 2)的维护方面都可以查看RTPS 的最高版本:关于Fast 性能的 快速RTPS 性能 。
它最被大家知道的可能是因为被 ROS2 设定为默认的消息。
Fast-RTPS支持平台包括:Windows、Linux、Mac OS、QNX、VxWorks、iOS、Android、Raspbian。
Fast-RTPS 具有以下优点:
对于实时应用程序而言,可以在最佳和可靠的通信策略上进行配置。
即即用的连接性,网络插播的所有成员自动发现其他新的成员。
扩展性和可扩展性允许网络中的设备不断增长。
可配置的网络行为和可替换/输入的最佳层传输:为每个部署选择协议和系统输出通道组合。
两个API层:一个简单易用的发布者-订阅者层和一个提供对RTPS协议内部层更好地控制的Writer-Reader。
模型体系结构:
Application 指的是采用 Fast DDS API 的各类应用。
DDS Layer 主要定义一个系统中不同的 Domain,
在同一个 Domain 下 Topic 按规则通信。
Fast RTPS 是通信协调层,是下层 Transport 的抽象。
Transport 层处理底层 UDP、TCP、SHM(共享内存)。
DataWriterHistory :这是对数据对象的更改列表。当数据写入器继续在特定主题下发布数据时,它实际上会在此数据中创建更改。在历史记录中注册的正是此更改。然后,这些更改将发送到订阅该特定主题的数据读取器。
DataReaderHistory:它包含数据读取器在订阅某个主题后收到的数据对象中的更改。
以数据为中心的模型,虚拟出全局数据空间的概念,各节点向该空间声明发布者或者订阅者的意图;
抽象出 Domain 以及 Topic 的概念,不同 Domain 之间数据独立不互通,在同一个 Domain 之间通过 Topic 发布/订阅数据;
代码库介绍:
FastCDR:库提供两种序列化机制。 一种是标准CDR序列化机制,另一种是更快的实现。
fastdds-gen:主要是一个用来自动生成代码的工具。它是一个java工具,可以将对应的idl文件生成对应的C++文件。免去我们自己手写对接fastdds的代码(虽然肯定后续要手写)。
foonathan_memory_vendor:与STL兼容的C++内存分配器库。
FastRTPS,eProsima快速DDS库的核心库。
数据类型与自动生成代码
动态类型(Dynamic Types)
动态类型提供了在RTPS上工作的可能性,而不受与IDL相关的限制。使用它们,用户可以声明他们需要的不同类型并直接管理信息,从而避免了更新IDL文件和生成C++类的额外步骤。
不使用idl,直接动态加载xml文件,使用xml里面的数据结构
内存管理对于动态类型至关重要,因为每个动态类型和动态数据都是用指针管理的。存储在动态对象中的每个对象都由其所有者管理,用户必须删除他们使用工厂创建的每个对象。
DynamicTypeBuilder* pBuilder = DynamicTypeBuilderFactory::get_instance()->create_uint32_builder();
DynamicType_ptr pType = DynamicTypeBuilderFactory::get_instance()->create_int32_type();
DynamicData* pData = DynamicDataFactory::get_instance()->create_data(pType);
DynamicTypeBuilderFactory::get_instance()->delete_builder(pBuilder);
DynamicDataFactory::get_instance()->delete_data(pData);
为了简化此管理,库定义了智能指针(DynamicTypeBuilder_ptr、DynamicType和DynamicData_ptr),这些指针将在不再需要对象时自动删除对象。DynamicType将始终返回为DynamicType_ptr,因为它的内存没有内部管理。
DynamicTypeBuilder_ptr pBuilder = DynamicTypeBuilderFactory::get_instance()->create_uint32_builder();
DynamicType_ptr pType = DynamicTypeBuilderFactory::get_instance()->create_int32_type();
DynamicData_ptr pData(DynamicDataFactory::get_instance()->create_data(pType));
唯一不能使用这些智能指针的情况是函数loan_value和return_loned_value。原始指针应与这些函数一起使用,因为不应删除返回的值,并且与它们一起使用智能指针会导致崩溃。
Fast DDS的静态类型(IDL Types)
使用fastdds-gen自动生成代码
整体生成的代码还是比较简单的,因为DDS主要还是围绕data来进行的,所以我们在定义好我们自己需要传输的数据结构,通过编写idl,然后用fastddsgen工具就可以生成对应的代码,进行通信了。
所以如果实际场景中,仅仅只有数据的单向流动的话,那么通过gen工具生成的对应代码已经完全能满足对应需求了。
但是如果想要实现更加复杂的业务,那么就需要在此基础上继续开发了。
使用fastdds-gen自动生成代码
1、写idl文件定义数据结构(Interface description language)
2、生成代码
/work/dds/src/fastddsgen/scripts/fastddsgen -example CMake Fantest.idl
3、代码分析:
**FantestPubSubMain:**main函数内部其实主要实现的就是一个参数判断,根据不同的参数去启动对应的publisher还是subscriber。
FantestPublisher:初始化、启动等待订阅者、订阅者上线,发送数据。
init主要做了如下的步骤:
创建participant
注册type
创建publisher
创建topic
创建writer
启动阶段是写了一个循环,检查listner_.matched,如果没有匹配到sub,就继续等待。
匹配到sub的话,就会发送对应的"DataWriter matched."
监听回调阶段
这里主要是实现对应listener的回调函数,当sub匹配到时,会调用到这里。
**Subscriber:**自动生成的代码中,sub主要做了如下的事情:
初始化
启动
订阅匹配
数据接收
初始化和pub的逻辑类似也是:
创建participant
注册type
创建subcriber
创建topic
创建reader
启动阶段
启动函数其实没做啥,主要就是打印一些内容
订阅匹配
匹配和pub的逻辑类似,匹配上之后会去设置matched值。
数据接受 on_data_available