目录结构:
|-- BUILD
|-- proto
| |-- BUILD
| `-- examples.proto
`-- talker.cc
proto文件下:
BUILD
(bazel配置proto)
package(default_visibility = ["//visibility:public"])
#生成两种库,examples_cc_proto和examples_proto
#依赖中冒号是什么意思
cc_proto_library(
name = "examples_cc_proto",
deps = [
":examples_proto",
],
)
proto_library(
name = "examples_proto",
srcs = ["examples.proto"],
)
过程:
源文件examples.proto生成库文件examples_proto,
依赖于库文件examples_proto又生成了examples_cc_proto(推测就是examples.pb.cc和examples.pb.h)。且这个examples.pb.h路径可以通过
zxj_example/proto/examples.pb.h
这个路径与zxj_example相对于apollo文件夹的路径有关
#include "zxj_example/proto/examples.pb.h"
即仿佛examples.pb.h时在本工程zxj_example/proto/下,但是其实并不是,实际在
/home/e301-ai/.cache/bazel/_bazel_e301-ai/540135163923dd7d5820f3ee4b306b32/execroot/apollo/bazel-out/local-fastbuild/genfiles/zxj_example/proto/examples.pb.h
后来的实验事实证明,examples.pb.h这个名字之和proto源文件examples.proto名字有关,和库名字“examples_cc_proto”无关
examples.proto
syntax = "proto2";
package apollo.cyber.examples.proto;
message Chatter
{
optional uint64 timestamp = 1;
optional uint64 lidar_timestamp = 2;
optional uint64 seq = 3;
optional bytes content = 4;
};
这里的
package apollo.cyber.examples.proto;
非常重要
根据Protocol Buffer的官方文档:
package foo.bar;
message Open { ... }
在C ++中,生成的类包装在C ++命名空间中。例如,类Open将在命名空间foo::bar中
同理,Chatter类将在examples.pb.h中apollo::cyber::examples::proto命名空间下
namespace appolo {
namespace cyber {
namespace examples {
namespace proto {
...
与talker.cc并列的BUILD:
load("//tools:cpplint.bzl","cpplint")
package(default_visibility = ["//visibility:public"])
# https://docs.bazel.build/versions/master/be/c-cpp.html#cc_binary
cc_binary(
name = "talker",
srcs = ["talker.cc"],
deps = [
"//cyber",
"//zxj_example/proto:examples_cc_proto",
],
)
cpplint()
通过源文件talker.cc和zxj_example路径下的examples_cc_proto库生成目标talker
talker.cc:
#include "cyber/cyber.h"
#include "zxj_example/proto/examples.pb.h"
#include "cyber/time/rate.h"
#include "cyber/time/time.h"
#include <iostream>
using apollo::cyber::Rate;
using apollo::cyber::Time;
using apollo::cyber::examples::proto::Chatter;
int main(int argc,char** argv)
{
apollo::cyber::Init(argv[0]);
auto talker_node = apollo::cyber::CreateNode("talker");
auto talker = talker_node->CreateWriter<Chatter>("channel/chatter");
Rate rate(1.0);
uint64_t seq = 0;
while (apollo::cyber::OK())
{
auto msg = std::make_shared<Chatter>();
msg->set_timestamp(Time::Now().ToNanosecond());
msg->set_lidar_timestamp(Time::Now().ToNanosecond());
msg->set_seq(seq);
msg->set_content("Hello,apollo!");
talker->Write(msg);
std::cout << "talker sent a message!No. " << seq << std::endl;
seq++;
rate.Sleep();
}
return 0;
}
步骤:
1.初始化
apollo::cyber::Init(argv[0]);
cyber/init.cc
bool Init(const char* binary_name) {
std::lock_guard<std::mutex> lg(g_mutex);
if (GetState() != STATE_UNINITIALIZED) {
return false;
}
InitLogger(binary_name);
auto thread = const_cast<std::thread*>(async_logger->LogThread());
scheduler::Instance()->SetInnerThreadAttr("async_log", thread);
std::signal(SIGINT, OnShutdown);
// Register exit handlers
if (!g_atexit_registered) {
if (std::atexit(ExitHandle) != 0) {
AERROR << "Register exit handle failed";
return false;
}
AINFO << "Register exit handle succ.";
g_atexit_registered = true;
}
SetState(STATE_INITIALIZED);
return true;
}
2.创建发送节点,并指定节点名称
auto talker_node = apollo::cyber::CreateNode("talker");
这里的auto
是 class std::unique_ptr<apollo::cyber::Node>
apollo::cyber::CreateNode()
在cyber/cyber.cc
文件中定义,参数是节点的名字,返回一个指向apollo::cyber::Node
的指针(unique_ptr)。
#include "cyber/cyber.h"
#include <memory>
#include <string>
#include <utility>
#include "cyber/common/global_data.h"
#include "cyber/proto/run_mode_conf.pb.h"
namespace apollo {
namespace cyber {
using apollo::cyber::common::GlobalData;
using apollo::cyber::proto::RunMode;
std::unique_ptr<Node> CreateNode(const std::string& node_name,
const std::string& name_space) {
bool is_reality_mode = GlobalData::Instance()->IsRealityMode();
if (is_reality_mode && !OK()) {
// add some hint log
AERROR << "please initialize cyber firstly.";
return nullptr;
}
std::unique_ptr<Node> node(new Node(node_name, name_space));
return std::move(node);
}
} // namespace cyber
} // namespace apollo
3.利用发送节点定义发送器,并指定话题名称
auto talker = talker_node->CreateWriter<Chatter>("channel/chatter");
这里的auto是class std::shared_ptr<apollo::cyber::Writer<apollo::cyber::examples::proto::Chatter>>
CreateWriter()函数在apollo/cyber/node/node.h中
template <typename MessageT>
auto Node::CreateWriter(const std::string& channel_name)
-> std::shared_ptr<Writer<MessageT>> {
return node_channel_impl_->template CreateWriter<MessageT>(channel_name);
}
4.根据proto文件的message类,定义消息msg
auto msg = std::make_shared<Chatter>();
这里的auto
是class std::shared_ptr<apollo::cyber::examples::proto::Chatter>
(指向Chatter的一个指针)
然后msg
可以通过msg->set_xxx()
调用set_xxx()
一系列API
5.利用Write()函数,通过发送器将消息发送出去
talker->Write(msg);
listener.cc:
#include "cyber/cyber.h"
#include "zxj_example/proto/examples.pb.h"
void MessageCallback(
const std::shared_ptr<apollo::cyber::examples::proto::Chatter> &msg)
{
std::cout << "Received message seq-> " << msg->seq() << ",";
std::cout << "msgcontent->" << msg->content() << std::endl;
}
int main(int argc,char** argv)
{
apollo::cyber::Init(argv[0]);
auto listener_node = apollo::cyber::CreateNode("listener");
auto listener =
listener_node->CreateReader<apollo::cyber::examples::proto::Chatter>(
"channel/chatter",MessageCallback
);
apollo::cyber::WaitForShutdown();
return 0;
}
现象:
ToDo:
研究智能指针原理