【Apollo Spark Project】——Cyber Basic Concept | Communication Mechanism

insert image description here

foreword

Because there are many articles on the Internet about the basic introduction of cyber, this article will not repeat them. This article mainly focuses on the implementation of cyber foundation and communication-related examples.
Course address : https://apollo.baidu.com/community/course/outline/329?activeId=10200
For more information, please refer to :
[1] Apollo Spark Project Study Notes ——The third lecture (Apollo Cyber ​​RT module detailed explanation and actual combat) https://blog.csdn.net/sinat_52032317/article/details/126924375
[2] Chapter 1: Cyber ​​RT basic introduction and practice https://apollo. baidu.com/community/article/1093 [TEST1 & TEST2]
[3] Chapter 2: Analysis and Practice of Cyber ​​RT Communication Mechanism https://apollo.baidu.com/community/article/1094 [TEST3 & TEST4 & TEST5 & TEST6]

Relevant code finishing

Link: https://pan.baidu.com/s/1ENgXE4yQ1v4nJRjcfZtd8w?pwd=ht4c Extraction code: ht4c

Basic Concept 1

For more information on this part, please refer to Chapter 1: Basic Introduction and Practice of Cyber ​​RT https://apollo.baidu.com/community/article/1093

Introduction to Cyber

Apollo Cyber ​​is the first high-performance and open-source real-time communication framework customized for autonomous driving. It mainly solves the problems of high concurrency , low latency , high throughput , and task scheduling in autonomous driving systems , and also provides a variety of communication mechanisms. And user-level coroutines, when resources are limited, they will be scheduled according to the priority of the task.

communication composition

Node is the basic construction of Cyber . Each module will contain a Node node, and the modules communicate through Node nodes. The communication between Nodes can be set in different modes, including Reader/Writerand Service/Client.

Cyber ​​uses a distributed system . Nodes are managed through Topology . Each Node is a vertex of this topology graph, and each Node vertex is connected through a Channel or Service. Node nodes are decentralized and can dynamically monitor the addition and deletion of nodes. Channel can be understood as a piece of shared memory , and the communication method of shared memory can greatly improve communication efficiency.

Introduction to Bazel

Apollo uses Bazel to compile. Bazel is an open source build and test tool developed by Google, and it is also a simple and easy-to-read build tool. Its advantages are as follows:

  • Bazel only rebuilds what is necessary. Get fast and incremental builds thanks to advanced local and distributed caching , optimized dependency analysis, and parallel execution.
  • Build and test for Java, C++, Android, iOS, and various other language platforms. Bazel runs on Windows, macOS, and Linux.
  • Bazel helps you scale your organization, code base, and continuous integration system. It can handle code bases of any size .

The Bazel project structure looks like this:

project
|-- pkg
|   |-- BUILD
|   |-- src.cc
|-- WORKSPACE
  • WORKSPACEfile identifying the directory and its contents as a Bazel workspace and located at the root of the project directory structure,
  • One or more BUILD files that tell Bazel how to build the different parts of the project.

Two common rules in BUILD files:

  • cc_binary : Indicates that the corresponding file is to be built into a binary file.

    • name: Indicates the name of the file after the build is completed.
    • srcs: Indicates the source files to be built.
    • deps: Indicates the related libraries that the file depends on.
  • cc_library : Indicates that the corresponding files are to be built to become related dependent libraries.

    • hdrs: Indicates the header file path corresponding to the source file.
    • package(default_visibility = [“//visibility: public”]) This code means that the file is public and can be found and relied on by all objects.

TEST1. Build a single package project

process

<1> Create the experimental project directory of this section;
<2> Write BUILD and cyberfile.xml files related to package management
; <3> Write source files and BUILD files; <4> Compile
the code directory;

  1. Create the experimental project directory (learning_cyber) of this section. After the creation is completed, it is as follows
.
├── BUILD
├── cyberfile.xml
├── learning_cyber.BUILD //内容为空
└── test01
    └── demo01
        ├── BUILD
        └── demo01.cc
  1. Write BUILD and cyberfile.xml files related to package management
load("//tools/install:install.bzl", "install", "install_src_files")

install(
    name = "install",
    data = [
        "learning_cyber.BUILD",
        "cyberfile.xml",
    ],
    deps = [
        "//learning_cyber/test01/demo01:install",
    ],
)

install_src_files(
    name = "install_src",
    src_dir = ["."],
    dest = "learning_cyber/src",
    filter = "*",
    deps = [
        "//learning_cyber/test01/demo01:install_src",
    ]
)

PS:
<1>The install rule can install the target defined in the module BUILD file to the local warehouse;
<2>The install_src rule directly installs the file to the local warehouse according to specific rules, and retains the source code directory structure;
<3>When adding a new module When (such as adding a demo02), the deps in the BUILD file should be modified accordingly.

cyberfile.xml

<package>
  <name>learning_cyber</name>
  <version>1.0.0</version>
  <description>
   learning_cyber
  </description>
  <maintainer email="AD-platform">[email protected]</maintainer>
  <type>module</type>
  <src_path>//learning_cyber</src_path>
  <license>BSD</license>
  <author>Apollo</author>
  <depend type="binary"  repo_name="cyber">cyber-dev</depend>
  <builder>bazel</builder>
</package>
  1. Write source files and BUILD files;
    demo01.cc
#include<cyber/cyber.h>

int main(int argc, char const *argv[])
{
    
    
    apollo::cyber::Init(argv[0]);
    AINFO << "hello Apollo";
    AWARN << "hello Apollo";
    AERROR << "hello Apollo";
    AFATAL << "hello Apollo";
    return 0;
}

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 = "demo01",
srcs = ["demo01.cc"],
deps = ["//cyber"], 
)

install(
name = "install",
runtime_dest = "learning_cyber/bin",
targets = [
":demo01"
    ],
)

install_src_files(
name = "install_src",
src_dir = ["."],
dest = "learning_cyber/src/cyberatest",
filter = "*",
)

The compilation rules of cc_binary can be found at https://docs.bazel.build/versions/5.1.0/be/c-cpp.html#cc_binary

  1. Compiled code directory
    Execute the buildtool compilation command in the apollo_workspace directory.
buildtool build -p learning_cyber/

In order to be able to see the results, print the output to the window through the following command, the command is as follows:

export GLOG_alsologtostderr=1
  1. run the executable
cd /opt/apollo/neo/bin

In /opt/apollo/neo/binthe directory, execute the following command:

./demo01

After the execution is complete, you can see the content of "hello Apollo" printed out in the command line window.

insert image description here

A single source code project can meet the needs of small projects, but in actual use, we often want to split larger projects into multiple packages to allow fast incremental builds (that is, rebuild only changed content) Next, We introduce using multiple packages to manage your projects.

TEST2. Build a multi-package project

  1. Manually create according to the following directory structure:
.
├── BUILD
├── cyberfile.xml
├── test_bazel
│   ├── demo_lib
│   │   ├── BUILD
│   │   ├── getName.cc
│   │   └── getName.h
│   └── demo_main
│       ├── BUILD
│       └── main.cc
└── test.BUILD
  1. Write the package management BUILD file and cyberfile.xml
    BUILD file content as follows:
load("//tools/install:install.bzl", "install", "install_src_files")

install(
    name = "install",
    data = [
        "test.BUILD",
        "cyberfile.xml",
    ],
    deps = [
        "//test/test_bazel/demo_main:install",
    ],
)

install_src_files(
    name = "install_src",
    src_dir = ["."],
    dest = "test/src",
    filter = "*",
    deps = [
        "//test/test_bazel/demo_main:install_src",
    ]
)

cyberfile.xml

<package>
  <name>test</name>
  <version>1.0.0</version>
  <description>
   test component
  </description>
  <maintainer email="AD-platform">[email protected]</maintainer>
  <type>module</type>
  <src_path>//test</src_path>
  <license>BSD</license>
  <author>Apollo</author>
  <depend type="binary" repo_name="cyber">cyber-dev</depend>
  <builder>bazel</builder>
</package>
  1. Write the source file and BUILD file
    Write the demo_lib library to implement the get_name function, obtain the input of the string and splice it with "Hello".

getName.h

#pragma once
#include <string>
using namespace std;

string get_name(const string& name);

getName.cc

#include "getName.h"
string get_name(const string& name){
    
    
    return "Hello" + name;
}

After the source code is written, build the getName.cc source code into the library file getName_lib through the cc_library rule. hdrs indicates the path of the header file corresponding to the source file. The content of the BUILD file of demo_lib is as follows:

load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library")
package(default_visibility = ["//visibility:public"])

cc_library(
    name = "getName_lib",
    srcs = ["getName.cc"],
    hdrs = ["getName.h"]
)

main.cc

#include "test/test_bazel/demo_lib/getName.h"
#include <iostream>

int main()
{
    
    
    for (int i = 0; i< 5; ++i)
    {
    
    
        std::cout << get_name(" Apollo ") << std::endl;
    }
    return 0;
}

The BUILD file of demo_main
compiles main.cc to build the executable file main through cc_binary configuration, and deps indicates the relevant libraries that the file depends on.

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 = "main",
    srcs = ["main.cc"],
    deps = ["//test/test_bazel/demo_lib:getName_lib"], 
)

install(
    name = "install",
    runtime_dest = "test/bin",
    targets = [
        ":main"
    ],
)

install_src_files(
    name = "install_src",
    src_dir = ["."],
    dest = "test/src/cyberatest",
    filter = "*",
)
  1. Compiled code directory
    Execute the buildtool compilation command in the apollo_workspace directory.
buildtool build -p cyber_demo
  1. run the executable
cd /opt/apollo/neo/bin
export GLOG_alsologtostderr=1
./main

You can also cd to bazel-bin to view

insert image description here

insert image description here

Basic Concept 2

For more information on this part, please refer to Chapter 2: Analysis and Practice of Cyber ​​RT Communication Mechanism https://apollo.baidu.com/community/article/1094

topic communication

insert image description here

  1. The Listener-Talker communication first creates two Nodes, namely the Talker Node and the Listener Node.
  2. Each Node instantiates the Writer class and the Reader class to read and write messages to the Channel.
  3. Writer and Reader are connected through Topic to read and write to the same shared memory (Channel).

The topic communication method is suitable for the application scenarios of continuous communication, such as the transmission of data such as radar signals and camera image information.

service communication

insert image description here
In Server-Client communication, when the client sends a message request, the server responds to the request and returns the data required by the client to the client. This communication mode is suitable for temporary message transmission and for scenarios that do not require continuous data transmission.

parameter communication

insert image description here
A communication mode that realizes data interaction between different nodes in a shared manner . The parameter server is implemented based on services, including client and server. The server node can store data, and the client node can access the operation data of the server node. Although this process is based on request response, there is no need to implement request and response by yourself. The process has been encapsulated, and the caller only needs to use a relatively simple and friendly API to implement parameter operations. Store these parameters in a way similar to "global variables", and define some custom parameters for use.

Data Communication Basics Protobuf

Introduction to Protobuf

Protobuf is a cross-language and platform serialized data structure developed by Google. It is a flexible and efficient protocol for serializing data. Compared with XML and JSON formats, Protobuf is smaller, faster, and more convenient. Its advantages are as follows:

  • High performance efficiency: After serialization, the space occupied by bytes is 3-10 times less than that of XML, and the time efficiency of serialization is 20-100 times faster than that of XML.
  • Convenient and convenient to use: the operation of structured data is encapsulated into a class, which is easy to use.
  • High compatibility: Both communication parties use the same data protocol. When one party modifies the data structure, it will not affect the use of the other party.
  • Cross-language: Support Java, C++, Python, Go, Ruby and other languages.

Protobuf file writing

Protobuf consists of several parts:

  • syntax : Indicates the version of Protobuf used, currently Protobuf supports proto3, but proto2 is used in Apollo;
  • package: Indicates the path of the file;
  • message: Indicates a data structure, the message is followed by the name of the data structure, and the format of the field definition in brackets is: field rule data type field name field number.
    There are three main types of field rules
  • required: The value of this field must be provided when calling, otherwise the message is considered "uninitialized", which is not officially recommended, and there will be compatibility issues when changing the field rule to other rules.
  • optional: The value of this field can be set or not set, and a default value will be generated according to the data type.
  • repeated: Similar to a dynamic array, it can store multiple data of the same type.

Protobuf compilation

The compilation of Protobuf is divided into two steps:

  • First, generate the proto library according to the .proto file;
  • Then generate C++ related source files according to the produced proto library.
    This source file is automatically written in C++ language and can be automatically recognized by C++ programs. Each message will be parsed to generate a class, and the fields in it are equivalent to the attributes of this class. Additional members are also generated in source files based on properties, such as functions to get and set properties.

TEST3. protobuf experiment

Use Protobuf to define the data format, set the data value in the main program and output it.

<1> Create the experimental project directory of this section
<2> Write the BUILD and cyberfile.xml files related to Apollo package management
<3> Write the proto file and BUILD file;
<4> Write the main code and BUILD file:
<5> Compile the code directory
<6> run executable

<1> Create the experimental project directory of this section:

cyber_demo
|-- cyber_03
    |-- proto
        |-- BUILD
        |-- car_msg.proto
    |-- test_proto
        |-- BUILD
        |-- car.cc
|--BUILD
|--cyberfile.xml
|--cyber_demo.BUILD

PS: You can also manually create the cyber03 folder and the files under it directly in the previously created folder and modify the cyberfile.xml and BUILD files.

<2> Write BUILD and cyberfile.xml files related to Apollo package management

BUILD file content:

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",
    ]
)

If you add to the previously created folder, you only need to modify and add the deps in install and install_src_files.

Write cyberfile :

<package>
  <name>cyber_demo</name>
  <version>1.0.0</version>
  <description>
   cyber_demo
  </description>
  <maintainer email="AD-platform">[email protected]</maintainer>
  <type>module</type>
  <src_path>//cyber_demo</src_path>
  <license>BSD</license>
  <author>Apollo</author>
  <depend type="binary" src_path="//cyber" repo_name="cyber">cyber-dev</depend>
  <depend lib_names="protobuf" repo_name="com_google_protobuf">3rd-protobuf-dev</depend>
  <builder>bazel</builder>
</package>

Compared with the previous experiment, there is one more sentence <depend lib_names="protobuf" repo_name="com_google_protobuf">3rd-protobuf-dev</depend>, adding protobuf-related dependencies.

<3> Write the proto source file and BUILD file;
write the proto file, which defines the vehicle information:

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;
}

Write proto's BUILD file:

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"],
)

Code analysis:

  • We use the BUILD file of the Bazel build system to generate the proto library and related source files.
  • First, a proto library called "car_msg_proto" is defined by the proto_library rule, which uses "car_msg.proto" as the source file.
  • Then, a source file generation rule named "car_msg_cc_proto" is defined through the cc_proto_library rule. It depends on the "car_msg_proto" library and uses this library to generate the relevant C++ source files.
  • The names in these rules are arbitrary and you can change them as needed.

<4> Write the main code and BUILD file
to output the basic information of the vehicle through car.cc:

#include "test/cyber_03/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;
}

Edit the BUILD file of car.cc:

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/cyber_03/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 = "*",
)

Modify the deps path in cc_binary

<5> Compile the code

cd /apollo_workspace
buildtool build -p test

<6> Run the executable file

cd /opt/apollo/neo/bin/
./car

result

owner:apollo
license_plate:京A88888
max_passenger:6
SUV Red electric 

TEST4.C++ topic communication practice case

For the file structure, refer to Chapter 2 of the document: Analysis and Practice of Cyber ​​RT Communication Mechanism https://apollo.baidu.com/community/article/1094

/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> proto file writing

// 定义proto使用的版本
syntax = "proto2";

//定义包名,在cc文件中调用(重名需更改)
package apollo.cyber.example.proto;

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

BUILD file

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_proto",
    srcs = ["car.proto"],
)

cc_proto_library(
    name = "car_cc_proto",
    deps = [":car_proto"],
)

<2> Write talker.cc in source files and BUILD files

//头文件引用
#include "test/communication/proto/car.pb.h" //注意路径
#include "cyber/cyber.h"
#include "cyber/time/rate.h"

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

#include "test/communication/proto/car.pb.h" //注意路径
#include "cyber/cyber.h"

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

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/communication/proto:car_cc_proto",
    ],
    linkstatic = True,
)

cc_binary(
    name = "listener",
    srcs = ["listener.cc"],
    deps = [
        "//cyber",
        "//test/communication/proto:car_cc_proto",
    ],
    linkstatic = True,
)

install(
    name = "install",
    runtime_dest = "test/bin",
    targets = [
        ":talker",
        ":listener"
    ],
)

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

<3> The BUILD file deps of the package management is modified, which is consistent with the previous steps.
<4> Compile

buildtool build -p test/

<5>Run
First, change the output method to console output.

export GLOG_alsologtostderr=1

Open two terminals and enter Apollo's docker environment. One terminal runs talker and the other runs listener. You will find that after the listener runs, it starts to receive the message of the car speed sent by talker.

# 运行talker
 ./bazel-bin/test/communication/cyber_test/talker
 # 运行listener
 ./bazel-bin/test/communication/cyber_test/listener

output result:
insert image description here

TEST5.C++ service communication practice case

<1> The proto file
has been written in TEST4, so there is no need to write it again.
<2> Source file and BUILD file are written
server.cc

#include "test/communication/proto/car.pb.h" //注意路径
#include "cyber/cyber.h"

//car数据定义的引用,可以看出其定义来源于一个proto
using apollo::cyber::example::proto::Car;

int main(int argc, char* argv[]) {
    
    
    apollo::cyber::Init(argv[0]);
    std::shared_ptr<apollo::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.cc

#include "test/communication/proto/car.pb.h" //注意路径
#include "cyber/cyber.h"

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

BUILD file

// 加上server 和 client
cc_binary(
    name = "server",
    srcs = ["server.cc"],
    deps = [
        "//cyber",
        "//test/communication/proto:car_cc_proto",
    ],
    linkstatic = True,
)

cc_binary(
    name = "client",
    srcs = ["client.cc"],
    deps = [
        "//cyber",
        "//test/communication/proto:car_cc_proto",
    ],
    linkstatic = True,
)
// 加上 server和client
install(
    name = "install",
    runtime_dest = "test/bin",
    targets = [
        ":talker",
        ":listener",
        ":client",
        ":server",
    ],
)

<3> The BUILD file deps modification of the package management is consistent with the previous steps (if TEST4 has been performed here, there is no need to change).
<4> Compile

buildtool build -p test/

<5>Run
First, change the output method to console output.

export GLOG_alsologtostderr=1

Open two terminals respectively, run server and client

# 运行server
./bazel-bin/test/communication/cyber_test/server
# 运行client
./bazel-bin/test/communication/cyber_test/client

output result:
insert image description here

TEST6.C++ parameter server communication practice case

<1> Write source files and BUILD file
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_ptr<apollo::cyber::Node> client_node =
      apollo::cyber::CreateNode("parameters_client");
    auto param_client = std::make_shared<ParameterClient>(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;
}

param_server.cc

#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_ptr<apollo::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<ParameterServer>(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;
}

BUILD
adds the following on the original basis:

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

cc_binary(
    name = "param_client",
    srcs = ["param_client.cc"],
    deps = [
        "//cyber",
        "//cyber/parameter",
    ],
    linkstatic = True,
)

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

<2> Package management BUILD (no need to change)
<3> Compile

buildtool build -p test/

<4>Run
First, change the output method to console output.

export GLOG_alsologtostderr=1

Run param_server and param_client in two terminals respectively

./bazel-bin/test/communication/cer_test/param_server
./bazel-bin/test/communication/ber_test/param_client

Output result:
insert image description here

reference

[1] Apollo Spark Project Study Notes - Lecture 3 (Apollo Cyber ​​RT Module Detailed Explanation and Practice) https://blog.csdn.net/sinat_52032317/article/details/126924375
[2] Cyber ​​RT Basic Introduction and Practice https: //apollo.baidu.com/community/article/1093
[3] Chapter 2: Analysis and Practice of Cyber ​​RT Communication Mechanism https://apollo.baidu.com/community/article/1094

Guess you like

Origin blog.csdn.net/sinat_52032317/article/details/131878429