eProsima Fast DDS getting started

系列文章目录



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提供了四种发现机制:

  1. Simple:这是默认机制。它在PDP和EDP阶段均使用RTPS标准,因此可与任何其他DDS和RTPS实现兼容。
  2. Static:此机制在PDP阶段使用Simple Participant Discovery Protocol。如果所有发布者和订阅者的地址以及端口和主题信息是事先知道的,则允许跳过EDP阶段。
  3. Discovery Server: 这种发现机制使用集中式发现结构,由服务器充当发现机制的Hub。
  4. 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 包括:

  1. DDS API实现
  2. Fast DDS-Gen,一种用于桥接类型化接口与中间件的生成工具 实现
  3. 底层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)
CMAKE_PREFIX_PATH指定find_package搜索路径set(CMAKE_PREFIX_PATH “path1;path2;path3”)

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

安装方法二:源码一键编译安装

  1. 下载FastDDS仓库及其引用
    git clone --recurse-submodules https://github.com/eProsima/Fast-DDS.git
    cd Fast-DDS
    git checkout v2.14.0
    
  2. 在thirdparty目录下拉取memory[https://github.com/foonathan/memory.git]和openssl-cmake[https://github.com/janbar/openssl-cmake]
    在这里插入图片描述
  3. 修改项目
    根据需要添加gettid函数。将
    #include <sys/syscall.h>
    inline static pid_t gettid()
    {
        return syscall(SYS_gettid);
    }
    
    添加到文件:Fast-DDS/src/cpp/utils/threading/threading_pthread.ipp
    编译时将文件/usr/share/cmake-3.22/Modules/FindOpenSSL.cmake换个别名,否则在编译rtps时会使用该.cmake文件中OpenSSL路径
  4. 将build.sh放入Fast-DDS目录然后运行
#!/bin/bash
GCC=aarch64-none-linux-gnu-gcc
GXX=aarch64-none-linux-gnu-g++
output_path=../build_orange
#

if [ $? -ne 0 ]; then  # -ne -eq # prev command is failed?
    echo "Command failed"
    exit 1
fi
# git checkout v2.14.0 4c2016660e7d6a6e94970e1a2b4dcd8e47f21581
current_commit_id=$(git rev-parse HEAD)
target_commit_id="4c2016660e7d6a6e94970e1a2b4dcd8e47f21581"
if [ "$current_commit_id" != "$target_commit_id" ]; then
    git checkout $target_commit_id
    if [ $? -ne 0 ]; then
        echo -e "\033[31m[error]\033[0m Command git checkout v2.14.0 failed"
        echo -e "\e[33mPlease running git checkout v2.14.0 manually\e[0m"
        sleep 5
    fi
fi


cpu_cores=$(grep -c ^processor /proc/cpuinfo)
curr_dir=`pwd`

if [ ! -d thirdparty  ];then
    echo "thirdparty directory not found"
    exit 1
fi
echo "thirdparty directory found. build thirdparty libraries."

function build_lib()
{
    echo "now building library $1"
    cd $curr_dir
    mkdir -p $output_path/tmp/$1
    if [ $? -ne 0 ]; then  # -ne -eq # prev command is failed?
        echo -e "\033[31m[error]\033[0m mkdir $output_path/tmp/$1 failed"
        exit 1
    fi
    build_path=$output_path/tmp/$1
    cmake \
        -DCMAKE_INSTALL_PREFIX=$build_path/install \
        -DCMAKE_C_COMPILER=$GCC \
        -DCMAKE_CXX_COMPILER=$GXX \
        -DBUILD_SHARED_LIBS=ON \
        -B $build_path -S thirdparty/$1
    if [ $? -ne 0 ]; then 
        echo -e "\033[31m[error]\033[0m cmake $1 failed"
        exit 1
    fi
    cd $build_path
    make -j$cpu_cores
    if [ $? -ne 0 ]; then 
        echo -e "\033[31m[error]\033[0m make $1 failed"
        exit 1
    fi
    make install
    if [ $? -ne 0 ]; then 
        echo -e "\033[31m[error]\033[0m install $1 failed"
        exit 1
    fi
    echo "build $1 done"
    cd $curr_dir
}
function build_foonathan_mem()
{
    echo "now building library $1"
    cd $curr_dir
    mkdir -p $output_path/tmp/$1
    if [ $? -ne 0 ]; then  # -ne -eq # prev command is failed?
        echo -e "\033[31m[error]\033[0m mkdir $output_path/tmp/$1 failed"
        exit 1
    fi
    build_path=$output_path/tmp/$1
    cmake \
        -DCMAKE_INSTALL_PREFIX=$build_path/install \
        -DCMAKE_C_COMPILER=$GCC \
        -DCMAKE_CXX_COMPILER=$GXX \
        -DBUILD_SHARED_LIBS=OFF \
        -DBUILD_MEMORY_EXAMPLES=OFF \
        -DBUILD_MEMORY_TESTS=OFF \
        -DBUILD_MEMORY_TOOLS=ON \
        -DCMAKE_POSITION_INDEPENDENT_CODE=ON \
        -DFOONATHAN_MEMORY_BUILD_EXAMPLES=OFF \
        -DFOONATHAN_MEMORY_BUILD_TESTS=OFF \
        -DFOONATHAN_MEMORY_BUILD_TOOLS=OFF \
        -B $build_path -S thirdparty/$1
    if [ $? -ne 0 ]; then 
        echo -e "\033[31m[error]\033[0m cmake $1 failed"
        exit 1
    fi
    cd $build_path
    make -j$cpu_cores
    if [ $? -ne 0 ]; then 
        echo -e "\033[31m[error]\033[0m make $1 failed"
        exit 1
    fi
    make install
    if [ $? -ne 0 ]; then 
        echo -e "\033[31m[error]\033[0m install $1 failed"
        exit 1
    fi
    echo "build $1 done"
    cd $curr_dir
}
function add_openssl_cmake_config()
{
    mkdir -p $output_path/tmp/openssl-cmake/install/lib/cmake
    cd $output_path/tmp/openssl-cmake/install/lib/cmake
cat <<EOL > openssl-config.cmake
    ###############################################
    ######## openssl-config.cmake begin ###########
    find_path(OPENSSL_INCLUDE_DIR
    NAMES
        openssl/ssl.h
    HINTS
        ${CMAKE_CURRENT_LIST_DIR}/../../include
    PATH
    ${CMAKE_CURRENT_LIST_DIR}/../../include
    )

    find_library(OPENSSL_LIBRARY
    NAMES 
        ssl
    HINTS
        ${CMAKE_CURRENT_LIST_DIR}/..
    PATHS
        ${CMAKE_CURRENT_LIST_DIR}/..
        PATH_SUFFIXES
        lib
    )

    find_library(OPENSSL_CRYPTO_LIBRARY
    NAMES
        crypto
    NAMES_PER_DIR
        ${CMAKE_CURRENT_LIST_DIR}/..
    HINTS
        ${CMAKE_CURRENT_LIST_DIR}/..
    PATH_SUFFIXES
        lib
    )


    set(OPENSSL_INCLUDE_DIRS ${OPENSSL_INCLUDE_DIR})
    set(OPENSSL_LIBRARIES ${OPENSSL_LIBRARY})
    set(OPENSSL_CRYPTO_LIBRARIES ${OPENSSL_CRYPTO_LIBRARY})

    set(OPENSSL_SSL_LIBRARY   ${OPENSSL_LIBRARY}) 
    set(OPENSSL_SSL_LIBRARIES ${OPENSSL_LIBRARY}) 
    set(OPENSSL_VERSION 1.1.1)

    function(_OpenSSL_target_add_dependencies target)
    if(_OpenSSL_has_dependencies)
        set_property( TARGET ${target} APPEND PROPERTY INTERFACE_LINK_LIBRARIES Threads::Threads )
        set_property( TARGET ${target} APPEND PROPERTY INTERFACE_LINK_LIBRARIES ${CMAKE_DL_LIBS} )
    endif()
    if(WIN32 AND OPENSSL_USE_STATIC_LIBS)
        set_property( TARGET ${target} APPEND PROPERTY INTERFACE_LINK_LIBRARIES ws2_32 )
        set_property( TARGET ${target} APPEND PROPERTY INTERFACE_LINK_LIBRARIES crypt32 )
    endif()
    endfunction()

    if(NOT TARGET OpenSSL::Crypto AND
        (EXISTS "${OPENSSL_CRYPTO_LIBRARY}" OR
        EXISTS "${LIB_EAY_LIBRARY_DEBUG}" OR
        EXISTS "${LIB_EAY_LIBRARY_RELEASE}")
        )
    add_library(OpenSSL::Crypto UNKNOWN IMPORTED)
    set_target_properties(OpenSSL::Crypto PROPERTIES
        INTERFACE_INCLUDE_DIRECTORIES "${OPENSSL_INCLUDE_DIR}")
    if(EXISTS "${OPENSSL_CRYPTO_LIBRARY}")
        set_target_properties(OpenSSL::Crypto PROPERTIES
        IMPORTED_LINK_INTERFACE_LANGUAGES "C"
        IMPORTED_LOCATION "${OPENSSL_CRYPTO_LIBRARY}")
    endif()
    if(EXISTS "${LIB_EAY_LIBRARY_RELEASE}")
        set_property(TARGET OpenSSL::Crypto APPEND PROPERTY
        IMPORTED_CONFIGURATIONS RELEASE)
        set_target_properties(OpenSSL::Crypto PROPERTIES
        IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "C"
        IMPORTED_LOCATION_RELEASE "${LIB_EAY_LIBRARY_RELEASE}")
    endif()
    if(EXISTS "${LIB_EAY_LIBRARY_DEBUG}")
        set_property(TARGET OpenSSL::Crypto APPEND PROPERTY
        IMPORTED_CONFIGURATIONS DEBUG)
        set_target_properties(OpenSSL::Crypto PROPERTIES
        IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "C"
        IMPORTED_LOCATION_DEBUG "${LIB_EAY_LIBRARY_DEBUG}")
    endif()
    _OpenSSL_target_add_dependencies(OpenSSL::Crypto)
    endif()

    if(NOT TARGET OpenSSL::SSL AND
        (EXISTS "${OPENSSL_SSL_LIBRARY}" OR
        EXISTS "${SSL_EAY_LIBRARY_DEBUG}" OR
        EXISTS "${SSL_EAY_LIBRARY_RELEASE}")
        )
    add_library(OpenSSL::SSL UNKNOWN IMPORTED)
    set_target_properties(OpenSSL::SSL PROPERTIES
        INTERFACE_INCLUDE_DIRECTORIES "${OPENSSL_INCLUDE_DIR}")
    if(EXISTS "${OPENSSL_SSL_LIBRARY}")
        set_target_properties(OpenSSL::SSL PROPERTIES
        IMPORTED_LINK_INTERFACE_LANGUAGES "C"
        IMPORTED_LOCATION "${OPENSSL_SSL_LIBRARY}")
    endif()
    if(EXISTS "${SSL_EAY_LIBRARY_RELEASE}")
        set_property(TARGET OpenSSL::SSL APPEND PROPERTY
        IMPORTED_CONFIGURATIONS RELEASE)
        set_target_properties(OpenSSL::SSL PROPERTIES
        IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "C"
        IMPORTED_LOCATION_RELEASE "${SSL_EAY_LIBRARY_RELEASE}")
    endif()
    if(EXISTS "${SSL_EAY_LIBRARY_DEBUG}")
        set_property(TARGET OpenSSL::SSL APPEND PROPERTY
        IMPORTED_CONFIGURATIONS DEBUG)
        set_target_properties(OpenSSL::SSL PROPERTIES
        IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "C"
        IMPORTED_LOCATION_DEBUG "${SSL_EAY_LIBRARY_DEBUG}")
    endif()
    if(TARGET OpenSSL::Crypto)
        set_target_properties(OpenSSL::SSL PROPERTIES
        INTERFACE_LINK_LIBRARIES OpenSSL::Crypto)
    endif()
    _OpenSSL_target_add_dependencies(OpenSSL::SSL)
    endif()

    if("${OPENSSL_VERSION_MAJOR}.${OPENSSL_VERSION_MAJOR}.${OPENSSL_VERSION_FIX}" VERSION_GREATER_EQUAL "0.9.8")
    if(MSVC)
        if(EXISTS "${OPENSSL_INCLUDE_DIR}")
        set(_OPENSSL_applink_paths PATHS ${OPENSSL_INCLUDE_DIR})
        endif()
        find_file(OPENSSL_APPLINK_SOURCE
        NAMES
            openssl/applink.c
        ${_OPENSSL_applink_paths}
        NO_DEFAULT_PATH)
        if(OPENSSL_APPLINK_SOURCE)
        set(_OPENSSL_applink_interface_srcs ${OPENSSL_APPLINK_SOURCE})
        endif()
    endif()
    if(NOT TARGET OpenSSL::applink)
        add_library(OpenSSL::applink INTERFACE IMPORTED)
        set_property(TARGET OpenSSL::applink APPEND
        PROPERTY INTERFACE_SOURCES
            ${_OPENSSL_applink_interface_srcs})
    endif()
    endif()

    ######## openssl-config.cmake end   ###########
    ###############################################
EOL
    cd $curr_dir
}
function restore()
{
    # cd $curr_dir
    # rm CMakeLists.txt
    # mv CMakeLists.txt.org CMakeLists.txt
    echo "yes"
}
function build_rtps()
{
    echo "now building lib$1.so"
    cd $curr_dir
    mkdir -p $output_path/tmp/$1
    if [ $? -ne 0 ]; then  # -ne -eq # prev command is failed?
        echo -e "\033[31m[error]\033[0m mkdir $output_path/tmp/$1 failed"
        exit 1
    fi
    build_path=$output_path/tmp/$1
    # change CMakeLists.txt
    # mv CMakeLists.txt CMakeLists.txt.org
    # add_line="set(CMAKE_PREFIX_PATH $output_path/tmp/tinyxml2/install/lib/cmake/tinyxml2;\
    #                                 $output_path/tmp/fastcdr/install/lib/cmake/fastcdr;\
    #                                 $output_path/tmp/foonathan_memory_vendor/foo_mem_ext_prj_install/lib/foonathan_memory/cmake;\
    #                                 $output_path/tmp/openssl-cmake/install/lib)"
    # { echo $add_line; cat CMakeLists.txt.org; } > CMakeLists.txt
    #
    cmake \
        -DCMAKE_INSTALL_PREFIX=$build_path/install \
        -DCMAKE_C_COMPILER=$GCC \
        -DCMAKE_CXX_COMPILER=$GXX \
        -DCMAKE_PREFIX_PATH="$output_path/tmp/fastcdr/install/lib/cmake/fastcdr;\
$output_path/tmp/tinyxml2/install/lib/cmake/tinyxml2;\
$output_path/tmp/memory/install/lib/foonathan_memory/cmake;\
$output_path/tmp/openssl-cmake/install/lib/cmake;\
$output_path/tmp/openssl-cmake/install/lib" \
        -DAsio_INCLUDE_DIR=$curr_dir/thirdparty/asio/asio/include \
        -DBUILD_SHARED_LIBS=ON \
        -DINCLUDE_DIR=$output_path/tmp/openssl-cmake/install/include/openssl \
        -DSHELL_BUILD_PATH=$curr_dir/$output_path \
        -B $build_path -S .

    if [ $? -ne 0 ]; then 
        echo -e "\033[31m[error]\033[0m cmake $1 failed"
        exit 1
    fi
    cd $build_path
    make -j$cpu_cores
    if [ $? -ne 0 ]; then 
        echo -e "\033[31m[error]\033[0m make $1 failed"
        exit 1
    fi
    make install
    if [ $? -ne 0 ]; then 
        echo -e "\033[31m[error]\033[0m install $1 failed"
        exit 1
    fi
    echo "build $1 done"
    cd $curr_dir
}
function reorganize()
{
    cd $output_path
    mkdir $1
    cp -R tmp/$1/install/* $1
    cd $curr_dir
}


build_lib fastcdr 
build_lib tinyxml2
build_lib openssl-cmake
add_openssl_cmake_config
build_foonathan_mem memory
echo "include(\${CMAKE_CURRENT_LIST_DIR}/tinyxml2Config.cmake)" > $output_path/tmp/tinyxml2/install/lib/cmake/tinyxml2/tinyxml2-config.cmake
build_rtps fastrtps


reorganize fastcdr
reorganize tinyxml2
reorganize openssl-cmake
reorganize fastrtps

echo -e "\e[32m Compile Fast-DDS and its dependency success, output path: $curr_dir/$output_path \033[0m"


一、C++ publisher、subscriber应用

什么是DDS

Data Distribution Service(DDS)是一个以数据为中心的通讯协议,它用于进程之间的通讯。它描述了通讯APIs和通讯双方的通讯语义。
Since it is a Data-Centric Publish Subscribe (DCPS) model, 三个关键点:

  1. 发布实体:生成数据并定义其格式、属性等
  2. 接收实体:数据接接收方
  3. 配置实体:定义信息类型,作为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 实体的元素。发布者在主题下产生信息,订阅者通过相同的主题接收信息。

  1. 创建应用程序空间
  2. 依赖库
    Fast DDS 和 Fast CDR
    如果是二进制安装,头文件在/usr/include/fastrtps/ /usr/include/fastcdr/;库文件在/usr/lib/
  3. 配置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")
  1. build the topic data type
    eProsima Fast DDS-Gen是一个生成源码的Java应用,它使用Interface Description Language(IDL)文件定义的数据类型。它有两个功能:
    1. 为topic生成C++定义
    2. 用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/

  • 15
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值