Apollo9.0 Planning2.0决策规划算法代码详细解析 (5): OnLanePlanning::Init()

news2024/10/5 21:39:17

🌟 面向自动驾驶规划算法工程师的专属指南 🌟

欢迎来到《Apollo9.0 Planning2.0决策规划算法代码详细解析》专栏!本专栏专为自动驾驶规划算法工程师量身打造,旨在通过深入剖析Apollo9.0开源自动驾驶软件栈中的Planning2.0模块,帮助读者掌握自动驾驶决策规划算法的核心原理与实现细节。

🔍 VSCode+GDB:精准调试,洞悉代码逻辑 🔍

在自动驾驶算法的开发过程中,调试是至关重要的一环。本专栏将带你深入掌握VSCode+GDB这一强大的调试工具组合,让你能够逐行分析代码,精准定位问题,从而洞悉算法背后的逻辑与原理。通过实战演练,你将学会如何高效地利用调试工具,提升代码质量与开发效率。

💻 C++语法同步讲解:构建算法基石 💻

C++作为自动驾驶领域的主流编程语言,其重要性不言而喻。本专栏在解析算法代码的同时,将同步介绍C++语法,从基础到进阶,涵盖数据类型、控制结构、面向对象编程等核心知识点。通过系统学习,你将能够熟练运用C++语言编写高效、可维护的自动驾驶规划算法代码。

🚀 掌握自动驾驶PNC工程师从业能力 🚀

完成本专栏的学习后,你将具备自动驾驶PNC(规划、导航与控制)工程师的从业能力。你将能够深入理解自动驾驶决策规划算法的设计思路与实现方法,掌握Apollo9.0 Planning2.0模块的核心技术,为自动驾驶汽车的智能决策提供有力支持。

🚀 Apollo9.0 Planning2.0:探索自动驾驶技术前沿 🚀

Apollo9.0作为百度开源的自动驾驶软件栈,其Planning2.0模块在决策规划算法方面取得了显著进展。本专栏将带你深入探索Apollo9.0 Planning2.0的奥秘,揭秘其背后的算法原理与实现细节。通过系统学习,你将能够站在自动驾驶技术的前沿,为自动驾驶汽车的未来发展贡献力量。

🎉 立即加入,开启自动驾驶规划算法之旅 🎉

无论你是自动驾驶领域的初学者,还是有一定经验的工程师,本专栏都将为你提供宝贵的学习资源与实战机会。立即加入《Apollo9.0 Planning2.0决策规划算法代码详细解析》专栏,与我们一起探索自动驾驶技术的无限可能,共同推动自动驾驶技术的未来发展!

一、OnLanePlanning模块介绍

Apollo的OnLanePlanning是自动驾驶框架中的一个核心模块,它主要负责在有车道线的道路上进行路径规划。以下是对OnLanePlanning的详细介绍:

1、模块位置与继承关系

  • OnLanePlanning的源代码位于modules\planning\on_lane_planning.h
  • 它继承自PlanningBase类,与NaviPlanning类并列,是Apollo规划模块中的两种主要规划方式之一。

2、初始化与运行

  • OnLanePlanning的初始化逻辑主要在Init函数中实现。该函数负责分配具体的Planner(规划器),并启动参考线提供器(ReferenceLineProvider)。
  • 在初始化过程中,会根据配置文件选择默认的规划器,通常为PublicRoadPlanner。

3、核心功能

  • OnLanePlanning的核心功能是在有车道线的道路上进行路径规划。它基于高精地图和车辆当前状态,生成一条安全且舒适的行驶路径。
  • 该模块会考虑实际临时或移动障碍物,以及速度、动力学约束等因素,尽量按照规划路径进行轨迹规划。
  • OnLanePlanning还包含决策功能,能够根据不同的场景(如红绿灯路口、停车场景等)进行决策,并生成相应的规划轨迹。

4、与其他模块的交互

  • OnLanePlanning的上游模块包括Localization(定位模块)、Prediction(预测模块)和Routing(路由模块)。这些模块为OnLanePlanning提供必要的输入信息,如车辆当前位置、障碍物预测信息和全局路线指引等。
  • OnLanePlanning的下游模块是Control(控制模块)。它将生成的规划轨迹传递给Control模块,由Control模块执行具体的车辆控制操作。

5、场景应用

  • OnLanePlanning主要适用于城区和高速公路等具有车道线的道路场景。在这些场景中,它能够有效地进行路径规划和决策,确保车辆的安全行驶。

6、技术特点

  • 基于车道线的规划:OnLanePlanning的规划算法都是基于车道的,即基于参考线的规划。这使得它能够更好地适应具有车道线的道路场景。
  • 实时性强:采用事件触发方式运行,能够根据车辆状态和道路情况实时生成规划轨迹。
  • 安全性高:在规划过程中会考虑实际临时或移动障碍物以及速度、动力学约束等因素,确保生成的规划轨迹是安全的。

综上所述,Apollo的OnLanePlanning是一个功能强大且高效的路径规划模块。它能够在具有车道线的道路场景中为自动驾驶车辆提供安全且舒适的行驶路径。

二、OnLanePlanning 类定义分析

class OnLanePlanning : public PlanningBase {
 public:
  explicit OnLanePlanning(const std::shared_ptr<DependencyInjector>& injector)
      : PlanningBase(injector) {}

  virtual ~OnLanePlanning();

  std::string Name() const override;

  common::Status Init(const PlanningConfig& config) override;

  void RunOnce(const LocalView& local_view,
               ADCTrajectory* const ptr_trajectory_pb) override;

  common::Status Plan(
      const double current_time_stamp,
      const std::vector<common::TrajectoryPoint>& stitching_trajectory,
      ADCTrajectory* const trajectory) override;

 private:
  common::Status InitFrame(const uint32_t sequence_num,
                           const common::TrajectoryPoint& planning_start_point,
                           const common::VehicleState& vehicle_state);

  common::VehicleState AlignTimeStamp(const common::VehicleState& vehicle_state,
                                      const double curr_timestamp) const;

  void ExportReferenceLineDebug(planning_internal::Debug* debug);
  bool CheckPlanningConfig(const PlanningConfig& config);
  void GenerateStopTrajectory(ADCTrajectory* ptr_trajectory_pb);
  void ExportFailedLaneChangeSTChart(const planning_internal::Debug& debug_info,
                                     planning_internal::Debug* debug_chart);
  void ExportOnLaneChart(const planning_internal::Debug& debug_info,
                         planning_internal::Debug* debug_chart);
  void ExportOpenSpaceChart(const planning_internal::Debug& debug_info,
                            const ADCTrajectory& trajectory_pb,
                            planning_internal::Debug* debug_chart);
  void AddOpenSpaceOptimizerResult(const planning_internal::Debug& debug_info,
                                   planning_internal::Debug* debug_chart);
  void AddPartitionedTrajectory(const planning_internal::Debug& debug_info,
                                planning_internal::Debug* debug_chart);

  void AddStitchSpeedProfile(planning_internal::Debug* debug_chart);

  void AddPublishedSpeed(const ADCTrajectory& trajectory_pb,
                         planning_internal::Debug* debug_chart);

  void AddPublishedAcceleration(const ADCTrajectory& trajectory_pb,
                                planning_internal::Debug* debug);

  void AddFallbackTrajectory(const planning_internal::Debug& debug_info,
                             planning_internal::Debug* debug_chart);

 private:
  PlanningCommand last_command_;
  std::unique_ptr<ReferenceLineProvider> reference_line_provider_;
  Smoother planning_smoother_;
};

构造函数与析构函数

  • 构造函数explicit OnLanePlanning(const std::shared_ptr<DependencyInjector>& injector)接收一个DependencyInjector的智能指针,用于依赖注入。这是Apollo框架中常用的设计模式,用于解耦模块间的依赖关系。
  • 析构函数virtual ~OnLanePlanning();是一个虚析构函数,确保当通过基类指针删除派生类对象时,能够正确调用派生类的析构函数。

成员函数

  • Name:返回规划模块的名称,即"OnLanePlanning"
  • Init:初始化函数,接收一个PlanningConfig对象作为配置参数,并返回初始化状态。在初始化过程中,会进行一系列的配置检查和资源分配。
  • RunOnce:规划模块的主逻辑函数,由定时器周期触发。它接收一个LocalView对象(包含局部环境信息)和一个ADCTrajectory指针(用于存储生成的规划轨迹)。
  • Plan:根据当前时间戳、拼接轨迹和规划轨迹指针,生成具体的规划轨迹。这个函数可能用于在特定情况下(如重新规划)生成新的轨迹。

私有成员函数

  • InitFrame:初始化规划帧,包括设置序列号、规划起点和车辆状态。
  • AlignTimeStamp:对齐车辆状态的时间戳,确保与当前时间一致。
  • ExportReferenceLineDebug:导出参考线的调试信息。
  • CheckPlanningConfig:检查规划配置的有效性。
  • GenerateStopTrajectory:生成停车轨迹。
  • ExportFailedLaneChangeSTChartExportOnLaneChartExportOpenSpaceChart:导出不同场景下的调试图表,包括车道变换失败、在车道上行驶和开放空间场景。
  • AddOpenSpaceOptimizerResultAddPartitionedTrajectory:向调试图表中添加开放空间优化结果和分区轨迹。
  • AddStitchSpeedProfileAddPublishedSpeedAddPublishedAcceleration:向调试图表中添加拼接速度曲线、发布的速度和加速度信息。
  • AddFallbackTrajectory:向调试图表中添加备用轨迹。

成员变量

  • last_command_:记录上一个规划命令。
  • reference_line_provider_:一个指向ReferenceLineProvider的唯一指针,用于提供参考线信息。
  • planning_smoother_:一个平滑器对象,用于对规划轨迹进行平滑处理。

总结

OnLanePlanning类是一个功能丰富的路径规划模块,它基于车道线进行规划,并考虑了多种场景和约束条件。通过提供的接口和成员函数,它能够生成安全、舒适且符合交通规则的行驶轨迹。此外,该类还提供了丰富的调试信息导出功能,有助于开发者进行问题诊断和性能优化。

三、OnLanePlanning::Init() 介绍

代码解析:

Status OnLanePlanning::Init(const PlanningConfig& config) {
  if (!CheckPlanningConfig(config)) {
    return Status(ErrorCode::PLANNING_ERROR,
                  "planning config error: " + config.DebugString());
  }

  PlanningBase::Init(config);

  // clear planning history
  injector_->history()->Clear();

  // clear planning status
  injector_->planning_context()->mutable_planning_status()->Clear();

  // load map
  hdmap_ = HDMapUtil::BaseMapPtr();
  ACHECK(hdmap_) << "Failed to load map";

  // instantiate reference line provider
  const ReferenceLineConfig* reference_line_config = nullptr;
  if (config_.has_reference_line_config()) {
    reference_line_config = &config_.reference_line_config();
  }
  reference_line_provider_ = std::make_unique<ReferenceLineProvider>(
      injector_->vehicle_state(), reference_line_config);
  reference_line_provider_->Start();

  // dispatch planner
  LoadPlanner();
  if (!planner_) {
    return Status(
        ErrorCode::PLANNING_ERROR,
        "planning is not initialized with config : " + config_.DebugString());
  }

  if (config_.learning_mode() != PlanningConfig::NO_LEARNING) {
    PlanningSemanticMapConfig renderer_config;
    ACHECK(apollo::cyber::common::GetProtoFromFile(
        FLAGS_planning_birdview_img_feature_renderer_config_file,
        &renderer_config))
        << "Failed to load renderer config"
        << FLAGS_planning_birdview_img_feature_renderer_config_file;

    BirdviewImgFeatureRenderer::Instance()->Init(renderer_config);
  }

  traffic_decider_.Init(injector_);

  start_time_ = Clock::NowInSeconds();
  return planner_->Init(injector_, FLAGS_planner_config_path);
}

OnLanePlanning::Init 函数是一个初始化函数,用于设置和准备OnLanePlanning类的实例。这个函数执行了以下关键步骤:

  1. 配置检查
    • 调用CheckPlanningConfig函数来验证传入的PlanningConfig配置对象是否有效。
    • 如果配置无效,则返回一个包含错误代码和错误信息的Status对象。
  2. 基类初始化
    • 调用基类PlanningBaseInit函数,传入相同的配置对象。
  3. 清除历史记录和状态
    • 通过injector_(一个依赖注入器)清除规划历史和规划状态。
  4. 加载地图
    • 使用HDMapUtil::BaseMapPtr()获取高清地图的指针,并存储在hdmap_成员变量中。
    • 使用ACHECK宏来确保地图加载成功;如果失败,则打印错误信息并终止程序。
  5. 实例化参考线提供者
    • 检查配置中是否包含参考线配置。
    • 根据配置(如果有)和车辆状态实例化ReferenceLineProvider
    • 启动参考线提供者。
  6. 加载规划器
    • 调用LoadPlanner函数来加载和设置规划器。
    • 如果规划器未成功加载,则返回一个包含错误代码和错误信息的Status对象。
  7. 学习模式设置(可选):
    • 如果配置中指定了学习模式,则加载渲染器配置并初始化BirdviewImgFeatureRenderer
  8. 交通决策器初始化
    • 调用traffic_decider_Init函数,传入依赖注入器。
  9. 记录开始时间
    • 记录初始化过程的开始时间到start_time_成员变量中。
  10. 规划器初始化
    • 最后,调用规划器的Init函数,传入依赖注入器和规划器配置路径。
    • 返回规划器初始化的结果。

这个函数是OnLanePlanning类的一个重要组成部分,因为它负责设置类的初始状态,包括加载必要的配置、资源和服务,以及确保所有依赖项都已正确初始化。如果初始化过程中的任何步骤失败,函数将返回一个包含错误信息的Status对象,这有助于调用者了解初始化失败的原因。

c++知识,派生来中调用基类函数:

在init函数中,调用了基类的init函数,

  PlanningBase::Init(config);
在C++中,派生类可以通过多种方式调用基类的函数。以下是几种常见的方法:

1. 直接调用基类成员函数(如果它不是虚函数)

如果基类的成员函数不是虚函数,派生类可以直接通过基类名和作用域解析运算符(::)来调用它,或者使用this->指针(虽然在这种情况下通常不是必需的)。但是,更常见的是直接使用成员函数名,因为编译器会根据上下文自动解析为基类的版本(如果派生类没有覆盖它)。

class Base {  
public:  
    void NonVirtualFunction() {  
        // 基类实现  
    }  
};  
 
class Derived : public Base {  
public:  
    void SomeFunction() {  
        // 直接调用基类的非虚函数  
        Base::NonVirtualFunction();  
        // 或者简单地调用(如果Derived没有同名函数)  
        NonVirtualFunction();  
    }  

};
2. 通过基类指针或引用调用虚函数

如果基类的成员函数是虚函数,并且派生类提供了覆盖(override),那么通过基类指针或引用调用该函数时,将调用派生类的版本。但是,有时你可能希望调用基类的版本。这可以通过使用Base::前缀来实现。

class Base {  
public:  
    virtual void VirtualFunction() {  
        // 基类实现  
    }  
};  
 
class Derived : public Base {  
public:  
    void VirtualFunction() override {  
        // 派生类实现  
        // 调用基类的虚函数  
        Base::VirtualFunction();  
    }  

};

在上面的例子中,当Derived的VirtualFunction被调用时,它首先会调用基类的VirtualFunction,然后执行自己的实现。


3. 使用this->指针调用虚函数(显式地调用基类版本)

虽然不常见,但你也可以使用this->指针和Base::前缀来显式地调用基类的虚函数。这通常用于在派生类的覆盖函数中调用基类的实现。

class Derived : public Base {  
public:  
    void VirtualFunction() override {  
        // 使用this指针和Base::前缀调用基类的虚函数  
        this->Base::VirtualFunction();  
        // 或者简单地  
        Base::VirtualFunction();  
        // 派生类自己的实现  
    }  

};
4. 构造函数和析构函数中的调用

在派生类的构造函数中,如果需要调用基类的构造函数,这必须在初始化列表中完成。对于析构函数,当派生类的析构函数被调用时,它会自动调用基类的析构函数(如果基类有析构函数的话)。

class Base {  
public:  
    Base() { /* 基类构造函数实现 */ }  
    virtual ~Base() { /* 基类析构函数实现 */ }  
};  
 
class Derived : public Base {  
public:  
    Derived() : Base() { /* 派生类构造函数实现 */ }  
    ~Derived() override { /* 派生类析构函数实现;基类析构函数会自动调用 */ }  

};

请注意,在析构函数中,你通常不需要(也不应该)显式地调用基类的析构函数,因为C++会自动处理这一点。然而,在构造函数中,你必须通过初始化列表来调用基类的构造函数。

总的来说,调用基类函数的方法取决于函数是否是虚函数、你是否有一个指向基类或派生类对象的指针或引用,以及你是在构造函数、析构函数还是普通成员函数中调用它。

四、reference_line_provider_参考线生成器线程启动

reference_line_provider_使用异步的方式进行参考线的更新与坐标系的计算,

  reference_line_provider_ = std::make_unique<ReferenceLineProvider>(
      injector_->vehicle_state(), reference_line_config);
  reference_line_provider_->Start();
bool ReferenceLineProvider::Start() {
  if (FLAGS_use_navigation_mode) {
    return true;
  }
  if (!is_initialized_) {
    AERROR << "ReferenceLineProvider has NOT been initiated.";
    return false;
  }

  if (FLAGS_enable_reference_line_provider_thread) {
    task_future_ = cyber::Async(&ReferenceLineProvider::GenerateThread, this);
  }
  return true;
}

ReferenceLineProvider::Start 函数是 ReferenceLineProvider 类的一个成员函数,用于启动参考线生成器。下面是对该函数的详细解释:

  1. 检查导航模式
    • 首先,函数检查全局标志 FLAGS_use_navigation_mode 是否被设置。
    • 如果设置了导航模式(即 FLAGS_use_navigation_modetrue),则函数直接返回 true,表示参考线提供者已启动(在导航模式下可能不需要额外的线程或处理)。
  2. 检查初始化状态
    • 接下来,函数检查成员变量 is_initialized_,以确定 ReferenceLineProvider 是否已经被正确初始化。
    • 如果 is_initialized_false,则打印错误日志,并返回 false,表示参考线提供者未能启动。
  3. 启动参考线生成线程
    • 如果全局标志 FLAGS_enable_reference_line_provider_thread 被设置(即允许启动参考线提供者线程),则函数会调用 cyber::Async 方法来异步启动一个线程。
    • cyber::Async 方法接受一个函数指针和对象指针作为参数,这里传递的是 ReferenceLineProvider::GenerateThread 成员函数和 this 指针(指向当前 ReferenceLineProvider 对象)。
    • task_future_ 成员变量被赋值为 cyber::Async 调用返回的 future 对象,这个对象可以用于等待线程完成或获取线程的结果(如果有的话)。不过,在这个特定的代码中,task_future_ 的值似乎没有被进一步使用。
  4. 返回成功
    • 最后,如果所有检查都通过,并且线程(如果需要的话)已经启动,函数返回 true,表示参考线提供者已成功启动。

需要注意的是,这个函数中有几个关键点:

  • 全局标志(如 FLAGS_use_navigation_modeFLAGS_enable_reference_line_provider_thread)用于控制函数的行为。这些标志通常在程序启动时设置,并影响整个程序的运行。
  • 成员变量 is_initialized_ 用于跟踪 ReferenceLineProvider 对象的初始化状态。
  • cyber::Async 是 Apollo 自动驾驶软件框架中用于异步执行任务的函数。它允许程序在不阻塞主线程的情况下执行耗时的操作。

此外,这个函数的实现假设了一些外部条件,比如 is_initialized_ 应该在某处被正确设置,以及 cyber::Async 调用能够成功启动线程。在实际应用中,这些假设需要得到保证,以确保程序的正确性和稳定性。

在planning模块运行时,输入条件如下:

五、LoadPlanner(),初始化规划器

void PlanningBase::LoadPlanner() {
  // Use PublicRoadPlanner as default Planner
  std::string planner_name = "apollo::planning::PublicRoadPlanner";
  if ("" != config_.planner()) {
    planner_name = config_.planner();
    planner_name = ConfigUtil::GetFullPlanningClassName(planner_name);
  }
  planner_ =
      cyber::plugin_manager::PluginManager::Instance()->CreateInstance<Planner>(
          planner_name);
}

PlanningBase::LoadPlanner 函数是 PlanningBase 类的一个成员函数,用于加载并初始化规划器(Planner)。这个函数的具体作用如下:

  1. 设置默认规划器
    • 函数开始时,将 planner_name 设置为 "apollo::planning::PublicRoadPlanner",这是默认的规划器名称。
  2. 检查配置
    • 接下来,函数检查成员变量 config_ 中的 planner 配置项是否为空。
    • 如果 config_.planner() 不为空(即用户指定了其他的规划器),则将 planner_name 更新为用户指定的规划器名称。
    • 然后,使用 ConfigUtil::GetFullPlanningClassName 函数来获取规划器的完整类名。这个函数可能会添加一些前缀或后缀,以确保类名与实际的规划器类匹配。
  3. 创建规划器实例
    • 最后,函数使用 cyber::plugin_manager::PluginManager::Instance()->CreateInstance<Planner> 方法来创建规划器实例。
    • 这里,planner_name 被用作模板参数,告诉插件管理器要创建哪个类的实例。
    • planner_ 成员变量被赋值为新创建的规划器实例。

需要注意的是:

  • config_ 成员变量应该是一个包含规划器配置信息的对象。它可能在 PlanningBase 类的构造函数或其他成员函数中被初始化。
  • cyber::plugin_manager::PluginManager 是 Apollo 自动驾驶软件框架中用于管理插件(如规划器)的类。CreateInstance 方法根据提供的类名动态地创建类的实例。
  • Planner 是一个抽象基类或接口,定义了规划器应该实现的方法。具体的规划器类(如 PublicRoadPlanner)将继承自 Planner 并实现其方法。
  • 如果 CreateInstance 方法无法找到或创建指定的规划器类实例,它可能会返回一个空指针或抛出异常。在实际应用中,应该检查 planner_ 是否为 nullptr,并相应地处理错误情况。

此外,这个函数的实现假设了 cyber::plugin_manager::PluginManager 和相关的配置系统已经正确设置,并且能够找到并创建用户指定的规划器类实例。在实际应用中,这些假设需要得到保证,以确保程序的正确性和稳定性。

六、TrafficDecider::Init()

bool TrafficDecider::Init(const std::shared_ptr<DependencyInjector> &injector) {
  if (init_) return true;
  // Load the pipeline config.
  AINFO << "Load config path:" << FLAGS_traffic_rule_config_filename;
  // Load the pipeline of scenario.
  if (!apollo::cyber::common::LoadConfig(FLAGS_traffic_rule_config_filename,
                                         &rule_pipeline_)) {
    AERROR << "Load pipeline of Traffic decider"
           << " failed!";
    return false;
  }
  //-----------------------------------------------
  for (int i = 0; i < rule_pipeline_.rule_size(); i++) {
    auto rule =
        apollo::cyber::plugin_manager::PluginManager::Instance()
            ->CreateInstance<TrafficRule>(ConfigUtil::GetFullPlanningClassName(
                rule_pipeline_.rule(i).type()));
    if (!rule) {
      AERROR << "Init of Traffic rule" << rule_pipeline_.rule(i).name()
             << " failed!";
      return false;
    }
    rule->Init(rule_pipeline_.rule(i).name(), injector);
    rule_list_.push_back(rule);
  }

  init_ = true;
  return true;
}

该函数的主要目的是初始化交通决策器,具体步骤和逻辑如下:

  1. 检查是否已经初始化:首先,函数通过检查init_成员变量的值来判断TrafficDecider是否已经初始化。如果init_true,表示已经初始化过,直接返回true

  2. 加载管道配置:接着,函数通过打印日志信息表明它正在加载配置文件的路径,这个路径是通过宏FLAGS_traffic_rule_config_filename指定的。然后,使用apollo::cyber::common::LoadConfig函数尝试加载该配置文件到rule_pipeline_成员变量中。如果加载失败,则打印错误信息并返回false

  3. 初始化规则列表:配置文件加载成功后,函数遍历rule_pipeline_中定义的每一条规则。对于每一条规则,它使用apollo::cyber::plugin_manager::PluginManagerCreateInstance方法来创建一个TrafficRule的实例。CreateInstance方法需要一个类名字符串作为参数,这个字符串通过ConfigUtil::GetFullPlanningClassName函数从规则配置中获取。

    • 如果CreateInstance无法创建TrafficRule实例(返回nullptr),则打印错误信息(包含规则的名字),并返回false
    • 如果实例创建成功,则调用该实例的Init方法,传入规则的名字和injector(一个依赖注入器)。
    • 将成功初始化的规则实例添加到rule_list_成员变量中,以便后续使用。
  4. 标记为已初始化:所有规则都成功初始化后,将init_成员变量设置为true,表示TrafficDecider已经初始化完成。

  5. 返回成功:最后,函数返回true,表示初始化成功。

总结来说,这个Init函数负责加载交通决策器的配置,并根据配置创建和初始化一系列的交通规则(TrafficRule)实例。如果在任何步骤中遇到错误(如配置文件加载失败、规则实例创建失败等),函数将提前返回false

 七、PublicRoadPlanner::Init()

Status PublicRoadPlanner::Init(
    const std::shared_ptr<DependencyInjector>& injector,
    const std::string& config_path) {
  Planner::Init(injector, config_path);
  LoadConfig<PlannerPublicRoadConfig>(config_path, &config_);
  scenario_manager_.Init(injector, config_);
  return Status::OK();
}

PublicRoadPlannerPlanner类的一个子类,专门用于处理公共道路场景的规划任务。下面是对这段代码的详细解读:

  1. 函数签名
    • Status PublicRoadPlanner::Init(const std::shared_ptr<DependencyInjector>& injector, const std::string& config_path)
    • 这个函数接收两个参数:一个是依赖注入器DependencyInjector的智能指针,另一个是配置文件的路径。
    • 函数返回一个Status对象,这通常用于表示操作的成功或失败状态。
  2. 调用基类初始化方法
    • Planner::Init(injector, config_path);
    • PublicRoadPlannerInit函数中,首先调用了基类PlannerInit方法,传入了相同的参数。
    • 这表明PublicRoadPlanner的初始化过程需要首先完成基类Planner的初始化。
  3. 加载配置
    • LoadConfig<PlannerPublicRoadConfig>(config_path, &config_);
    • 接下来,使用LoadConfig模板函数从指定的配置文件路径加载配置。
    • LoadConfig函数接受两个参数:配置文件的路径和一个指向配置对象(在这里是PlannerPublicRoadConfig类型的对象)的指针。
    • PlannerPublicRoadConfig是专门为PublicRoadPlanner设计的配置类,用于存储与公共道路规划相关的配置信息。
    • 加载的配置信息被存储在config_成员变量中,供后续使用。
  4. 初始化场景管理器
    • scenario_manager_.Init(injector, config_);
    • 然后,调用scenario_manager_成员变量的Init方法,同样传入了依赖注入器和配置信息。
    • scenario_manager_是负责管理和处理不同交通场景的对象。
    • 通过初始化scenario_manager_PublicRoadPlanner能够根据不同的交通场景做出相应的规划决策。
  5. 返回成功状态
    • return Status::OK();
    • 最后,函数返回一个表示操作成功的状态对象。
    • Status::OK()通常是一个静态方法,用于创建一个表示成功状态的Status对象。

总结来说,PublicRoadPlannerInit函数首先完成了基类的初始化,然后加载了专门的配置信息,并初始化了场景管理器。这个过程确保了PublicRoadPlanner在开始执行规划任务之前已经做好了充分的准备。

八、ScenarioManager::Init()

bool ScenarioManager::Init(const std::shared_ptr<DependencyInjector>& injector,
                           const PlannerPublicRoadConfig& planner_config) {
  if (init_) {
    return true;
  }
  injector_ = injector;
  for (int i = 0; i < planner_config.scenario_size(); i++) {
    auto scenario = PluginManager::Instance()->CreateInstance<Scenario>(
        ConfigUtil::GetFullPlanningClassName(
            planner_config.scenario(i).type()));
    ACHECK(scenario->Init(injector_, planner_config.scenario(i).name()))
        << "Can not init scenario" << planner_config.scenario(i).name();
    scenario_list_.push_back(scenario);
    if (planner_config.scenario(i).name() == "LANE_FOLLOW") {
      default_scenario_type_ = scenario;
    }
  }
  AINFO << "Load scenario list:" << planner_config.DebugString();
  current_scenario_ = default_scenario_type_;
  init_ = true;
  return true;
}

ScenarioManager负责管理不同交通场景规划的对象。下面是对这段代码的详细解读:

  1. 函数签名
    • bool ScenarioManager::Init(const std::shared_ptr<DependencyInjector>& injector, const PlannerPublicRoadConfig& planner_config)
    • 函数接收两个参数:一个是依赖注入器DependencyInjector的智能指针,另一个是PlannerPublicRoadConfig类型的配置对象(通常这种配置对象很大,使用引用传递以避免不必要的复制)。
    • 函数返回一个布尔值,表示初始化是否成功。
  2. 检查是否已经初始化
    • if (init_) { return true; }
    • 如果ScenarioManager已经初始化过(init_true),则直接返回true,避免重复初始化。
  3. 保存依赖注入器
    • injector_ = injector;
    • 将传入的依赖注入器智能指针保存到成员变量injector_中,供后续使用。
  4. 遍历配置中的场景
    • 使用for循环遍历planner_config中定义的场景列表。
    • 对于每个场景,使用PluginManager::Instance()->CreateInstance<Scenario>方法创建一个Scenario的实例。
      • 这个方法需要一个类名字符串作为参数,这个字符串通过ConfigUtil::GetFullPlanningClassName函数从场景配置中获取。
  5. 初始化场景实例
    • 使用ACHECK宏来检查场景实例的Init方法是否成功。
      • ACHECK是一个断言宏,如果条件不满足(即scenario->Init(...)返回false),则打印错误信息并终止程序。
      • 错误信息包括无法初始化的场景名称。
    • 如果初始化成功,将场景实例添加到scenario_list_成员变量中。
  6. 设置默认场景
    • 如果场景的名称是"LANE_FOLLOW",则将该场景设置为默认场景(default_scenario_type_)。
  7. 打印加载的场景列表
    • 使用AINFO宏打印加载的场景列表的调试信息。
    • planner_config.DebugString()方法可能返回一个包含所有场景配置的字符串表示。
  8. 设置当前场景
    • 将当前场景(current_scenario_)设置为默认场景。
  9. 标记为已初始化
    • init_成员变量设置为true,表示ScenarioManager已经初始化完成。
  10. 返回成功
    • 函数返回true,表示初始化成功。

总结来说,ScenarioManagerInit函数负责根据配置信息加载和初始化一系列的场景(Scenario)实例,并设置一个默认场景。如果在任何步骤中遇到错误(如场景实例创建失败、场景初始化失败等),函数将使用ACHECK宏终止程序。成功初始化后,函数将标记ScenarioManager为已初始化状态,并返回true

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2190570.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

nginx反向代理,负载均衡,HTTP配置简述(说人话)

文章目录 反向代理正向代理反向代理普通反向代理分析解释 四层反向代理 负载均衡HTTPS配置基本配置Nginx 账户认证功能 反向代理 正向代理 所谓的正向代理&#xff0c;通俗来说就是&#xff0c;正向代理是一个位于客户端和目标服务器之间的服务器&#xff0c;它代表客户端向目…

Python 工具库每日推荐 【NumPy】

文章目录 引言Python科学计算库的重要性今日推荐:NumPy工具库主要功能:使用场景:安装与配置快速上手示例代码代码解释实际应用案例案例:图像处理案例分析高级特性广播机制高级索引通用函数(ufunc)性能优化技巧扩展阅读与资源优缺点分析优点:缺点:总结【 已更新完 TypeS…

哪个牌子充电宝好用性价比又高?推荐5款2024年性价比充电宝!

在充电宝的世界里&#xff0c;技术的进步日新月异&#xff0c;它们早已超越了简单的便携充电功能&#xff0c;成为了我们日常生活中不可或缺的移动电源。然而&#xff0c;随着市场的繁荣&#xff0c;选择一款可靠、安全的充电宝变得愈发困难。许多品牌为了降低成本&#xff0c;…

【EXCEL数据处理】000017 案例 Match和Index函数。

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;今天给大家分享一篇文章&#xff01;创作不易&#xff0c;如果能帮助到大家或者给大家一些灵感和启发&#xff0c;欢迎收藏关注哦 &#x1f495; 目录 【EXCEL数据处理】000016 案例 Match和Index函数。使用的软件&#xff…

静态路由故障排查

1、开始 静态路由是否能够加入到全局路由表中并成功指导报文正确转发, 取决于其出接口状态与下一跳可达性&#xff0c;以及相关检测联动的状态等方面。因此静态路由定位故障的思路是: 首先查看全局路由表中是否有该静态路由&#xff1b;然后据此相应地检查出接口状态、下一跳可…

融媒体服务中PBO进行多重采样抗锯齿(MSAA)

如果不理解pbo 那先去了解概念&#xff0c;在此不再解释&#xff0c;这是我为了做融合服务器viewpointserver做的一部分工作&#xff0c;融合服务器的功能是将三维和流媒体&#xff0c;AI融合在一起&#xff0c;viewpointserver会直接读取三维工程的文件&#xff0c;同时融合rt…

MySQL基础之约束

MySQL基础之约束 概述 概念&#xff1a;约束是作用在字段的规则&#xff0c;限制表中数据 演示 # 多个约束之间不需要加逗号 # auto_increment 自增 create table user(id int primary key auto_increment comment 主键,name varchar(10) not null unique comment 姓名,age i…

表达式求值(可以计算两位数以上)

此程序可计算两位数以上的表达式 import java.util.Stack;public class ExpressionEvaluator {public int evaluate(String s) {Stack<Integer> numbers new Stack<>();Stack<Character> operators new Stack<>();int i 0;char c s.charAt(i);whil…

stm32定时器中断和外部中断

一&#xff0c;中断系统的介绍 中断&#xff1a;在主程序运行过程中&#xff0c;出现了特定的中断触发条件&#xff08;中断源&#xff09;&#xff0c;使得CPU暂停当前正在运行的程序&#xff0c;转而去处理中断程序&#xff0c;处理完成后又返回原来被暂停的位置继续运行 中…

平衡二叉树——AVl树

AVL树 AVl树的概念AVL树的实现AVL树的结构AVl树的插入AVL树的旋转左单旋右单旋左右双旋右左双旋 AVl树以高度递归实现完整代码 AVl树的概念 AVL树是一种自平衡的二叉搜索树&#xff08;Binary Search Tree, BST&#xff09;&#xff0c;由两位苏联数学家 Georgy Adelson-Velsk…

jQuery——事件处理

1、事件绑定&#xff08;2种&#xff09; ① eventName&#xff08;function&#xff08;&#xff09;{ }&#xff09; 绑定对应事件名的监听&#xff0c;例如&#xff1a;$&#xff08;‘#div’&#xff09;. click&#xff08;function&#xff08;&#xff09;{ }&#xf…

【复习】CSS中的选择器

文章目录 东西有点多 以实战为主选择器盒子模型 东西有点多 以实战为主 选择器 CSS选择器&#xff08;CSS Selectors&#xff09;是用于在HTML或XML文档中查找和选择元素&#xff0c;以便应用CSS样式的一种方式。 元素选择器&#xff08;Type Selector&#xff09; 选择所有…

在谷歌colab运行YOLO系列(重要比在云服务器搭建运行快)

在谷歌colab运行YOLO系列&#xff08;重要比在云服务器搭建运行快&#xff09; 一、谷歌云硬盘二、克隆 YOLOV5进行运行测试1&#xff0c;修改prepare文件中的参数2&#xff0c;修改voc.yaml3&#xff0c;修改yolov5s.yaml4&#xff0c;防止colab自动断开的方式&#xff08;必须…

今日指数项目个股描述功能实现

个股描述功能实现 1 个股描述功能实现说明 1&#xff09;原型示意 2&#xff09;接口说明 功能描述&#xff1a;个股主营业务查询接口 服务路径&#xff1a;/api/quot/stock/describe 服务方法&#xff1a;GET 请求参数&#xff1a;code #股票编码 响应参数&#xff1a; {…

Koa2项目实战3 (koa-body,用于处理 HTTP 请求中的请求体)

以用户注册接口为例&#xff0c;需要在请求里携带2个参数&#xff1a;用户名&#xff08;user_name&#xff09;和密码&#xff08;password&#xff09;。 开发者需要在接口端&#xff0c;解析出user_name 、password。 在使用Koa开发的接口中&#xff0c;如何解析出请求携带…

八、Drf解析器

八、解析器 8.1概念 解析用户请求发送过来的数据&#xff08;常用的是JSON&#xff09; 请求类型&#xff1a; get: ​ 方式1&#xff1a; http://127.0.0.1/web/?arg1v1&arg2v2 ​ 方式2&#xff1a;通过请求头发送 post: ​ 请求头&#xff1a; ​ content-typ…

数据库管理-第247期 23ai:全球分布式数据库-Schema对象(20241004)

数据库管理247期 2024-10-04 数据库管理-第247期 23ai&#xff1a;全球分布式数据库-Schema对象&#xff08;20241004&#xff09;1 分区、表空间和Chunk&#xff08;块&#xff09;2 表空间组3 分片表4 分片表族5 复制表6 在所有分片上创建的非表对象总结 数据库管理-第247期 …

C++——模板进阶、继承

文章目录 一、模板1. 非类型模板参数2. 模板的特化函数模板特化类模板特化1. 全特化2. 偏特化部分特化参数更进一步的限制 二、继承1. 概念2. 定义定义格式 3. 继承基类成员访问⽅式的变化4. 继承类模板5.基类和派⽣类间的转换6. 继承中的作⽤域隐藏规则&#xff1a; 7. 派⽣类…

LinuxO(1)调度算法

概念 在Linux中&#xff0c;O(1)调度算法是一种进程调度算法。O(1)表示算法的时间复杂度是常数级别的&#xff0c;与系统中的进程数量无关。 运行队列结构 他采用了两个运行队列&#xff0c;一个活动队列和一个过期队列。活动队列中的进程是有资格获取CPU时间片的进程&#x…