fastdds在windows下的编译和使用
很久没更新了,由于本人工作原因以及个人原因(懒),现更新一个中间件编译和使用方法,以便以后进行翻阅。
fastdds源码编译
一、fastdds介绍
[scode type="blue"]
fastDDS 是由OMG定义的数据分发服务(DDS)规范的 C++实现。fastdds库提供了应用程序编程接口(API)和通信协议,部署了以数据为中心的发布-订阅(DCPS)模型,旨在实现实时系统之间高效且可靠的信息分布。
DDS 采用的通信模型是一种多对多的单向数据交换,其中生成数据的应用程序将数据发布到属于消费数据应用程序的订阅者的本地缓存中。 信息流由负责数据交换的实体之间建立的服务质量 (QoS) 策略进行调节。
<来自官网翻译>
以下为DDS 数据流图,具体详细讲解请参考官网。
[/scode]
二、FASTDDS编译
在windows中,你需要安装好visual studio,作者本人使用的visual studio版本为2019企业版,当前FASTDDS版本为3.3.0
- 第一步,克隆代码
git clone https://github.com/eProsima/Fast-DDS.git
cd Fast-DDS
git submodule update --init #拉取子模块android,asio,fascdr,tinyxml2
git submodule add https://github.com/foonathan/memory.git thirdparty/foonathan-memory #需要添加一个子模块
- 第二步,编译依赖库
找到vs2019控制台(x64 Native Tools Command Prompt for VS 2019),打开,以下编译过程需要在vs2019控制台中操作,如下图
2.1 编译 foonathan-memory
cd thirdparty/foonathan-memory #进入foonathan-memory目录
mkdir build
cd build #构建build目录
cmake ../ -DFOONATHAN_MEMORY_BUILD_EXAMPLES=OFF -DFOONATHAN_MEMORY_BUILD_TESTS=OFF -DCMAKE_INSTALL_PREFIX=F:\fastdds\cmake\Fast-DDS\thirdparty\install #指定安装目录和配置foonathan-memory相关功能
cmake --build . --target install --config Release #在vs2019下
执行完毕后foonathan-memory安装在F:fastddscmakeFast-DDSthirdpartyinstall目录。
2.2 编译 fastcdr
编译fastcdr与编译foonathan-memory类似,这里就不多赘述了。
cd ../..
cd fastcdr
mkdir build
cd build
cmake ../ -DCMAKE_INSTALL_PREFIX=F:\fastdds\cmake\Fast-DDS\thirdparty\install
cmake --build . --target install --config Release
2.3 编译 tinyxml2
编译tinyxml2与编译foonathan-memory类似,同样不多赘述了。
cd ../..
cd tinyxml2
mkdir build
cd build
cmake ../ -DCMAKE_INSTALL_PREFIX=F:\fastdds\cmake\Fast-DDS\thirdparty\install
cmake --build . --target install --config Release
2.3 编译 Fast-DDS
编译Fast-DDS需要指定上述第三方库的安装位置和asio,然后进行编译。
cd ../../../../
cd Fast-DDS
mkdir build
cd build
cmake ../ -DCMAKE_INSTALL_PREFIX=F:\fastdds\cmake\Fast-DDS\install -DCMAKE_PREFIX_PATH="F:\fastdds\cmake\Fast-DDS\thirdparty\asio\asio;F:\fastdds\cmake\Fast-DDS\thirdparty\install" -DNO_TLS=ON -DCOMPILE_EXAMPLES=ON
cmake --build . --target install --config Release
如下图为编译后第三方库目录结构:
如下图为编译后FASTDDS目录结构<未截全>:
在bin目录下,生成以下文件:
就此,编译成功
- 使用方法
3.1 编写IDL文件,以hello world为例(helloworld.idl):
module HelloWorldModule {
struct HelloWorld
{
unsigned long index;
string message;
};
};
3.2 IDL生成
使用fastddsgen.bat进行代码生成
fastddsgen.bat helloworld.idl -d hello/ -language c++
生成后截图:
三、fastdds使用
3.3 工程使用
在vs2019中新建工程,引入头文件和cpp文件,如下图所示:
3.4 配置预处理器
需要你在工程,属性C/C++选项,预处理器选项卡,预处理器定义中添加以下内容,告诉编译器使用 Fast CDR和FASTDDS 的动态链接版本:
FASTCDR_DYN_LINK
FASTDDS_DYN_LINK
截图如下:
3.5 添加订阅者
在工程中添加订阅者代码
#include <chrono>
#include <fastdds/dds/domain/DomainParticipant.hpp>
#include <fastdds/dds/domain/DomainParticipantFactory.hpp>
#include <fastdds/dds/publisher/DataWriter.hpp>
#include <fastdds/dds/publisher/DataWriterListener.hpp>
#include <fastdds/dds/publisher/Publisher.hpp>
#include <fastdds/dds/topic/TypeSupport.hpp>
#include <thread>
#include "helloworldPubSubTypes.hpp"
using namespace eprosima::fastdds::dds;
using namespace HelloWorldModule;
class HelloWorldPublisher {
private:
HelloWorld hello_;
DomainParticipant* participant_;
Publisher* publisher_;
Topic* topic_;
DataWriter* writer_;
TypeSupport type_;
class PubListener : public DataWriterListener {
public:
PubListener() : matched_(0) {}
~PubListener() override {}
void on_publication_matched(DataWriter*, const PublicationMatchedStatus& info) override {
if (info.current_count_change == 1) {
matched_ = info.total_count;
std::cout << "Publisher matched." << std::endl;
}
else if (info.current_count_change == -1) {
matched_ = info.total_count;
std::cout << "Publisher unmatched." << std::endl;
}
else {
std::cout << info.current_count_change
<< " is not a valid value for PublicationMatchedStatus current count change." << std::endl;
}
}
std::atomic_int matched_;
} listener_;
public:
HelloWorldPublisher()
: participant_(nullptr),
publisher_(nullptr),
topic_(nullptr),
writer_(nullptr),
type_(new HelloWorldPubSubType()) {}
virtual ~HelloWorldPublisher() {
if (writer_ != nullptr) {
publisher_->delete_datawriter(writer_);
}
if (publisher_ != nullptr) {
participant_->delete_publisher(publisher_);
}
if (topic_ != nullptr) {
participant_->delete_topic(topic_);
}
DomainParticipantFactory::get_instance()->delete_participant(participant_);
}
//! Initialize the publisher
bool init() {
hello_.index(0);
hello_.message("HelloWorld");
DomainParticipantQos participantQos;
participantQos.name("Participant_publisher");
participant_ = DomainParticipantFactory::get_instance()->create_participant(0, participantQos);
if (participant_ == nullptr) {
std::cout << "Error creating participant." << std::endl;
return false;
}
// Register the Type
type_.register_type(participant_);
// Create the publications Topic
topic_ = participant_->create_topic("HelloWorldTopic1", type_.get_type_name(), TOPIC_QOS_DEFAULT);
if (topic_ == nullptr) {
std::cout << "Error creating topic." << std::endl;
return false;
}
// Create the Publisher
publisher_ = participant_->create_publisher(PUBLISHER_QOS_DEFAULT, nullptr);
if (publisher_ == nullptr) {
std::cout << "Error creating publisher." << std::endl;
return false;
}
// Create the DataWriter
writer_ = publisher_->create_datawriter(topic_, DATAWRITER_QOS_DEFAULT, &listener_);
if (writer_ == nullptr) {
std::cout << "Error creating writer." << std::endl;
return false;
}
return true;
}
//! Send a publication
bool publish() {
if (listener_.matched_ > 0) {
hello_.index(hello_.index() + 1);
writer_->write(&hello_);
return true;
}
return false;
}
//! Run the Publisher
void run(uint32_t samples) {
uint32_t samples_sent = 0;
while (true) {
if (publish()) {
samples_sent++;
std::cout << "Message: " << hello_.message() << " with index: " << hello_.index() << " SENT" << std::endl;
}
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
}
};
int main(int argc, char** argv) {
std::cout << "Starting publisher." << std::endl;
uint32_t samples = 10;
HelloWorldPublisher* mypub = new HelloWorldPublisher();
if (mypub->init()) {
mypub->run(samples);
}
delete mypub;
return 0;
}
编译,不出意外订阅者编译成功。
3.6 添加发布者
在工程中添加发布者代码
#include <chrono>
#include <fastdds/dds/domain/DomainParticipant.hpp>
#include <fastdds/dds/domain/DomainParticipantFactory.hpp>
#include <fastdds/dds/publisher/DataWriter.hpp>
#include <fastdds/dds/publisher/DataWriterListener.hpp>
#include <fastdds/dds/publisher/Publisher.hpp>
#include <fastdds/dds/topic/TypeSupport.hpp>
#include <thread>
#include "helloworldPubSubTypes.hpp"
using namespace eprosima::fastdds::dds;
using namespace HelloWorldModule;
class HelloWorldPublisher {
private:
HelloWorld hello_;
DomainParticipant* participant_;
Publisher* publisher_;
Topic* topic_;
DataWriter* writer_;
TypeSupport type_;
class PubListener : public DataWriterListener {
public:
PubListener() : matched_(0) {}
~PubListener() override {}
void on_publication_matched(DataWriter*, const PublicationMatchedStatus& info) override {
if (info.current_count_change == 1) {
matched_ = info.total_count;
std::cout << "Publisher matched." << std::endl;
}
else if (info.current_count_change == -1) {
matched_ = info.total_count;
std::cout << "Publisher unmatched." << std::endl;
}
else {
std::cout << info.current_count_change
<< " is not a valid value for PublicationMatchedStatus current count change." << std::endl;
}
}
std::atomic_int matched_;
} listener_;
public:
HelloWorldPublisher()
: participant_(nullptr),
publisher_(nullptr),
topic_(nullptr),
writer_(nullptr),
type_(new HelloWorldPubSubType()) {}
virtual ~HelloWorldPublisher() {
if (writer_ != nullptr) {
publisher_->delete_datawriter(writer_);
}
if (publisher_ != nullptr) {
participant_->delete_publisher(publisher_);
}
if (topic_ != nullptr) {
participant_->delete_topic(topic_);
}
DomainParticipantFactory::get_instance()->delete_participant(participant_);
}
//! Initialize the publisher
bool init() {
hello_.index(0);
hello_.message("HelloWorld");
DomainParticipantQos participantQos;
participantQos.name("Participant_publisher");
participant_ = DomainParticipantFactory::get_instance()->create_participant(0, participantQos);
if (participant_ == nullptr) {
std::cout << "Error creating participant." << std::endl;
return false;
}
// Register the Type
type_.register_type(participant_);
// Create the publications Topic
topic_ = participant_->create_topic("HelloWorldTopic1", type_.get_type_name(), TOPIC_QOS_DEFAULT);
if (topic_ == nullptr) {
std::cout << "Error creating topic." << std::endl;
return false;
}
// Create the Publisher
publisher_ = participant_->create_publisher(PUBLISHER_QOS_DEFAULT, nullptr);
if (publisher_ == nullptr) {
std::cout << "Error creating publisher." << std::endl;
return false;
}
// Create the DataWriter
writer_ = publisher_->create_datawriter(topic_, DATAWRITER_QOS_DEFAULT, &listener_);
if (writer_ == nullptr) {
std::cout << "Error creating writer." << std::endl;
return false;
}
return true;
}
//! Send a publication
bool publish() {
if (listener_.matched_ > 0) {
hello_.index(hello_.index() + 1);
writer_->write(&hello_);
return true;
}
return false;
}
//! Run the Publisher
void run(uint32_t samples) {
uint32_t samples_sent = 0;
while (true) {
if (publish()) {
samples_sent++;
std::cout << "Message: " << hello_.message() << " with index: " << hello_.index() << " SENT" << std::endl;
}
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
}
};
int main(int argc, char** argv) {
std::cout << "Starting publisher." << std::endl;
uint32_t samples = 10;
HelloWorldPublisher* mypub = new HelloWorldPublisher();
if (mypub->init()) {
mypub->run(samples);
}
delete mypub;
return 0;
}
编译,不出意外,发布者编译成功
四、运行截图
左边为订阅者,右侧为发布者。
当前页面是本站的「Google AMP」版。查看和发表评论请点击:完整版 »