当前位置:   article > 正文

【QT开发(6)】0926-QT 中加入 fastDDS 通信库的程序使用说明_qt 实现dds

qt 实现dds

在智能驾驶中,DDS有可能被广泛使用,因此推出这篇说明教程。

1、基于【QT开发(5)】教程的项目文档进行开发

仓库地址

https://gitee.com/hiyanyx/qt5.14-cpp_dds_-project/tree/qt-dds

git分支"qt-dds"

2、安装DDS

查看《【eProsima Fast DDS(1)】安装eProsima Fast DDS》

至少安装:

foonathan_memory_vendor,一个 STL 兼容的 C++ 内存分配器 库。
fastcdr,一个根据 CDR 标准进行数据序列化的 C++ 库。
fastrtps,eProsima Fast DDS库的核心库。

测试安装是否正确的方法:在cmakelists 中加入

find_package(fastcdr REQUIRED)
find_package(foonathan_memory REQUIRED)
find_package(fastrtps REQUIRED)
  • 1
  • 2
  • 3

如果cmake 提示找到了该库,则表示库ok。

3、在项目中添加通信message文件

我们一般是先写 DDS 的idl 文件(本质是定义定义数据结构体类型),然后通过DDS的代码生成工具生成 cpp 和hpp文件。如下图:
在这里插入图片描述

因为我们使用的【QT开发(5)】教程的项目文档进行开发,哪个项目直接遍历src 目录里面全部的cpp和hpp文件。因此我们把message 复制进入src目录即可,不用变更cmakelists

例如我们定义两个数据结构体PerceptionCommand 和WorkingStatus

module auto_msg {
  module msg {
    struct PerceptionCommand {
      uint64 time_stamp;
      uint8 system_command;
      uint8 system_reset;
    };
  };
};

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

module auto_msg {
  module msg {
    struct WorkingStatus {
      uint64 time_stamp;
      uint32 counter;
    };
  };
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

4、为了保持ROS2 代码的风格兼容,我们导入了rclcpp

目的:移植rclcpp 的publisher、subscription、和timer

因为我们使用的【QT开发(5)】教程的项目文档进行开发,哪个项目直接遍历src 目录里面全部的cpp和hpp文件。因此我们把rclcpp复制进入src目录即可,不用变更cmakelists

5、修改cmakelists 增加fastrtps

增加

find_package(fastcdr REQUIRED)
find_package(foonathan_memory REQUIRED)
find_package(fastrtps REQUIRED)

  • 1
  • 2
  • 3
  • 4

修改target_link_libraries ,增加fastrtps

    target_link_libraries( emptyApp 
                            fmt
                             Qt5::Widgets
                             ${OpenCV_LIBS}
                             fastrtps
                             pthread
                            )
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

因为我们使用的【QT开发(5)】教程的项目文档进行开发,哪个项目直接遍历src 目录里面全部的cpp和hpp文件。因此我们把message 、rclcpp复制进入src目录即可,不用变更cmakelists

6、增加一个基于DDS 通信的核心功能

我们建立一个example文件夹,建立example.cpp 和 example.hpp

先写 example.hpp,首先引入头文件

#include <rclcpp/rclcpp.hpp>
#include <PerceptionCommand.hpp>  // 这个是message 里面定义的 dds 通信数据结构体
#include <WorkingStatus.hpp>    // 这个是message 里面定义的 dds 通信数据结构体
  • 1
  • 2
  • 3

然后建立一个对象Example class

class Example : public rclcpp::Node
{
 public:
  Example();
  ~Example();
  int Init();

 private:
  // 1# 订阅者
  rclcpp::Subscription<auto_msg::msg::PerceptionCommand>::SharedPtr perceptionCommand_sub_;
  // 2#  信息存储的成员
  rclcpp::AtomicSet<auto_msg::msg::PerceptionCommand> perceptionCommand_;

  // 3#建立 订阅者的回调函数 msg_PerceptionCommand_callback,实现的数据存放在perceptionCommand_成员
  void msg_PerceptionCommand_callback(const auto_msg::msg::PerceptionCommand::SharedPtr msg);

  // 4# 建立一个50ms 的定时器
    rclcpp::TimerBase::SharedPtr workingStatus_timer_;

  // 5# 建立发布者 Publisher
  rclcpp::Publisher<auto_msg::msg::WorkingStatus>::SharedPtr workingStatus_pub_;
  rclcpp::AtomicSet<auto_msg::msg::WorkingStatus> workingStatus_;

  // 6# 定时器的回调函数
  void timer_WorkingStatus_callback();

};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

我们建立了6个函数,分别的作用是
1、建立一个 perceptionCommand_sub_ 订阅者
2、建立一个 perceptionCommand_ 的信息存储的成员
3、建立 订阅者的回调函数 msg_PerceptionCommand_callback,实现把收到的数据存放在 perceptionCommand_ 的信息存储的成员里面
4、建立一个50ms 的定时器
5、建立一个 workingStatus_pub_ 的发布者;4、建立一个 workingStatus_ 成员
6、建立一个 定时器的回调函数,处理perceptionCommand_ 成员的数据,并发送workingStatus_pub_ 数据。

example.cpp 里面这么写

int Example::Init()
{
  counter_ = 0;

  workingStatus_pub_ = this->create_publisher<auto_msg::msg::WorkingStatus>(
    "example_status_pub",
    2);


  perceptionCommand_sub_ = this->create_subscription<auto_msg::msg::PerceptionCommand>(
    "perception_command_pub",
    2,
    std::bind(&Example::msg_PerceptionCommand_callback, this, _1));

  workingStatus_timer_ = this->create_wall_timer(50, std::bind(&Example::timer_WorkingStatus_callback, this)); // 50 millisecond

  return 0;
}


void Example::timer_WorkingStatus_callback()
{
  // here is how use the msg which had received
  auto_msg::msg::PerceptionCommand perceptionCommand = perceptionCommand_.Get();
  if (perceptionCommand.system_command() == 0x06) {
    // for example, do sth what you want when command equal some value
    int a = 1;
  }


  auto_msg::msg::WorkingStatus workingStatus;
  workingStatus.time_stamp() = rclcpp::PlatformGetMs();
  workingStatus_pub_->publish(workingStatus);
}


void Example::msg_PerceptionCommand_callback(const auto_msg::msg::PerceptionCommand::SharedPtr msg)
{
  perceptionCommand_.Set(*msg);
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41

7、修改main 文件

增加头文件引用

#include <rclcpp/rclcpp.hpp>
#include "example.h"
  • 1
  • 2

main 函数里面加入

        rclcpp::init(argc, argv);
        std::shared_ptr<yanyx::auto::Example> example = std::make_shared<yanyx::auto::Example>();
        example->Init();
        rclcpp::spin(example);
  • 1
  • 2
  • 3
  • 4

关于 rclcpp::spin() 的说明可以看我的另外一篇文章《【eProsima Fast DDS(2)】ROS2:spin() spin_some()函数》,这个是堵塞了main 函数。

整体上处理的思路是:

1、建立一个 perceptionCommand_sub_ 订阅者
2、建立一个 perceptionCommand_ 的信息存储的成员
3、建立 订阅者的回调函数 msg_PerceptionCommand_callback,实现把收到的数据存放在 perceptionCommand_ 的信息存储的成员里面
4、建立一个50ms 的定时器
5、建立一个 workingStatus_pub_ 的发布者;4、建立一个 workingStatus_ 成员
6、建立一个 定时器的回调函数,处理perceptionCommand_ 成员的数据,并发送workingStatus_pub_ 数据。

建立一个订阅者
建立一个存储成员
订阅者的回调函数把收到的数据存放在成员
建立一个50ms 的定时器
建立发布者
定时器回调>处理存储的数据>并调用发布者发数据
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/81707
推荐阅读
相关标签
  

闽ICP备14008679号