赞
踩
Apollo中的Planning(规划)模块的场景选择是通过scenario-stage-task并利用状态机行车对车辆状态和规划功能进行维护的。
scenario代表当前所处的场景,包括正常的路上行驶场景、停车场景、红绿灯路口场景等。
scenario功能模块中的主要功能如下:
1.1 场景管理scenario_manager
planning模块对于scenario的切换的代码是在scenario_manager中实现的,目前apollo一共支持了11多种场景和场景的定义。
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。
在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。
在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()。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。