当前位置: 首页 > news >正文

cyber_back

1.1 话题通信

模式:
以发布订阅的方式实现不同节点之间数据交互的通信模式。
如图1-1所示,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中。
1.2 服务通信

模式:
以请求响应的方式实现不同节点之间数据交互的通信模式。
如图1-2所示,Server-Client通信可以在客户端发出消息请求时,服务端才进⾏请求回应,并将客户端所需的数据返回给客户端。
场景:
我们想要获得⼩⻋的详细信息,⽐如⻋牌这些,但是⼜不需要⼀直获得该信息,想要在需要知道这些信息的时候请求⼀下就好,于是考虑⽤Server- Client通信实现该功能。

使用:
该通信模式适合临时的消息传输,适⽤于不需要持续性发送数据的场景。
数据定义:
其传输的数据定义依然在对应的proto⽂件中。
1.3 参数通信

模式:
以共享的方式实现不同节点之间数据交互的通信模式。
参数服务器是基于服务实现的,包含客户端和服务器端,服务端节点可以存储数据,客户端节点可以访问服务端节点操作数据,这个过程虽然基于请求响应的,但是无需自己实现请求与响应,此过程已经被封装,调用者只需要通过比较简单友好的API就可以实现参数操作。
场景:
自动驾驶场景中有一些参数比如该车的最高限速、最多乘客以及是否自动驾驶等需要被各个模块使用数据,比如是否自动驾驶这个参数可能同时影响这很多模块,也可能被很多模块运行时所更改。
这些数据如何实现在不同模块之间的共享呢?
使用:
类似于“全局变量”的方式来存储这些参数,并定义一些自定义参数来进行使用。
数据定义:
Cyber中设计了全局参数服务器来实现这个功能,其通信基于RTPS协议。该通信方式服务端和客户端都可以设置参数和更改参数。

第二节:数据通信基础Protobuf
1.3 Protobuf简介
2.1 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 等多种语言。
    2.2 Protobuf 文件编写
    为了方便讲解,使用cyber/examples/proto/examples.proto文件来讲解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;
};
2.3 Protobuf编译
Protobuf的编译要分为两个步骤:

  • 首先要根据.proto文件生成proto库;
  • 然后再根据生产的proto库生成C++相关的源文件。
    这个源文件是C++语言自动编写的,可以被C++程序自动识别。每一个message会被解析生一个类,里面的字段就相当于这个类的属性。在源文件中也会根据属性生成额外的成员,如获取和设置属性的函数。
    package(default_visibility = [“//visibility:public”])
    #1、生成proto库
    proto_library(
    name = “examples_proto”,
    srcs = [“examples.proto”],
    )
    #2、生成源文件
    cc_proto_library(
    name = “examples_cc_proto”,
    deps = [
    “:examples_proto”,
    ],
    )
    代码解析:
  • 我们使用Bazel构建系统的BUILD文件,用于生成proto库和相关的源文件。
  • 首先,通过proto_library规则定义了一个名为"examples_proto"的proto库,它使用"examples.proto"作为源文件。
  • 然后,通过cc_proto_library规则定义了一个名为"examples_cc_proto"的源文件生成规则。它依赖于"examples_proto"库,并使用该库生成相关的C++源文件。
  • 这些规则中的名称是任意定义的,您可以根据需要进行更改。
    2.4 小案例
    目的:使用Protobuf来定义数据格式,在main程序中设置数据值并输出。
    流程:
    <1> 创建本节实验工程目录
    <2> 编写Apollo包管理相关的BUILD和cyberfile.xml文件文件
    <3> 编写proto文件及BUILD文件;
    <4> 编写主代码及BUILD文件:
    <5> 编译代码目录
    <6> 运行可执行文件
    <1> 创建本节实验工程目录:
    cyber_demo
    |-- cyber_03
    |-- proto
    |-- BUILD
    |-- car_msg.proto
    |-- test_proto
    |-- BUILD
    |-- car.cc
    |–BUILD
    |–cyberfile.xml
    |–cyber_demo.BUILD
    <2> 编写Apollo包管理相关的BUILD和cyberfile.xml文件
  • BUILD文件内容:

load(“//tools/install:install.bzl”, “install”, “install_src_files”)

install(
name = “install”,
data = [
“cyber_demo.BUILD”,
“cyberfile.xml”,
],
deps = [
“//cyber_demo/cyber_03/test_proto:install”,
],
)

install_src_files(
name = “install_src”,
src_dir = [“.”],
dest = “cyber_demo/src”,
filter = “*”,
deps = [
“//cyber_demo/cyber_03/test_proto:install_src”,
]
)
编写cyberfile文件:

cyber_demo
1.0.0

cyber_demo

AD-platform@baidu.com
module
<src_path>//cyber_demo</src_path>
BSD
Apollo
cyber-dev
3rd-protobuf-dev
bazel

<3> 编写proto源文件及BUILD文件;
编写proto文件,文件中定义了车辆的信息:
syntax = “proto2”;

package apollo.cyber.test.proto;
message CarMsg {
required string owner = 1;
optional string license_plate = 2;
optional uint64 max_passenger = 3;
repeated string car_info = 4;
}
编写proto的BUILD文件:
load(“@rules_proto//proto:defs.bzl”, “proto_library”)
load(“@rules_cc//cc:defs.bzl”, “cc_proto_library”)
load(“//tools:python_rules.bzl”, “py_proto_library”)

package(default_visibility = [“//visibility:public”])

proto_library(
name = “car_msg_proto”,
srcs = [“car_msg.proto”],
)

cc_proto_library(
name = “car_msg_cc_proto”,
deps = [“:car_msg_proto”],
)
<4> 编写主代码及BUILD文件
通过car.cc输出车辆基本信息:
#include “test/proto/car_msg.pb.h”
using namespace std;

int main()
{
apollo::cyber::test::proto::CarMsg car;

car.set_owner("apollo");
car.set_license_plate("京A88888");
car.set_max_passenger(6);
car.add_car_info("SUV"); //车型
car.add_car_info("Red"); //车身颜色
car.add_car_info("electric"); //电动string owner = car.owner();
string license_plate = car.license_plate();
uint64_t max_passenger = car.max_passenger();cout << "owner:" << owner << endl;
cout << "license_plate:" << license_plate << endl;
cout << "max_passenger:" << max_passenger << endl;for (int i = 0; i < car.car_info_size(); ++i){string info = car.car_info(i);cout << info << " ";
}
cout << endl;
return 0;

}
注意
本段代码中内容需要进行
#include “test/proto/car_msg.pb.h”

--------------------需要替换为---------------------------

#include “cyber_demo/cyber_03/proto/car_msg.pb.h”

编辑car.cc的BUILD文件:
load(“@rules_cc//cc:defs.bzl”, “cc_binary”, “cc_library”)
load(“//tools/install:install.bzl”, “install”, “install_src_files”)
load(“//tools:cpplint.bzl”, “cpplint”)

package(default_visibility = [“//visibility:public”])

cc_binary(
name = “car”,
srcs = [“car.cc”],
deps = [“//test/proto:car_msg_cc_proto”],
)

install(
name = “install”,
runtime_dest = “test/bin”,
targets = [
“:car”
],
)

install_src_files(
name = “install_src”,
src_dir = [“.”],
dest = “test/src/cyberatest”,
filter = “*”,
)

注意
本段BUILD代码中内容需要进行修改
cc_binary(
name = “car”,
srcs = [“car.cc”],
deps = [“//test/proto:car_msg_cc_proto”],
)

--------------------需要替换为---------------------------

cc_binary(
name = “car”,
srcs = [“car.cc”],
deps = [“//cyber_demo/cyber_03/proto:car_msg_cc_proto”],
)

<5> 编译代码
cd /apollo_workspace
buildtool build -p cyber_demo/
编译结果如图所示:

编译完成后会在 /opt/apollo/neo/bin/的目录下生成可执行文件car,如下图所示:

<6> 运行可执行文件
cd /opt/apollo/neo/bin/
./car
运行结果如下图:

所有者:apollo
车牌号:京A88888
最大乘客人数:6
SUV 红色 电动
内容导入:
第三节:Cyber RT通信机制解析与实践

  1. 实践简介
    在第一章中,鹏飞老师已经说明了Node、Channel等Cyber的基础概念,本节我们基于这些基础概念,重点介绍 cyber 中的三种通信方式之一 - Listener 和 Talker通讯原理。为了更好的说明 Listener 和 Talker通信机制的用法,本节我们通过实现一个案例来说明该部分内容。
    案例如下,假设我们拥有了一辆自己的“无人车“,apollo号,现在我们想通过通信,获得该车辆的“实时”速度、车的详细信息以及车的通用参数。那么现在会有几个问题:
  • 车本身有的变量有哪些,应该在哪里定义?
  • 实现“实时”车速的获取和实现车的详细信息等应该用什么通信方式?在哪里实现?
  • 实现的代码应该如何运行起来?
    不要着急,接来下我们就开始用Cyber实现这个小demo,并一一解答以上疑问。该案例我们创建在/apollo/workspace/test文件下,命名为communication整体目录结构如下:
    /apollo_workspace/
    |–test
    | |–communication
    | | |–BUILD //cyber_test编译文件
    | |–talker.cc //talker-listener通信实现
    | |–listener.cc
    | |–server.cc //server-client通信实现
    | |–client.cc
    | |–param_server.cc //parameter server-client通信实现
    | |–param_client.cc
    |–proto
    |–BUILD //car.proto 编译文件
    |–car.proto //小车数据定义的文件ß
  1. 编写C++话题通信实践案例
  2. proto文件编写
    通过第一节内容,我们知道了proto文件的使用方法,那么这一章,我们来自己编写一个proto文件,来实现我们“车”的变量定义,在后续的三种通信方式的案例中都是用这一数据定义。
    对car.proto文件进行编写,其内容如下:
    // 定义proto使用的版本
    syntax = “proto2”;

//定义包名,在cc文件中调用
package apollo.cyber.test.proto;

//定义一个车的消息,车的型号,车主,车的车牌号,已跑公里数,车速
message Car{
optional string plate = 1;
optional string type = 2;
optional string owner = 3;
optional uint64 kilometers = 4;
optional uint64 speed = 5;
};
2.1 实现小车的实时速度获取——Listener-Talker通信

  1. talker.cc 文件编写
  • 我们来编写一个talker.cc来实现主动对话。
    //头文件引用
    #include “test/proto/car.pb.h”
    #include “cyber/cyber.h”
    #include “cyber/time/rate.h”

//car数据定义的引用,可以看出其定义来源于一个proto
using apollo::cyber::examples::cyber_test_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;

}

  1. listener.cc 文件编写
  • 编写一个listener来实现对talker发送过来的内容进行接收。
    #include “test/proto/car.pb.h”
    #include “cyber/cyber.h”

using apollo::cyber::examples::cyber_test_proto::Car;

//接收到消息后的响应函数
void message_callback(
const std::shared_ptr& 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;

}

  1. 运行与测试
  2. bazel 编译文件编写
    编写bazel编译文件(编写在cyber/examples/cyber_test/BUILD中)。
    load(“@rules_cc//cc:defs.bzl”, “cc_binary”, “cc_library”)
    load(“//tools/install:install.bzl”, “install”, “install_src_files”)
    load(“//tools:cpplint.bzl”, “cpplint”)

package(default_visibility = [“//visibility:public”])

cc_binary(
name = “talker”,
srcs = [“talker.cc”],
deps = [
“//cyber”,
“//test/proto:car_cc_proto”,
],
linkstatic = True,
)

cc_binary(
name = “listener”,
srcs = [“listener.cc”],
deps = [
“//cyber”,
“//test/proto:car_cc_proto”,
],
linkstatic = True,
)
2. 编译:
使用apollo 包管理开发方式提供的buildtool工具
buildtool build -p test/communication/
如下图所示,则编译成功。

  1. 运行案例
    首先,先将输出方法改为控制台输出。
    export GLOG_alsologtostderr=1
    打开两个终端,都进入Apollo的docker环境,一个终端运行talker,另一个运行listener,会发现listener运行后开始接收talker发送的小车速度的消息。
    ./bazel-bin/test/communication/talker
    结果显示:

./bazel-bin/test/communication/listener
结果显示:

总体运行效果如下图所示。

第四节:Cyber RT 本地部署之话题通信实践案例

  1. Apollo 本地安装部署
    Apollo 本地部署安装方式

  2. 创建和进入 Apollo 环境容器

  3. 创建工作空间
    创建并进入目录
    mkdir application-demo
    cd application-demo

  4. 启动 apollo 环境容器
    aem start
    如果一切正常,将会见到类似下图的提示:

  5. 进入 apollo 环境容器
    aem enter
    脚本执行成功后,将显示以下信息,您将进入 Apollo 的运行容器:

工作空间文件夹将被挂载到容器的 /apollo_workspace 中。

  1. 初始化工作空间
    aem init

至此 Apollo 环境管理工具及容器已经安装完成。
3. Protobuf、talker-listener实践案例演示

  1. Protobuf 案例:
    打印日志
    export GLOG_alsologtostderr=1
    运行car:
    cd /apollo_workspace/bazel-bin/test_proto/
    ./car
    car 运行结果如图所示

  2. talker-listener 案例:
    talker进入环境配置打印日志:
    aem start
    aem enter
    export GLOG_alsologtostderr=1
    运行talker:
    cd /apollo_workspace/bazel-bin/test/communication/
    ./talker
    talker 运行结果如图所示

listener进入环境配置打印日志:
aem start
aem enter
export GLOG_alsologtostderr=1
运行listener:
cd /apollo_workspace/bazel-bin/test/communication/
./listener
listener 运行结果如图所示

课后学习内容:
作业:
编写Python话题通信实现。
练习一: 实现小车详细信息的获取——Server-Client通信
1.1 Server-Client 简介

我们想要获得小车的详细信息,比如车牌这些,但是又不需要一直获得该信息,想要在需要知道这些信息的时候请求一下就好,于是考虑用Server- Client通信实现该功能。如图2-1所示,Server-Client通信可以在客户端发出消息请求时,服务端才进行请求回应,并将客户端所需的数据返回给客户端。该通信模式适合临时的消息传输,适用于不需要持续性发送数据的场景。其传输的数据定义依然在对应的proto文件中。
1.2 Server-Client 案例实现
编写一个Server来对Client请求的消息进行回应,这里我们返回车的车牌号、车主、已行驶公里数等信息。
#include “test/proto/car.pb.h”

#include “cyber/cyber.h”
//使用proto中定义好的car数据结构,还记得这个数据结构在那定义的吗?
using apollo::cyber::test::proto::Car;

int main(int argc, char* argv[]) {
apollo::cyber::Init(argv[0]);
std::shared_ptrapollo::cyber::Node node(
apollo::cyber::CreateNode(“server”));

//创建server node并设置topic名称,定义响应函数
auto server = node->CreateService<Car, Car>("service_client", 
[](const std::shared_ptr<Car>& request,std::shared_ptr<Car>& response) {AINFO << "Hi, I am your car's server.";response->set_type("apollo");response->set_plate("京A8888888");response->set_owner("xxx");response->set_kilometers(5);});apollo::cyber::WaitForShutdown();
return 0;

}
编写一个Client来请求车的详细信息,并获取数据。
#include “test/proto/car.pb.h”

#include “cyber/cyber.h”

//使用proto中定义好的car数据结构
using apollo::cyber::examples::cyber_test_proto::Car;

int main(int argc, char* argv[]){
//初始化cyber框架
apollo::cyber::Init(argv[0]);

//创建client node
std::shared_ptr<apollo::cyber::Node> node(apollo::cyber::CreateNode("client"));
auto client = node->CreateClient<Car, Car>("service_client");AINFO << "Hi server, I want to know car's information";//创建一个请求
auto request = std::make_shared<Car>();//发送请求并获得回应数据
auto response = client->SendRequest(request);
if(apollo::cyber::OK){if (response != nullptr) {AINFO << "this car owner is : " << response->owner();AINFO << "this car plate is : " << response->plate();AINFO << "this car type is : " << response->type();AINFO << "this car has run : " << response->kilometers()<<"kilometers";} else {AINFO << "service may not ready.";}
}apollo::cyber::WaitForShutdown();
return 0;

}
编写bazel编译文件(编写在cyber/examples/cyber_test/BUILD中)。
cc_binary(
name = “server”,
srcs = [“server.cc”],
deps = [
“//cyber”,
“//test/proto:car_cc_proto”,
],
linkstatic = True,
)

cc_binary(
name = “client”,
srcs = [“client.cc”],
deps = [
“//cyber”,
“//test/proto:car_cc_proto”,
],
linkstatic = True,
)

  • 编译:
    仍然打开两个终端,进入apollo的docker环境后,进行编译,其BUILD文件和talker.cc等为同一个文件,所以编译语句相同,也可以精准编译,先编译server再编译client, 这里为了方便整体编译了。
    buildtool build test/communication/

  • 运行:
    ./bazel-bin/test/communication/server
    ./bazel-bin/test/communication/client
    运行成功后结果如下:

练习二: 实现小车通用参数的设置——Parameter Server-Client
2.1 Parameter Server-Client 简介

有一些参数比如该车的最高限速,最多乘客以及是否自动驾驶等需要被各个模块所使用,比如是否自动驾驶这个参数可能同时影响这很多模块,也可能被很多模块运行时所更改。我们希望有一个类似于“全局变量”的方式来存储这些参数,并定义一些自定义参数来进行使用。Cyber中设计了全局参数服务器来实现这个功能,其通信依然基于RTPS协议,如图2-8所示。该通信方式服务端和客户端都可以设置参数和更改参数。
2.2 Parameter Server-Client 案例实现
#include “cyber/cyber.h”
#include “cyber/parameter/parameter_client.h”
#include “cyber/parameter/parameter_server.h”

using apollo::cyber::Parameter;
using apollo::cyber::ParameterServer;

int main(int argc, char** argv) {
//初始化cyber框架
//创建一个node,该node的名字和Topic名字同名
apollo::cyber::Init(*argv);
std::shared_ptrapollo::cyber::Node server_node =
apollo::cyber::CreateNode(“parameters_server”);
AINFO << “Hi,I’am your car’s parameter server.”;

//从该node创建参数服务器
auto param_server = std::make_shared(server_node);

//服务端进行参数设置,对小车的最高速度、最大人数、是否自动驾驶等参数进行了设置
param_server->SetParameter(Parameter("max_speed", 120));
param_server->SetParameter(Parameter("max_people", 5));
param_server->SetParameter(Parameter("if_auto", true));//尝试客户端修改一个参数,如max_speed,查看服务端目前的值
Parameter car_parameter;
param_server->GetParameter("max_speed", &car_parameter);
AINFO << "origin max_speed " << car_parameter.AsInt64();apollo::cyber::WaitForShutdown();
return 0;

}

编写param_client.cc。
#include “cyber/cyber.h”
#include “cyber/parameter/parameter_client.h”

using apollo::cyber::Parameter;
using apollo::cyber::ParameterClient;

using apollo::cyber::Parameter;
using apollo::cyber::ParameterClient;

int main(int argc, char** argv){
apollo::cyber::Init(*argv);
std::shared_ptrapollo::cyber::Node client_node =
apollo::cyber::CreateNode(“parameters_client”);
auto param_client = std::make_shared(client_node,“parameters_server”);
AINFO<<“Hi, I’m car’s parameters client!”;

//获取所有参数,用vector获取所有参数
std::vector<Parameter> car_parameters;
param_client->ListParameters(&car_parameters);
//遍历获取的参数,显示参数的名字以及参数的类型
for(auto &&parameter : car_parameters){AINFO << parameter.Name() <<" is " << parameter.TypeName();
}//客户端选择一个参数进行修改,比如修改max_speed
param_client->SetParameter(Parameter("max_speed",180));//获取修改后的max_speed
Parameter car_parameter;
param_client->GetParameter("max_speed", &car_parameter);
AINFO << "now max_speed " << car_parameter.AsInt64();apollo::cyber::WaitForShutdown();
return 0;

}
编写编译文件(编写在cyber/examples/cyber_test/BUILD中)。

deps = ["//cyber","//cyber/parameter",
],
linkstatic = True,

)

cc_binary(
name = “param_server”,
srcs = [“param_server.cc”],
deps = [
“//cyber”,
“//cyber/parameter”,
],
linkstatic = True,
)

install(
name = “install”,
runtime_dest = “test/bin”,
targets = [
“:talker”,
“:listener”,
“:server”,
“:client”,
“:param_client”,
“:param_server”
],
)

install_src_files(
name = “install_src”,
src_dir = [“.”],
dest = “test/src/cyberatest”,
filter = “*”,
)

  • 编译:
    还是打开两个终端,进入apollo的docker环境后,先进行编译。
    buildtool build test/communication/

  • 运行:
    ./bazel-bin/test/communication/server/param_server
    ./bazel-bin/test/communication/server/param_client

好啦,至此通过“小车”案例已经介绍完了Cyber三种通信方式的简单用法,快动起手来试试吧~

相关文章:

cyber_back

1.1 话题通信 模式&#xff1a; 以发布订阅的方式实现不同节点之间数据交互的通信模式。 如图1-1所示&#xff0c;Listener-Talker通信首先创建了两个Node&#xff0c;分别是Talker Node和 Listener Node。 每个Node实例化Writer类和Reader类对Channel进行消息的读写。 Writer…...

价值 1k 嵌入式面试题-单片机 main 函数之前都做了啥?

开门见山 请说下单片机&#xff08;Arm&#xff09;在运行到 main() 函数前&#xff0c;都做了哪些工作&#xff1f; 常见问题 系统初始化工作&#xff0c;太泛泛硬件初始化&#xff0c;比较不具体 答题思路 这道题应该从两方面回答&#xff0c;一个是比较表面的硬件的初始化…...

美团2024校招6000人;伯克利博士讲Llama 2技术细节;互联网转行AIGC最全指北;技术进步周期与创客崛起 | ShowMeAI日报

&#x1f440;日报&周刊合集 | &#x1f3a1;生产力工具与行业应用大全 | &#x1f9e1; 点赞关注评论拜托啦&#xff01; &#x1f916; 美团 2024 届校园招聘将录用 6000 人&#xff0c;技术类岗位扩招超 50% 美团招聘公众号宣布启动 2024 届校园招聘&#xff01;此次招聘…...

【严重】PowerJob<=4.3.3 远程代码执行漏洞

漏洞描述 PowerJob 是一款开源的分布式任务调度框架。 由于 PowerJob 未对网关进行鉴权&#xff0c;4.3.3 及之前版本中&#xff0c;未经授权的攻击者可向 /instance/detail 端点发送恶意构造的 instanceId 参数远程执行任意代码。 漏洞名称 PowerJob<4.3.3 远程代码执行漏…...

什么是 ASP.NET Core SignalR?

所有连接了 Internet 的应用程序都由服务器和客户端组成。 客户端依赖于服务器获取数据&#xff0c;而它们获取数据的主要机制是通过发出超文本传输协议 (HTTP) 请求来进行的。 某些客户端应用程序需要经常更改的数据。 ASP.NET Core SignalR 提供了一个 API&#xff0c;用于创…...

Centos/Ubuntu 替换yum/apt源?

yum/apt源如果不满足要求, 可以考虑将源替换为阿里云的源。 1.CentOS更换阿里云yum源 1. 备份 mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base-bak.repo 2. 下载 wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Cent…...

【RabbitMQ(day3)】扇形交换机和主题交换机的应用

文章目录 第三种模型&#xff08;Publish/Subscribe 发布/订阅&#xff09;扇型&#xff08;funout&#xff09;交换机Public/Subscribe 模型绑定 第四、第五种模型&#xff08;Routing、Topics&#xff09;第四种模型&#xff08;Routing&#xff09;主题交换机&#xff08;To…...

redis 高级篇 redis 源码的读取分析

一 redis源码分析 1.1 源码分析 1每一个kv键值对应有一个dictEntry。 2.底层数据结构...

Acwing.873.欧拉函数

题目 给定n个正整数ai&#xff0c;请你求出每个数的欧拉函数。 输入格式 第一行包含整数n。 接下来n行&#xff0c;每行包含一个正整数ai。 输出格式 输出共n行&#xff0c;每行输出一个正整数an的欧拉函数。 数据范围 1 ≤n ≤100 1≤ai≤2* 109 输入样例: 3 3 6 8输…...

深入浅出FPGA——笔记7 代码风格

1 寄存器电路的设计方式 废话&#xff1a;时序逻辑设计是核心&#xff0c;而寄存器又是时序逻辑的基础。 1: 简单的时序输入输出模型 如下图所示&#xff0c;在每个时钟信号clk的有效沿&#xff08;通常是上升沿&#xff09;&#xff0c;输入端数据din将被锁存到输出端dout。…...

npm, yarn配置

一、npm 1. 查看当前的镜像源。 npm config get registry 2. 设置为淘宝源 npm config set registry https://registry.npm.taobao.org 3. 还原默认源 npm config set registry https://registry.npmjs.org/ 二、Yarn 1.yarn的安装 npm install -g yarn 2. 查看当…...

跨域情况下,vue如何下载后台接口提供的application/octet-stream文件流Excel文件

前言 由于跨域&#xff0c;所以无法直接通过window.location.href或者a标签直接下载&#xff0c;直接拼后台接口地址又暴露了后台地址&#xff0c;不可行。 所以在这种跨域情况下&#xff0c;本章讲一下vue如何下载后台接口提供的application/octet-stream文件流Excel文件。 …...

学C的第三十一天【通讯录的实现】

相关代码gitee自取&#xff1a;C语言学习日记: 加油努力 (gitee.com) 接上期&#xff1a; 学C的第三十天【自定义类型&#xff1a;结构体、枚举、联合】_高高的胖子的博客-CSDN博客 通讯录需求&#xff1a; 实现一个通讯录&#xff0c; 通讯录中存放保存人的信息&#xff1…...

Linux操作系统学习,Linux基础命令大全

目录 第一章、Linux简介和安装1.1&#xff09;Linux简介和分类1.2&#xff09;安装VMware虚拟机&#xff0c;在虚拟机中安装CentOS 7 第二章、虚拟机中Linux的IP地址配置详解2.1&#xff09;什么是IP地址&#xff0c;如何查看2.2&#xff09;虚拟机NAT模式中Linux的IP地址设置有…...

【软件测试】说说你对TDD测试驱动开发的理解?

很多公司在面测试中高级岗时&#xff0c;都会不同程度地问到“有没有了解过TDD”“你认为TDD可以解决什么问题”或者“说说测试驱动开发的流程”等等&#xff0c;即使公司并不会用到此开发流程&#xff0c;面试官也会通过你对这个相对还比较“陌生”的概念的讲述来了解你对一些…...

B. Binary Cafe(二进制的妙用)

题目&#xff1a;Problem - B - Codeforces 总结&#xff1a; 对于该题最简单的方法为使用二进制的数表示状态 例如&#xff1a; 对于一个数7的二进制&#xff1a;111 它的每一位都可表示两种状态我们可以理解为取或者不取 对于7这个数字它可以表示一种状态即在三个位置都…...

SpringBoot单元测试

目录 1.什么是单元测试? 2.单元测试有哪些好处? 3.Spring Boot单元测试使⽤ 单元测试的实现步骤 1. ⽣成单元测试类 2. 添加单元测试代码 2.1 .添加Spring Boot框架测试注解:SpringBootTest 2.2 添加单元测试业务逻辑 简单的断⾔说明 1.什么是单元测试? 单元测试(un…...

刷题 41-45

四十一、移除元素 示例 1&#xff1a; 输入&#xff1a;nums [3,2,2,3], val 3 输出&#xff1a;2, nums [2,2] 解释&#xff1a;函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。你不需要考虑数组中超出新长度后面的元素。例如&#xff0c;函数返回的新长度为 2 …...

Centos时间同步

前言 在 Linux 操作系统中&#xff0c;正确的时间同步是非常重要的&#xff0c;因为它对于很多应用程序都是必需的。本文将介绍两种在 Centos 系统中同步当前时间的方式。 方法一&#xff1a;使用 ntpdate 命令同步当前时间 ntpdate 命令是一种简单快捷的同步当前时间的方式&a…...

Linux 查看磁盘空间

1 查看当前目录的总大小 &#xff1a;du -sh ps&#xff1a;du(disk usage) 2 查看某个目录的总大小&#xff1a;du -sh 目录名 3 查找出/目录下占用空间最大的前10个文件或者文件夹&#xff1a;sudo du -a / | sort -n -r | head -n 10 4 查看磁盘信息:df -h...

AI Agent与Agentic AI:原理、应用、挑战与未来展望

文章目录 一、引言二、AI Agent与Agentic AI的兴起2.1 技术契机与生态成熟2.2 Agent的定义与特征2.3 Agent的发展历程 三、AI Agent的核心技术栈解密3.1 感知模块代码示例&#xff1a;使用Python和OpenCV进行图像识别 3.2 认知与决策模块代码示例&#xff1a;使用OpenAI GPT-3进…...

大型活动交通拥堵治理的视觉算法应用

大型活动下智慧交通的视觉分析应用 一、背景与挑战 大型活动&#xff08;如演唱会、马拉松赛事、高考中考等&#xff09;期间&#xff0c;城市交通面临瞬时人流车流激增、传统摄像头模糊、交通拥堵识别滞后等问题。以演唱会为例&#xff0c;暖城商圈曾因观众集中离场导致周边…...

UE5 学习系列(三)创建和移动物体

这篇博客是该系列的第三篇&#xff0c;是在之前两篇博客的基础上展开&#xff0c;主要介绍如何在操作界面中创建和拖动物体&#xff0c;这篇博客跟随的视频链接如下&#xff1a; B 站视频&#xff1a;s03-创建和移动物体 如果你不打算开之前的博客并且对UE5 比较熟的话按照以…...

如何在看板中有效管理突发紧急任务

在看板中有效管理突发紧急任务需要&#xff1a;设立专门的紧急任务通道、重新调整任务优先级、保持适度的WIP&#xff08;Work-in-Progress&#xff09;弹性、优化任务处理流程、提高团队应对突发情况的敏捷性。其中&#xff0c;设立专门的紧急任务通道尤为重要&#xff0c;这能…...

智能仓储的未来:自动化、AI与数据分析如何重塑物流中心

当仓库学会“思考”&#xff0c;物流的终极形态正在诞生 想象这样的场景&#xff1a; 凌晨3点&#xff0c;某物流中心灯火通明却空无一人。AGV机器人集群根据实时订单动态规划路径&#xff1b;AI视觉系统在0.1秒内扫描包裹信息&#xff1b;数字孪生平台正模拟次日峰值流量压力…...

Spring数据访问模块设计

前面我们已经完成了IoC和web模块的设计&#xff0c;聪明的码友立马就知道了&#xff0c;该到数据访问模块了&#xff0c;要不就这俩玩个6啊&#xff0c;查库势在必行&#xff0c;至此&#xff0c;它来了。 一、核心设计理念 1、痛点在哪 应用离不开数据&#xff08;数据库、No…...

算法笔记2

1.字符串拼接最好用StringBuilder&#xff0c;不用String 2.创建List<>类型的数组并创建内存 List arr[] new ArrayList[26]; Arrays.setAll(arr, i -> new ArrayList<>()); 3.去掉首尾空格...

MySQL账号权限管理指南:安全创建账户与精细授权技巧

在MySQL数据库管理中&#xff0c;合理创建用户账号并分配精确权限是保障数据安全的核心环节。直接使用root账号进行所有操作不仅危险且难以审计操作行为。今天我们来全面解析MySQL账号创建与权限分配的专业方法。 一、为何需要创建独立账号&#xff1f; 最小权限原则&#xf…...

浪潮交换机配置track检测实现高速公路收费网络主备切换NQA

浪潮交换机track配置 项目背景高速网络拓扑网络情况分析通信线路收费网络路由 收费汇聚交换机相应配置收费汇聚track配置 项目背景 在实施省内一条高速公路时遇到的需求&#xff0c;本次涉及的主要是收费汇聚交换机的配置&#xff0c;浪潮网络设备在高速项目很少&#xff0c;通…...

RSS 2025|从说明书学习复杂机器人操作任务:NUS邵林团队提出全新机器人装配技能学习框架Manual2Skill

视觉语言模型&#xff08;Vision-Language Models, VLMs&#xff09;&#xff0c;为真实环境中的机器人操作任务提供了极具潜力的解决方案。 尽管 VLMs 取得了显著进展&#xff0c;机器人仍难以胜任复杂的长时程任务&#xff08;如家具装配&#xff09;&#xff0c;主要受限于人…...