planning模块对于scenario的切换的代码是在scenario_manager中实现的,目前apollo一共支持了11多种场景和场景的定义。
LaneFollowscenario
:默认驾驶场景,包括本车道保持、变道、基本转弯
TrafficLightProtectedScenario
有保护交通灯,即有明确的交通指示灯(左转、右转),是有路权保护的红绿灯场景,在该场景下可以实现在红绿灯路口前红灯停车,绿灯通过路口。
EmergencyStopScenario
: 紧急停车场景,车辆在行驶过程中如果收到PadMessage命令“PadMessage::STOP”,主车计算停车距离,直接停车。
ParkAndGoScenario
:从车位出库到路线上,用于车辆在远离终点且静止条件下,在非城市车道或匹配不到道路点的位置,通过freespace规划,实现车辆由开放空间驶入道路的功能。
ValetParkingScenario
可以在停车区域泊入指定的车位。
PullOverScenario
: 靠边停车场景, enable_pull_over_at_destination
设置为 true
时, 当车辆到达终点附近时,将自动切入 PullOverScenario
并完成靠边停车。
BareIntersectionUnprotectedScenario
: 无保护裸露交叉路口场景,在交通路口既没有停止标志,也没有交通灯,车辆在路口前一段距离范围内切换到此场景。
EmergencyPullOverScenario
: 紧急靠边停车场景,车辆在行驶过程中如果收到PadMessage命令“PULL_OVER”,车辆就近找到合适的位置在当前车道内停车,相比于直接停车,这样保证了行驶过程中的停车安全性和舒适性。
StopSignUnprotectedScenario
无保护停止标志,场景可以在高精地图中有停止标记的路口时停车,观望周边车辆,等待周围车辆驶离后跛行,再快速通过路口。
TrafficLightUnprotectedLeftTurnScenario
是没有路权保护的红绿灯左转场景。在该场景下,主车在左转车道线上
TrafficLightUnprotectedRightTurnScenario
是有路权保护的红绿灯右转场景,在该场景下可以实现在红绿灯路口前红灯停车,绿灯通过路口。
YieldSignScenario
场景可以在有让行标记的场景减速观望,然后慢速通过。
ValetParkingScenario
可以在停车区域泊入指定的车位。
场景切入条件
- planning command里存在泊车命令
- 距离泊车点距离parking_spot_range_to_start以内
1. 检查泊车指令有效性
if (!frame.local_view().planning_command->has_parking_command()) {
return false; // 无泊车指令时阻断场景切换
}
2. 输入参数校验
if (other_scenario == nullptr || frame.reference_line_info().empty()) {
return false; // 上下文或参考线缺失时退出
}
other_scenario
为空表示无前序场景上下文,可能导致状态错误。3. 解析目标停车位 ID
std::string target_parking_spot_id;
if (frame.local_view().planning_command->has_parking_command() &&
frame.local_view().planning_command->parking_command().has_parking_spot_id()) {
// 从指令中提取停车位 ID
target_parking_spot_id = ...;
} else {
ADEBUG << "No parking space id from routing";
return false;
}
parking_spot_id
)。4. 搜索目标停车位
const auto& nearby_path = frame.reference_line_info().front().reference_line().map_path();
PathOverlap parking_space_overlap;
if (!SearchTargetParkingSpotOnPath(nearby_path, target_parking_spot_id, &parking_space_overlap)) {
ADEBUG << "No such parking spot found...";
return false; // 停车位不在当前路径上则退出
}
map_path
),匹配指定 ID 的停车位。parking_space_overlap
)。5. 检查距离条件
double parking_spot_range_to_start = context_.scenario_config.parking_spot_range_to_start();
if (!CheckDistanceToParkingSpot(frame, vehicle_state, nearby_path,
parking_spot_range_to_start,
parking_space_overlap)) {
ADEBUG << "target parking spot too far...";
return false;
}
start_s
)的纵向距离。parking_spot_range_to_start
(如 50米),判定为过远。parking_spot_range_to_start
来自 scenario_conf.pb.txt
配置文件。6. 更新场景上下文
context_.target_parking_spot_id = target_parking_spot_id;
return true; // 满足所有条件,允许切换至代客泊车场景
StageApproachingParkingSpot
)使用。关联设计总结
场景切换条件
安全冗余机制
other_scenario
和 reference_line_info
的空指针检查避免运行时崩溃。调试与日志
ADEBUG
记录关键判定结果(如停车位未找到或距离过远),便于问题排查。true
,触发后续阶段的初始化。典型应用场景
阶段:接近停车位阶段
1. 阶段标识与输入校验
ADEBUG << "stage: StageApproachingParkingSpot"; // 标记当前为接近停车位阶段
CHECK_NOTNULL(frame); // 确保帧数据指针有效性
StageResult result; // 初始化阶段结果对象
2. 上下文有效性校验
auto scenario_context = GetContextAs<ValetParkingContext>();
if (scenario_context->target_parking_spot_id.empty()) {
return result.SetStageStatus(StageStatusType::ERROR); // 无目标停车位ID时返回错误
}
ValetParkingContext
包含 target_parking_spot_id
字段用于标识目标停车位 。3. 设置开放空间信息
// 将上下文中的停车位ID传递至当前帧
*(frame->mutable_open_space_info()->mutable_target_parking_spot_id()) =
scenario_context->target_parking_spot_id;
// 同步预停止标志及坐标点
frame->mutable_open_space_info()->set_pre_stop_rightaway_flag(
scenario_context->pre_stop_rightaway_flag);
*(frame->mutable_open_space_info()->mutable_pre_stop_rightaway_point()) =
scenario_context->pre_stop_rightaway_point;
pre_stop_rightaway_flag
:标记是否需要立即预停车(如检测到障碍物)。pre_stop_rightaway_point
:预停车目标点坐标 。4. 参考线遍历与障碍物处理
auto* reference_lines = frame->mutable_reference_line_info();
for (auto& reference_line : *reference_lines) {
auto* path_decision = reference_line.path_decision();
if (nullptr == path_decision) continue;
// 查找并处理目的地虚拟障碍物(ID为FLAGS_destination_obstacle_id)
auto* dest_obstacle = path_decision->Find(FLAGS_destination_obstacle_id);
if (nullptr == dest_obstacle) continue;
ObjectDecisionType decision;
decision.mutable_ignore(); // 设置忽略决策
dest_obstacle->EraseDecision();
dest_obstacle->AddLongitudinalDecision("ignore-dest-in-valet-parking", decision);
}
DESTINATION
标签),避免误触发停车决策 。"ignore-dest-in-valet-parking"
标识此操作场景,便于调试追踪 。5. 执行参考线任务链
result = ExecuteTaskOnReferenceLine(planning_init_point, frame);
PathDecider
)。SpeedOptimizer
生成平滑速度曲线。6. 同步预停止状态
scenario_context->pre_stop_rightaway_flag =
frame->open_space_info().pre_stop_rightaway_flag();
scenario_context->pre_stop_rightaway_point =
frame->open_space_info().pre_stop_rightaway_point();
7. 阶段退出条件判断
if (CheckADCStop(*frame)) { // 检查车辆是否完全停止
next_stage_ = "VALET_PARKING_PARKING"; // 进入停车阶段
return StageResult(StageStatusType::FINISHED); // 当前阶段完成
}
if (result.HasError()) { // 任务链执行异常
AERROR << "StopSignUnprotectedStagePreStop planning error";
return result.SetStageStatus(StageStatusType::ERROR);
}
VALET_PARKING_PARKING
阶段(实际泊入操作) 。8. 默认状态返回
return result.SetStageStatus(StageStatusType::RUNNING); // 继续执行当前阶段
设计关联与关键机制
虚拟障碍物管理
ignore-dest-in-valet-parking
)增强调试可追溯性 。跨阶段状态同步
ValetParkingContext
)与帧数据(OpenSpaceInfo
)双向同步,确保路径规划的连贯性 。安全冗余设计
代码解释:
StageResult StageApproachingParkingSpot::Process(
const common::TrajectoryPoint& planning_init_point, Frame* frame) {
ADEBUG << "stage: StageApproachingParkingSpot";// 标记当前为接近停车位阶段
CHECK_NOTNULL(frame);
StageResult result;
auto scenario_context = GetContextAs<ValetParkingContext>();
// 无目标停车位ID时返回错误
if (scenario_context->target_parking_spot_id.empty()) {
return result.SetStageStatus(StageStatusType::ERROR);
}
// 将上下文中的停车位ID传递至当前帧
*(frame->mutable_open_space_info()->mutable_target_parking_spot_id()) =
scenario_context->target_parking_spot_id;
// 同步预停止标志及坐标点
frame->mutable_open_space_info()->set_pre_stop_rightaway_flag(
scenario_context->pre_stop_rightaway_flag);// 标记是否需要立即预停车(如检测到障碍物)。
*(frame->mutable_open_space_info()->mutable_pre_stop_rightaway_point()) =
scenario_context->pre_stop_rightaway_point;//预停车目标点坐标 。
auto* reference_lines = frame->mutable_reference_line_info();
// 参考线遍历与障碍物处理
for (auto& reference_line : *reference_lines) {
auto* path_decision = reference_line.path_decision();
if (nullptr == path_decision) {
continue;
}
// 查找并处理目的地虚拟障碍物(ID为FLAGS_destination_obstacle_id)
auto* dest_obstacle = path_decision->Find(FLAGS_destination_obstacle_id);
if (nullptr == dest_obstacle) {
continue;
}
ObjectDecisionType decision;
decision.mutable_ignore(); // 设置忽略决策
dest_obstacle->EraseDecision();
dest_obstacle->AddLongitudinalDecision("ignore-dest-in-valet-parking",
decision);
}
// 执行参考线任务链
result = ExecuteTaskOnReferenceLine(planning_init_point, frame);
// 同步预停止状态
scenario_context->pre_stop_rightaway_flag =
frame->open_space_info().pre_stop_rightaway_flag();
scenario_context->pre_stop_rightaway_point =
frame->open_space_info().pre_stop_rightaway_point();
if (CheckADCStop(*frame)) { // 检查车辆是否完全停止
next_stage_ = "VALET_PARKING_PARKING";// 进入停车阶段
return StageResult(StageStatusType::FINISHED);//当前阶段完成
}
if (result.HasError()) {
AERROR << "StopSignUnprotectedStagePreStop planning error";
return result.SetStageStatus(StageStatusType::ERROR);
}
return result.SetStageStatus(StageStatusType::RUNNING);
}
以下是对 StageParking::Process
函数的逐行解释,结合 Apollo 代客泊车场景逻辑及搜索结果内容:
1. 上下文注释说明
// Open space planning doesn't use planning_init_point from upstream because
// of different stitching strategy
2. 获取场景上下文
auto scenario_context = GetContextAs<ValetParkingContext>();
ValetParkingContext
,包含目标停车位 ID、预停止状态等跨阶段共享数据。target_parking_spot_id
在 ValetParkingScenario::IsTransferable
阶段已通过停车位搜索和距离校验。3. 设置开放空间信息
frame->mutable_open_space_info()->set_is_on_open_space_trajectory(true); // 标记为开放空间模式
*(frame->mutable_open_space_info()->mutable_target_parking_spot_id()) =
scenario_context->target_parking_spot_id; // 传递目标停车位ID
4. 执行开放空间任务链
StageResult result = ExecuteTaskOnOpenSpace(frame);
OpenSpaceRoiDecider
)。OpenSpaceTrajectoryOptimizer
结合车辆动力学参数优化轨迹平滑性。5. 错误处理与状态返回
if (result.HasError()) {
AERROR << "StageParking planning error"; // 记录错误日志
return result.SetStageStatus(StageStatusType::ERROR); // 终止阶段
}
return result.SetStageStatus(StageStatusType::RUNNING); // 继续执行
RUNNING
直至车辆完全停入车位(需外部条件触发)。关联设计参数与配置
轨迹优化配置
轨迹拼接策略
典型应用场景
与其他阶段的协同
StageApproachingParkingSpot
负责将车辆引导至停车位附近并触发预停止。代码解释:
StageResult 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
// 获取场景上下文
auto scenario_context = GetContextAs<ValetParkingContext>();
frame->mutable_open_space_info()->set_is_on_open_space_trajectory(true);// 标记为开放空间模式
*(frame->mutable_open_space_info()->mutable_target_parking_spot_id()) =
scenario_context->target_parking_spot_id;// 传递目标停车位ID
// 执行开放空间任务链
StageResult result = ExecuteTaskOnOpenSpace(frame);
if (result.HasError()) {
AERROR << "StageParking planning error";
return result.SetStageStatus(StageStatusType::ERROR);
}
return result.SetStageStatus(StageStatusType::RUNNING);
}
StageResult StageParking::FinishStage() {
return StageResult(StageStatusType::FINISHED);
}
PullOverScenario
: 靠边停车场景,如果参数配置 enable_pull_over_at_destination
设置为 true
, 当车辆到达终点附近时,将自动切入 PullOverScenario
并完成靠边停车。
lane_follow_command
FLAGS_enable_pull_over_at_destination
参数配置允许靠边停车场景1. 基础条件校验
if (!frame.local_view().planning_command->has_late_follow_command()) {
return false; // 当前规划指令非车道跟随模式时阻断场景切换
}
if (other_scenario == nullptr || frame.reference_line_info().empty()) {
return false; // 上下文或参考线缺失时退出
}
if (!FLAGS_enable_pull_over_at_destination) {
return false; // 全局参数禁用靠边停车功能则退出
}
lane_follow_command
)时才允许切换场景。FLAGS_enable_pull_over_at_destination
控制是否启用终点靠边停车功能[[1][63]]。2. 终点位置有效性检查
const auto routing_end = frame.local_view().end_lane_way_point;
if (nullptr == routing_end) {
return false; // 路由终点无效时退出
}
common::SLPoint dest_sl;
reference_line.XYToSL(routing_end->pose(), &dest_sl);
if (!reference_line.IsOnLane(dest_sl)) {
return false; // 终点不在当前车道内则阻断
}
3. 纵向距离校验
const double adc_front_edge_s = reference_line_info.AdcSlBoundary().end_s();
const double adc_distance_to_dest = dest_sl.s() - adc_front_edge_s;
bool pull_over_scenario = (
frame.reference_line_info().size() == 1 && // 禁止变道中切入
adc_distance_to_dest >= context_.scenario_config.pull_over_min_distance_buffer() &&
adc_distance_to_dest <= context_.scenario_config.start_pull_over_scenario_distance()
);
4. 终点过近处理
if (adc_distance_to_dest < context_.scenario_config.max_distance_stop_search()) {
pull_over_scenario = false; // 终点过近时停止搜索停车位
}
5. 避开交通设施区域
constexpr double kDistanceToAvoidJunction = 8.0; // 禁止在交叉口附近停车
for (const auto& overlap : first_encountered_overlaps) {
if (overlap.first 为 PNC_JUNCTION/SIGNAL/STOP_SIGN/YIELD_SIGN) {
// 计算与交通设施的相对距离
if (距离在 kDistanceToAvoidJunction 内) {
pull_over_scenario = false;
break;
}
}
}
6. 右侧车道合法性校验
while (check_s < dest_sl.s()) {
reference_line.GetLaneFromS(check_s, &lanes);
// 检查右侧相邻车道类型
for (const auto& neighbor_lane_id : lane->right_neighbor_forward_lane_id()) {
if (neighbor_lane->type() == CITY_DRIVING) {
rightmost_driving_lane = false; // 右侧存在可行驶车道则禁止停车
break;
}
}
}
CITY_DRIVING
)进行靠边停车,右侧若存在同类型车道说明当前车道非最右侧[[48][63]]。Stages
阶段名 | 类型 | 描述 |
---|---|---|
PULL_OVER_APPROACH |
apollo::planning::PullOverStageApproach |
主车靠近靠边停车点 |
PULL_OVER_RETRY_APPROACH_PARKING |
apollo::planning::PullOverStageRetryApproachParking |
接近Parking位置点,主车速度、距离误差达到阈值后,进入下一个stage |
PULL_OVER_RETRY_PARKING |
apollo::planning::PullOverStageRetryParking |
执行openspace的轨迹规划,主车位置、航向达到阈值后,退出该stage |
PullOverStageApproach
: 该阶段用于主车规划接近靠边停车点,获取靠边停车轨迹,并检查是否完成靠边停车。
Process: 该阶段处理的主函数,输入为规划初始点 planning_init_point
、Frame
;输出为当前阶段处理状态StageResult
planning_init_point
、Frame
信息,按照该stage配置的task列表,依次进行规划。PullOverState
。状态返回值分为: UNKNOWN
, PASS_DESTINATION
, APPROACHING
, PARK_COMPLETE
和 PARK_FAIL
。如果完成靠边停车,即状态为 PASS_DESTINATION
或 PARK_COMPLETE
,则进入FinishStage
,结束当前Stage,并且退出当前PullOverScenario
;如果靠边停车失败,即状态为PARK_FAIL
,则进入FinishStage
,结束当前Stage,进入PULL_OVER_RETRY_APPROACH_PARKING
阶段。path_fail==true
, 在未到达停靠点前设置STOP
的虚拟障碍物。主车到达虚拟障碍物后,进入FinishStage
,结束当前Stage,进入PULL_OVER_RETRY_APPROACH_PARKING
阶段。如果path_fail==false
,则仍处于PULL_OVER_APPROACH
阶段。FinishStage: 该阶段的退出函数,输入为bool success
,即该阶段是否靠边停车成功。
success==true
,退出PULL_OVER_APPROACH
阶段,并退出PullOverScenario
。success==false
,退出PULL_OVER_APPROACH
阶段,进入PULL_OVER_RETRY_APPROACH_PARKING
阶段。PullOverStageRetryApproachParking
:上一阶段直接靠边停车失败,进入该阶段重试接近靠边停车点。
Process: 该阶段处理的主函数,输入为规划初始点 planning_init_point
、Frame
;输出为当前阶段处理状态StageResult
planning_init_point
、Frame
信息,按照该stage配置的task列表,依次进行规划。Frame
信息。主车满足速度小于阈值,位置距离规划设置的open_space_pre_stop_fence_s
小于阈值,进入FinishStage
,结束当前Stage。FinishStage: 该阶段的退出函数。
PULL_OVER_RETRY_APPROACH_PARKING
阶段,进入PULL_OVER_RETRY_PARKING
阶段。PullOverStageRetryParking
:上一阶段靠近停车点后,进入该阶段实线停车。
Process: 该阶段处理的主函数,输入为规划初始点 planning_init_point
、Frame
;输出为当前阶段处理状态StageResult
planning_init_point
、Frame
信息,按照该stage配置的task列表,依次进行规划。该阶段主要时调用Openspace的轨迹规划方法进行靠边停车规划。Frame
信息。主车与目标点的位置、航向偏差小于阈值,进入FinishStage
,结束当前Stage。FinishStage: 该阶段的退出函数。
PULL_OVER_RETRY_PARKING
阶段,退出当前PullOverScenario
。