• Apollo planning之PathBoundsDecider


    目录

    1 类的继承与调用关系

    1.1 继承关系

    1.2 调用关系

    2 路径边界决策数据

    2.1 输入和输出

    2.2 参数设置

    2.3 数据结构

    3 代码流程及框架

     3.1 fallback

    3.2 pull over

    3.3 lane change

    3.4 regular


    1 类的继承与调用关系

    1.1 继承关系

    PathBoundsDecider类继承了Decider类实现了Process方法,路径边界决策主要的执行过程就在Process方法中。

    1. // modules/planning/tasks/deciders/path_bounds_decider/path_bounds_decider.h
    2. class PathBoundsDecider : public Decider {
    3. ... };

    Decider类继承了Task类实现Excute方法,主要是给两个变量赋值:frame和reference-line-info,并且执行Process方法。和上述的Process方法相对应

    1. // modules/planning/tasks/deciders/decider.h
    2. class Decider : public Task {
    3. ... };
    4. // modules/planning/tasks/deciders/decider.cc
    5. apollo::common::Status Decider::Execute(
    6. Frame* frame, ReferenceLineInfo* reference_line_info) {
    7. Task::Execute(frame, reference_line_info);
    8. return Process(frame, reference_line_info);
    9. }
    10. apollo::common::Status Decider::Execute(Frame* frame) {
    11. Task::Execute(frame);
    12. return Process(frame);
    13. }

    Task类,定义类保护类型的变量,是路径边界决策的输入

    1. // modules/planning/tasks/task.h
    2. class Task {
    3. public:
    4. // 虚方法,主要是给frame和reference_line_info赋值
    5. virtual common::Status Execute(Frame* frame,
    6. ReferenceLineInfo* reference_line_info);
    7. virtual common::Status Execute(Frame* frame);
    8. protected:
    9. // frame和reference_line_info变量
    10. Frame* frame_ = nullptr;
    11. ReferenceLineInfo* reference_line_info_ = nullptr;
    12. // 配置与名字
    13. TaskConfig config_;
    14. std::string name_;
    15. ... };

    1.2 调用关系

    主要描述task在stage中是如何创建和调用

    TaskFactory类,注册所有的task,包括decider、optimizer和other(E2E的task)。工厂模式

    1. // modules/planning/tasks/task_factory.h
    2. class TaskFactory {
    3. public:
    4. // 两个函数都是static属性
    5. static void Init(...); // 在初始化函数中,注册所有的task
    6. static std::unique_ptr CreateTask(...); // 创建具体task的实例,返回指向该实例的指针
    7. ... };

    stage中task的创建与执行

    • 创建:在stage的构造函数中根据stage配置创建task。并将指针放入到task_和task_list_

    • 使用:在具体的stage中,重写Process方法。调用Process方法,进而调用ExecuteTask*方法(ExecuteTaskOnReferenceLine),最后调用相应的task的Process方法

    1. // modules/planning/scenarios/stage.h
    2. class Stage {
    3. // 在构造函数中根据stage的配置创建task
    4. Stage(const ScenarioConfig::StageConfig& config,
    5. const std::shared_ptr& injector);
    6. public:
    7. // 纯虚函数,留给具体的stage实现,不同的stage有不同的实现逻辑
    8. virtual StageStatus Process(
    9. const common::TrajectoryPoint& planning_init_point, Frame* frame) = 0;
    10. protected:
    11. // 三个执行task的函数,在每个函数中都调用类task的Excute方法,进一步调用具体task的Process方法
    12. bool ExecuteTaskOnReferenceLine(
    13. const common::TrajectoryPoint& planning_start_point, Frame* frame);
    14. bool ExecuteTaskOnReferenceLineForOnlineLearning(
    15. const common::TrajectoryPoint& planning_start_point, Frame* frame);
    16. bool ExecuteTaskOnOpenSpace(Frame* frame);
    17. protected:
    18. // task的map,key是TaskType,value是指向Task的指针
    19. std::map> tasks_;
    20. // 保存Task列表
    21. std::vector task_list_;
    22. // stage 配置
    23. ScenarioConfig::StageConfig config_;
    24. ...};

    2 路径边界决策数据

    2.1 输入和输出

    输入变量就是上面提到的Task类中的保护变量,即 frame reference-line-info

    frame中有进行一次规划所需要的所有实时数据,reference-line-info包含所有关于参考线的信息

    1. // modules/planning/common/frame.h
    2. class Frame {
    3. private:
    4. static DrivingAction pad_msg_driving_action_;
    5. uint32_t sequence_num_ = 0;
    6. /* Local_view是一个结构体,包含了如下信息
    7. // modules/planning/common/local_view.h
    8. struct LocalView {
    9. std::shared_ptr prediction_obstacles;
    10. std::shared_ptr chassis;
    11. std::shared_ptr localization_estimate;
    12. std::shared_ptr traffic_light;
    13. std::shared_ptr routing;
    14. std::shared_ptr relative_map;
    15. std::shared_ptr pad_msg;
    16. std::shared_ptr stories;
    17. };
    18. */
    19. LocalView local_view_;
    20. // 高清地图
    21. const hdmap::HDMap *hdmap_ = nullptr;
    22. common::TrajectoryPoint planning_start_point_;
    23. // 车辆状态
    24. // modules/common/vehicle_state/proto/vehicle_state.proto
    25. common::VehicleState vehicle_state_;
    26. // 参考线信息
    27. std::list reference_line_info_;
    28. bool is_near_destination_ = false;
    29. /**
    30. * the reference line info that the vehicle finally choose to drive on
    31. **/
    32. const ReferenceLineInfo *drive_reference_line_info_ = nullptr;
    33. ThreadSafeIndexedObstacles obstacles_;
    34. std::unordered_mapconst perception::TrafficLight *>
    35. traffic_lights_;
    36. // current frame published trajectory
    37. ADCTrajectory current_frame_planned_trajectory_;
    38. // current frame path for future possible speed fallback
    39. DiscretizedPath current_frame_planned_path_;
    40. const ReferenceLineProvider *reference_line_provider_ = nullptr;
    41. OpenSpaceInfo open_space_info_;
    42. std::vector future_route_waypoints_;
    43. common::monitor::MonitorLogBuffer monitor_logger_buffer_;
    44. };
    1. // modules/planning/common/reference_line_info.h
    2. class ReferenceLineInfo {
    3. ...
    4. private:
    5. static std::unordered_mapbool> junction_right_of_way_map_;
    6. const common::VehicleState vehicle_state_; // 车辆状态
    7. const common::TrajectoryPoint adc_planning_point_; // TrajectoryPoint定义在modules/common/proto/pnc_point.proto中
    8. /* 参考线,以道路中心线,做过顺滑的一条轨迹,往后80米,往前130米。
    9. class ReferenceLine {
    10. ...
    11. private:
    12. struct SpeedLimit {
    13. double start_s = 0.0;
    14. double end_s = 0.0;
    15. double speed_limit = 0.0; // unit m/s
    16. ...};
    17. // This speed limit overrides the lane speed limit
    18. std::vector speed_limit_;
    19. std::vector reference_points_; // ReferencePoint包含有信息(k, dk, x, y, heading, s, l)
    20. hdmap::Path map_path_;
    21. uint32_t priority_ = 0;
    22. };
    23. */
    24. ReferenceLine reference_line_;
    25. /**
    26. * @brief this is the number that measures the goodness of this reference
    27. * line. The lower the better.
    28. */
    29. // 评价函数,值越低越好
    30. double cost_ = 0.0;
    31. bool is_drivable_ = true;
    32. // PathDecision包含了一条路径上的所有obstacle的决策,有两种:lateral(Nudge, Ignore)和longitudinal(Stop, Yield, Follow, Overtake, Ignore)
    33. PathDecision path_decision_;
    34. // 指针
    35. Obstacle* blocking_obstacle_;
    36. /* path的边界,结果保存在这个变量里。通过**SetCandidatePathBoundaries**方法保存到此变量
    37. // modules/planning/common/path_boundary.h
    38. class PathBoundary {
    39. ...
    40. private:
    41. double start_s_ = 0.0;
    42. double delta_s_ = 0.0;
    43. std::vector> boundary_;
    44. std::string label_ = "regular";
    45. std::string blocking_obstacle_id_ = "";
    46. };
    47. */
    48. std::vector candidate_path_boundaries_;
    49. // PathData类,包含XY坐标系和SL坐标系的相互转化
    50. std::vector candidate_path_data_;
    51. PathData path_data_;
    52. PathData fallback_path_data_;
    53. SpeedData speed_data_;
    54. DiscretizedTrajectory discretized_trajectory_;
    55. RSSInfo rss_info_;
    56. /**
    57. * @brief SL boundary of stitching point (starting point of plan trajectory)
    58. * relative to the reference line
    59. */
    60. SLBoundary adc_sl_boundary_;
    61. ... };

    输出信息则是都保存在 reference-line-info 中

    1. Status PathBoundsDecider::Process(
    2. Frame* const frame, ReferenceLineInfo* const reference_line_info)

    2.2 参数设置

    例如,规划的纵向距离设置为100m,采样距离为0.5m

    1. // modules/planning/tasks/deciders/path_bounds_decider/path_bounds_decider.cc
    2. // s方向的距离
    3. constexpr double kPathBoundsDeciderHorizon = 100.0;
    4. // s方向的间隔
    5. constexpr double kPathBoundsDeciderResolution = 0.5;
    6. // Lane宽度
    7. constexpr double kDefaultLaneWidth = 5.0;
    8. // Road的道路
    9. constexpr double kDefaultRoadWidth = 20.0;
    10. // TODO(all): Update extra tail point base on vehicle speed.
    11. constexpr int kNumExtraTailBoundPoint = 20;
    12. constexpr double kPulloverLonSearchCoeff = 1.5;
    13. constexpr double kPulloverLatSearchCoeff = 1.25;

    2.3 数据结构

    路径边界点用纵向距离以及上下限的横向距离来描述,相当于是一定分辨率的扫描

    把障碍物分解成两个edge

    1. // modules/planning/tasks/deciders/path_bounds_decider/path_bounds_decider.cc
    2. namespace {
    3. // PathBoundPoint contains: (s, l_min, l_max). 路径边界点
    4. using PathBoundPoint = std::tuple<double, double, double>;
    5. // PathBound contains a vector of PathBoundPoints. 路径边界
    6. using PathBound = std::vector;
    7. // ObstacleEdge contains: (is_start_s, s, l_min, l_max, obstacle_id). 障碍物的边
    8. using ObstacleEdge = std::tuple<int, double, double, double, std::string>;
    9. } // namespace
    1. for (const auto* obstacle : indexed_obstacles.Items()) {
    2. // Only focus on those within-scope obstacles.
    3. if (!IsWithinPathDeciderScopeObstacle(*obstacle)) {
    4. continue;
    5. }
    6. // Only focus on obstacles that are ahead of ADC.
    7. if (obstacle->PerceptionSLBoundary().end_s() < adc_frenet_s_) {
    8. continue;
    9. }
    10. // Decompose each obstacle's rectangle into two edges: one at
    11. // start_s; the other at end_s.
    12. const auto obstacle_sl = obstacle->PerceptionSLBoundary();
    13. sorted_obstacles.emplace_back(
    14. 1, obstacle_sl.start_s() - FLAGS_obstacle_lon_start_buffer,
    15. obstacle_sl.start_l() - FLAGS_obstacle_lat_buffer,
    16. obstacle_sl.end_l() + FLAGS_obstacle_lat_buffer, obstacle->Id());
    17. sorted_obstacles.emplace_back(
    18. 0, obstacle_sl.end_s() + FLAGS_obstacle_lon_end_buffer,
    19. obstacle_sl.start_l() - FLAGS_obstacle_lat_buffer,
    20. obstacle_sl.end_l() + FLAGS_obstacle_lat_buffer, obstacle->Id());
    21. }
    1. std::sort(sorted_obstacles.begin(), sorted_obstacles.end(),
    2. [](const ObstacleEdge& lhs, const ObstacleEdge& rhs) {
    3. if (std::get<1>(lhs) != std::get<1>(rhs)) {
    4. return std::get<1>(lhs) < std::get<1>(rhs);
    5. } else {
    6. return std::get<0>(lhs) > std::get<0>(rhs);
    7. }
    8. });

    通过依次遍历按纵向距离排列的ObstacleEdge后,最后得到道路边界,如下图红线

    扫到ObstacleEdge进入或退出,并更新一下边界

    3 代码流程及框架

     3.1 fallback

    fallback场景生成过程如上图所示。fallback是其他3种场景计算PathBound失败时的备选(没有办法的办法),只考虑自车信息和静态道路信息,不考虑静态障碍物。因此,这种情况下speed decider负责让自车在障碍物前停车。

    1. Status PathBoundsDecider::GenerateFallbackPathBound(
    2. const ReferenceLineInfo& reference_line_info, PathBound* const path_bound) {
    3. // 1. Initialize the path boundaries to be an indefinitely large area.
    4. if (!InitPathBoundary(reference_line_info, path_bound)) { ... }
    5. // 2. Decide a rough boundary based on lane info and ADC's position
    6. std::string dummy_borrow_lane_type;
    7. if (!GetBoundaryFromLanesAndADC(reference_line_info,
    8. LaneBorrowInfo::NO_BORROW, 0.5, path_bound,
    9. &dummy_borrow_lane_type)) { ... }
    10. return Status::OK();
    11. }

    fallback主要调用以下两个函数

    InitPathBoundary

    生成一条默认的fall back pathbound,在正常求解轨迹无解或失败的情况下使用

    1. bool PathBoundsDecider::InitPathBoundary(
    2. ...
    3. // Starting from ADC's current position, increment until the horizon, and
    4. // set lateral bounds to be infinite at every spot.
    5. // 从adc当前位置开始,以0.5m为间隔取点,直到终点,将 [左, 右] 边界设置为double的 [lowerst, max]
    6. for (double curr_s = adc_frenet_s_;
    7. curr_s < std::fmin(adc_frenet_s_ +
    8. std::fmax(kPathBoundsDeciderHorizon,
    9. reference_line_info.GetCruiseSpeed() *
    10. FLAGS_trajectory_time_length),
    11. reference_line.Length());
    12. curr_s += kPathBoundsDeciderResolution) {
    13. path_bound->emplace_back(curr_s, std::numeric_limits<double>::lowest(),
    14. std::numeric_limits<double>::max());
    15. }
    16. ...}

    GetBoundaryFromLanesAndADC

    GetBoundaryFromLanesAndADC则包含了根据自车信息、车道信息计算PathBound的具体细节。首先根据当前位置获取当前车道的左右宽度,然后根据左右借道获取相邻车道的宽度(当然,fallback设定不借道),最后综合各因素,更新PathBound。

     

    1. // TODO(jiacheng): this function is to be retired soon.
    2. bool PathBoundsDecider::GetBoundaryFromLanesAndADC(
    3. ...
    4. for (size_t i = 0; i < path_bound->size(); ++i) {
    5. double curr_s = std::get<0>((*path_bound)[i]);
    6. // 1. Get the current lane width at current point.获取当前点车道的宽度
    7. if (!reference_line.GetLaneWidth(curr_s, &curr_lane_left_width,
    8. &curr_lane_right_width)) {
    9. AWARN << "Failed to get lane width at s = " << curr_s;
    10. curr_lane_left_width = past_lane_left_width;
    11. curr_lane_right_width = past_lane_right_width;
    12. } else {...}
    13. // 2. Get the neighbor lane widths at the current point.获取当前点相邻车道的宽度
    14. double curr_neighbor_lane_width = 0.0;
    15. if (CheckLaneBoundaryType(reference_line_info, curr_s, lane_borrow_info)) {
    16. hdmap::Id neighbor_lane_id;
    17. if (lane_borrow_info == LaneBorrowInfo::LEFT_BORROW) {
    18. // 借左车道
    19. ...
    20. } else if (lane_borrow_info == LaneBorrowInfo::RIGHT_BORROW) {
    21. // 借右车道
    22. ...
    23. }
    24. }
    25. // 3. 根据道路宽度,adc的位置和速度计算合适的边界。
    26. static constexpr double kMaxLateralAccelerations = 1.5;
    27. double offset_to_map = 0.0;
    28. reference_line.GetOffsetToMap(curr_s, &offset_to_map);
    29. double ADC_speed_buffer = (adc_frenet_ld_ > 0 ? 1.0 : -1.0) *
    30. adc_frenet_ld_ * adc_frenet_ld_ /
    31. kMaxLateralAccelerations / 2.0;
    32. // 向左车道借到,左边界会变成左侧车道左边界
    33. double curr_left_bound_lane =
    34. curr_lane_left_width + (lane_borrow_info == LaneBorrowInfo::LEFT_BORROW
    35. ? curr_neighbor_lane_width
    36. : 0.0);
    37. // 和上面类似
    38. double curr_right_bound_lane =
    39. -curr_lane_right_width -
    40. (lane_borrow_info == LaneBorrowInfo::RIGHT_BORROW
    41. ? curr_neighbor_lane_width
    42. : 0.0);
    43. double curr_left_bound = 0.0; // 左边界
    44. double curr_right_bound = 0.0; // 右边界
    45. // 计算左边界和右边界
    46. if (config_.path_bounds_decider_config()
    47. .is_extend_lane_bounds_to_include_adc() ||
    48. is_fallback_lanechange) {
    49. // extend path bounds to include ADC in fallback or change lane path
    50. // bounds.
    51. double curr_left_bound_adc =
    52. std::fmax(adc_l_to_lane_center_,
    53. adc_l_to_lane_center_ + ADC_speed_buffer) +
    54. GetBufferBetweenADCCenterAndEdge() + ADC_buffer;
    55. curr_left_bound =
    56. std::fmax(curr_left_bound_lane, curr_left_bound_adc) - offset_to_map;
    57. double curr_right_bound_adc =
    58. std::fmin(adc_l_to_lane_center_,
    59. adc_l_to_lane_center_ + ADC_speed_buffer) -
    60. GetBufferBetweenADCCenterAndEdge() - ADC_buffer;
    61. curr_right_bound =
    62. std::fmin(curr_right_bound_lane, curr_right_bound_adc) -
    63. offset_to_map;
    64. } else {
    65. curr_left_bound = curr_left_bound_lane - offset_to_map;
    66. curr_right_bound = curr_right_bound_lane - offset_to_map;
    67. }
    68. // 4. 更新边界.
    69. if (!UpdatePathBoundaryWithBuffer(i, curr_left_bound, curr_right_bound,
    70. path_bound, is_left_lane_boundary,
    71. is_right_lane_boundary)) {
    72. path_blocked_idx = static_cast<int>(i);
    73. }
    74. ... }

    3.2 pull over

    GetBoundaryFromRoads

    GetBoundaryFromLanesAndADC不同,GetBoundaryFromRoads函数根据道路信息计算出边界: 获取参考线信息,并对路径上的点,逐点计算新的路径边界

    GetBoundaryFromStaticObstacle

    根据障碍物,调整路径边界:

    • 计算障碍物在frenet坐标系下的坐标

    • 扫描线排序,S方向扫描

      • 只关注在路径边界内的障碍物和在adc前方的障碍物(避免冗余避障,提高计算速度

      • 将障碍物分解为两个边界,开始和结束

    • 映射障碍物ID

      • Adc能从左边通过为True,否则为False

    • 逐个点的检查path路径上的障碍物(新的和旧的

    SearchPullOverPosition

    搜索pull over位置(所谓停车点)的过程:

    • 根据pull_over_status.pull_over_type()判断是前向搜索(pull over开头第一个点),还是后向搜索(pull over末尾后一个点)

    • 两层循环,外层控制搜索的索引 idx,内层控制进一步的索引(前向idx+1,后向idx-1)。

    • 根据内外两层循环的索引,判断搜索到的空间是否满足车辆宽度和长度要求,判断是否可以pull over

    1. bool PathBoundsDecider::SearchPullOverPosition( ... ) {
    2. // search direction
    3. bool search_backward = false; // search FORWARD by default
    4. //01.先根据不同场景搜索一个考察可停车区域的大致端点,然后从该端点出发确定可停车区域
    5. double pull_over_s = 0.0;
    6. if (pull_over_status.pull_over_type() == PullOverStatus::EMERGENCY_PULL_OVER) {
    7. //紧急情况,前方停车
    8. if (!FindEmergencyPullOverS(reference_line_info, &pull_over_s)) { ... }
    9. search_backward = false; // search FORWARD from target position
    10. } else if (pull_over_status.pull_over_type() == PullOverStatus::PULL_OVER) {
    11. if (!FindDestinationPullOverS(frame, reference_line_info, path_bound,
    12. &pull_over_s)) { ... }
    13. //理想的停车点是route的终点,因此要反向搜索,以找到匹配的bounds
    14. search_backward = true; // search BACKWARD from target position
    15. } else {
    16. return false;
    17. }
    18. int idx = 0;
    19. if (search_backward) {
    20. // 1. Locate the first point before destination.
    21. idx = static_cast<int>(path_bound.size()) - 1;
    22. while (idx >= 0 && std::get<0>(path_bound[idx]) > pull_over_s) {
    23. --idx;
    24. }
    25. //反向搜索时,idx表示停车区域的末端
    26. } else {
    27. // 1. Locate the first point after emergency_pull_over s.
    28. while (idx < static_cast<int>(path_bound.size()) &&
    29. std::get<0>(path_bound[idx]) < pull_over_s) {
    30. ++idx;
    31. }
    32. //前向搜索时,idx表示停车区域的开端
    33. }
    34. if (idx < 0 || idx >= static_cast<int>(path_bound.size())) { ... }
    35. // Search for a feasible location for pull-over
    36. ... //根据一些条件计算pull_over_space_length 和 pull_over_space_width
    37. // 2. Find a window that is close to road-edge.(not in any intersection)
    38. //02.搜索可停车的区域始末。内外2层while循环,外循环控制一个开始搜索的端点idx,因为当
    39. //考察的区域不符合安全性和尺寸条件时,idx也要变化。内循环控制另一个端点j。
    40. bool has_a_feasible_window = false;
    41. while ((search_backward && idx >= 0 &&
    42. std::get<0>(path_bound[idx]) - std::get<0>(path_bound.front()) >
    43. pull_over_space_length) ||
    44. (!search_backward && idx < static_cast<int>(path_bound.size()) &&
    45. std::get<0>(path_bound.back()) - std::get<0>(path_bound[idx]) >
    46. pull_over_space_length)) {
    47. int j = idx;
    48. bool is_feasible_window = true;
    49. ... // Check if the point of idx is within intersection.
    50. //如果遇到路口,调整开始搜索的端点idx,重新搜索
    51. if (!junctions.empty()) {
    52. AWARN << "Point is in PNC-junction.";
    53. idx = search_backward ? idx - 1 : idx + 1;
    54. continue;
    55. }
    56. //搜索一段宽度达标、长度达标的可停车区域。即,搜索合适的端点j
    57. while ((search_backward && j >= 0 &&
    58. std::get<0>(path_bound[idx]) - std::get<0>(path_bound[j]) <
    59. pull_over_space_length) ||
    60. (!search_backward && j < static_cast<int>(path_bound.size()) &&
    61. std::get<0>(path_bound[j]) - std::get<0>(path_bound[idx]) <
    62. pull_over_space_length)) {
    63. double curr_s = std::get<0>(path_bound[j]);
    64. double curr_right_bound = std::fabs(std::get<1>(path_bound[j]));
    65. reference_line_info.reference_line().GetRoadWidth(
    66. curr_s, &curr_road_left_width, &curr_road_right_width);
    67. if (curr_road_right_width - (curr_right_bound + adc_half_width) >
    68. config_.path_bounds_decider_config().pull_over_road_edge_buffer()) {
    69. AERROR << "Not close enough to road-edge. Not feasible for pull-over.";
    70. is_feasible_window = false;
    71. break;
    72. }
    73. if(std::get<2>(path_bound[j])-std::get<1>(path_bound[j]) < pull_over_space_width) {
    74. AERROR << "Not wide enough to fit ADC. Not feasible for pull-over.";
    75. is_feasible_window = false;
    76. break;
    77. }
    78. j = search_backward ? j - 1 : j + 1;
    79. }
    80. if (j < 0) {
    81. return false;
    82. }
    83. //03.找到可停车区域后,获取停车目标点的位姿
    84. if (is_feasible_window) {
    85. // estimate pull over point to have the vehicle keep same safety distance
    86. // to front and back
    87. ...
    88. int start_idx = j;
    89. int end_idx = idx;
    90. if (!search_backward) {
    91. start_idx = idx;
    92. end_idx = j;
    93. }
    94. //根据start_idx和end_idx计算pull_over_idx。注意index是相对于bounds的
    95. ...
    96. const auto& pull_over_point = path_bound[pull_over_idx];
    97. //根据找到的停车点,设定相关信息,并根据参考线计算停车点的朝向角
    98. ...
    99. *pull_over_configuration = std::make_tuple(pull_over_x, pull_over_y,
    100. pull_over_theta, static_cast<int>(pull_over_idx));
    101. break; //一旦找到可停车区域,退出最外层while循环,返回结果
    102. }
    103. idx = search_backward ? idx - 1 : idx + 1;
    104. }
    105. }

    3.3 lane change

    1. Status PathBoundsDecider::GenerateLaneChangePathBound(
    2. const ReferenceLineInfo& reference_line_info,
    3. std::vectordouble, double, double>>* const path_bound) {
    4. // 1.初始化,和前面的步骤类似
    5. if (!InitPathBoundary(reference_line_info, path_bound)) {...}
    6. // 2. 根据道路和adc的信息获取一个大致的路径边界
    7. std::string dummy_borrow_lane_type;
    8. if (!GetBoundaryFromLanesAndADC(reference_line_info,
    9. LaneBorrowInfo::NO_BORROW, 0.1, path_bound,
    10. &dummy_borrow_lane_type, true)) {...}
    11. // 3. Remove the S-length of target lane out of the path-bound.
    12. GetBoundaryFromLaneChangeForbiddenZone(reference_line_info, path_bound);
    13. // 根据静态障碍物调整边界.
    14. if (!GetBoundaryFromStaticObstacles(reference_line_info.path_decision(),
    15. path_bound, &blocking_obstacle_id)) {...}
    16. ...
    17. }

    GetBoundaryFromLaneChangeForbiddenZone函数是lane change重要的函数。运行过程如下:

    • 如果当前位置可以变道,则直接变道

    • 如果有一个lane-change的起点,则直接使用它

    • 逐个检查变道前的点的边界,改变边界的值(如果已经过了变道点,则返回)

    1. void PathBoundsDecider::GetBoundaryFromLaneChangeForbiddenZone(
    2. const ReferenceLineInfo& reference_line_info, PathBound* const path_bound) {
    3. // 1.当前位置直接变道。
    4. auto* lane_change_status = injector_->planning_context()
    5. ->mutable_planning_status()
    6. ->mutable_change_lane();
    7. if (lane_change_status->is_clear_to_change_lane()) {
    8. ADEBUG << "Current position is clear to change lane. No need prep s.";
    9. lane_change_status->set_exist_lane_change_start_position(false);
    10. return;
    11. }
    12. // 2.如果已经有一个lane-change的起点,就直接使用它,否则再找一个
    13. double lane_change_start_s = 0.0;
    14. if (lane_change_status->exist_lane_change_start_position()) {
    15. common::SLPoint point_sl;
    16. reference_line.XYToSL(lane_change_status->lane_change_start_position(),
    17. &point_sl);
    18. lane_change_start_s = point_sl.s();
    19. } else {
    20. // TODO(jiacheng): train ML model to learn this.
    21. // 设置为adc前方一段距离为变道起始点
    22. lane_change_start_s = FLAGS_lane_change_prepare_length + adc_frenet_s_;
    23. // Update the decided lane_change_start_s into planning-context.
    24. // 更新变道起始点的信息
    25. common::SLPoint lane_change_start_sl;
    26. lane_change_start_sl.set_s(lane_change_start_s);
    27. lane_change_start_sl.set_l(0.0);
    28. common::math::Vec2d lane_change_start_xy;
    29. reference_line.SLToXY(lane_change_start_sl, &lane_change_start_xy);
    30. lane_change_status->set_exist_lane_change_start_position(true);
    31. lane_change_status->mutable_lane_change_start_position()->set_x(
    32. lane_change_start_xy.x());
    33. lane_change_status->mutable_lane_change_start_position()->set_y(
    34. lane_change_start_xy.y());
    35. }
    36. // Remove the target lane out of the path-boundary, up to the decided S.
    37. // 逐个检查变道前的点的边界,改变边界的值
    38. for (size_t i = 0; i < path_bound->size(); ++i) {
    39. double curr_s = std::get<0>((*path_bound)[i]);
    40. if (curr_s > lane_change_start_s) {
    41. break;
    42. }
    43. double curr_lane_left_width = 0.0;
    44. double curr_lane_right_width = 0.0;
    45. double offset_to_map = 0.0;
    46. reference_line.GetOffsetToMap(curr_s, &offset_to_map);
    47. if (reference_line.GetLaneWidth(curr_s, &curr_lane_left_width,
    48. &curr_lane_right_width)) {
    49. double offset_to_lane_center = 0.0;
    50. reference_line.GetOffsetToMap(curr_s, &offset_to_lane_center);
    51. curr_lane_left_width += offset_to_lane_center;
    52. curr_lane_right_width -= offset_to_lane_center;
    53. }
    54. curr_lane_left_width -= offset_to_map;
    55. curr_lane_right_width += offset_to_map;
    56. std::get<1>((*path_bound)[i]) =
    57. adc_frenet_l_ > curr_lane_left_width
    58. ? curr_lane_left_width + GetBufferBetweenADCCenterAndEdge()
    59. : std::get<1>((*path_bound)[i]);
    60. std::get<1>((*path_bound)[i]) =
    61. std::fmin(std::get<1>((*path_bound)[i]), adc_frenet_l_ - 0.1);
    62. std::get<2>((*path_bound)[i]) =
    63. adc_frenet_l_ < -curr_lane_right_width
    64. ? -curr_lane_right_width - GetBufferBetweenADCCenterAndEdge()
    65. : std::get<2>((*path_bound)[i]);
    66. std::get<2>((*path_bound)[i]) =
    67. std::fmax(std::get<2>((*path_bound)[i]), adc_frenet_l_ + 0.1);
    68. }
    69. }

    3.4 regular

    1. Status PathBoundsDecider::GenerateRegularPathBound(
    2. const ReferenceLineInfo& reference_line_info,
    3. const LaneBorrowInfo& lane_borrow_info, PathBound* const path_bound,
    4. std::string* const blocking_obstacle_id,
    5. std::string* const borrow_lane_type) {
    6. // 1.初始化边界.
    7. if (!InitPathBoundary(reference_line_info, path_bound)) {...}
    8. // 2.根据adc位置和lane信息确定大致的边界
    9. if (!GetBoundaryFromLanesAndADC(reference_line_info, lane_borrow_info, 0.1,
    10. path_bound, borrow_lane_type)) {...}
    11. // PathBoundsDebugString(*path_bound);
    12. // 3.根据障碍物调整道路边界
    13. if (!GetBoundaryFromStaticObstacles(reference_line_info.path_decision(),
    14. path_bound, blocking_obstacle_id)) {...}
    15. ...
    16. }

     借道有如下三种类型

    1. enum class LaneBorrowInfo {
    2. LEFT_BORROW,
    3. NO_BORROW,
    4. RIGHT_BORROW,
    5. };

    本文参考路径边界决策 — Apollo Auto 0.0.1 文档 (daobook.github.io)

    Path Bounds Decider - IcathianRain - 博客园 (cnblogs.com)

    Baidu Apollo代码解析之path_bounds_decider_linxigjs的博客-CSDN博客

    若侵权请联系删除 

  • 相关阅读:
    ffmpeg错误码
    【Element-UI】Mock.js,案例首页导航、左侧菜单
    网课自动暂停解决方法、挂课后台播放方法、解决继续教育自动暂停
    读书笔记:《海龟交易法则》
    虚基类设计 c++
    【Day3】最长上升子序列|Python
    C++ | Leetcode C++题解之第326题3的幂
    【WebRTC---源码篇】(十:一)WEBRTC 发送视频RTP包
    acm拿国奖的第一关:数组和字符串
    NLP模型笔记2022-33:Sentence-BERT STS模型列表与预训练方法
  • 原文地址:https://blog.csdn.net/weixin_65089713/article/details/126335201