一、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。