以scripts/camera.sh脚本为例,若要启用camera,只需要执行该脚本即可
查看内容,在start()中调用了cyber_launch start /apollo/modules/drivers/camera/launch/camera.launch
cyber_launch就是cyber\tools\cyber_launch\cyber_launch py脚本文件,它是何时加载的呢?
在camera.sh Line24, source "${DIR}/apollo_base.sh"
配置了基本的环境,而且执行了source /apollo/cyber/setup.bash
,其中就把cyber_launch加入了PATH中,这样就可找到了
先看camera.launch文件里的内容有哪些:
<cyber>
<module>
<name>camera</name>
<dag_conf>/apollo/modules/drivers/camera/dag/camera.dag</dag_conf>
<process_name>usb_cam</process_name>
</module>
</cyber>
沿用了ros1的xml格式,自定义了模块名,以及配置文件dag_conf
cyber\tools\cyber_launch\cyber_launch中的start方法中,关键代码:
if process_name not in process_list:
if process_type == 'binary':
pw = ProcessWrapper(
process_name.split()[0], 0, [
""], process_name, process_type,
exception_handler)
# Default is library
else:
pw = ProcessWrapper(
g_binary_name, 0, dag_dict[
str(process_name)], process_name,
process_type, sched_name, exception_handler)
result = pw.start()
pmon.register(pw)
process_list.append(process_name)
如果时可执行文件,就用py的多进程直接调起来,如果是lib文件,要通过g_binary_name="mainboard"这个程序来动态加载lib库文件
也就是说,mainboard可执行文件是通用的程序,按照制定的标准api来加载运行lib
源码位置: cyber\mainboard\mainboard.cc
逻辑比较简单,主要是解析参数,然后将参数传入ModuleController的对象,在ModuleController::Init()中会调用ModuleController::LoadAll() -> ModuleController::LoadModule
看下关键代码:
bool ModuleController::LoadModule(const DagConfig& dag_config) {
class_loader_manager_.LoadLibrary(load_path);
for (auto& component : module_config.components()) {
const std::string& class_name = 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));
}
for (auto& component : module_config.timer_components()) {
const std::string& class_name = 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));
}
}
return true;
}
首先会解析出lib的路径,然后通过class_loader_manager_加载动态库,拿到基类指针,并调用基类方法base->Initialize(component.config())
,在基类方法中,调用虚函数Init()和Pross(),利用继承的特性调用到实际加载的lib子类中的初始化方法和处理方法。