> 文档中心 > Apollo规划决策算法仿真调试(3):ReferenceLineProvider参考线生成流程

Apollo规划决策算法仿真调试(3):ReferenceLineProvider参考线生成流程

前言:

在Apollo规划决策算法中,即planning模块中,参考线ReferenceLine 的作用至关重要,ReferenceLine 是整个规划算法的基础,规划的目的就是使车辆按照ReferenceLine行驶。

目前关于ReferenceLine 的平滑方法介绍很多,但很少介绍ReferenceLine 在整个apollo的planning模块中,是在哪一步进行生成,它的整个运行机制与流程是怎样的。

本文将使用vscode与dreamview 联合调试的方法,来展示ReferenceLine 在apollo的planning模块中是如何一步步生成。

如果对Apollo规划决策算法仿真调试感兴趣,想了解规划算法的实施细节,可以持续关注系列文章: 

Apollo规划决策算法仿真调试(1): 使用Vscode断点调试apollo的方法

Apollo规划决策算法仿真调试(2):使用bazel 编译自定义代码模块

Apollo规划决策算法仿真调试(4):  动态障碍物绕行 

正文如下:

1、Apollo在onlanePlanning中进行ReferenceLine 的生成,整体的调度过程如下:

下图是一次调试时vscode中堆栈区的截图,可以看到在planning模块中,参考线ReferenceLine 的生成路径如下:

OnLanePlanning::RunOnce( )  -->>  InitFrame(frame_num, stitching_trajectory.back(), vehicle_state)  -->>  

GetReferenceLines(&reference_lines,  &segments))  -->> CreateReferenceLine(reference_lines, segments) -->> 

CreateRouteSegments(vehicle_state, segments) -->>  GetRouteSegments(vehicle_state, segments)  ......

从本文后续的代码分析可以看出,RouteSegments 对于参考线ReferenceLine 的生成至关重要,有几个RouteSegments 决定有几条参考线的生成。

2、OnLanePlanning::RunOnce( ) 是执行规划认为的主函数,在调用具体的规划器planner进行轨迹规划任务前,会首先初始化frame,其中在初始化frame时,进行了参考线的调用,即GetReferenceLines()。

OnLanePlanning::RunOnce( ) 中  InitFrame( ) 的相关代码: 

 injector_->ego_info()->Update(stitching_trajectory.back(), vehicle_state);  const uint32_t frame_num = static_cast(seq_num_++);  status = InitFrame(frame_num, stitching_trajectory.back(), vehicle_state);  if (status.ok()) {    injector_->ego_info()->CalculateFrontObstacleClearDistance(        frame_->obstacles());  }

 在  InitFrame( ) 中 GetReferenceLines( )的相关代码如下:

  std::list reference_lines;  std::list segments;  if (!reference_line_provider_->GetReferenceLines(&reference_lines,                                                   &segments)) {   const std::string msg = "Failed to create reference line";    AERROR << msg;   return Status(ErrorCode::PLANNING_ERROR, msg);  }

3、ReferenceLineProvider 中获取参考线ReferenceLine:

从调试过程中变量分析,在GetReferenceLines(&reference_lines,  &segments)) 中,主要是调用CreateReferenceLine(reference_lines, segments) 来生成参考线,二者都属于ReferenceLineProvider 类中的方法。

调试过程中,关键变量取值如下:

 

代码如下:

bool ReferenceLineProvider::GetReferenceLines(    std::list *reference_lines,    std::list *segments) {  CHECK_NOTNULL(reference_lines);  CHECK_NOTNULL(segments);  if (FLAGS_use_navigation_mode) {   double start_time = Clock::NowInSeconds();   bool result = GetReferenceLinesFromRelativeMap(reference_lines, segments);   if (!result) {      AERROR << "Failed to get reference line from relative map";   }   double end_time = Clock::NowInSeconds();    last_calculation_time_ = end_time - start_time;   return result;  }  if (FLAGS_enable_reference_line_provider_thread) {    std::lock_guard lock(reference_lines_mutex_);   if (!reference_lines_.empty()) {      reference_lines->assign(reference_lines_.begin(), reference_lines_.end());      segments->assign(route_segments_.begin(), route_segments_.end());     return true;   }  } else {   double start_time = Clock::NowInSeconds();   if (CreateReferenceLine(reference_lines, segments)) {     UpdateReferenceLine(*reference_lines, *segments);     double end_time = Clock::NowInSeconds();      last_calculation_time_ = end_time - start_time;     return true;   }  }  AWARN << "Reference line is NOT ready.";  if (reference_line_history_.empty()) {    AERROR <assign(reference_line_history_.back().begin(),                          reference_line_history_.back().end());  segments->assign(route_segments_history_.back().begin(),                  route_segments_history_.back().end());  AWARN << "Use reference line from history!";  return true;}

4、GetReferenceLines( ) 中参考线ReferenceLine 的生成逻辑

在GetReferenceLines( ) 中可以看到 ReferenceLine 是通过遍历segments 来进行生成的,所以segment 的数量以及位置,便决定了参考线ReferenceLine 的数量与位置;对于每个segments ,通过调用参考线平滑方法SmoothRouteSegment(*iter, &reference_lines->back()) 来生成参考线。

if (!CreateRouteSegments(vehicle_state, segments)) {    AERROR <begin(); iter != segments->end();) {      reference_lines->emplace_back();     if (!SmoothRouteSegment(*iter, &reference_lines->back())) {        AERROR <pop_back();        iter = segments->erase(iter);     } else {        common::SLPoint sl;       if (!reference_lines->back().XYToSL(vehicle_state, &sl)) {          AWARN << "Failed to project point: {" << vehicle_state.x() << ","               << vehicle_state.y() <back(), &(*iter));       ++iter;     }   }   return true;

5、ReferenceLineProvider::CreateRouteSegments()逻辑

可以看到对于参考线至关重要的RouteSegments,是根据地图提供的pnc_map 来进行生成,其中又可以通过配置FLAGS_prioritize_change_lane 来确定是否变道优先。

代码如下:

bool ReferenceLineProvider::CreateRouteSegments(   const common::VehicleState &vehicle_state,    std::list *segments) {  {    std::lock_guard lock(pnc_map_mutex_);   if (!pnc_map_->GetRouteSegments(vehicle_state, segments)) {      AERROR <empty();}

6、从调试结果中看到,生成了两个RouteSegments,所以也会生成两条参考线

7、关于RouteSegments 生成的具体方法,将在之后的文章中进行介绍。