Apollo Planning(三)

一、Scenario

我们同样先看下"scenarios"的目录结构:

.
├── bare_intersection
├── common
├── dead_end
├── emergency
├── lane_follow            // 车道线保持
├── narrow_street_u_turn   // 狭窄掉头
├── learning_model
├── park			// 泊车
├── park_and_go
├── stop_sign			// 停止
├── traffic_light		// 红绿灯
├── util
├── yield_sign
├── BUILD
├── scenario.cc
├── scenario.h
├── scenario_manager.cc
├── scenario_manager.h 
├── stage.cc
├── stage.h

Scenario_manager负责管理场景,每个场景分为一个或者多个阶段(stage),每个阶段又由不同的任务(task)组成。

1.1场景生成及转换

场景管理类"scenario_manager.cc"实现了场景注册、创建、初始化和更新场景的功能。

bool ScenarioManager::Init(const PlanningConfig& planning_config) {
  // 注册场景
  RegisterScenarios();
  default_scenario_type_ = ScenarioConfig::LANE_FOLLOW;
  // 创建场景,默认为lane_follow
  current_scenario_ = CreateScenario(default_scenario_type_);
  return true;
}

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

// 场景分发
void ScenarioManager::ScenarioDispatch(const Frame& frame) {
  ...
  ScenarioConfig::ScenarioType scenario_type;
  ...
  if (...) {
    scenario_type = ScenarioDispatchLearning();
  } else {
	// 每次切换场景都是从默认场景(LANE_FOLLOW)开始,即每次场景切换之后都会回到默认场景
    scenario_type = ScenarioDispatchNonLearning(frame);
  }
  ...
  // update PlanningContext
  UpdatePlanningContext(frame, scenario_type);
  if (current_scenario_->scenario_type() != scenario_type) {
  // 创建场景,此处的场景已经为具体场景,如ValetParkingScenario
    current_scenario_ = CreateScenario(scenario_type);
  }
}

// 创建场景
std::unique_ptr<Scenario> ScenarioManager::CreateScenario(
    ScenarioConfig::ScenarioType scenario_type) {
  std::unique_ptr<Scenario> ptr;
// 根据type创建场景,以valet_parking场景为例
  switch (scenario_type) {
    ...
case ScenarioConfig::VALET_PARKING:
      ptr.reset(new scenario::valet_parking::ValetParkingScenario(
          config_map_[scenario_type], &scenario_context_, injector_));
      break;
    ...
    default:
      return nullptr;
  }

  if (ptr != nullptr) {
   // 具体场景初始化
    ptr->Init();
  }
  return ptr;
}

1.2场景运行

执行一个场景,就是顺序执行不同阶段的不同任务。valet_parking场景的运行流程图如下:

 

其中scenario对应的stage和task在"planning/conf/scenario"中,以泊车为例,场景配置文件在“planning/conf/scenario/valet_parking_config.pb.txt”中:

// Scenario对应的Stage
scenario_type: VALET_PARKING
valet_parking_config: {
  ...
}
stage_type: VALET_PARKING_APPROACHING_PARKING_SPOT
stage_type: VALET_PARKING_PARKING
// Stage对应的Task
stage_config: {
  stage_type: VALET_PARKING_APPROACHING_PARKING_SPOT
  ...
}
stage_config: {
  stage_type: VALET_PARKING_PARKING
  enabled: true
  task_type: OPEN_SPACE_ROI_DECIDER
  ...
  task_config: {
    ...
  }
  ...
}

1.3 Stage

CreateScenario中会完成场景初始化“ptr->Init();”场景初始化过程中又会完成Stage的创建,具体实现为:

void ValetParkingScenario::Init() {
  ...
  Scenario::Init();
  ...
  hdmap_ = hdmap::HDMapUtil::BaseMapPtr();
  CHECK_NOTNULL(hdmap_);
}  
//场景初始化
void Scenario::Init() {
  ...
  current_stage_ = 
      CreateStage(*stage_config_map_[config_.stage_type(0)], injector_);
}

类Scenario是各场景的基类,scenario.cc中的CreateStage()是virtual函数,具体实现在子类中完成,如在ValetParkingScenario中:

std::unique_ptr<Stage> ValetParkingScenario::CreateStage(
    const ScenarioConfig::StageConfig& stage_config,
const std::shared_ptr<DependencyInjector>& injector) {
// 判断Stage是否已注册,注册Stage
  if (s_stage_factory_.Empty()) {
    RegisterStages();
  }
  // 生成stage
  auto ptr = s_stage_factory_.CreateObjectOrNull(stage_config.stage_type(),                                                 stage_config, injector);
  if (ptr) {
    ptr->SetContext(&context_);
  }
  return ptr;
} 

       此外需要注意,在RegisterStages,Stage在构造函数中完成Task的创建:

Stage::Stage(const ScenarioConfig::StageConfig& config,
             const std::shared_ptr<DependencyInjector>& injector)
    : config_(config), injector_(injector) {
  ...
  name_ = ScenarioConfig::StageType_Name(config_.stage_type());
  next_stage_ = config_.stage_type();
  std::unordered_map<TaskConfig::TaskType, const TaskConfig*, std::hash<int>> config_map;
  for (const auto& task_config : config_.task_config()) {
    config_map[task_config.task_type()] = &task_config;
  }
  for (int i = 0; i < config_.task_type_size(); ++i) {
    auto task_type = config_.task_type(i);
    ...
    auto iter = tasks_.find(task_type);
    if (iter == tasks_.end()) {
	// 创建Task
      auto ptr = TaskFactory::CreateTask(*config_map[task_type], injector_);
      task_list_.push_back(ptr.get());
      tasks_[task_type] = std::move(ptr);
    } else {
      task_list_.push_back(iter->second.get());
    }
  }
}

场景初始化完成之后,Stage和Task也都创建完成,执行具体场景的Process()。由于Scenario都是顺序执行,只需要判断这一阶段是否结束,然后转到下一个Stage就可以了。具体的实现在:

Stage::StageStatus StageParking::Process(
    const common::TrajectoryPoint& planning_init_point, Frame* frame) {
  // Open space planning doesn't use planning_init_point from upstream because of different stitching strategy
  frame->mutable_open_space_info()->set_is_on_open_space_trajectory(true);
  bool plan_ok = ExecuteTaskOnOpenSpace(frame);
  if (!plan_ok) {
    AERROR << "StageParking planning error";
    return StageStatus::ERROR;
  }
  return StageStatus::RUNNING;
}

   Process功能主要由ExecuteTaskOnOpenSpace(frame)完成,在stage.cc文件中找到该函数:

bool Stage::ExecuteTaskOnOpenSpace(Frame* frame) {
auto ret = common::Status::OK();
// 完成Task列表中的各具体task
for (auto* task : task_list_) {
  ret = task->Execute(frame);
  ...
  }
}
...
return true;
}

   在这里各task得到执行task->Execute(frame)task按顺序执行完毕,进入下一stage,或scenario完全执行完毕进入下一scenario


版权声明:本文为whuzhang16原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。