Apollo cyber 源码解析—— launch 详解

以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子类中的初始化方法和处理方法。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。