CyberRT通信介绍与基于Reader、Writer的通信实践(apollo9.0)

news2024/10/19 6:39:39

目录

数据通信场景

CyberRT中的通信方式 

​编辑

通信模式

话题通信

服务通信

参数通信

protobuf

protobuf简介

 protobuf文件编写

topic通信实验

实验环境

实验准备

代码编写

定义消息格式

发送消息

接收消息

定义编译规则

程序编译

运行程序


数据通信场景

数据间通信一般分三种情况,分别是

  • 进程内通信
  • 进程间通信
  • 跨主机通信

针对三种不同的通信场景也有不同的通信方式,如

  • 进程内通信方式:对象指针、函数
  • 进程间通信方式:共享内存、管道、消息队列等
  • 跨主机进程间通信方式:RTPS、GRPC等

CyberRT中的通信方式 

以下是CyberRT中针对不同通信场景所使用的通信方式

但是一般情况下我们是不知道通信对方是与我们同一个进程还是不同进程甚至是否一个主机的,而CyberRT对此做出以下判断

  • 判断对端ip与本进程的ip是否相同,如果不同则采用跨主机通信
  • 判断对端进程id与本进程id是否相同,如果不同则采用进程间通信
  • 如果前两者都相同,则采用进程内通信方式

通信模式

CyberRT中的数据通信模式主要有三种:

  • Writer/Reader:发布订阅者模式
  • Service/Client:服务客户通信模式
  • Parameter Server-Client:参数服务客户通信模式

话题通信

模式

以发布订阅的方式实现不同节点之间数据交互的通信模式。

如图所示

  • Listener-Talker通信首先创建了两个Node,分别是Talker Node和 Listener Node。
  • 每个Node实例化Writer类和Reader类对Channel进行消息的读写。
  • Writer和Reader通过Topic连接,对同一块共享内存(Channel)进行读写处理。
  • Talker Node 为了实现其“诉说”的功能,实例化Writer,通过Writer来对Channel进行消息写操作。
  • Listener Node为了实现其“聆听”功能,实例化reader类,通过Reader来对channel进行读操作。

场景

话题通信方式适合于持续性通信的应用场景,比如雷达信号,摄像头图像信息这类数据的传输。

使用:

Listener-Talker通信一方主动送消息,一方被动接收。

我们想要一直获取车的速度,该需求不需要向发送方返回什么消息,也不需要发送方对消息进行进一步处理。所以我们选择了Listener-Talker通信方式实现该功能。

数据定义:

话题通信中用的的数据格式的定义car message 定义在car.proto中。

服务通信

模式

以请求响应的方式实现不同节点之间数据交互的通信模式。

如图所示,Server-Client通信可以在客户端发出消息请求时,服务端才进⾏请求回应,并将客户端所需的数据返回给客户端。

场景

我们想要获得⼩⻋的详细信息,⽐如⻋牌这些,但是⼜不需要⼀直获得该信息,想要在需要知道这些信息的时候请求⼀下就好,于是考虑⽤Server- Client通信实现该功能。

使用:

该通信模式适合临时的消息传输,适⽤于不需要持续性发送数据的场景。

数据定义:

其传输的数据定义依然在对应的proto⽂件中。

参数通信

模式

以共享的方式实现不同节点之间数据交互的通信模式。

参数服务器是基于服务实现的,包含客户端和服务器端,服务端节点可以存储数据,客户端节点可以访问服务端节点操作数据,这个过程虽然基于请求响应的,但是无需自己实现请求与响应,此过程已经被封装,调用者只需要通过比较简单友好的API就可以实现参数操作。

场景

自动驾驶场景中有一些参数比如该车的最高限速、最多乘客以及是否自动驾驶等需要被各个模块使用数据,比如是否自动驾驶这个参数可能同时影响这很多模块,也可能被很多模块运行时所更改。

这些数据如何实现在不同模块之间的共享呢?

使用:

类似于“全局变量”的方式来存储这些参数,并定义一些自定义参数来进行使用。

数据定义:

Cyber中设计了全局参数服务器来实现这个功能,其通信基于RTPS协议。该通信方式服务端和客户端都可以设置参数和更改参数。

protobuf

protobuf简介

Protobuf 是 Google 公司开发的一种跨语言和平台的序列化数据结构的方式,是一个灵活的、高效的用于序列化数据的协议,与 XML 和 JSON 格式相比,Protobuf 更小、更快、更便捷。

Protobuf 是跨语言的,并且自带一个编译器( protoc ),只需要用protoc进行编译,就可以编译成 Java、Python、C++、C#、Go 等多种语言代码,然后可以直接使用,不需要再写其它代码,自带有解析的代码。只需要将要被序列化的结构化数据定义一次(在 .proto 文件定义),便可以使用特别生成的源代码(使用protobuf提供的生成工具)轻松的使用不同的数据流完成对结构数据的读写操作。甚至可以更新 .proto 文件中对数据结构的定义而不会破坏依赖旧格式编译出来的程序。其优点如下:

  • 性能效率高序列化后字节占用空间比 XML 少3-10倍,序列化的时间效率比 XML 快20-100倍。

  • 使用便捷便捷:将对结构化数据的操作封装成一个类,便于使用。

  • 兼容性高:通信两方使用同一数据协议,当有一方修改了数据结构,不会影响另一方的使用。

  • 跨语言:支持 Java,C++,Python、Go、Ruby 等多种语言。

 protobuf文件编写示例

Protobuf有几个部分构成:

  • syntax :表示使用Protobuf的版本,目前Protobuf支持proto3,但在Apollo中使用的是proto2;

  • package: 表示该文件的路径

  • message:表示一种数据结构,message后面跟的是数据结构名字,括号里的字段定义格式为:字段规则 数据类型 字段名称 字段编号。

字段规则主要有三种

  • required:调用时必须提供该字段的值,否则该消息被视为“未初始化”,官方不建议使用,当把字段规则改为其他规则会存在兼容性问题。

  • optional:该字段的值可以设置也可以不设置,会根据数据类型生成一个默认的值

  • repeated类似于动态数组,可以存储多个同类型的数据

如下示例

# examples.proto
syntax = "proto2";
package apollo.cyber.examples.proto;
message SamplesTest1 {
  optional string class_name = 1;
  optional string case_name = 2;
};
message Chatter {
  optional uint64 timestamp = 1;
  optional uint64 lidar_timestamp = 2;
  optional uint64 seq = 3;
  optional bytes content = 4;
};
message Driver {
  optional string content = 1;
  optional uint64 msg_id = 2;
  optional uint64 timestamp = 3;
};

topic通信实验

实验环境

apollo9.0,安装见官网说明,安装完成后进入容器即可

apollo.baidu.com/community/Apollo-Homepage-Document?doc=BYFxAcGcC4HpYIbgPYBtXIHQCMEEsATAV0wGNkBbWA5UyRFdZWVBEAU0hFgoIH0adPgCY%2BADwCiAVnEBBCeIAcATnETFcgMxKZkgGxKAwkoDsa3YoAi45WdGSLxsYt0SzY%2BXICMa98oAMSgYALF7%2B2NhemsLBJsrCYZqKwors7AikBIp6miYmpFJSXpigFKhAA

实验准备

创建代码结构目录

buildtool create --template component communication
touch /apollo_workspace/communication/listener.cc
touch /apollo_workspace/communication/talker.cc

 最终的实验目录结构如下

communication
 ├── BUILD
 ├── communication.cc
 ├── communication.h
 ├── conf
 │   ├── communication.conf
 │   └── communication.pb.txt
 ├── cyberfile.xml
 ├── dag
 │   └── communication.dag
 ├── launch
 │   └── communication.launch
 ├── listener.cc <必须有>
 ├── proto <必须有>
 │   ├── BUILD <必须有>
 │   └── communication.proto <必须有>
 └── talker.cc <必须有>

代码编写

定义消息格式

编写proto/communication.proto文件

syntax = "proto2";
 
package apollo.communication.proto;
 
 //定义一个车的消息,车的型号,车主,车的车牌号,已跑公里数,车速
 message Car{
     optional string plate = 1;
     optional string type = 2;
     optional string owner = 3;
     optional uint64 kilometers = 4;
     optional uint64 speed = 5;
 };

发送消息

编写发送方 talker 代码,talker.cc 代码如下

#include "communication/proto/communication.pb.h"
 #include "cyber/cyber.h"
 #include "cyber/time/rate.h"
 
 //car数据定义的引用,可以看出其定义来源于一个proto
 using apollo::communication::proto::Car;
 
 int main(int argc, char *argv[]) {
   // 初始化一个cyber框架
   apollo::cyber::Init(argv[0]);
   // 创建talker节点
   auto talker_node = apollo::cyber::CreateNode("talker");
   // 从节点创建一个Topic,来实现对车速的查看
   auto talker = talker_node->CreateWriter<Car>("car_speed");
   AINFO << "I'll start telling you the current speed of the car.";
 
   //设置初始速度为0,然后速度每秒增加5km/h
   uint64_t speed = 0;
   while (apollo::cyber::OK()) {
       auto msg = std::make_shared<Car>();
       msg->set_speed(speed);
       //假设车速持续增加
       speed += 5;
       talker->Write(msg);
       sleep(1);
   }
   return 0;
 }

接收消息

编写接受方 listener 代码,listener.cc 代码如下

#include "communication/proto/communication.pb.h"
 #include "cyber/cyber.h"
 
 using apollo::communication::proto::Car;
 
 //接收到消息后的响应函数
 void message_callback(
         const std::shared_ptr<Car>& msg) {
     AINFO << "now speed is: " << msg->speed();
 }
 
 int main(int argc, char* argv[]) {
     //初始化cyber框架
     apollo::cyber::Init(argv[0]);
     //创建监听节点
     auto listener_node = apollo::cyber::CreateNode("listener");
     //创建监听响应进行消息读取
     auto listener = listener_node->CreateReader<Car>(
             "car_speed", message_callback);
     apollo::cyber::WaitForShutdown();
     return 0;
 }

定义编译规则

修改 BUILD 文件,将新写的代码加入到编译中,communication/BUILD文件修改如下

load("//tools:apollo_package.bzl", "apollo_cc_library", "apollo_cc_binary", "apollo_package", "apollo_component")
load("//tools:cpplint.bzl", "cpplint")
 
package(default_visibility = ["//visibility:public"])
 
apollo_cc_binary(
    name = "talker",
    srcs = ["talker.cc"],
    deps = [
        "//cyber",
        "//communication/proto:communication_proto",
    ],
    linkstatic = True,
)
apollo_cc_binary(
    name = "listener",
    srcs = ["listener.cc"],
    deps = [
        "//cyber",
        "//communication/proto:communication_proto",
    ],
    linkstatic = True,
)
 
apollo_package()
 
cpplint()

程序编译

//回到 /apollo_workspace目录下编译
cd /apollo_workspace
buildtool build -p communication

 编译成功显示如下:

运行程序

打开一个终端,运行talker程序

// 设置将输出结果到控制台
export GLOG_alsologtostderr=1
// 编译产生的可执行文件在 /opt/apollo/neo/bin/
cd /opt/apollo/neo/bin/
// 执行talker
./talker

 重新打开一个终端,运行listener程序

// 设置将输出结果到控制台
export GLOG_alsologtostderr=1
// 编译产生的可执行文件在 /opt/apollo/neo/bin/
cd /opt/apollo/neo/bin/
// 执行listener
./listener

运行结果如下图所示,左侧是talker发送消息,右侧是listener接收消息

参考

apollo.baidu.com/community/Apollo-Homepage-Document?doc=BYFxAcGcC4HpYIbgPYBtXIHQCMEEsATAV0wGNkBbWA5UyRFdZWVBEAU0hFgoIH0adPgCY%2BADwCiAVnEBBCeIAcATnETFcgMxKZkgGxKAwkoDsa3YoAi45WdGSLxsYt0SzY%2BXICMa98oAMSgYALF7%2B2NhemsLBJsrCYZqKwors7AikBIp6miYmpFJSXpigFKhAA 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2218299.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

STM32-Modbus协议(一文通)

Modbus协议原理 RT-Thread官网开源modbus RT-Thread官方提供 FreeModbus开源。 野火有移植的例程。 QT经常用 libModbus库。 Modbus是什么&#xff1f; Modbus协议&#xff0c;从字面理解它包括Mod和Bus两部分&#xff0c;首先它是一种bus&#xff0c;即总线协议&#xff0c;和…

开发一个微信小程序要多少钱?

在当今数字化时代&#xff0c;微信小程序成为众多企业和个人拓展业务、提供服务的热门选择。那么&#xff0c;开发一个微信小程序究竟需要多少钱呢&#xff1f; 开发成本主要取决于多个因素。首先是功能需求的复杂程度。如果只是一个简单的信息展示小程序&#xff0c;功能仅限…

使用HIP和OpenMP卸载的Jacobi求解器

Jacobi Solver with HIP and OpenMP offloading — ROCm Blogs (amd.com) 作者&#xff1a;Asitav Mishra, Rajat Arora, Justin Chang 发布日期&#xff1a;2023年9月15日 Jacobi方法作为求解偏微分方程&#xff08;PDE&#xff09;的基本迭代线性求解器在高性能计算&#xff…

Java实现油画滤镜效果【参数可调】

油画滤镜的基本原理 油画滤镜的基本思想是通过改变图像的像素&#xff0c;将每个像素用周围随机选择的像素来代替&#xff0c;从而产生类似油画笔触的效果。这种处理方式可以模糊图像的细节&#xff0c;使得图像的色块更加连贯&#xff0c;从而模仿油画的艺术效果。 核心步骤…

后台管理员登录实现--系统篇

我的小系统后台原来就有一个上传图片的功能还夹带个删除图片的功能&#xff0c;还嵌到了一个菜单里面。之前效果如下 那么现在为了加大安全力度&#xff0c;想增加一个登录页面。通过登录再到这个页面。看着貌似很简单&#xff0c;但是听我细细说来&#xff0c;要新增些什么东西…

OpenLayers:构建现代Web地图应用

&#x1f493; 博客主页&#xff1a;瑕疵的CSDN主页 &#x1f4dd; Gitee主页&#xff1a;瑕疵的gitee主页 ⏩ 文章专栏&#xff1a;《热点资讯》 OpenLayers&#xff1a;构建现代Web地图应用 文章目录 OpenLayers&#xff1a;构建现代Web地图应用1. 简介2. 为什么选择 OpenLa…

Redis 高可用:从主从到集群的全面解析

目录 一、主从复制 (基础)1. 同步复制a. 全量数据同步b. 增量数据同步c. 可能带来的数据不一致 2. 环形缓冲区a. 动态调整槽位 3. runid4. 主从复制解决单点故障a. 单点故障b. 可用性问题 5. 注意事项a. Replica 主动向 Master 建立连接b. Replica 主动向 Master 拉取数据 二、…

腾讯云宝塔面板前后端项目发版

后端发版 1. 打开“网站”页面&#xff0c;找到java项目&#xff0c;点击状态暂停服务 2.打开“文件”页面&#xff0c;进入jar包目录&#xff0c;删除原有的jar包&#xff0c;上传新jar包 3. 再回到第一步中的网站页面&#xff0c;找到jar项目&#xff0c;启动项目即可 前端发…

C#的小数位保留以及四舍五入

C#使用Math.Round("数值","保留位","保留方式")进行小数位保留以及四舍五入 //1.MidpointRounding.ToEven(四舍六入五成双) //当保留小数位后一位为0~4时&#xff0c;舍去末位 var x1 Math.Round(1.124, 2, MidpointRo…

立仪科技:光谱共焦传感器精准测量玻璃

光谱共焦测量技术作为一种创新的光学检测方法&#xff0c;近年来在工业领域引起了广泛关注。 它以其高精度、非接触式的特点&#xff0c;特别适用于透明或半透明材料如玻璃的厚度和表面形貌测量。 接下来&#xff0c;立仪科技小编将深入探讨光谱共焦技术在玻璃测量上的应用及其…

计算机毕业设计Hadoop+Hive+Spark+Flink广告推荐系统 广告预测 广告数据分析可视化 广告爬虫 大数据毕业设计 深度学习 机器学习

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 专业 小四号宋体 班级 小…

飞机大战告尾

参考 PPO算法逐行代码详解 链接 通过网盘分享的文件&#xff1a;PlaneWar 链接: https://pan.baidu.com/s/1cbLKTcBxL6Aem3WkyDtPzg?pwd1234 提取码: 1234 10.17关于博客发了又改这件事 悲催的事 今天训练了一早上ppo模型&#xff0c;满怀期待的检测成果时发现一点长进都…

mac安装brew时踩坑解决方案

安装包 mac上如果按照git等工具可能会使用brew&#xff0c;例如使用&#xff1a;$ brew install git命令&#xff0c;如果电脑没有按照brew&#xff0c;则会提示&#xff1a;zsh: command not found: brew 解决方案 需要我们打开brew的官网https://brew.sh/&#xff0c;复制…

动态规划一>下降路径最小和

1.题目&#xff1a; 2.解析&#xff1a; 代码&#xff1a; /**1.创建dp表2.初始化3.填表4.返回值*/public int minFallingPathSum(int[][] matrix) {int n matrix.length;int[][] dp new int[n1][n2];int minNum Integer.MAX_VALUE; for(int i 1; i < n; i) dp[i][0]…

【CSS】纯CSS Loading动画组件

<template><div class"ai-loader-box"><!-- AI loader --><div class"ai-loader"><div class"text"><p>AI智能分析中....</p></div><div class"horizontal"><div class&quo…

简单说说 spring是如何实现AOP的(源码分析)

在spring生命周期流程中&#xff0c;有一个过程是执行BeanPostProcessor的后置方法 BeanPostProcessor 是一个接口&#xff0c;其实现有 aop实现的核心类是AbstractAutoProxyCreator&#xff0c;其位于spring-aop包下&#xff0c;实现了BeanPostProcessor //BeanPostProcesso…

【Java小白图文教程】-04-分支结构

本套课程将会从0基础讲解Java语言核心技术&#xff0c;适合人群&#xff1a; 大学中开设了Java语言课程的同学想要专升本或者考研的同学想要考计算机等级证书的同学想要从事Java相关开发开发的同学 精品专题&#xff1a; 01.《C语言从不挂科到高绩点》课程详细笔记 https:/…

transformers 推理 Qwen2.5 等大模型技术细节详解(一)transformers 初始化和对象加载(文末免费送书)

上周收到一位网友的私信&#xff0c;希望老牛同学写一篇有关使用 transformers 框架推理大模型的技术细节的文章。 老牛同学刚开始以为这类的文章网上应该会有很多&#xff0c;于是想着百度几篇质量稍高一点的回复这位网友。结果&#xff0c;老牛同学搜索后发现&#xff0c;类…

力扣61~65题

题61&#xff08;中等&#xff09;&#xff1a; 分析&#xff1a; python代码&#xff1a; # Definition for singly-linked list. # class ListNode: # def __init__(self, val0, nextNone): # self.val val # self.next next class Solution:def rot…

【含开题报告+文档+PPT+源码】基于SpringBoot电脑DIY装机教程网站的设计与实现

开题报告 随着科技的发展和人们对电脑需求的增加&#xff0c;越来越多的人开始自己组装电脑。然而&#xff0c;针对初学者来说&#xff0c;如何选择合适的硬件配置并进行装机是一个相对复杂的过程。随着各种品牌、型号和规格的硬件不断增多&#xff0c;用户需要一个方便快捷的…