apollo规划架构

算法的基本架构

我们在最开始直接给出规划决策算法架构框图,然后一一介绍每个框图结构的细节:

在这里插入图片描述

  1. 模块的入口是 PlanningComponent,在 Cyber 中注册模块,订阅和发布消息,并且注册对应的 Planning 类。
  2. Planning 的过程之前是定时器触发,即每隔一段固定的时间执行一次,现已经改为事件触发,即只要收集完成对应 TOPIC 的消息,就会触发执行,这样的好处是提高的实时性。
  3. Planning 类主要实现了 2 个功能,一个是启动 ReferenceLineProvider 来提供参考线,后面生成的轨迹都是在参考线的基础上做优化,ReferenceLineProvider 启动了一个单独的线程,每隔 50ms 执行一次,和 Planning 主流程并行执行。Planning 类另外的一个功能是执行 Planning 主流程。
  4. Planning 主流程先是选择对应的 Planner,我们这里主要分析 PublicRoadPlanner,在配置文件中定义了 Planner 支持的场景(Scenario),把规划分为具体的几个场景来执行,每个场景又分为几个阶段(Stage),每个阶段会执行多个任务(Task),任务执行完成后,对应的场景就完成了。不同场景间的切换是由一个状态机(ScenarioDispatch)来控制的。规划控制器根据 ReferenceLineProvider 提供的参考线,在不同的场景下做切换,生成一条车辆可以行驶的轨迹,并且不断重复上述过程直到到达目的地。

PlanningComponent

规划模块的入口是 PlanningComponent。PlanningComponent 的两大核心函数是 Init 和 Proc.

在初始化中,我们可以看到如下的代码,FLAGS_use_navigation_mode 的标志位直接决定了我们等等实例化的 planning_base_ 的具体 planner,到底是 NaviPlanning 还是 OnLanePlanning:

if (FLAGS_use_navigation_mode) {
    planning_base_ = std::make_unique<NaviPlanning>(injector_);
  } else {
    planning_base_ = std::make_unique<OnLanePlanning>(injector_);
  }

其实在更早的版本中有更多选项,7.0 为什么简化了呢?

if (FLAGS_open_space_planner_switchable) {
    planning_base_ = std::make_unique<OpenSpacePlanning>();
  } else {
    if (FLAGS_use_navigation_mode) {
      planning_base_ = std::make_unique<NaviPlanning>();
    } else {
      planning_base_ = std::make_unique<OnLanePlanning>();
    }
  }

而在 Proc(…)函数中,最核心部分则是调用对应 planner 的 RunOnce 函数:

planning_base_->RunOnce(local_view_, &adc_trajectory_pb);

接下来的具体例子中我们都以这个 planing_base_被实例化为 OnLanePlanning 作为前提。

下图是几个规划器的结构。这里我们要讨论的是 PublicRoadPlanner,这里只是简单的给出结构,后面的对应小节会具体介绍函数中如何运行和管理。

在这里插入图片描述

OnLanePlanning

RunOnce 函数的三大重要函数是:

// 初始化frame
status = InitFrame(frame_num, stitching_trajectory.back(), vehicle_state);
......
//进行traffic decider
for (auto& ref_line_info : *frame_->mutable_reference_line_info()) {
    TrafficDecider traffic_decider;
    traffic_decider.Init(traffic_rule_configs_);
    auto traffic_status =
        traffic_decider.Execute(frame_.get(), &ref_line_info, injector_);
    if (!traffic_status.ok() || !ref_line_info.IsDrivable()) {
      ref_line_info.SetDrivable(false);
      AWARN << "Reference line " << ref_line_info.Lanes().Id()
            << " traffic decider failed";
    }
  }
  ......
  //plan主函数
status = Plan(start_timestamp, stitching_trajectory, ptr_trajectory_pb);

Plan

这个 plan 函数中主要核心则是:

auto status = planner_->Plan(stitching_trajectory.back(), frame_.get(),
                               ptr_trajectory_pb);

而这个 planner_则是通过 DispatchPlanner 来指定:

// dispatch planner
  planner_ = planner_dispatcher_->DispatchPlanner(config_, injector_);

具体来说就是:

std::unique_ptr<Planner> OnLanePlannerDispatcher::DispatchPlanner(
    const PlanningConfig& planning_config,
    const std::shared_ptr<DependencyInjector>& injector) {
  return planner_factory_.CreateObject(
      planning_config.standard_planning_config().planner_type(0), injector);
}
//其中这个config是:
standard_planning_config {
  planner_type: PUBLIC_ROAD
  planner_public_road_config {
  }
}

Plan 函数中主要的几个步骤是:

Status PublicRoadPlanner::Plan(const TrajectoryPoint& planning_start_point,
                               Frame* frame,
                               ADCTrajectory* ptr_computed_trajectory) {
  //更新当前的scenario
  scenario_manager_.Update(planning_start_point, *frame);
  // 获取当前场景
  scenario_ = scenario_manager_.mutable_scenario();
  // 执行当前场景的任务
  auto result = scenario_->Process(planning_start_point, frame);

  。。。。。。
}

Scenario 是 apollo 决策规划算法中的重要概念,apollo 可以应对自动驾驶所面临的不同道路场景,都是通过 Scenario 统一注册与管理;Scenario 通过一个有限状态机来选择不同场景。

更新当前的 scenario

scenario_manager_.Update(planning_start_point, *frame);

我们来看 Update,做了这么几件事:

void ScenarioManager::Update(const common::TrajectoryPoint& ego_point,
                             const Frame& frame) {
  ACHECK(!frame.reference_line_info().empty());
  // 保留当前帧
  Observe(frame);
  // 场景分发  
  ScenarioDispatch(frame);
}

这里能够提供的场景库包括:

enum ScenarioType {
    LANE_FOLLOW = 0;  // default scenario

    // intersection involved
    BARE_INTERSECTION_UNPROTECTED = 2;
    STOP_SIGN_PROTECTED = 3;
    STOP_SIGN_UNPROTECTED = 4;
    TRAFFIC_LIGHT_PROTECTED = 5;
    TRAFFIC_LIGHT_UNPROTECTED_LEFT_TURN = 6;
    TRAFFIC_LIGHT_UNPROTECTED_RIGHT_TURN = 7;
    YIELD_SIGN = 8;

    // parking
    PULL_OVER = 9;
    VALET_PARKING = 10;

    EMERGENCY_PULL_OVER = 11;
    EMERGENCY_STOP = 12;

    // misc
    NARROW_STREET_U_TURN = 13;
    PARK_AND_GO = 14;

    // learning model sample
    LEARNING_MODEL_SAMPLE = 15;
    // turn around
    DEADEND_TURNAROUND = 16;
}

获取当前场景

//获取当前场景
Scenario* mutable_scenario() { return current_scenario_.get(); }

执行当前场景的任务

//通过Process函数进行场景运行
Scenario::ScenarioStatus Scenario::Process(
    const common::TrajectoryPoint& planning_init_point, Frame* frame)

场景下有 stage, 运行 stage 的 Process 函数:

auto ret = current_stage_->Process(planning_init_point, frame);

我们拿 LaneFollowStage 为例,则运行他的每个 task:

//首先进入函数:
auto cur_status =
        PlanOnReferenceLine(planning_start_point, frame, &reference_line_info);
        
//然后是在PlanOnReferenceLine函数中遍历每个task
for (auto* task : task_list_) {
    const double start_timestamp = Clock::NowInSeconds();

    ret = task->Execute(frame, reference_line_info);
    。。。。。。
  }

以 lane follow 这个 stage 为例,这个 task list 包括:

scenario_type: LANE_FOLLOW
stage_type: LANE_FOLLOW_DEFAULT_STAGE
stage_config: {
  stage_type: LANE_FOLLOW_DEFAULT_STAGE
  enabled: true
  task_type: LANE_CHANGE_DECIDER
  task_type: PATH_REUSE_DECIDER
  task_type: PATH_LANE_BORROW_DECIDER
  task_type: PATH_BOUNDS_DECIDER
  task_type: PIECEWISE_JERK_PATH_OPTIMIZER
  task_type: PATH_ASSESSMENT_DECIDER
  task_type: PATH_DECIDER
  task_type: RULE_BASED_STOP_DECIDER
  task_type: SPEED_BOUNDS_PRIORI_DECIDER
  task_type: SPEED_HEURISTIC_OPTIMIZER
  task_type: SPEED_DECIDER
  task_type: SPEED_BOUNDS_FINAL_DECIDER
  task_type: PIECEWISE_JERK_SPEED_OPTIMIZER
  # task_type: PIECEWISE_JERK_NONLINEAR_SPEED_OPTIMIZER
  task_type: RSS_DECIDER
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hebastast

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值