前面已经介绍过了参考线的平滑算法,接下来继续介绍路径规划算法.
1.
bool PlanningComponent::Proc(
const std::shared_ptr<prediction::PredictionObstacles>&
prediction_obstacles,
const std::shared_ptr<canbus::Chassis>& chassis,
const std::shared_ptr<localization::LocalizationEstimate>&
localization_estimate)
prediction_obstacles:感知结果
chassis:底盘数据
localization_estimate:定位数据
2.
planning_base_->RunOnce(local_view_, &adc_trajectory_pb);
local_view_:用来集中保存一次规划周期中Planning所“看到”的所有输入数据
adc_trajectory_pb:planning最终输出的轨迹
3.
status = Plan(start_timestamp, stitching_trajectory, ptr_trajectory_pb);
start_timestamp:时钟同步后,系统启动以来流逝了多少秒
stitching_trajectory:拼接轨迹
ptr_trajectory_pb:planning最终输出的轨迹
轨迹拼接会单独介绍,这里先介绍第一次规划轨迹的流程,轨迹拼接是在有上一帧轨迹的情况下,才会判断是否进行拼接.所以这里跳过并不影响理清路径规划的流程.但还是要看一下ComputeStitchingTrajectory函数.
std::vector<TrajectoryPoint> TrajectoryStitcher::ComputeStitchingTrajectory(
const canbus::Chassis& vehicle_chassis, const VehicleState& vehicle_state,
const double current_timestamp, const double planning_cycle_time,
const size_t preserved_points_num, const bool replan_by_offset,
const PublishableTrajectory* prev_trajectory, std::string* replan_reason,
const control::ControlInteractiveMsg& control_interactive_msg)
vehicle_chassis:底盘数据
vehicle_state:当前自车数据
current_timestamp:时钟同步后,系统启动以来流逝了多少秒
planning_cycle_time:表示planning每隔多久执行一次,默认是0.01s
preserved_points_num:表示在轨迹拼接时,从上一帧已发布轨迹中“保留多少个轨迹点”继续使用,默认是20个轨迹点
replan_by_offset:默认为true
prev_trajectory:上一帧生成的轨迹
replan_reason:重新规划的原因
control_interactive_msg:
std::vector<TrajectoryPoint> TrajectoryStitcher::ComputeStitchingTrajectory(
const canbus::Chassis& vehicle_chassis, const VehicleState& vehicle_state,
const double current_timestamp, const double planning_cycle_time,
const size_t preserved_points_num, const bool replan_by_offset,
const PublishableTrajectory* prev_trajectory, std::string* replan_reason,
const control::ControlInteractiveMsg& control_interactive_msg) {
// 1.check replan not by offset
size_t time_matched_index = 0;
if (need_replan_by_necessary_check(vehicle_state, current_timestamp,
prev_trajectory, replan_reason,
&time_matched_index)) {
return ComputeReinitStitchingTrajectory(planning_cycle_time, vehicle_state);
}
bool TrajectoryStitcher::need_replan_by_necessary_check(
const common::VehicleState& vehicle_state, const double current_timestamp,
const PublishableTrajectory* prev_trajectory, std::string* replan_reason,
size_t* time_matched_index) {
if (!FLAGS_enable_trajectory_stitcher) {
*replan_reason = "stitch is disabled by gflag.";
return true;
}
if (!prev_trajectory) {
*replan_reason = "replan for no previous trajectory.";
return true;
}
如果上一帧轨迹为空,则直接返回true
ComputeReinitStitchingTrajectory函数
std::vector<TrajectoryPoint>
TrajectoryStitcher::ComputeReinitStitchingTrajectory(
const double planning_cycle_time, const VehicleState& vehicle_state) {
TrajectoryPoint reinit_point;
static constexpr double kEpsilon_v = 0.1;
static constexpr double kEpsilon_a = 0.4;
// TODO(Jinyun/Yu): adjust kEpsilon if corrected IMU acceleration provided
if (std::abs(vehicle_state.linear_velocity()) < kEpsilon_v &&
std::abs(vehicle_state.linear_acceleration()) < kEpsilon_a) {
reinit_point = ComputeTrajectoryPointFromVehicleState(planning_cycle_time,
vehicle_state);
} else {
VehicleState predicted_vehicle_state;
predicted_vehicle_state =
VehicleModel::Predict(planning_cycle_time, vehicle_state);
reinit_point = ComputeTrajectoryPointFromVehicleState(
planning_cycle_time, predicted_vehicle_state);
}
return std::vector<TrajectoryPoint>(1, reinit_point);
}
因为最开始的时候,车一定是停着的,所以车的速度和加速度为0,那么就会直接调用
ComputeTrajectoryPointFromVehicleState函数
TrajectoryPoint TrajectoryStitcher::ComputeTrajectoryPointFromVehicleState(
const double planning_cycle_time, const VehicleState& vehicle_state) {
TrajectoryPoint point;
point.mutable_path_point()->set_s(0.0);
point.mutable_path_point()->set_x(vehicle_state.x());
point.mutable_path_point()->set_y(vehicle_state.y());
point.mutable_path_point()->set_z(vehicle_state.z());
point.mutable_path_point()->set_theta(vehicle_state.heading());
point.mutable_path_point()->set_kappa(vehicle_state.kappa());
point.set_v(vehicle_state.linear_velocity());
point.set_a(vehicle_state.linear_acceleration());
point.set_relative_time(planning_cycle_time);
return point;
}
此时返回的拼接轨迹stitching_trajectory,只有一个轨迹点在当前自车位置
4.
auto status = planner_->Plan(stitching_trajectory.back(), frame_.get(),
ptr_trajectory_pb);
stitching_trajectory.back():就是上面使用自车位置构建的轨迹点,这也是规划的起点
frame_:Frame类包含了planning一次执行中所用到的所有信息,它也包括后续规划器的所有的输入信息,输出信息
这个专栏只介绍PublicRoadPlanner规划器
Status PublicRoadPlanner::Plan(const TrajectoryPoint& planning_start_point,
Frame* frame,
ADCTrajectory* ptr_computed_trajectory) {
scenario_manager_.Update(planning_start_point, frame);
scenario_manager_:是场景管理器,public road planner包含的所有场景在配置文件/home/zsy/apollo/modules/planning/planners/public_road/conf/planner_config.pb.txt中
void ScenarioManager::Update(const common::TrajectoryPoint& ego_point,
Frame* frame) {
CHECK_NOTNULL(frame);
for (auto scenario : scenario_list_) {
if (current_scenario_.get() == scenario.get() &&
current_scenario_->GetStatus() ==
ScenarioStatusType::STATUS_PROCESSING) {
// The previous scenario has higher priority
return;
}
if (scenario->IsTransferable(current_scenario_.get(), *frame)) {
current_scenario_->Exit(frame);
AINFO << "switch scenario from" << current_scenario_->Name() << " to "
<< scenario->Name();
current_scenario_ = scenario;
current_scenario_->Reset();
current_scenario_->Enter(frame);
return;
}
}
}
当一个规划器调用Update时,它会遍历planner_config.pb.txt配置中的所有场景,然后通过调用每个场景自己的IsTransferable来判断,当前自车所在位置符合进入哪个场景.
auto result = scenario_->Process(planning_start_point, frame);
ScenarioResult Scenario::Process(
const common::TrajectoryPoint& planning_init_point, Frame* frame) {
if (current_stage_ == nullptr) {
current_stage_ = CreateStage(
*stage_pipeline_map_[scenario_pipeline_config_.stage(0).name()]);
根据modules/planning/scenarios/lane_follow/conf/pipeline.pb.txt配置文件创建stage
auto ret = current_stage_->Process(planning_init_point, frame);
这里主要介绍LANE_FOLLOW_STAGE
result =
PlanOnReferenceLine(planning_start_point, frame, &reference_line_info);
在LaneFollowStage::Process中,会遍历平滑后的参考线,然后分别执行上面逻辑
task->Execute(frame, reference_line_info)
在PlanOnReferenceLine函数中会遍历当前stage,modules/planning/scenarios/lane_follow/conf/pipeline.pb.txt中所有task任务.
每个task类的父类PathGeneration中有一个
apollo::common::Status PathGeneration::Execute(
Frame* frame, ReferenceLineInfo* reference_line_info) {
Task::Execute(frame, reference_line_info);
return Process(frame, reference_line_info);
}
这样的话,配置文件中的每一个task自己的Process函数都会被执行
在介绍lane_follow中的task前,介绍一下初始化流程
bool PlanningComponent::Init() {
injector_ = std::make_shared<DependencyInjector>();
...
planning_base_->Init(config_);
planner_->Init(injector_, FLAGS_planner_config_path);
scenario_manager_.Init(injector, config_);
scenario->Init(injector_, planner_config.scenario(i).name())
stage_ptr->Init(stage_pipeline, injector_, config_dir_, GetContext())
task_ptr->Init(task_config_dir, task.name(), injector)
injector_是DependencyInjector类型.
DependencyInjector:是一个数据缓存中心,管理planning过程中的实时数据和几乎所有的历史数据,用于规划任务的前后帧之间的承接,以及异常处理的回溯
- PlanningContext planning_context:负责planning上下文的缓存,比如变道、借道、巡航等各种场景下的规划信息。
- FrameHistory frame_history:是一个可索引队列,负责planning的输入、输出主要信息的缓存,以Frame类进行组织,内部包含LocalView结构体(负责输入数据的融合管理)。与上述的History不同的是,该数据自模块启动后就开始缓存所有的Frame对象,不受routing变动的影响。
- History history:负责障碍物状态的缓存,包括运动状态、决策结果。该数据与routing结果绑定,routing变更后会清理掉历史数据。
- EgoInfo ego_info:提供车辆动、静信息,即车辆运动状态参数(轨迹、速度、加速度等)和车辆结构参数(长宽高等)。
- apollo::common::VehicleStateProvider vehicle_state:车辆状态提供器,用于获取车辆实时信息。
- LearningBasedData learning_based_data:基于学习的数据,用于学习建模等。
LANE_FOLLOW_STAGE中,如果是换道的情况,下面task会被执行
I1215 22:07:27.587636 365977 lane_follow_stage.cc:169] Planning Perf: task name [LANE_CHANGE_PATH], 0.139952 ms.
I1215 22:07:27.590972 365977 lane_follow_stage.cc:169] Planning Perf: task name [LANE_FOLLOW_PATH], 3.33333 ms.
I1215 22:07:27.590978 365977 lane_follow_stage.cc:169] Planning Perf: task name [LANE_BORROW_PATH], 0.00405312 ms.
I1215 22:07:27.590981 365977 lane_follow_stage.cc:169] Planning Perf: task name [FALLBACK_PATH], 0.00119209 ms.
I1215 22:07:27.591069 365977 lane_follow_stage.cc:169] Planning Perf: task name [PATH_DECIDER], 0.0867844 ms.
I1215 22:07:27.591073 365977 lane_follow_stage.cc:169] Planning Perf: task name [RULE_BASED_STOP_DECIDER], 0.00119209 ms.
I1215 22:07:27.591271 365977 lane_follow_stage.cc:169] Planning Perf: task name [SPEED_BOUNDS_PRIORI_DECIDER], 0.198126 ms.
I1215 22:07:27.591984 365977 lane_follow_stage.cc:169] Planning Perf: task name [SPEED_HEURISTIC_OPTIMIZER], 0.710964 ms.
I1215 22:07:27.591989 365977 lane_follow_stage.cc:169] Planning Perf: task name [SPEED_DECIDER], 0.0026226 ms.
I1215 22:07:27.592176 365977 lane_follow_stage.cc:169] Planning Perf: task name [SPEED_BOUNDS_FINAL_DECIDER], 0.186205 ms.
I1215 22:07:27.594007 365977 lane_follow_stage.cc:169] Planning Perf: task name [PIECEWISE_JERK_SPEED], 1.82629 ms.