49 const std::string& config_dir,
50 const std::string& name,
51 const std::shared_ptr<DependencyInjector>& injector) {
56 return Task::LoadConfig<LaneChangePathGenericConfig>(&config_);
60 UpdateLaneChangeStatus();
61 const auto& status =
injector_->planning_context()->mutable_planning_status()->mutable_change_lane()->status();
68 ADEBUG <<
injector_->planning_context()->mutable_planning_status()->mutable_change_lane()->DebugString();
69 return Status(ErrorCode::PLANNING_ERROR,
"Not satisfy lane change conditions");
71 std::vector<PathBoundary> candidate_path_boundaries;
72 std::vector<PathData> candidate_path_data;
75 if (!DecidePathBounds(&candidate_path_boundaries)) {
76 return Status(ErrorCode::PLANNING_ERROR,
"lane change path bounds failed");
78 if (!OptimizePath(candidate_path_boundaries, &candidate_path_data)) {
79 return Status(ErrorCode::PLANNING_ERROR,
"lane change path optimize failed");
81 if (!AssessPath(&candidate_path_data, reference_line_info->
mutable_path_data())) {
82 return Status(ErrorCode::PLANNING_ERROR,
"No valid lane change path");
88bool LaneChangePathGeneric::DecidePathBounds(std::vector<PathBoundary>* boundary) {
89 boundary->emplace_back();
90 auto& path_bound = boundary->back();
91 double path_narrowest_width = 0;
94 const std::string msg =
"Failed to initialize path boundaries.";
100 AERROR <<
"Failed to decide a rough boundary based on self lane.";
103 path_bound.DebugString(
"from_self_lane_l");
106 AERROR <<
"Failed to decide a rough boundary based on adc.";
109 path_bound.DebugString(
"extend_boundary_by_ADC_l");
111 path_bound.set_label(
"regular/lane_change");
114 std::string blocking_obstacle_id;
122 &blocking_obstacle_id,
123 &path_narrowest_width);
124 path_bound.DebugString(
"from_static_obstacles_l");
128 GetBoundaryFromLaneChangeForbiddenZone(&path_bound);
129 path_bound.DebugString(
"forbidden_zone_l");
132 GetBoundaryFromNudgeDecision(&path_bound);
133 path_bound.DebugString(
"from_nudge_decision_l");
140 while (!blocking_obstacle_id.empty() && path_bound.size() < temp_path_bound.size()
141 && counter < FLAGS_num_extra_tail_bound_point) {
142 path_bound.push_back(temp_path_bound[path_bound.size()]);
146 path_bound.set_blocking_obstacle_id(blocking_obstacle_id);
150bool LaneChangePathGeneric::OptimizePath(
151 const std::vector<PathBoundary>& path_boundaries,
152 std::vector<PathData>* candidate_path_data) {
155 std::array<double, 3> end_state = {0.0, 0.0, 0.0};
156 for (
const auto& path_boundary : path_boundaries) {
157 size_t path_boundary_size = path_boundary.boundary().size();
158 if (path_boundary_size <= 1U) {
159 AERROR <<
"Get invalid path boundary with size: " << path_boundary_size;
162 std::vector<double> opt_l, opt_dl, opt_ddl;
163 std::vector<std::pair<double, double>> ddl_bounds;
166 std::vector<double> ref_l(path_boundary_size, 0);
167 std::vector<double> weight_ref_l(path_boundary_size, 0);
169 path_boundary, config.path_reference_l_weight(), &ref_l, &weight_ref_l);
185 opt_l, opt_dl, opt_ddl, path_boundary.delta_s(), path_boundary.start_s());
187 path_data.SetReferenceLine(&reference_line);
188 path_data.SetFrenetPath(std::move(frenet_frame_path));
189 if (FLAGS_use_front_axe_center_in_path_planning) {
190 auto discretized_path
192 path_data.SetDiscretizedPath(discretized_path);
194 path_data.set_path_label(path_boundary.label());
195 path_data.set_blocking_obstacle_id(path_boundary.blocking_obstacle_id());
196 candidate_path_data->push_back(std::move(path_data));
199 if (candidate_path_data->empty()) {
205bool LaneChangePathGeneric::AssessPath(std::vector<PathData>* candidate_path_data, PathData* final_path) {
206 std::vector<PathData> valid_path_data;
207 for (
auto& curr_path_data : *candidate_path_data) {
209 SetPathInfo(&curr_path_data);
213 if (curr_path_data.Empty()) {
214 AINFO <<
"lane change path is empty after trimed";
217 valid_path_data.push_back(curr_path_data);
220 if (valid_path_data.empty()) {
221 AINFO <<
"All lane change path are not valid";
225 *final_path = valid_path_data[0];
231void LaneChangePathGeneric::UpdateLaneChangeStatus() {
232 std::string change_lane_id;
233 auto* prev_status =
injector_->planning_context()->mutable_planning_status()->mutable_change_lane();
236 if (!prev_status->has_status()) {
241 if (!has_change_lane) {
249 const auto* history_frame =
injector_->frame_history()->Latest();
250 if (!CheckLastFrameSucceed(history_frame)) {
252 is_exist_lane_change_start_position_ =
false;
257 ADEBUG <<
"change_lane_id" << change_lane_id;
261 ADEBUG <<
"change lane again after failed";
267 AINFO <<
"change lane again after success";
270 if (prev_status->path_id() != change_lane_id) {
271 AINFO <<
"change_lane_id" << change_lane_id <<
"prev" << prev_status->path_id();
278bool LaneChangePathGeneric::IsClearToChangeLane(ReferenceLineInfo* reference_line_info) {
279 double ego_start_s = reference_line_info->AdcSlBoundary().start_s();
280 double ego_end_s = reference_line_info->AdcSlBoundary().end_s();
281 double ego_v = std::abs(reference_line_info->vehicle_state().linear_velocity());
283 for (
const auto* obstacle : reference_line_info->path_decision()->obstacles().Items()) {
284 if (obstacle->IsVirtual() || obstacle->IsStatic()) {
285 ADEBUG <<
"skip one virtual or static obstacle";
289 double start_s = std::numeric_limits<double>::max();
290 double end_s = -std::numeric_limits<double>::max();
291 double start_l = std::numeric_limits<double>::max();
292 double end_l = -std::numeric_limits<double>::max();
294 for (
const auto& p : obstacle->PerceptionPolygon().points()) {
296 reference_line_info->reference_line().XYToSL(p, &sl_point);
297 start_s = std::fmin(start_s, sl_point.
s());
298 end_s = std::fmax(end_s, sl_point.
s());
300 start_l = std::fmin(start_l, sl_point.
l());
301 end_l = std::fmax(end_l, sl_point.
l());
304 if (reference_line_info->IsChangeLanePath()) {
305 double left_width(0), right_width(0);
306 reference_line_info->mutable_reference_line()->GetLaneWidth(
307 (start_s + end_s) * 0.5, &left_width, &right_width);
308 if (end_l < -right_width || start_l > left_width) {
315 bool same_direction =
true;
316 if (obstacle->HasTrajectory()) {
317 double obstacle_moving_direction = obstacle->Trajectory().trajectory_point(0).path_point().theta();
318 const auto& vehicle_state = reference_line_info->vehicle_state();
319 double vehicle_moving_direction = vehicle_state.heading();
323 double heading_difference
325 same_direction = heading_difference < (M_PI / 2.0);
329 static constexpr double kSafeTimeOnSameDirection = 3.0;
330 static constexpr double kSafeTimeOnOppositeDirection = 5.0;
331 static constexpr double kForwardMinSafeDistanceOnSameDirection = 10.0;
332 static constexpr double kBackwardMinSafeDistanceOnSameDirection = 10.0;
333 static constexpr double kForwardMinSafeDistanceOnOppositeDirection = 50.0;
334 static constexpr double kBackwardMinSafeDistanceOnOppositeDirection = 1.0;
335 static constexpr double kDistanceBuffer = 0.5;
337 double kForwardSafeDistance = 0.0;
338 double kBackwardSafeDistance = 0.0;
339 if (same_direction) {
340 kForwardSafeDistance = std::fmax(
341 kForwardMinSafeDistanceOnSameDirection, (ego_v - obstacle->speed()) * kSafeTimeOnSameDirection);
342 kBackwardSafeDistance = std::fmax(
343 kBackwardMinSafeDistanceOnSameDirection, (obstacle->speed() - ego_v) * kSafeTimeOnSameDirection);
345 kForwardSafeDistance = std::fmax(
346 kForwardMinSafeDistanceOnOppositeDirection,
347 (ego_v + obstacle->speed()) * kSafeTimeOnOppositeDirection);
348 kBackwardSafeDistance = kBackwardMinSafeDistanceOnOppositeDirection;
351 if (HysteresisFilter(
352 ego_start_s - end_s, kBackwardSafeDistance, kDistanceBuffer, obstacle->IsLaneChangeBlocking())
354 start_s - ego_end_s, kForwardSafeDistance, kDistanceBuffer, obstacle->IsLaneChangeBlocking())) {
355 reference_line_info->path_decision()->Find(obstacle->Id())->SetLaneChangeBlocking(
true);
356 ADEBUG <<
"Lane Change is blocked by obstacle" << obstacle->Id();
359 reference_line_info->path_decision()->Find(obstacle->Id())->SetLaneChangeBlocking(
false);
365void LaneChangePathGeneric::GetLaneChangeStartPoint(
366 const ReferenceLine& reference_line,
368 common::math::Vec2d* start_xy) {
370 common::SLPoint lane_change_start_sl;
371 lane_change_start_sl.set_s(lane_change_start_s);
372 lane_change_start_sl.set_l(0.0);
373 reference_line.SLToXY(lane_change_start_sl, start_xy);
376void LaneChangePathGeneric::GetBoundaryFromLaneChangeForbiddenZone(PathBoundary*
const path_bound) {
378 CHECK_NOTNULL(path_bound);
380 if (is_clear_to_change_lane_) {
381 is_exist_lane_change_start_position_ =
false;
384 double lane_change_start_s = 0.0;
388 if (is_exist_lane_change_start_position_) {
389 common::SLPoint point_sl;
390 reference_line.
XYToSL(lane_change_start_xy_, &point_sl);
391 lane_change_start_s = point_sl.s();
397 GetLaneChangeStartPoint(reference_line,
init_sl_state_.first[0], &lane_change_start_xy_);
406 for (
size_t i = 0; i < path_bound->size(); ++i) {
407 double curr_s = (*path_bound)[i].s;
408 if (curr_s > lane_change_start_s) {
411 double curr_lane_left_width = 0.0;
412 double curr_lane_right_width = 0.0;
413 double offset_to_map = 0.0;
414 reference_line.GetOffsetToMap(curr_s, &offset_to_map);
415 if (reference_line.GetLaneWidth(curr_s, &curr_lane_left_width, &curr_lane_right_width)) {
416 double offset_to_lane_center = 0.0;
417 reference_line.GetOffsetToMap(curr_s, &offset_to_lane_center);
418 curr_lane_left_width += offset_to_lane_center;
419 curr_lane_right_width -= offset_to_lane_center;
421 curr_lane_left_width -= offset_to_map;
422 curr_lane_right_width += offset_to_map;
424 (*path_bound)[i].l_lower.l =
init_sl_state_.second[0] > curr_lane_left_width
425 ? curr_lane_left_width + adc_half_width
426 : (*path_bound)[i].l_lower.l;
427 (*path_bound)[i].l_lower.l = std::fmin((*path_bound)[i].l_lower.l,
init_sl_state_.second[0] - 0.1);
428 (*path_bound)[i].l_upper.l =
init_sl_state_.second[0] < -curr_lane_right_width
429 ? -curr_lane_right_width - adc_half_width
430 : (*path_bound)[i].l_upper.l;
431 (*path_bound)[i].l_upper.l = std::fmax((*path_bound)[i].l_upper.l,
init_sl_state_.second[0] + 0.1);
435bool LaneChangePathGeneric::GetBoundaryFromNudgeDecision(PathBoundary*
const path_bound) {
439 bool is_use_nudge_key_points = FLAGS_enable_nudge_decider && nudge_info.is_enable()
440 && nudge_info.extra_nudge_key_points().size() > 1 && nudge_info.extra_nudge_key_points().at(0).size() > 1;
441 if (!is_use_nudge_key_points) {
442 AINFO <<
"GetBoundaryFromNudgeDecision, not use nudge key points";
446 double start_pt_s, end_pt_s;
447 int key_points_index = is_right_change_lane ? 0 : 1;
448 start_pt_s = nudge_info.extra_nudge_key_points().at(key_points_index).front().s();
449 end_pt_s = nudge_info.extra_nudge_key_points().at(key_points_index).back().s();
451 if (is_right_change_lane) {
452 for (
size_t i = 1; i < path_bound->size(); ++i) {
453 auto& left_bound = path_bound->at(i).l_upper;
454 auto& right_bound = path_bound->at(i).l_lower;
455 double check_s = path_bound->at(i).s;
456 if (check_s < start_pt_s) {
458 }
else if (check_s < end_pt_s) {
460 if (nudge_info.GetInterpolatedNudgeL(
true, check_s, &nudge_l)) {
461 right_bound.l = std::max(std::min(nudge_l, left_bound.l), right_bound.l);
468 for (
size_t i = 1; i < path_bound->size(); ++i) {
469 auto& left_bound = path_bound->at(i).l_upper;
470 auto& right_bound = path_bound->at(i).l_lower;
471 double check_s = path_bound->at(i).s;
472 if (check_s < start_pt_s) {
474 }
else if (check_s < end_pt_s) {
476 if (nudge_info.GetInterpolatedNudgeL(
false, check_s, &nudge_l)) {
477 left_bound.l = std::min(std::max(nudge_l, right_bound.l), left_bound.l);
487void LaneChangePathGeneric::UpdateStatus(
490 const std::string& path_id) {
491 auto* lane_change_status =
injector_->planning_context()->mutable_planning_status()->mutable_change_lane();
492 AINFO <<
"lane change update from " << lane_change_status->DebugString() <<
"to";
493 lane_change_status->set_timestamp(timestamp);
494 lane_change_status->set_path_id(path_id);
495 lane_change_status->set_status(status_code);
496 AINFO << lane_change_status->DebugString();
499bool LaneChangePathGeneric::HysteresisFilter(
500 const double obstacle_distance,
501 const double safe_distance,
502 const double distance_buffer,
503 const bool is_obstacle_blocking) {
504 if (is_obstacle_blocking) {
505 return obstacle_distance < safe_distance + distance_buffer;
507 return obstacle_distance < safe_distance - distance_buffer;
511void LaneChangePathGeneric::SetPathInfo(PathData*
const path_data) {
512 std::vector<PathPointDecision> path_decision;
515 const auto& discrete_path = path_data->discretized_path();
516 SLBoundary ego_sl_boundary;
517 for (
size_t i = 0; i < discrete_path.size(); ++i) {
519 ADEBUG <<
"Unable to get SL-boundary of ego-vehicle.";
522 double lane_left_width = 0.0;
523 double lane_right_width = 0.0;
524 double middle_s = (ego_sl_boundary.start_s() + ego_sl_boundary.end_s()) / 2.0;
527 double back_to_inlane_extra_buffer = 0.2;
530 if (ego_sl_boundary.start_l() > lane_left_width || ego_sl_boundary.end_l() < -lane_right_width) {
534 ego_sl_boundary.start_l() > -lane_right_width + back_to_inlane_extra_buffer
535 && ego_sl_boundary.end_l() < lane_left_width - back_to_inlane_extra_buffer) {
543 AERROR <<
"reference line not ready when setting path point guide";
547 path_data->SetPathPointDecisionGuide(std::move(path_decision));
552 for (
const auto& reference_line_info : last_frame->reference_line_info()) {
553 if (!reference_line_info.IsChangeLanePath()) {
556 const auto history_trajectory_type = reference_line_info.trajectory_type();
565void LaneChangePathGeneric::GetSLPolygons(std::vector<SLPolygon>* polygons) {
570 for (
const auto* obstacle : obstacles.Items()) {
576 if (nudge_info.IsObsIgnoreNudgeDecision(
577 obstacle->Id(), obstacle->PerceptionSLBoundary().start_s(), check_dis)) {
580 auto xy_poly = obstacle->PerceptionPolygon();
585 if (obstacle->PerceptionSLBoundary().end_s() < adc_back_edge_s) {
588 const auto obstacle_sl = obstacle->PerceptionSLBoundary();
589 polygons->emplace_back(obstacle_sl, obstacle->Id(), obstacle->Perception().type());
591 sort(polygons->begin(), polygons->end(), [](
const SLPolygon& a,
const SLPolygon& b) {
592 return a.MinS() < b.MinS();
A general class to denote the return status of an API call.
static Status OK()
generate a success status.
@Brief This is a helper class that can load vehicle configurations.
static const VehicleConfig & GetConfig()
Get the current vehicle configuration.
Rectangular (undirected) bounding box in 2-D.
The class of polygon in 2-D.
Implements a class of 2-dimensional vectors.
a singleton clock that can be used to get the current timestamp.
static double NowInSeconds()
gets the current time in second.
const std::string & Id() const
routing::ChangeLaneType PreviousAction() const
Get the previous change lane action need to take by the vehicle to reach current segment,...
Frame holds all data for one planning cycle.
const std::list< ReferenceLineInfo > & reference_line_info() const
bool Init(const std::string &config_dir, const std::string &name, const std::shared_ptr< DependencyInjector > &injector) override
static void InitPathPointDecision(const PathData &path_data, const PathData::PathPointType type, std::vector< PathPointDecision > *const path_point_decision)
Init path_point_decision as type
static void TrimTailingOutLanePoints(PathData *const path_data)
Trim the points at tail of path which away from lane
static bool IsValidRegularPath(const ReferenceLineInfo &reference_line_info, const PathData &path_data)
Check if the generated path is valid
static bool GetBoundaryFromSelfLane(const ReferenceLineInfo &reference_line_info, const SLState &init_sl_state, PathBoundary *const path_bound)
generate path bound by self lane and adc position
static bool UpdatePathBoundaryBySLPolygon(const ReferenceLineInfo &reference_line_info, std::vector< SLPolygon > *const sl_polygon, const SLState &init_sl_state, PathBoundary *const path_boundary, std::string *const blocked_id, double *const narrowest_width)
static bool ExtendBoundaryByADC(const ReferenceLineInfo &reference_line_info, const SLState &init_sl_state, const double extend_buffer, PathBoundary *const path_bound)
extend boundary to include adc
static bool AddExtraPathBound(const std::vector< SLPolygon > &sl_polygons, PathBoundary *const path_boundary, const SLState &init_sl_state, std::string *const blocked_id)
static bool IsWithinPathDeciderScopeObstacle(const Obstacle &obstacle)
Is obstacle should be considered in path decision
static bool InitPathBoundary(const ReferenceLineInfo &reference_line_info, PathBoundary *const path_bound, SLState init_sl_state)
Starting from ADC's current position, increment until the path length, and set lateral bounds to be i...
const IndexedList< std::string, Obstacle > & obstacles() const
void RecordDebugInfo(const PathBound &path_boundaries, const std::string &debug_name, ReferenceLineInfo *const reference_line_info)
add path_boundary debug info for PnC monitor
bool GetSLBoundary(const PathData &path_data, int point_index, const ReferenceLineInfo *reference_line_info, SLBoundary *const sl_boundary)
get sl boundary of the point on PathData
std::vector< SLPolygon > obs_sl_polygons_
void GetStartPointSLState()
calculate init sl state by planning start point, result will store in init_sl_state_
static std::vector< common::PathPoint > ConvertPathPointRefFromFrontAxeToRearAxe(const PathData &path_data)
static void CalculateAccBound(const PathBoundary &path_boundary, const ReferenceLine &reference_line, std::vector< std::pair< double, double > > *ddl_bounds)
calculate ddl bound by referenceline kappa and adc lat accleration
static FrenetFramePath ToPiecewiseJerkPath(const std::vector< double > &x, const std::vector< double > &dx, const std::vector< double > &ddx, const double delta_s, const double start_s)
Data format tramform from raw data to FrenetFramePath
static double EstimateJerkBoundary(const double vehicle_speed)
Calculation of jerk boundary based on vehicle kinematics model.
static bool OptimizePath(const SLState &init_state, const std::array< double, 3 > &end_state, std::vector< double > l_ref, std::vector< double > l_ref_weight, const PathBoundary &path_boundary, const std::vector< std::pair< double, double > > &ddl_bounds, double dddl_bound, const PiecewiseJerkPathConfig &config, std::vector< double > *x, std::vector< double > *dx, std::vector< double > *ddx)
Piecewise jerk path optimizer.
static void UpdatePathRefWithBound(const PathBoundary &path_boundary, double weight, std::vector< double > *ref_l, std::vector< double > *weight_ref_l)
If ref_l is below or above path boundary, will update its values and weights
ReferenceLineInfo holds all data for one reference line.
bool path_reusable() const
PathDecision * path_decision()
const common::VehicleState & vehicle_state() const
std::vector< SLPolygon > * mutable_obs_sl_polygons()
const hdmap::RouteSegments & Lanes() const
const ReferenceLine & reference_line() const
double SDistanceToDestination() const
const SLBoundary & AdcSlBoundary() const
bool IsChangeLanePath() const
Check if the current reference line is a change lane reference line, i.e., ADC's current position is ...
PathData * mutable_path_data()
bool XYToSL(const common::math::Vec2d &xy_point, common::SLPoint *const sl_point, double warm_start_s=-1.0) const
Transvert Cartesian coordinates to Frenet.
bool GetLaneWidth(const double s, double *const lane_left_width, double *const lane_right_width) const
std::shared_ptr< DependencyInjector > injector_
ReferenceLineInfo * reference_line_info_
virtual bool Init(const std::string &config_dir, const std::string &name, const std::shared_ptr< DependencyInjector > &injector)
Planning module main class.
double NormalizeAngle(const double angle)
Normalize angle to [-PI, PI).
constexpr double kJunctionClearanceDist
constexpr double kIntersectionClearanceDist
std::vector< PathBoundPoint > PathBound
optional VehicleParam vehicle_param
optional double linear_velocity
optional PiecewiseJerkPathConfig path_optimizer_config
optional double change_lane_fail_freeze_time
optional double lane_change_prepare_length
optional bool enable_forbidden_zone
optional double extend_adc_buffer
optional double change_lane_success_freeze_time