記事ディレクトリ
序文
サイバーの基本的な紹介についてはインターネット上に多数の記事があるため、この記事では繰り返しません。この記事では、主にサイバー基盤の実装と通信関連の例に焦点を当てています。
コースアドレス: https://apollo.baidu.com/community/course/outline/329?activeId=10200
詳細については、次を参照してください:
[1 】アポロ スパーク プロジェクト学習ノート ——第3回講義(アポロ サイバーRTモジュール詳細説明と実戦)https://blog.csdn.net/sinat_52032317/article/details/126924375
[2]第1章:サイバーRTの基礎入門と実践https://apollo.baidu.com/community/article/1093 [TEST1 & TEST2]
[3]第2章:サイバーRTコミュニケーションメカニズムの分析と実践https://apollo.baidu.com /community/article/1094 [TEST3 & TEST4 & TEST5 & TEST6]関連コードの仕上げ
リンク: https://pan.baidu.com/s/1ENgXE4yQ1v4nJRjcfZtd8w?pwd=ht4c抽出コード: ht4c
基本的な考え方1
この部分の詳細については、第 1 章: サイバー RT の基本的な導入と実践https://apollo.baidu.com/community/article/1093を参照してください。
サイバー入門
Apollo Cyber は、自動運転用にカスタマイズされた初の高性能かつオープンソースのリアルタイム通信フレームワークであり、主に自動運転システムにおける高同時実行性、低遅延、高スループット、タスク スケジューリングの問題を解決し、また、さまざまな通信メカニズム、およびユーザーレベルのコルーチンは、リソースが限られている場合、タスクの優先度に従ってスケジュールされます。
コミュニケーション構成
ノードは Cyber の基本構造であり、各モジュールには Node ノードが含まれ、モジュールは Node ノードを介して通信します。ノード間の通信は、 や などのさまざまなモードで設定できReader/Writer
ますService/Client
。
Cyber は分散システムを使用しており、ノードはトポロジによって管理されます。各ノードはこのトポロジ グラフの頂点であり、各ノードの頂点はチャネルまたはサービスを通じて接続されます。ノードノードは分散化されており、ノードの追加と削除を動的に監視できます。チャネルは共有メモリの一部として理解でき、共有メモリの通信方法により通信効率が大幅に向上します。
バゼルの紹介
Apollo は、コンパイルに Bazel を使用します。Bazel は、Google によって開発されたオープンソースのビルドおよびテスト ツールであり、シンプルで読みやすいビルド ツールでもあります。その利点は次のとおりです。
- Bazel は必要なものだけを再構築します。高度なローカルおよび分散キャッシュ、最適化された依存関係分析、並列実行により、高速かつ増分ビルドを実現します。
- Java、C++、Android、iOS、その他のさまざまな言語プラットフォームを構築してテストします。Bazel は Windows、macOS、Linux 上で動作します。
- Bazel は、組織、コード ベース、継続的統合システムの拡張に役立ちます。あらゆるサイズのコードベースを処理できます。
Bazel プロジェクトの構造は次のようになります。
project
|-- pkg
| |-- BUILD
| |-- src.cc
|-- WORKSPACE
WORKSPACE
ディレクトリとその内容を Bazel ワークスペースとして識別し、プロジェクトのディレクトリ構造のルートに配置されるファイル、- Bazel にプロジェクトのさまざまな部分をビルドする方法を指示する 1 つ以上の BUILD ファイル。
BUILD ファイルの 2 つの一般的なルール:
-
cc_binary : 対応するファイルがバイナリ ファイルに組み込まれることを示します。
- name: ビルド完了後のファイルの名前を示します。
- srcs: ビルドするソースファイルを示します。
- deps: ファイルが依存する関連ライブラリを示します。
-
cc_library : 対応するファイルが、関連する依存ライブラリとなるようにビルドされることを示します。
- hdrs: ソースファイルに対応するヘッダファイルのパスを示します。
- package(default_visibility = [“//visibility: public”]) このコードは、ファイルがパブリックであり、すべてのオブジェクトによって見つけられ、信頼できることを意味します。
TEST1. 単一パッケージプロジェクトをビルドする
プロセス
<1> このセクションの実験プロジェクト ディレクトリを作成します; |
- 本節の実験プロジェクトディレクトリ(learning_cyber)を作成 作成完了後は以下のようになります
.
├── BUILD
├── cyberfile.xml
├── learning_cyber.BUILD //内容为空
└── test01
└── demo01
├── BUILD
└── demo01.cc
- パッケージ管理に関連するBUILDおよび cyberfile.xml ファイルを作成します。
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: |
サイバーファイル.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>
- ソースファイルとBUILDファイルを書き込みます;
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;
}
建てる
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 = "*",
)
cc_binary のコンパイル ルールは、 https://docs.bazel.build/versions/5.1.0/be/c-cpp.html#cc_binaryにあります。
- コンパイルされたコード ディレクトリ
apollo_workspace ディレクトリで buildtool コンパイル コマンドを実行します。
buildtool build -p learning_cyber/
結果を確認するには、次のコマンドを使用して出力をウィンドウに出力します。コマンドは次のとおりです。
export GLOG_alsologtostderr=1
- 実行可能ファイルを実行する
cd /opt/apollo/neo/bin
/opt/apollo/neo/bin
ディレクトリで次のコマンドを実行します。
./demo01
実行が完了すると、コマンド ライン ウィンドウに「hello Apollo」の内容が出力されることがわかります。
単一のソース コード プロジェクトで小規模プロジェクトのニーズを満たすことができますが、実際の使用では、高速な増分ビルド (つまり、変更されたコンテンツのみをリビルド) を可能にするために、大きなプロジェクトを複数のパッケージに分割することがよくあります。 次に、複数のパッケージを使用して、プロジェクトを管理します。
TEST2. マルチパッケージプロジェクトをビルドする
- 次のディレクトリ構造に従って手動で作成します。
.
├── BUILD
├── cyberfile.xml
├── test_bazel
│ ├── demo_lib
│ │ ├── BUILD
│ │ ├── getName.cc
│ │ └── getName.h
│ └── demo_main
│ ├── BUILD
│ └── main.cc
└── test.BUILD
- パッケージ管理 BUILD ファイルと cyberfile.xml
BUILDファイルの内容を次のように記述します。
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",
]
)
サイバーファイル.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>
- ソース ファイルと BUILD ファイルを作成し
、get_name 関数を実装するためのdemo_lib ライブラリを作成し、文字列の入力を取得して「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;
}
ソースコードを記述した後、cc_library ルールに従って getName.cc のソースコードをライブラリファイル getName_lib にビルドします (hdrs はソースファイルに対応するヘッダファイルのパスを示します。demo_lib の BUILD ファイルの内容は次のとおりです)。
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;
}
demo_main の BUILD ファイルは、
main.cc をコンパイルして、cc_binary 構成を通じて実行可能ファイル main をビルドします。deps は、ファイルが依存する関連ライブラリを示します。
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 = "*",
)
- コンパイルされたコード ディレクトリ
apollo_workspace ディレクトリで buildtool コンパイル コマンドを実行します。
buildtool build -p cyber_demo
- 実行可能ファイルを実行する
cd /opt/apollo/neo/bin
export GLOG_alsologtostderr=1
./main
bazel-bin に cd して表示することもできます
基本的な考え方2
この部分の詳細については、第 2 章: サイバー RT 通信メカニズムの分析と実践https://apollo.baidu.com/community/article/1094を参照してください。
トピックコミュニケーション
- リスナーとトーカーの通信では、まずトーカー ノードとリスナー ノードという 2 つのノードが作成されます。
- 各ノードは、チャネルに対してメッセージを読み書きするために Writer クラスと Reader クラスをインスタンス化します。
- Writer と Reader はトピックを介して接続され、同じ共有メモリ (チャネル) の読み取りと書き込みを行います。
トピック通信方式は、レーダー信号やカメラ画像情報などのデータ伝送など、継続的に通信を行うアプリケーションシナリオに適しています。
サービスコミュニケーション
サーバークライアント通信では、クライアントがメッセージリクエストを送信すると、サーバーはそのリクエストに応答し、クライアントが必要とするデータをクライアントに返します。この通信モードは、一時的なメッセージ送信や継続的なデータ送信を必要としないシナリオに適しています。
パラメータ通信
異なるノード間でデータのやりとりを共有的に実現する通信方式。パラメータサーバーは、クライアントとサーバーを含むサービスをベースに実装されます。サーバーノードはデータを保存し、クライアントノードはサーバーノードの操作データにアクセスできます。この処理はリクエストとレスポンスをベースにしていますが、リクエストとレスポンスを独自に実装する必要はありませんプロセスはカプセル化されているため、呼び出し元は比較的シンプルで使いやすい API を使用するだけでパラメータ操作を実装できます。これらのパラメータを「グローバル変数」と同様の方法で保存し、使用するカスタム パラメータを定義します。
データ通信の基礎 Protobuf
Protobuf の概要
Protobuf は、Google が開発したクロス言語およびプラットフォームでシリアル化されたデータ構造です。データをシリアル化するための柔軟かつ効率的なプロトコルです。XML 形式や JSON 形式と比較して、Protobuf は小さく、高速で、より便利です。その利点は次のとおりです。
- 高いパフォーマンス効率: シリアル化後、バイトが占めるスペースは XML の 3 ~ 10 分の 1 であり、シリアル化の時間効率は XML の 20 ~ 100 倍高速です。
- 便利で使いやすい: 構造化データの操作はクラスにカプセル化されており、使いやすいです。
- 高い互換性: 双方の通信者が同じデータプロトコルを使用するため、一方がデータ構造を変更しても、もう一方の使用には影響しません。
- クロス言語: Java、C++、Python、Go、Ruby およびその他の言語をサポートします。
Protobufファイルの書き込み
Protobuf はいくつかの部分で構成されています。
- syntax : 使用されている Protobuf のバージョンを示します。現在 Protobuf は proto3 をサポートしていますが、Apollo では proto2 が使用されています。
- package: ファイルのパスを示します。
- メッセージ: データ構造を示します。メッセージの後にデータ構造の名前が続きます。括弧内のフィールド定義の形式は次のとおりです: フィールド ルール データ タイプ フィールド名 フィールド番号。
フィールド ルールには主に 3 つのタイプがあります - required: 呼び出し時にこのフィールドの値を指定する必要があります。そうでない場合、メッセージは「初期化されていない」と見なされますが、これは公式には推奨されていません。また、フィールド ルールを他のルールに変更するときに互換性の問題が発生します。
- オプション: このフィールドの値は設定することも設定しないこともでき、データ型に応じてデフォルト値が生成されます。
- 繰り返し: 動的配列と同様に、同じタイプの複数のデータを格納できます。
プロトバッファのコンパイル
Protobuf のコンパイルは 2 つのステップに分かれています。
- まず、.proto ファイルに従って proto ライブラリを生成します。
- 次に、作成した proto ライブラリに基づいて C++ 関連のソース ファイルを生成します。
このソース ファイルは C++ 言語で自動的に記述され、C++ プログラムによって自動的に認識されます。各メッセージは解析されてクラスが生成され、その中のフィールドはこのクラスの属性に相当します。追加のメンバーも、プロパティを取得および設定する関数などのプロパティに基づいてソース ファイル内に生成されます。
TEST3. protobuf 実験
Protobuf を使用してデータ形式を定義し、メインプログラムにデータ値を設定して出力します。
<1> このセクションの実験プロジェクト ディレクトリを作成します |
<1> このセクションの実験プロジェクト ディレクトリを作成します。
cyber_demo
|-- cyber_03
|-- proto
|-- BUILD
|-- car_msg.proto
|-- test_proto
|-- BUILD
|-- car.cc
|--BUILD
|--cyberfile.xml
|--cyber_demo.BUILD
PS: 以前に作成したフォルダー内に cyber03 フォルダーとその下のファイルを手動で直接作成し、cyberfile.xml および BUILD ファイルを変更することもできます。
<2> Apollo パッケージ管理に関連する BUILD および cyberfile.xml ファイルを作成する
ビルドファイルの内容:
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",
]
)
以前に作成したフォルダーに追加する場合は、install および install_src_files の deps を変更して追加するだけで済みます。
サイバーファイルを書き込みます:
<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>
前の実験と比較すると、文が 1 つ増え <depend lib_names="protobuf" repo_name="com_google_protobuf">3rd-protobuf-dev</depend>
、protobuf 関連の依存関係が追加されています。
<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"],
)
コード分析:
- Bazel ビルド システムの BUILD ファイルを使用して、プロト ライブラリと関連ソース ファイルを生成します。
- まず、「car_msg_proto」というプロト ライブラリが proto_library ルールによって定義され、「car_msg.proto」をソース ファイルとして使用します。
- 次に、cc_proto_library ルールによって「car_msg_cc_proto」という名前のソース ファイル生成ルールが定義されます。これは「car_msg_proto」ライブラリに依存しており、このライブラリを使用して関連する C++ ソース ファイルを生成します。
- これらのルールの名前は任意であり、必要に応じて変更できます。
<4> car.cc を通じて車両の基本情報を出力するメイン コードと BUILD ファイルを記述します。
#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;
}
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/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 = "*",
)
cc_binary の deps パスを変更します。
<5> コードをコンパイルする
cd /apollo_workspace
buildtool build -p test
<6> 実行ファイルを実行する
cd /opt/apollo/neo/bin/
./car
結果
owner:apollo
license_plate:京A88888
max_passenger:6
SUV Red electric
TEST4.C++ トピックコミュニケーションの実践例
ファイル構造については、ドキュメントの第 2 章を参照してください: サイバー RT 通信メカニズムの分析と実践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ファイルの書き込み
// 定义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;
};
ビルドファイル
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>ソースファイルとBUILDファイルに
talker.ccを記述する
//头文件引用
#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;
}
リスナー.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 は
パスの変更を通知します
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> パッケージ管理の BUILD ファイル deps が変更され、前の手順と一致します。
<4> コンパイルします。
buildtool build -p test/
<5>実行
まず出力方法をコンソール出力に変更します。
export GLOG_alsologtostderr=1
2 つのターミナルを開き、Apollo の Docker 環境に入ります。1 つのターミナルは talker を実行し、もう 1 つのターミナルは listen を実行します。リスナーが実行された後、talker から送信された車の速度のメッセージの受信を開始することがわかります。
# 运行talker
./bazel-bin/test/communication/cyber_test/talker
# 运行listener
./bazel-bin/test/communication/cyber_test/listener
出力結果:
TEST5.C++ サービス通信の実践例
<1> protoファイルは
TEST4で書き込まれているので再度書き込む必要はありません<2> ソースファイルとBUILDファイルを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;
}
ビルドファイル
// 加上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>パッケージ管理の BUILD ファイルの deps 変更は、前の手順と一致します (ここで TEST4 が実行されている場合は、変更する必要はありません)。
buildtool build -p test/
<5>実行
まず出力方法をコンソール出力に変更します。
export GLOG_alsologtostderr=1
2 つのターミナルをそれぞれ開き、サーバーとクライアントを実行します
# 运行server
./bazel-bin/test/communication/cyber_test/server
# 运行client
./bazel-bin/test/communication/cyber_test/client
出力結果:
TEST6.C++パラメータサーバー通信の実践例
<1> ソースファイルとBUILDファイル
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 &¶meter : 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 は、
元のベースに以下を追加します。
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> パッケージ管理 BUILD (変更不要)
<3> コンパイル
buildtool build -p test/
<4>実行
まず出力方法をコンソール出力に変更します。
export GLOG_alsologtostderr=1
2 つの端末でそれぞれ param_server と param_client を実行します
./bazel-bin/test/communication/cer_test/param_server
./bazel-bin/test/communication/ber_test/param_client
出力結果:
参考
[1] Apollo Spark プロジェクト学習ノート - 講義 3 (Apollo Cyber RT モジュールの詳細な説明と実践) https://blog.csdn.net/sinat_52032317/article/details/126924375
[2] Cyber RT の基礎入門と実践https://apollo.baidu.com/community/article/1093
[3]第2章:サイバーRT通信メカニズムの分析と実践https://apollo.baidu.com/community/article/1094