当前位置:   article > 正文

apollo规划:scenario->stage->task_apollo scenario创建

apollo scenario创建

Apollo中的Planning(规划)模块的场景选择是通过scenario-stage-task并利用状态机行车对车辆状态和规划功能进行维护的。

一.场景scenario

scenario代表当前所处的场景,包括正常的路上行驶场景、停车场景、红绿灯路口场景等。

scenario功能模块中的主要功能如下:

preview

  1. 通过Scenario_manager作为scenario场景的执行和处理的入口,是由PublicRoadPlanner::Plan()调用
  2. scenario及其子类,通过定义的场景以及config配置文件具体执行后续的scenario-stage-task流程
  3. tasks及其子类
  4. 整个scenario的数据信息来源来自于ReferenceLineInfo类,其中主要通过reference_line, lanes, vehicle_state以及adc_planning_point.

1.1 场景管理scenario_manager

planning模块对于scenario的切换的代码是在scenario_manager中实现的,目前apollo一共支持了11多种场景和场景的定义。

  1. Lane Follow scenario:默认驾驶场景,包括本车道保持、变道、基本转弯
  2. Bare intersection unprotected:无保护裸露交叉路口
  3. Stop sign unprotected:无保护停止标志
  4. Traffic light protected:有保护交通灯,即有明确的交通指示灯(左转、右转)
  5. Traffic light unprotected left turn:无保护交通灯左转,即没有明确的左转指示灯,需要避让对向的直行来车
  6. Traffic light unprotected right turn:无保护交通灯右转,需要避让交通流
  7. Pull over :靠边停车
  8. Emergency pull over :紧急靠边
  9. Narrow street u turn :禁止车辆临时或长时停放
  10. Park and go:停车和启动
  11. Yield sign:让路标志

1.2 场景配置

在apollo的planning中,场景首先通过配置文件进行配置, 如在/planning/proto/planning_config.proto中定义一个场景的结构。

// scenario configs
message ScenarioConfig {
  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;
  }

这里是定义了一个ScenarioType, 同时在这文件中还定义stage 于type字段,这个会在stage与type部分细说。

1.3场景注册

从一开始的图片,我们已经可以看出ScenarioManager负责实际的场景注册,而这个场景注会读取/modules/planning/config/scenario目录下的配置文件,具体在代码中是通过ScenarioManager::RegisterScenario这个函数对场景配置文件进行读取,这里注意的是在ScenarioManager::Init()初始化的时候,也就是刚开始执行planning场景时会定义一个默认的场景LANE_FOLLOW。

//场景注册
void ScenarioManager::RegisterScenarios() {
  // lane_follow
  if (planning_config_.learning_mode() == PlanningConfig::HYBRID ||
      planning_config_.learning_mode() == PlanningConfig::HYBRID_TEST) {
    // HYBRID or HYBRID_TEST
    ACHECK(Scenario::LoadConfig(FLAGS_scenario_lane_follow_hybrid_config_file,
                                &config_map_[ScenarioConfig::LANE_FOLLOW]));
  } else {
    ACHECK(Scenario::LoadConfig(FLAGS_scenario_lane_follow_config_file,
                                &config_map_[ScenarioConfig::LANE_FOLLOW]));
  }

1.4场景更新

采用有限状态机算法,在多个场景中选择当前条件合适的场景.

//更新场景
void ScenarioManager::Update(const common::TrajectoryPoint& ego_point,
                             const Frame& frame) {
  ACHECK(!frame.reference_line_info().empty());
  //保留当前帧
  Observe(frame);
  //场景分发 通过一个有限状态机,决定当前场景
  ScenarioDispatch(frame);
}

1.5 场景确认

ScenarioManager除了负责场景的配置与注册外也负责对场景进行具体的确认,具体实现来看主要是ScenarioManager::Update进行这部分功能代码逻辑的实现。这个函数有两个输入:common::TrajectoryPoint 与 Frame。其中TrajectoryPoint包含了车辆的基础位置,速度,加速度,方向等自车信息。Frame则代表了一次planning循环计算后所有的需要存储的结果与中间信息。

//更新场景
void ScenarioManager::Update(const common::TrajectoryPoint& ego_point,
                             const Frame& frame) {
  ACHECK(!frame.reference_line_info().empty());
  //保留当前帧
  Observe(frame);
  //场景分发 通过一个有限状态机,决定当前场景
  ScenarioDispatch(frame);
}

其中,ScenarioManager::Observe函数获取当前各个模块的信息,并更新first_encountered_overlaps。

在apollo里 Overlap 是指地图上任意重合的东西,比如PNC_JUNCTION里是道路之间有相互重合,SIGNAL是信号灯与道路有重合,STOP_SIGN是停止标志与道路有重合,YIELD_SIGN是合标志与道路有重合。

void ScenarioManager::Observe(const Frame& frame) {
  // init first_encountered_overlap_map_
  first_encountered_overlap_map_.clear();
  const auto& reference_line_info = frame.reference_line_info().front();
  const auto& first_encountered_overlaps =
      reference_line_info.FirstEncounteredOverlaps();
  for (const auto& overlap : first_encountered_overlaps) {
    if (overlap.first == ReferenceLineInfo::PNC_JUNCTION ||
        overlap.first == ReferenceLineInfo::SIGNAL ||
        overlap.first == ReferenceLineInfo::STOP_SIGN ||
        overlap.first == ReferenceLineInfo::YIELD_SIGN) {
      first_encountered_overlap_map_[overlap.first] = overlap.second;
    }
  }
}

而ScenarioManager::ScenarioDispatch函数则会对场景进行具体的处理,在apollo 6.0的planning模块中共有2种处理模式,分别是经典模式(能够有具体的场景定义的)与学习模式(通过深度学习进行场景处理的),分别会根据配置文件调用其后的ScenarioManager::ScenarioLearningDispatch与ScenarioManager::ScenarioNoLearningDispatch。

ScenarioManager::ScenarioNoLearningDispatch则是通过车辆状态frame中的scenario_type对车辆具体场景模块进行切换 ScenarioManager::Select*Scenario,并且由场景执行stage。

二.stage

在planning模块确定scenarios之后就会进入stage阶段,stage是plannin衔接scenarios与后具体执行器task的中间阶段。

以最简单的lane_follow为例,在scenarios中会调用http://lane_follow_scenarios.cc的中的 LaneFollowScenario::CreateStage创建LaneFollowStage,而具体的LaneFollowStage的具体实现则在lane_follow_stage中。

执行具体stage的逻辑的入口则在中scenario.cc的Process中,根据最后一行的current_stage_->Process() 会调用到lane_follow_stage中的LaneFollowStage::Process函数,并返回目前stage的状态。

//执行场景中stage和task,具体stage的入口
Scenario::ScenarioStatus Scenario::Process(
    const common::TrajectoryPoint& planning_init_point, Frame* frame) {
  if (current_stage_ == nullptr) {
    AWARN << "Current stage is a null pointer.";
    return STATUS_UNKNOWN;
  }
  //如果当前阶段完成,则退出
  if (current_stage_->stage_type() == ScenarioConfig::NO_STAGE) {
    scenario_status_ = STATUS_DONE;
    return scenario_status_;
  }
  //进入下一阶段执行或者错误处理,返回当前stage的状态
  auto ret = current_stage_->Process(planning_init_point, frame);

在配置文件中我们看见,LANE_FOLLOW只注册了一个stage,这个stage中注册了一系列的task。而apollo的stage会在LaneFollowStage::Process函数中的LaneFollowStage::PlanOnReferenceLine中对所有注册的Task执行task->Execute()。

上面提到的LANE_FOLLOW是一个只包含一个stage的场景,下面再以一个多stage的场景举例。

首先在配置文件方面。BARE_INTERSECTION_UNPROTECTED注册了APPROACH与INTERSECTION_CRUISE两个阶段。每个阶段分别注册了不同的TASK。

scenario_type: BARE_INTERSECTION_UNPROTECTED//无保护裸露交叉路口
bare_intersection_unprotected_config: {
  start_bare_intersection_scenario_distance: 25.0
  enable_explicit_stop: false
  min_pass_s_distance: 3.0
  approach_cruise_speed: 6.7056  # 15 mph
  stop_distance: 0.5
  stop_timeout_sec: 8.0
  creep_timeout_sec: 10.0
}
//两个stage, stage1:
stage_type: BARE_INTERSECTION_UNPROTECTED_APPROACH
stage_type: BARE_INTERSECTION_UNPROTECTED_INTERSECTION_CRUISE

stage_config: {
  stage_type: BARE_INTERSECTION_UNPROTECTED_APPROACH
  enabled: true
  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: ST_BOUNDS_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_NONLINEAR_SPEED_OPTIMIZER
  task_config: {
    task_type: PATH_LANE_BORROW_DECIDER
  }
  task_config: {
    task_type: PATH_BOUNDS_DECIDER
  }
  task_config: {
    task_type: PIECEWISE_JERK_PATH_OPTIMIZER
  }
  ...
}

stage_config: {
  stage_type: BARE_INTERSECTION_UNPROTECTED_INTERSECTION_CRUISE
  enabled: true
  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: ST_BOUNDS_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_NONLINEAR_SPEED_OPTIMIZER
  task_config: {
    task_type: PATH_LANE_BORROW_DECIDER
    path_lane_borrow_decider_config {
      allow_lane_borrowing: true
    }
  }
  task_config: {
    task_type: PATH_BOUNDS_DECIDER
  }
  task_config: {
    task_type: PIECEWISE_JERK_PATH_OPTIMIZER
  }
...
}

在scenarios的具体实现中,apollo分别在bare_instersection中创建了>BareIntersectionUnprotectedScenario(bare_intersection_unprotected_scenario)类, BareIntersectionUnprotectedStageApproach(stage_approach)类与BareIntersectionUnprotectedStageIntersectionCruise(stage_intersection_cruise)类。其中注册的BARE_INTERSECTION_UNPROTECTED_APPROACH与BARE_INTERSECTION_UNPROTECTED_INTERSECTION_CRUISE这两个阶段分别对应了BareIntersectionUnprotectedStageApproach类与BareIntersectionUnprotectedStageIntersectionCruise类。这两个阶段会在BareIntersectionUnprotectedScenario::RegisterStages函数中被创建。

//注册stage->两个stage
void BareIntersectionUnprotectedScenario::RegisterStages() {
  if (!s_stage_factory_.Empty()) {
    s_stage_factory_.Clear();
  }
  s_stage_factory_.Register(
      ScenarioConfig::BARE_INTERSECTION_UNPROTECTED_APPROACH,
      [](const ScenarioConfig::StageConfig& config,
         const std::shared_ptr<DependencyInjector>& injector) -> Stage* {
        return new BareIntersectionUnprotectedStageApproach(config, injector);
      });
  s_stage_factory_.Register(
      ScenarioConfig::BARE_INTERSECTION_UNPROTECTED_INTERSECTION_CRUISE,
      [](const ScenarioConfig::StageConfig& config,
         const std::shared_ptr<DependencyInjector>& injector) -> Stage* {
        return new BareIntersectionUnprotectedStageIntersectionCruise(config,
                                                                      injector);
      });
}

每个stage具体实现和LANE_FOLLOW一样是stage::Process执行。最终会返回这个stage的状态ERROR,READY,RUNNING与FINISHED。

三.task

在apollo/modules/planning/tasks文件夹中,Task分为3类:deciders(决策),optimizers(规划),learning_model。task.h定义了Task基类,其中重要的是2个Execute()函数。向上而言,这两个函数会在前序的stage部分被ExecuteTaskOnReferenceLine以执行task的具体逻辑。

在具体Execute继承而言decider/decider.h中定义了Decider类,继承自Task类,对应着继承而来的2个Execute(),分别定义了2个Process(),即Task的执行是通过Decider::Process()运行的。learning_model 与 optimizers也是类似的继承逻辑。

不过这里有几个decider是例外的是直接继承了Task类的而不是继承Decider类,例如PathDecider与SpeedDecider

在deciders(决策)模块中apollo中apollo实现了14个deciders(决策)任务,optimizers(规划)实现了三个Tasks的基本大类,PathOptimizer,SpeedOptimizer,TrajectoryOptimizer。这3种Optimizer实现了各自的Execute(),并定义了纯虚函数Process()在Execute()中被调用,由子类实现具体的Process()。不同的优化器,如PiecewiseJerkPathOptimizer是继承自PathOptimizer的,实现自己的Process()。

preview

 

声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号