cyberRT启动
cyberRT的launch也是封装了mainboard模块
mainboard 功能:解析配置参数,加载相应的动态库文件
minaboard模块中一共有五个文件,两个类(module_argument、module_controller)和一个主文件mainboard.cc
类:
using apollo::cyber::mainboard::ModuleArgument;
using apollo::cyber::mainboard::ModuleController;
文件
mainboard.cc 主函数-入口函数
module_argument.h : 解析启动参数,即 $ mainboard -p … -d … -s … module_argument.cc
module_controller.h : 加载共享库,调用ClassLoaderManager加载类 module_controller.cc
###判断条件也是执行的一部分
### 如果条件为真(即非零值),则执行if语句后的代码块;如果条件为假(即零值),则跳过该代码块
###01. C++ 中关注if的条件,很多模块代码返回值是true或者false--所以条件中会有执行的逻辑
###02. .emplace_back
直接插入 已经存在对象时,emplace_back和push_back两个方法都是调用了 的左值引用的拷贝构造函数,
直接插入 临时对象时,emplace_back和push_back两个方法都是调用了Test的右值引用的拷贝构造函数,都做了资源转移,两者无区别。
for (auto module_path:paths){
AINFO << "" << module_path;
if(!LoadModule(moodule_path)){
AERROR << "" <<module_path;
}
return true;
}
工厂模式-- Component实例时 会调用工厂类的 CreateClassObj 来返回实例
std::vector<std::shared_ptr<ComponentBase>> componenet_list_;
class_loader::ClassLoaderManager class_loader_manager_;
1.抽象产品-Abstract Product
class ComponentBase
class Component : public ComponentBase{}
#define CYBER_REGISTER_COMPONENT(name) CLASS_LOADER_REGISTER_CLASS(name,apollo::cyber::ComponentBase)
class TimerComponent: public ComponentBase{}
2.具体产品
,在modules/xxx/xxx_component.h中的最后都会有一句 CYBER_REGISTER_COMPONENT(XxxComponent)
,class CommonComponentSample :public Component<> { } CYBER_REGISTER_COMPONENT(CommonComponentSample)
, class TimerComponentSample :public TimerComponent {} CYBER_REGISTER_COMPONENT(TimerComponentSample)
3.抽象工程-Factory: AbstractClassFactoryBase 子类AbstractClassFactory可以视为Factory (cyber/class_loader/utility/class_factory.h
4.具体工厂 FactoryA/B:ClassFactory 。代码位于(cyber/class_loader/utility/class_factory.h);
client-module_contriller.cc:
for(auto& component:module_config.components()){
}
for(auto& component:module_config.timer_components()){
}
const std::string$class_nmae = component.class_name();
std::shared_ptr<ComponentBase> base = class_loader_manager_.CreateClassObj<ComponentBase>(class_name);
if(base == nullptr || ! base->Initialize(component.config() ) ){return false;}
component_list_.emplace_back(std::move(base))
引入了动态库的加载
ClassLoader
class_factory.h
class ClassFactoryBase
class AbstractClassFactory : public ClassFactoryBase
class ClassFactory : public AbstractClassFactory
class_loader_utility.cc
using BaseToClassFactoryMapMap= map<string,map<string,utility::AbstractClassFactoryBase*>> ;
RegisterClass
apollo::cyber::class_loader::utility::ClassFactory<apollo::xxx::XxxComponent, apollo::cyber::ComponentBase >
apollo::cyber::class_loader::utility::ClassFactory<apollo::xxx::XxxComponent, apollo::cyber::ComponentBase >
class_loader_register_macro.h
apollp::cyber::class_loader::utility::RegisterClass
#define CLASS_LOADER_REGISTER_CLASS_INTERNAL
#define CLASS_LOADER_REGISTER_CLASS
class_loader.h
#include "class_loader_register_macro.h"
ClassLoader
判断动态库是否已经加载IsLibraryLoaded,这个函数最后会调用到utility::IsLibraryloaded
class_loader_manager.h 用来管理ClassLoader的
动态库的加载入口为ClassLoaderManager::LoadLibrary(const std::string& library_path)
ClassLoaderManager::CreateClassObj()
ClassLoader::CreateClassObj()
实现类的加载、卸载以及管理功能,如类的注册、注销等。
Protobuf
动态加载 .pb 文件并发送 Protobuf 消息
方式一:
根据proto文件编译生成的类来反序列化消息
方式二:
ProtoBuf提供了动态解析机制-动态解析,
就是消费者不根据proto文件编译生成的类来反序列化消息,
而是通过proto文件生成的descriptor来构造动态消息类,然后反序列化(解析)消息
通过proto文件生成的descriptor来构造动态消息类,然后反序列化(解析)消息
ProtoBuf提供了动态解析机制,
它要求提供二进制内容的基础上,
再提供对应类的Descriptor对象,在解析时通过 DynamicMessage类的成员方法来获得对象结果
常用的方式
1. 生产者:通过proto文件编译产生的类构造一个消息(byteArray数组);
消费者:1)根据proto文件生成descriptor文件;2)创建DynamicMessage类解析消息(byteArray数组);
ProtoBuf的反射机制 FileDescriptor – 用来描述 文件 Descriptor – 用来描述 消息
.cyber/message/protobuf_factory.h
protobuf_factory 系列(头文件、实现文件、测试文件、traits文件):
对消息进行注册和查询,注册主要包括消息、消息描述、消息文件描述等,注册之后就可以根据上述任一值查询到其他值。
2.message
message_header :消息头,序列化的时候将次头放在protobuf形成的内存前面,主要记录一些属性值,比如消息序列号、消息体的大小等,
message_traits
protbuf_traits.h
RawMessage ,原始消息 由文件raw_message实现,为了统一规范,该类实现了类似protobuf实现的接口函数
PyMessageWrap py_message文件 用于python使用cyber通讯的消息体
消息传递方式三种: ShmTransmitter
消息格式主要分为两大类,
通用(Common)消息格式各模块通用的消息格式,如定义时间的时间戳消息格式、错误代码消息格式。
特定模块消息格式各模块独有的消息格式。
类型 traits 是一组模板类或函数,用于在编译时期获取或修改类型的信息。 特化 是实现类型traits的关键
用来为同一类数据(包括自定义数据类型和内置数据类型)提供统一的操作函数
方案一:函数重载 首先想到的方法就是函数重载,对于不同的数据类型提供不同的编码函数实现
方案二:模板函数+内置字段 使用模板函数来实现,自定义数据类型中定义类型字段,然后在函数中进行判断
方案三:traits 模板类 板类的特化为自定义类型生成独有的 type_traits
利用模板特化的功能,实现对自定义数据和编译器内置数据的统一 tratis 技术常见于标准库的实现中,但对日常开发中降低代码冗余也有很好的借鉴意
模板特化(Template Specialization) traits 使用的关键技术 —— 模板的特化与偏特化。
函数,类或者一些封装的通用算法中的某些部分会因为数据类型不同而导致处理或逻辑不同
(而我们又不希望因为数据类型的差异而修改算法本身的封装时),traits会是一种很好的解决方案。
3.cyber/transport/message/message_info.h
模板特化-message
模板
message_traits.h
intra_dispatcher.h
shm_dispatcher.h
rtps_dispatcher.h
shm_transmitter.h
rtps_transmitter.h
cyber_topology_mesage.cc
channel_manager
manager
node_channel_impl.h
impl是“implementation”(实现)的缩写,指在编程中用于具体实现接口或抽象类的类。这类类通过提供抽象方法的具体逻辑