Fast DDS入门五、在Windows平台创建一个简单的Fast DDS示例程序

2023-11-18

1、创建简单示例程序

在这里,先建立一个IDL文件,然后通过使用Fast DDS-Gen生成程序生成这个简单示例程序。Fast DDS-Gen程序的编译安装请参考《Fast DDS入门二、Fast DDS在Windows平台的编译安装》,Fast DDS-Gen程序的使用请参考《Fast DDS入门四、Fast DDS-Gen使用介绍》。

(1)创建IDL文件

先建立一个单独的目录HelloWorldExample,在该目录下建立IDL文件和生成示例程序的c++源程序文件。

本示例构建最小的应用程序,必须通过IDL文件定义Topic。在本例中,IDL定义的Topic数据类型只是一个字符串消息。在首选文本编辑器中,创建具有以下内容的HelloWorld.IDL文件,并将其保存在HelloWorldExample目录中。

// HelloWorld.IDL

struct HelloWorld

{

string message;

};

(2)Fast DDS-Gen生成示例程序源码

然后,将此文件转换为Fast DDS能够理解的内容。为此,使用Fast DDS Gen代码生成工具,它可以执行生成示例的操作。执行如下命令:

fastddsgen.bat -example CMake HelloWorld.IDL

执行命令成功结束后,会产生一系列源文件,如下所示:

(3)CMake配置生成vs解决方案

Fast DDS-Gen生成示例程序源码后,生成了系列的.h、.cxx源文件,同时生成了CMakeLists.txt文件。因此可以通过CMake配置示例程序的依赖项目生成vs解决方案,然后通过vs编译生成可执行程序。相关依赖项的编译生成可参考《Fast DDS入门二、Fast DDS在Windows平台的编译安装》,以下为CMake界面程序的配置参考:

Configure和generate成功后,在out子目录下生成了项目、解决方案等文件,在out目录下可看到如下:

2、示例代码分析及编译运行

用vs打开CMake生成的generated_code.sln解决方案,如下图所示:

可以看到有4个项目,其中源码项目是:HelloWorld_lib和HelloWorld项目。HelloWorld_lib项目包含IDL生成的结构体类HelloWorld.h和HelloWorld.cxx,这个项目生成lib静态库。HelloWorld项目,依赖于HelloWorld_lib项目,可生成发布/订阅可执行程序。

(1)源代码分析

HelloWorld_lib项目的HelloWorld类,主要实现了IDL定义结构体类型的序列化和反序列化,头文件简要如下:

class HelloWorld
{
public: 
   /*!
    * @brief This function serializes an object using CDR serialization.
    * @param cdr CDR serialization object.
    */
   eProsima_user_DllExport void serialize(
            eprosima::fastcdr::Cdr& cdr) const;
 
   /*!
    * @brief This function deserializes an object using CDR serialization.
    * @param cdr CDR serialization object.
    */
   eProsima_user_DllExport void deserialize(
            eprosima::fastcdr::Cdr& cdr);
 
private:
   std::stringm_message;
};

HelloWorld项目的HelloWorldPubSubType类是HelloWorld类的封装类,其继承自TopicDataType类,该类可注册到Fast DDS中,序列化和反序列化函数是vitual函数在父类中声明,在子类中实现,在发布订阅函数中实现回调处理,发布时将HelloWorld类序列化并通过socket发送,订阅时通过socket接收到二进制后执行HelloWorld类的反序列化,以下为HelloWorldPubSubType类的核心代码:

bool HelloWorldPubSubType::serialize( //序列化函数
       void* data,
       SerializedPayload_t* payload)
{
   HelloWorld* p_type= static_cast<HelloWorld*>(data);
   // Object that manages the raw buffer.
   eprosima::fastcdr::FastBuffer fastbuffer(reinterpret_cast<char*>(payload->data), payload->max_size);
   // Object that serializes the data.
   eprosima::fastcdr::Cdr ser(fastbuffer, eprosima::fastcdr::Cdr::DEFAULT_ENDIAN,eprosima::fastcdr::Cdr::DDS_CDR);
   payload->encapsulation= ser.endianness() == eprosima::fastcdr::Cdr::BIG_ENDIANNESS ? CDR_BE : CDR_LE;
   // Serialize encapsulation
   ser.serialize_encapsulation();
   try
   {
       // Serialize the object.
       p_type->serialize(ser);
   }
   catch(eprosima::fastcdr::exception::NotEnoughMemoryException& /*exception*/)
   {
       return false;
   }
 
   // Get the serialized length
   payload->length= static_cast<uint32_t>(ser.getSerializedDataLength());
    return true;
}
 
bool HelloWorldPubSubType::deserialize(  //反序列化函数
       SerializedPayload_t* payload,
       void* data)
{
   try
   {
       //Convert DATA to pointer of your type
       HelloWorld* p_type= static_cast<HelloWorld*>(data);
       // Object that manages the raw buffer.
       eprosima::fastcdr::FastBuffer fastbuffer(reinterpret_cast<char*>(payload->data), payload->length);
       // Object that deserializes the data.
       eprosima::fastcdr::Cdr deser(fastbuffer, eprosima::fastcdr::Cdr::DEFAULT_ENDIAN,eprosima::fastcdr::Cdr::DDS_CDR);
       // Deserialize encapsulation.
       deser.read_encapsulation();
       payload->encapsulation= deser.endianness() == eprosima::fastcdr::Cdr::BIG_ENDIANNESS ? CDR_BE : CDR_LE;
       // Deserialize the object.
       p_type->deserialize(deser);
   }
   catch(eprosima::fastcdr::exception::NotEnoughMemoryException& /*exception*/)
   {
       return false;
   }
   return true;
}

HelloWorld项目的发布订阅类分别是:HelloWorldPublisher类和HelloWorldSubscriber类。发布类的核心源码有两个重要的成员函数,初始化函数init()和发送数据函数run(),代码如下所示:

bool HelloWorldPublisher::init()  //初始化函数
{
   /* Initialize data_ here */
   //CREATE THE PARTICIPANT
   DomainParticipantQos pqos;
   pqos.name("Participant_pub");
   participant_ = DomainParticipantFactory::get_instance()->create_participant(0, pqos);
   if(participant_ == nullptr)
   {
       return false;
   }
   //REGISTER THE TYPE
   type_.register_type(participant_);
   //CREATE THE PUBLISHER
   publisher_ = participant_->create_publisher(PUBLISHER_QOS_DEFAULT, nullptr);
   if(publisher_ == nullptr)
   {
       return false;
   }
   //CREATE THE TOPIC
   topic_ = participant_->create_topic(
       "HelloWorldTopic",
       type_.get_type_name(),
       TOPIC_QOS_DEFAULT);
   if (topic_== nullptr)
   {
       return false;
   }
   // CREATE THE WRITER
   writer_ = publisher_->create_datawriter(topic_,DATAWRITER_QOS_DEFAULT, &listener_);
   if(writer_ == nullptr)
   {
       return false;
   }
   std::cout << "HelloWorld DataWriter created." << std::endl;
   return true;
}

发布者的初始化函数,首先创建参与者participant,参与者participant是publisher和subscriber的容器,可用来创建发布者和订阅者。之后参与者注册HelloWorld的数据类型,创建publisher,创建topic主题,最后通过发布者publisher创建写入器writer,通过writer可直接发送数据。

void HelloWorldPublisher::run()  //运行函数发送数据
{
   std::cout << "HelloWorld DataWriter waiting forDataReaders." << std::endl;
   while(listener_.matched == 0)
   {
       std::this_thread::sleep_for(std::chrono::milliseconds(250)); // Sleep 250 ms
   }
   // Publication code
   HelloWorld st;
   /* Initialize your structure here */
   int msgsent= 0;
   char ch = 'y';
   do
   {
       if (ch == 'y')
       {
            writer_->write(&st);
            ++msgsent;
            std::cout << "Sendingsample, count=" << msgsent << ", sendanother sample?(y-yes,n-stop): ";
       }
       else if (ch == 'n')
       {
            std::cout << "Stoppingexecution " << std::endl;
            break;
       }
       else
       {
            std::cout << "Command" << ch << " notrecognized, please enter \"y/n\":";
       }
   } while(std::cin >> ch);
}

发送数据函数通过publisher的写入器writer直接发送HelloWorld类型的数据st。

订阅类的核心源码也有两个重要的成员函数,初始化函数init()和其订阅监听器子类成员函数SubListener::on_data_available(),Init()成员函数雷同于publisher的init()成员函数,只不过是subscriber的init()函数是建立订阅者subscriber和监听器listener,通过监听器回调接收订阅的数据。

监听器SubListener::on_data_available()数据接收代码如下所示:

void HelloWorldSubscriber::SubListener::on_data_available(  //监听接收数据函数
       DataReader* reader)
{
   // Take data
   HelloWorld st;
   SampleInfo info;
 
   if (reader->take_next_sample(&st,&info) == ReturnCode_t::RETCODE_OK)
   {
       if(info.valid_data)
       {
            // Printyour structure data here.
            ++samples;
            std::cout << "Samplereceived, count=" << samples << std::endl;
       }
   }
}

on_data_available()函数,是监听器的回调函数,被订阅者subscriber的阅读器reader接收到数据后,将socket接收的二进制数据反序列化成HelloWorld类数据,是开发人员的订阅接收数据入口。

(2)编译运行可执行程序

在vs开发工具中执行build命令,将在out/debug或release目录下生成可执行二进制文件HelloWorld.exe,同时将其依赖的库文件也拷贝到这里。如下所示:

然后通过powershell执行两个HelloWorld.exe命令,第一个命令后面空格后输入subscriber字符,第二个命令后面空格后输入publisher字符,发布程序和订阅程序将能够正常运行。运行界面如下所示:

至此,Fast DDS的简单发布订阅示例程序的创建、编译、运行就成功结束了。

CSDN下载:免费下载Fast DDS简单发布订阅示例程序源码

github下载:git clone https://github.com/FantasticSaltedFish/Fast-DDS.git

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Fast DDS入门五、在Windows平台创建一个简单的Fast DDS示例程序 的相关文章

  • list的模拟实现

    list的模拟实现 1 创建 链表结点 2 创建 链表迭代器 3 创建 链表 4 测试 模拟实现的list的功能 1 创建 链表结点 namespace JPC 创建 链表结点 template

随机推荐

  • 全国首批城市级5G车联网应用项目落地!

    司机变身 安全员 公交车自主选择车道 避让障碍物和行人 还能接收交通信号灯信息 实现一路畅行 近日 央视综合频道 报道了 聪明车 开上 智慧路 的黑科技 日前 依托苏州良好的车联网产业环境 全国首批城市级5G车联网应用项目落地苏州 中国移动
  • 改善java程序的151个建议 - 读书笔记

    目录 第1章 java开发中通用的方法和准则 1 字母 l 和数字1 字母 o 和数字0易混淆 3 三元操作符的类型务必一致 7 警惕自增陷阱 11 好习惯是显示声明UID 12 Serializable类中的final成员变量的赋值 14
  • 基于开源大模型Vicuna-13B构建私有制库问答系统

    本教程专注在怎么使用已经开源的模型和项目 构建一个可以私有化部署的问答知识库 而且整体效果要有所保障 主要工作包括 选择基础模型 openAI claude 这些商用的 或者其他的开源的 这次我们选择 Vicuna 13B 开源有很多的知识
  • 如何把极坐标化为直角坐标_如何将极坐标转化为直角坐标

    展开全部 极坐标转换为直角坐标 32313133353236313431303231363533e58685e5aeb931333366306532 转化方法及其步骤 第一步 把极坐标方程中的 整理成cos 和sin 的形式 第二步 把co
  • 基础15:npm、yarn、pnpm

    npm2 用 node 版本管理工具把 node 版本降到 4 那 npm 版本就是 2 x 了 执行 npm init npm install express 可以看到node modules目录如下 可以看到 npm2的node mod
  • 深入理解计算机系统(2.3)---整数的表示方式精解》无符号与补码编码(重要)...

    上一章我们简单的介绍了布尔代数以及C语言的位运算 本次我们主要来看 二进制如何表示整数 这是很重要的一章 希望各位猿友莫要错过 C语言中的整数类型及范围 我们依然以C语言为例 C语言当中提供了多种整数类型 一共十种 位数为1 2 4 8 其
  • ShellExecuteEx中与被调进程同步

    在实际的开发中会遇到这样的情况 A进程在运行时 需要调起B进程完成某些工作 例如取回关键文件 且必须等待该进程完成工作结束后才能往下继续 那么这时候 就可以采用ShellExecuteEx和WaitForSingleObject的结合对被调
  • 新媒体运营怎么追热点?这四个技巧一定可以帮到你

    作为一个新媒体运营 热点追不好 冷板凳少不了 热点追得好不但能带来账号的曝光 还能带来良好的涨粉效果 但是很多人都不知道热点到底要怎么追 那么今天就给大家分享一下 追热点4个百试不爽的套路 01 怎样找热点 热点可以分为常规型热点和突发型热
  • R语言——数据排序

    R语言中涉及排序的基本函数有order sort和rank三个 下面看看它们的基本用法 x表示需要排序的数据 decreasing表示是否按降序排序数据 method表示所使用的排序算法 na last表示如何处理NA值 缺失值 若为FAL
  • eclipse中导入idea项目的基本步骤

    eclipse导入idea项目 前段时间有个idea项目 SSM maven 需要导入eclispe运行 最后搞了很久才运行成功 这里整理一下导入项目时需要修改一些配置 第一步 import时建议选择导入Maven项目 选择Maven下的导
  • 在Centos7中搭建http服务器

    一 简介 二 安装 二 编辑配置文件 三 配置主页文件 或者将做好的网站放入根目录 四 配置安全访问规则 五 启动http服务 六 访问测试 七 心得体会 一 简介 Centos7默认的http服务器为Apache Apache HTTP
  • Python提取网页信息并保存

    使用Python爬取网页内容时 获取网页源码文件后使用一系列解析方法提取我们需要的信息 对于提取到的信息怎么保存下来 本文提供常见的两种方法 保存到本地文件或MySQL数据库 保存到本地csv文件 将数据以一定的格式保存到本地csv文件需要
  • 修改cdh6.3.2集群内部弱口令步骤

    在这里插入图片描述 cdh管理页面修改 hive hue oozie 密码 主节点修改 另外修订mysql数据库内密码 首先登陆mysql 具体参考 https blog csdn net weixin 43214644 article d
  • STM32---外部中断

    目录 1 外部中断描述 2 外部中断框图 总结 经过分析框图 可以产生软件中断和事件中断 软件中断的目的是进中断服务函数 事件中断是产生一个脉冲信号给片内外设 属于硬件级别的 3 各寄存器作用 4 端口对应 5 编程思路 EXIT NVIC
  • mysql8.0出现group by报错

    数据库跟目录执行set GLOBAL sql mode STRICT TRANS TABLES NO ZERO IN DATE NO ZERO DATE ERROR FOR DIVISION BY ZERO NO ENGINE SUBSTI
  • Qt 使用笔记 --转自 wangwenx190/Note

    转自 https github com wangwenx190 notes blob master qt zh cn md Qt 使用笔记 Qt 6 目标平台变更 Qt6 不再支持32位Windows系统 不再支持Windows 7 Win
  • pageHelper.startPage(m,n)的用法

    pageHelper startPage m n 的用法 pageHelper startPage m n 是分页查询 PageHelper startPage m n 两个参数 第一个参数是页数 第二个参数是条数 每页查询的条数 例如我想
  • 疯壳AI开源无人机SPI(六轴传感器数据获取)

    一 ICM20602简介 六轴传感器在当今智能穿戴和定位导航产品中被广泛应用 而六轴传感器中做的最好的要属InvenSense公司的产品了 ICM20602便是其推出的优秀六轴传感器之一 ICM20602集成3轴加速度计和3轴陀螺仪 其中陀
  • bat命令备份oracle数据库,并且删除7天之前的数据文件

    用批处理命令备份oracle数据库 我是用在windows server 2008 服务器上 并且创建了定时任务 让他7天执行一次 下面贴出代码 echo off echo echo Windows环境下Oracle数据库的自动备份脚本 e
  • Fast DDS入门五、在Windows平台创建一个简单的Fast DDS示例程序

    1 创建简单示例程序 在这里 先建立一个IDL文件 然后通过使用Fast DDS Gen生成程序生成这个简单示例程序 Fast DDS Gen程序的编译安装请参考 Fast DDS入门二 Fast DDS在Windows平台的编译安装 Fa