赞
踩
规划的本质是一个搜索问题,从数学角度来说寻找函数最优解
个人认为规划模块是整个自动驾驶系统中最复杂的模块,代码的量级方面可以与感知模块匹敌,但是感知包括了各个类型的传感器和融合,而规划仅可以解耦为横纵。规划模块复杂的只是相关的逻辑处理,和过程计算。
对于规划的三维问题,目前的解决方案是降维+迭代:将三维问题分解为ST和SL二维的优化问题,在一个维度上优化完之后,在另一个维度上再进行优化,最后整合为三维的轨迹,降维后分开求解后合并的解并不是高维下的最优解,但是那样已经足够使用。
apollo9.0的planning的代码解析
9.0的planning的文件结构
Planning模块的入口为
/modules/planning/planning_component/planning_component.h
/modules/planning/planning_component/planning_component.cc
模块的接口为 PlanningComponent类,该类不可被继承。
在Init函数中:
injector_ = std::make_shared<DependencyInjector>(); //构造智能指针
planning_base_ = std::make_unique<NaviPlanning>(injector_);
planning_base_ = std::make_unique<OnLanePlanning>(injector_); //构造出智能指针planning_base_ 类型为OnLanePlanning
将config参数传到OnLanePlanning的对象中:
planning_base_->Init(config_);
进行OnLanePlanning的init
Status OnLanePlanning::Init(const PlanningConfig& config) {
if (!CheckPlanningConfig(config)) {
return Status(ErrorCode::PLANNING_ERROR,
"planning config error: " + config_.DebugString());
}//
PlanningBase::Init(con加载配置文件fig_);//planning_context初始化
// clear planning history
injector_->history()->Clear();
// clear planning status
injector_->planning_context()->mutable_planning_status()->Clear();
// load map
hdmap_ = HDMapUtil::BaseMapPtr();
ACHECK(hdmap_) << "Failed to load map";
// instantiate reference line provider
const ReferenceLineConfig* reference_line_config = nullptr;
if (config_.has_reference_line_config()) {
reference_line_config = &config_.reference_line_config();
}
reference_line_provider_ = std::make_unique<ReferenceLineProvider>(
injector_->vehicle_state(), reference_line_config);
reference_line_provider_->Start();//启动重要的函数,参考线相关的操作均由该函数开始
// dispatch planner
LoadPlanner();//加载规划器
if (!planner_) {
return Status(
ErrorCode::PLANNING_ERROR,
"planning is not initialized with config : " + config_.DebugString());
}
if (config_.learning_mode() != PlanningConfig::NO_LEARNING) {//学习模型相关的
PlanningSemanticMapConfig renderer_config;
ACHECK(apollo::cyber::common::GetProtoFromFile(
FLAGS_planning_birdview_img_feature_renderer_config_file,
&renderer_config))
<< "Failed to load renderer config"
<< FLAGS_planning_birdview_img_feature_renderer_config_file;
BirdviewImgFeatureRenderer::Instance()->Init(renderer_config);
}
traffic_decider_.Init(injector_);//decider初始化
start_time_ = Clock::NowInSeconds();
return planner_->Init(injector_, FLAGS_planner_config_path);//planner初始化
}
然后进行Proc主程序:
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) {
// check and process possible rerouting request /** *
检查是否需要重新规划线路。 * **/
// 步骤1
CheckRerouting();
再进行local_view_赋值,保存外部变量
需要注意的是9.0引入的planning_command
{
std::lock_guard<std::mutex> lock(mutex_);
if (!local_view_.planning_command ||
!common::util::IsProtoEqual(local_view_.planning_command->header(),
planning_command_.header())) {
local_view_.planning_command =
std::make_shared<PlanningCommand>(planning_command_);
}
}
切入规划器,修改轨迹相对时间
planning_base_->RunOnce(local_view_, &adc_trajectory_pb);
auto start_time = adc_trajectory_pb.header().timestamp_sec();
common::util::FillHeader(node_->Name(), &adc_trajectory_pb);
// modify trajectory relative time due to the timestamp change in header
const double dt = start_time - adc_trajectory_pb.header().timestamp_sec();
for (auto& p : *adc_trajectory_pb.mutable_trajectory_point()) {
p.set_relative_time(p.relative_time() + dt);
}
planning_writer_->Write(adc_trajectory_pb);
RunOnce函数在class OnLanePlanning 中被实例化
void OnLanePlanning::RunOnce(const LocalView& local_view,
ADCTrajectory* const ptr_trajectory_pb) {
// when rerouting, reference line might not be updated. In this case, planning
// module maintains not-ready until be restarted.
local_view_ = local_view;
const double start_timestamp = Clock::NowInSeconds();
const double start_system_timestamp =
std::chrono::duration<double>(
std::chrono::system_clock::now().time_since_epoch())
.count();
// localization
ADEBUG << "Get localization:"
<< local_view_.localization_estimate->DebugString();
// chassis
ADEBUG << "Get chassis:" << local_view_.chassis->DebugString();
Status status = injector_->vehicle_state()->Update(
*local_view_.localization_estimate, *local_view_.chassis);
VehicleState vehicle_state = injector_->vehicle_state()->vehicle_state();
const double vehicle_state_timestamp = vehicle_state.timestamp();
DCHECK_GE(start_timestamp, vehicle_state_timestamp)
<< "start_timestamp is behind vehicle_state_timestamp by "
<< start_timestamp - vehicle_state_timestamp << " secs";
if (!status.ok() || !util::IsVehicleStateValid(vehicle_state)) {
const std::string msg =
"Update VehicleStateProvider failed "
"or the vehicle state is out dated.";
AERROR << msg;
ptr_trajectory_pb->mutable_decision()
->mutable_main_decision()
->mutable_not_ready()
->set_reason(msg);
status.Save(ptr_trajectory_pb->mutable_header()->mutable_status());
// TODO(all): integrate reverse gear
ptr_trajectory_pb->set_gear(canbus::Chassis::GEAR_DRIVE);
FillPlanningPb(start_timestamp, ptr_trajectory_pb);
GenerateStopTrajectory(ptr_trajectory_pb);
return;
}
if (start_timestamp + 1e-6 < vehicle_state_timestamp) {
common::monitor::MonitorLogBuffer monitor_logger_buffer(
common::monitor::MonitorMessageItem::PLANNING);
monitor_logger_buffer.ERROR("ego system time is behind GPS time");
}
if (start_timestamp - vehicle_state_timestamp <
FLAGS_message_latency_threshold) {
vehicle_state = AlignTimeStamp(vehicle_state, start_timestamp);
}
// Update reference line provider and reset scenario if new routing
reference_line_provider_->UpdateVehicleState(vehicle_state);
if (local_view_.planning_command->is_motion_command() &&
util::IsDifferentRouting(last_command_, *local_view_.planning_command)) {
last_command_ = *local_view_.planning_command;
AINFO << "new_command:" << last_command_.DebugString();
reference_line_provider_->Reset();
injector_->history()->Clear();
injector_->planning_context()->mutable_planning_status()->Clear();
reference_line_provider_->UpdatePlanningCommand(
*(local_view_.planning_command));
planner_->Reset(frame_.get());
}
// Get end lane way point.
reference_line_provider_->GetEndLaneWayPoint(local_view_.end_lane_way_point);
// planning is triggered by prediction data, but we can still use an estimated
// cycle time for stitching
const double planning_cycle_time =
1.0 / static_cast<double>(FLAGS_planning_loop_rate);
std::string replan_reason;
std::vector<TrajectoryPoint> stitching_trajectory =
TrajectoryStitcher::ComputeStitchingTrajectory(
*(local_view_.chassis), vehicle_state, start_timestamp,
planning_cycle_time, FLAGS_trajectory_stitching_preserved_length,
true, last_publishable_trajectory_.get(), &replan_reason);
injector_->ego_info()->Update(stitching_trajectory.back(), vehicle_state);
const uint32_t frame_num = static_cast<uint32_t>(seq_num_++);
status = InitFrame(frame_num, stitching_trajectory.back(), vehicle_state);
AINFO << "Planning start frame sequence id = [" << frame_num << "]";
if (status.ok()) {
injector_->ego_info()->CalculateFrontObstacleClearDistance(
frame_->obstacles());
}
if (FLAGS_enable_record_debug) {
frame_->RecordInputDebug(ptr_trajectory_pb->mutable_debug());
}
ptr_trajectory_pb->mutable_latency_stats()->set_init_frame_time_ms(
Clock::NowInSeconds() - start_timestamp);
if (!status.ok()) {
AERROR << status.ToString();
if (FLAGS_publish_estop) {
// "estop" signal check in function "Control::ProduceControlCommand()"
// estop_ = estop_ || local_view_.trajectory.estop().is_estop();
// we should add more information to ensure the estop being triggered.
ADCTrajectory estop_trajectory;
EStop* estop = estop_trajectory.mutable_estop();
estop->set_is_estop(true);
estop->set_reason(status.error_message());
status.Save(estop_trajectory.mutable_header()->mutable_status());
ptr_trajectory_pb->CopyFrom(estop_trajectory);
} else {
ptr_trajectory_pb->mutable_decision()
->mutable_main_decision()
->mutable_not_ready()
->set_reason(status.ToString());
status.Save(ptr_trajectory_pb->mutable_header()->mutable_status());
GenerateStopTrajectory(ptr_trajectory_pb);
}
// TODO(all): integrate reverse gear
ptr_trajectory_pb->set_gear(canbus::Chassis::GEAR_DRIVE);
FillPlanningPb(start_timestamp, ptr_trajectory_pb);
frame_->set_current_frame_planned_trajectory(*ptr_trajectory_pb);
const uint32_t n = frame_->SequenceNum();
injector_->frame_history()->Add(n, std::move(frame_));
return;
}
for (auto& ref_line_info : *frame_->mutable_reference_line_info()) {
auto traffic_status =
traffic_decider_.Execute(frame_.get(), &ref_line_info);
if (!traffic_status.ok() || !ref_line_info.IsDrivable()) {
ref_line_info.SetDrivable(false);
AWARN << "Reference line " << ref_line_info.Lanes().Id()
<< " traffic decider failed";
}
}
status = Plan(start_timestamp, stitching_trajectory, ptr_trajectory_pb);
PrintCurves print_curve;
for (const auto& p : ptr_trajectory_pb->trajectory_point()) {
print_curve.AddPoint("trajxy", p.path_point().x(), p.path_point().y());
}
print_curve.PrintToLog();
const auto end_system_timestamp =
std::chrono::duration<double>(
std::chrono::system_clock::now().time_since_epoch())
.count();
const auto time_diff_ms =
(end_system_timestamp - start_system_timestamp) * 1000;
ADEBUG << "total planning time spend: " << time_diff_ms << " ms.";
ptr_trajectory_pb->mutable_latency_stats()->set_total_time_ms(time_diff_ms);
ADEBUG << "Planning latency: "
<< ptr_trajectory_pb->latency_stats().DebugString();
if (!status.ok()) {
status.Save(ptr_trajectory_pb->mutable_header()->mutable_status());
AERROR << "Planning failed:" << status.ToString();
if (FLAGS_publish_estop) {
AERROR << "Planning failed and set estop";
// "estop" signal check in function "Control::ProduceControlCommand()"
// estop_ = estop_ || local_view_.trajectory.estop().is_estop();
// we should add more information to ensure the estop being triggered.
EStop* estop = ptr_trajectory_pb->mutable_estop();
estop->set_is_estop(true);
estop->set_reason(status.error_message());
}
}
ptr_trajectory_pb->set_is_replan(stitching_trajectory.size() == 1);
if (ptr_trajectory_pb->is_replan()) {
ptr_trajectory_pb->set_replan_reason(replan_reason);
}
if (frame_->open_space_info().is_on_open_space_trajectory()) {
FillPlanningPb(start_timestamp, ptr_trajectory_pb);
ADEBUG << "Planning pb:" << ptr_trajectory_pb->header().DebugString();
frame_->set_current_frame_planned_trajectory(*ptr_trajectory_pb);
} else {
auto* ref_line_task =
ptr_trajectory_pb->mutable_latency_stats()->add_task_stats();
ref_line_task->set_time_ms(reference_line_provider_->LastTimeDelay() *
1000.0);
ref_line_task->set_name("ReferenceLineProvider");
// TODO(all): integrate reverse gear
ptr_trajectory_pb->set_gear(canbus::Chassis::GEAR_DRIVE);
FillPlanningPb(start_timestamp, ptr_trajectory_pb);
ADEBUG << "Planning pb:" << ptr_trajectory_pb->header().DebugString();
frame_->set_current_frame_planned_trajectory(*ptr_trajectory_pb);
if (FLAGS_enable_planning_smoother) {
planning_smoother_.Smooth(injector_->frame_history(), frame_.get(),
ptr_trajectory_pb);
}
}
const uint32_t n = frame_->SequenceNum();
AINFO << "Planning end frame sequence id = [" << n << "]";
injector_->frame_history()->Add(n, std::move(frame_));
}
apollo的ppt链接
https://www.cnblogs.com/fuhang/p/9563884.html
省流版:
lattice planner
先对t采样,得到s,根据s采样,得到L,然后组合得到完整的S、L、t,再从Frenet坐标系转为世界坐标系,这样轨迹就出现了。
0、轨迹拼接;*在上一帧轨迹中的匹配点。两个维度出发:时间t和历程s。拼接轨迹规划起点;
1、离散参考线上的点;
2、寻找参考线上匹配的点;*匹配点,最近点;
3、frenet坐标系转换;
4、ST、SL图构建;200m,8s
5、横向、纵向规划;*降维解耦,轨迹=纵向+横向+时间;*T和s得到s和速度,根据s和l得到坐标,
纵向规划,巡航(四次多项式)、跟车(五次多项式)、超车(五次多项式),难点在于终点的位置和速度选择,以及分辨率的选择。
横向规划分为采样点规划(五次多项式)、二次规划(调用osqp求解器的库),Apollo默认进入二次规划,因为速度快。
以ds=1m进行采样,遍历每个采样点的横向可达范围,即每个点的横向约束,通过这么多约束构建对应的二次型,最后通过调用OSQP进行二次规划求解…
6、轨迹评价;*可行性判断;cost计算
cost的内容
a、Cost of missing the objective, e.g., cruise, stop, etc.
b、Cost of longitudinal jerk
c、Cost of longitudinal collision
d、向心加速度
e、Cost of lateral offsets
f、Cost of lateral comfort
7、合并轨迹;我们可以计算出在T时刻的纵向偏移量和横向偏移量,再通过参考线,即可还原成一个二维平面中的轨迹点。通过一系列的时间点T0,T1,…,Tn,可以获得一系列的轨迹点P0,P1,…,Pn,最终形成一条完整的轨迹;
入口为plan函数:
Status LatticePlanner::Plan(const TrajectoryPoint& planning_start_point,
Frame* frame,
ADCTrajectory* ptr_computed_trajectory) {
size_t success_line_count = 0;
size_t index = 0;
for (auto& reference_line_info : *frame->mutable_reference_line_info()) {//遍历参考线。进行分别规划
if (index != 0) {
reference_line_info.SetPriorityCost(
FLAGS_cost_non_priority_reference_line);
} else {
reference_line_info.SetPriorityCost(0.0);
}
auto status =
PlanOnReferenceLine(planning_start_point, frame, &reference_line_info);//每条参考线进行规划
if (status != Status::OK()) {
if (reference_line_info.IsChangeLanePath()) {
AERROR << "Planner failed to change lane to "
<< reference_line_info.Lanes().Id();
} else {
AERROR << "Planner failed to " << reference_line_info.Lanes().Id();
}
} else {
success_line_count += 1;
}
++index;
}
if (success_line_count > 0) {
return Status::OK();
}
return Status(ErrorCode::PLANNING_ERROR,
"Failed to plan on any reference line.");
}
算法主逻辑:
Status LatticePlanner::PlanOnReferenceLine(
const TrajectoryPoint& planning_init_point, Frame* frame,
ReferenceLineInfo* reference_line_info) {
static size_t num_planning_cycles = 0;
static size_t num_planning_succeeded_cycles = 0;
double start_time = Clock::NowInSeconds();
double current_time = start_time;
ADEBUG << "Number of planning cycles: " << num_planning_cycles << " "
<< num_planning_succeeded_cycles;
++num_planning_cycles;
reference_line_info->set_is_on_reference_line();
// 1. obtain a reference line and transform it to the PathPoint format.
// 1、离散化参考线的点
auto ptr_reference_line =
std::make_shared<std::vector<PathPoint>>(ToDiscretizedReferenceLine(
reference_line_info->reference_line().reference_points()));
// 2. compute the matched point of the init planning point on the reference
// line.
// 2、计算规划起始点在参考线上的匹配点
PathPoint matched_point = PathMatcher::MatchToPath(
*ptr_reference_line, planning_init_point.path_point().x(),
planning_init_point.path_point().y());
// 3. according to the matched point, compute the init state in Frenet frame.
// 3、计算出起始点的frenet坐标系的坐标
std::array<double, 3> init_s;
std::array<double, 3> init_d;
ComputeInitFrenetState(matched_point, planning_init_point, &init_s, &init_d);
ADEBUG << "ReferenceLine and Frenet Conversion Time = "
<< (Clock::NowInSeconds() - current_time) * 1000;
current_time = Clock::NowInSeconds();
auto ptr_prediction_querier = std::make_shared<PredictionQuerier>(
frame->obstacles(), ptr_reference_line);
// 4. parse the decision and get the planning target.
// 4、生成S-T图
auto ptr_path_time_graph = std::make_shared<PathTimeGraph>(
ptr_prediction_querier->GetObstacles(), *ptr_reference_line,
reference_line_info, init_s[0],
init_s[0] + FLAGS_speed_lon_decision_horizon, 0.0,
FLAGS_trajectory_time_length, init_d);
double speed_limit =
reference_line_info->reference_line().GetSpeedLimitFromS(init_s[0]);
reference_line_info->SetLatticeCruiseSpeed(speed_limit);
PlanningTarget planning_target = reference_line_info->planning_target();
if (planning_target.has_stop_point()) {
ADEBUG << "Planning target stop s: " << planning_target.stop_point().s()
<< "Current ego s: " << init_s[0];
}
ADEBUG << "Decision_Time = " << (Clock::NowInSeconds() - current_time) * 1000;
current_time = Clock::NowInSeconds();
// 5. generate 1d trajectory bundle for longitudinal and lateral respectively.
// 5、生成轨迹簇,横向采样d{0.0, -0.5, 0.5},s{10.0, 20.0, 40.0, 80.0};
// 纵向s不固定,采用四次多项式进行求解,包括巡航、跟车、超车等决策
// 横向采用五次多项式进行求解
Trajectory1dGenerator trajectory1d_generator(
init_s, init_d, ptr_path_time_graph, ptr_prediction_querier);
std::vector<std::shared_ptr<Curve1d>> lon_trajectory1d_bundle;
std::vector<std::shared_ptr<Curve1d>> lat_trajectory1d_bundle;
trajectory1d_generator.GenerateTrajectoryBundles(
planning_target, &lon_trajectory1d_bundle, &lat_trajectory1d_bundle);
ADEBUG << "Trajectory_Generation_Time = "
<< (Clock::NowInSeconds() - current_time) * 1000;
current_time = Clock::NowInSeconds();
// 6. first, evaluate the feasibility of the 1d trajectories according to
// dynamic constraints.
// second, evaluate the feasible longitudinal and lateral trajectory pairs
// and sort them according to the cost.
TrajectoryEvaluator trajectory_evaluator(
init_s, planning_target, lon_trajectory1d_bundle, lat_trajectory1d_bundle,
ptr_path_time_graph, ptr_reference_line);
ADEBUG << "Trajectory_Evaluator_Construction_Time = "
<< (Clock::NowInSeconds() - current_time) * 1000;
current_time = Clock::NowInSeconds();
ADEBUG << "number of trajectory pairs = "
<< trajectory_evaluator.num_of_trajectory_pairs()
<< " number_lon_traj = " << lon_trajectory1d_bundle.size()
<< " number_lat_traj = " << lat_trajectory1d_bundle.size();
// Get instance of collision checker and constraint checker
CollisionChecker collision_checker(frame->obstacles(), init_s[0], init_d[0],
*ptr_reference_line, reference_line_info,
ptr_path_time_graph);
// 7. always get the best pair of trajectories to combine; return the first
// collision-free trajectory.
size_t constraint_failure_count = 0;
size_t collision_failure_count = 0;
size_t combined_constraint_failure_count = 0;
size_t lon_vel_failure_count = 0;
size_t lon_acc_failure_count = 0;
size_t lon_jerk_failure_count = 0;
size_t curvature_failure_count = 0;
size_t lat_acc_failure_count = 0;
size_t lat_jerk_failure_count = 0;
size_t num_lattice_traj = 0;
while (trajectory_evaluator.has_more_trajectory_pairs()) {
double trajectory_pair_cost =
trajectory_evaluator.top_trajectory_pair_cost();
auto trajectory_pair = trajectory_evaluator.next_top_trajectory_pair();
// combine two 1d trajectories to one 2d trajectory
auto combined_trajectory = TrajectoryCombiner::Combine(
*ptr_reference_line, *trajectory_pair.first, *trajectory_pair.second,
planning_init_point.relative_time());
// check longitudinal and lateral acceleration
// considering trajectory curvatures
auto result = ConstraintChecker::ValidTrajectory(combined_trajectory);
if (result != ConstraintChecker::Result::VALID) {
++combined_constraint_failure_count;
switch (result) {
case ConstraintChecker::Result::LON_VELOCITY_OUT_OF_BOUND:
lon_vel_failure_count += 1;
break;
case ConstraintChecker::Result::LON_ACCELERATION_OUT_OF_BOUND:
lon_acc_failure_count += 1;
break;
case ConstraintChecker::Result::LON_JERK_OUT_OF_BOUND:
lon_jerk_failure_count += 1;
break;
case ConstraintChecker::Result::CURVATURE_OUT_OF_BOUND:
curvature_failure_count += 1;
break;
case ConstraintChecker::Result::LAT_ACCELERATION_OUT_OF_BOUND:
lat_acc_failure_count += 1;
break;
case ConstraintChecker::Result::LAT_JERK_OUT_OF_BOUND:
lat_jerk_failure_count += 1;
break;
case ConstraintChecker::Result::VALID:
default:
// Intentional empty
break;
}
continue;
}
// check collision with other obstacles
if (collision_checker.InCollision(combined_trajectory)) {
++collision_failure_count;
continue;
}
// put combine trajectory into debug data
const auto& combined_trajectory_points = combined_trajectory;
num_lattice_traj += 1;
reference_line_info->SetTrajectory(combined_trajectory);
reference_line_info->SetCost(reference_line_info->PriorityCost() +
trajectory_pair_cost);
reference_line_info->SetDrivable(true);
// Print the chosen end condition and start condition
ADEBUG << "Starting Lon. State: s = " << init_s[0] << " ds = " << init_s[1]
<< " dds = " << init_s[2];
// cast
auto lattice_traj_ptr =
std::dynamic_pointer_cast<LatticeTrajectory1d>(trajectory_pair.first);
if (!lattice_traj_ptr) {
ADEBUG << "Dynamically casting trajectory1d ptr. failed.";
}
if (lattice_traj_ptr->has_target_position()) {
ADEBUG << "Ending Lon. State s = " << lattice_traj_ptr->target_position()
<< " ds = " << lattice_traj_ptr->target_velocity()
<< " t = " << lattice_traj_ptr->target_time();
}
ADEBUG << "InputPose";
ADEBUG << "XY: " << planning_init_point.ShortDebugString();
ADEBUG << "S: (" << init_s[0] << ", " << init_s[1] << "," << init_s[2]
<< ")";
ADEBUG << "L: (" << init_d[0] << ", " << init_d[1] << "," << init_d[2]
<< ")";
ADEBUG << "Reference_line_priority_cost = "
<< reference_line_info->PriorityCost();
ADEBUG << "Total_Trajectory_Cost = " << trajectory_pair_cost;
ADEBUG << "OutputTrajectory";
for (uint i = 0; i < 10; ++i) {
ADEBUG << combined_trajectory_points[i].ShortDebugString();
}
break;
/*
auto combined_trajectory_path =
ptr_debug->mutable_planning_data()->add_trajectory_path();
for (uint i = 0; i < combined_trajectory_points.size(); ++i) {
combined_trajectory_path->add_trajectory_point()->CopyFrom(
combined_trajectory_points[i]);
}
combined_trajectory_path->set_lattice_trajectory_cost(trajectory_pair_cost);
*/
}
ADEBUG << "Trajectory_Evaluation_Time = "
<< (Clock::NowInSeconds() - current_time) * 1000;
ADEBUG << "Step CombineTrajectory Succeeded";
ADEBUG << "1d trajectory not valid for constraint ["
<< constraint_failure_count << "] times";
ADEBUG << "Combined trajectory not valid for ["
<< combined_constraint_failure_count << "] times";
ADEBUG << "Trajectory not valid for collision [" << collision_failure_count
<< "] times";
ADEBUG << "Total_Lattice_Planning_Frame_Time = "
<< (Clock::NowInSeconds() - start_time) * 1000;
if (num_lattice_traj > 0) {
ADEBUG << "Planning succeeded";
num_planning_succeeded_cycles += 1;
reference_line_info->SetDrivable(true);
return Status::OK();
} else {
AERROR << "Planning failed";
if (FLAGS_enable_backup_trajectory) {
AERROR << "Use backup trajectory";
BackupTrajectoryGenerator backup_trajectory_generator(
init_s, init_d, planning_init_point.relative_time(),
std::make_shared<CollisionChecker>(collision_checker),
&trajectory1d_generator);
DiscretizedTrajectory trajectory =
backup_trajectory_generator.GenerateTrajectory(*ptr_reference_line);
reference_line_info->AddCost(FLAGS_backup_trajectory_cost);
reference_line_info->SetTrajectory(trajectory);
reference_line_info->SetDrivable(true);
return Status::OK();
} else {
reference_line_info->SetCost(std::numeric_limits<double>::infinity());
}
return Status(ErrorCode::PLANNING_ERROR, "No feasible trajectories");
}
}
首先我们要生成reference line,后续的规划都是基于Frenet坐标系进行的,同时也需要明白笛卡尔坐标系-frenet之间的转换,因为输出给控制模块的是绝对坐标系下的轨迹。
EM迭代框架:
EM迭代过程如下图,基本思想就是先利用上个周期的规划轨迹以及本周期的目标预测先进行路径规划(S-L)再进行速度规划(S-T),其中路径规划与速度规划均采用DP+QP求解最优,最后将路径与速度结合生成轨迹送往控制模块以及作为下一周期规划的条件。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。