Apollo:参考线提供者ReferenceLineProvider

ReferenceLineProvider是规划模块的关键组件,它接收Routing模块的高精度路径,通过平滑处理生成用于动作规划的参考线。该类使用C++11的多线程和单例模式,确保在多线程环境下的安全操作。其主要功能包括初始化、路径平滑、线程管理和路径更新。当路由改变时,它会创建新的参考线,否则基于车辆状态和当前路线更新现有参考线。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

作用

这个类为planning模块提供平滑的参考线

  • ReferenceLineProvider是规划模块中候选路径(即参考线)的提供和管理者
  • ReferenceLineProvider以Routing模块输出的高精度路径(从起点到终点的Lane片段集)为输入数据,经优化处理后生成平滑的参考线给给后续的动作规划子模块使用。
  • ReferenceLineProvider类是采用c++11标准提供的多线程类,每次调用ReferenceLineProvider::Start()函数后,该类会在内部开启一个新线程,执行参考线的优化
  • ReferenceLineProvider类是使用宏DECLARE_SINGLETON(ReferenceLineProvider)定义的单实例类,获取该类对象请使用ReferenceLineProvider::instance()。

在这里插入图片描述

这个类的主要作用:
在这里插入图片描述

成员变量

数据类型成员变量说明
boolis_initialized_ = false;初始化是否完成标志
std::atomic<bool>is_stop_{false};当前线程是否停止
std::unique_ptr<ReferenceLineSmoother>smoother_;这是一个参考线平滑类对象,用来执行参考线平滑任务
ReferenceLineSmootherConfigsmoother_config_;读取二次规划样条参考线平滑配置的类对象
std::mutexpnc_map_mutex_;运行规划控制地图在多线程环境下安全使用的互斥类对象
std::unique_ptr< hdmap::PncMap>pnc_map_;规划控制模块使用的地图数据类对象
std::shared_ptr< relative_map::MapMsg>relative_map_;如果是导航模式则启动相对地图,如果不是则启动pnc_map
std::mutexvehicle_state_mutex_;允许车辆状态在多线程环境下安全使用的互斥体类对象
common::VehicleStatevehicle_state_;当前的车辆状态
std::mutexrouting_mutex_;允许路由寻径响应在多线程环境下安全使用的互斥体类对象
routing::RoutingResponserouting_;Routing模块输出的路由寻径数据
boolhas_routing_ = false;从起点到终点是否具备路由
std::mutexreference_lines_mutex_;允许参考线在多线程环境下安全使用的互斥体类对象
std::list< ReferenceLine>reference_lines_;存储多条候选路径
std::list< hdmap::RouteSegments>route_segments_;存储多条路由片段
doublelast_calculation_time_ = 0.0;上次计算平滑参考线耗时
std::queue<std::list< ReferenceLine>>reference_line_history_;用于检索历史路径片段的ID
std::queue<std::list< hdmap::RouteSegments>>route_segments_history_;存储多条历史路由路径片段
std::future< void>task_future_;
std::atomic< bool>is_reference_line_updated_{true};
const common::VehicleStateProvider*vehicle_state_provider_ = nullptr;

在这里插入图片描述

成员函数

该类的重要成员函数包括:构造函数、Start、Stop、GenerateThread、CreateReferenceLine、UpdateReferenceLine,其他函数都是辅助性的功能函数

构造函数

初始化各种成员变量

  • 初始化车辆状态提供者
    在这里插入图片描述

  • 如果是导航模式则启动相对地图,如果不是则启动pnc_map

在这里插入图片描述

  • 初始化平滑器
    • 先使用配置文件初始化smoother_config_

      modules/planning/common/planning_gflags.cc中定义了(没有这个文件)
      在这里插入图片描述
      modules/planning/conf/planning.conf中定义了(是这个文件)
      在这里插入图片描述

    • 然后使用配置初始化平滑器

在这里插入图片描述

  • 最后(注意,is_initialized_只在这里设置了。感觉是个没有用的变量,因为只要申请成功了就一定会设置它为true)

在这里插入图片描述

开始线程:ReferenceLineProvider::start

  • 如果是导航模式直接返回,不做任何实际工作。

  • 若启用参考线提供者线程,则以ReferenceLineProvider:: GenerateThread为入口函数创建一个新线程并返回true
    在这里插入图片描述

    • FLAGS_enable_reference_line_provider_thread定义在modules/planning/common/planning_gflags.cc中
      在这里插入图片描述

小结:只有不是导航模式&&设置了FLAGS_enable_reference_line_provider_thread才会生成参考线

接下来我们看下线程入口

线程入口:ReferenceLineProvider::GenerateThread

这是ReferenceLineProvider类线程的入口函数。

  • 首先入口就是一个循环函数,只要没有设置is_stop_,那么就会一直循环执行(这个is_stop_在 ReferenceLineProvider::Stop()中设置)
    在这里插入图片描述
  • 如果没有设置is_stop_,那么先让当前线程暂停,并且休眠50ms,将调度机会留给其他线程,当操作系统空闲时执行后续代码
  • 休眠回来之后,看是否重新routing了,如果没有,说明可以复用之前的参考线,那么重新sleep
    在这里插入图片描述
  • 如果发现重新routing了(当发生车祸修路时会重新routing),那么先调用CreateReferenceLine生成参考线和短期路由,然后UpdateReferenceLine更新参考线,最后计算此次参考线生成所消耗的时间

在这里插入图片描述

在这里插入图片描述
开启线程之后通过下面2个方法,刷新routing请求和车辆状态。也就是说参考线通过实时的routing请求和车辆状态来生成参考线

  bool UpdateRoutingResponse(const routing::RoutingResponse& routing);

  void UpdateVehicleState(const common::VehicleState& vehicle_state);

生成一条参考线:ReferenceLineProvider::CreateReferenceLine

  • 获取当前车辆状态
    在这里插入图片描述

  • 获取当前全局的导航路径

    • 先获取当前的在apollo中,routing模块从base map地图获取道路的拓扑信息,并根据RoutingRequest中包含起点和终点位置,使用A star算法搜索出最终的路由线路,放在RoutingResponse中。
      在这里插入图片描述
    • 接着调用pnc_map_->IsNewRouting(routing)判断当前路由是否为新路由, 若是则调用pnc_map_->UpdateRoutingResponse(routing)更新路由
      • PncMap对接了Routing的搜索结果。
      • 如果Routing的路线变了,这里需要进行更新。
        在这里插入图片描述
  • 之后,调用CreateRouteSegments函数来创建路由片段

    • 在行驶过程中,车辆的位置一直会变动(vehicle_state中包含了这个信息)。
    • CreateRouteSegments方法中会调用pnc_map_->GetRouteSegments(vehicle_state, segments)来获取车辆当前位置周边范围的RouteSegment。
    • 如果Routing的结果需要变道,则segments将是多个,否则就是一个(直行的情况)。
      在这里插入图片描述
  • 创建路由判断之后,判断是否需要粘合参考线

    • 若不需粘合参考线(!FLAGS_enable_reference_line_stitching),则调用SmoothRouteSegment函数来平滑各路由片段列表segments,并将平滑后的路由片段存储到参考线列表reference_lines中,同时将不能平滑的路由片段从segments中删除;
      • 如果是新的routing,对于新的Routing,则根据segments生成ReferenceLine,两者的数量是对应的。并且,ReferenceLine将直接从RouteSegment里面获取到道路的点的信息。
    • 若需粘合参考线(FLAGS_enable_reference_line_stitching),则调用ExtendReferenceLine函数来合并不同参考线片段的重合部分,并将粘合后的路由片段保存到参考线列表reference_lines中,同时将不能粘合的路由片段从列表segments中删除。
      • 大部分情况下,在车辆行驶过程中,会不停的根据车辆的位置对ReferenceLine进行长度延伸。ReferenceLine的长度是200多米的范围(往后30米左右,往前180米或者250米左右)。

在这里插入图片描述
小结: 参考线生成是由CreateReferenceLine函数实现的。

  • 首先由UpdateVehicleState函数获取车辆的状态
  • 再由UpdateRoutingResponse函数获取Routing的结果,生成RouteSegment。
  • routing是新生成的,则对其进行平滑与分割;若不是,则沿用上一个周期的参考线,并对其进行扩展与延伸。
    在这里插入图片描述

在这里插入图片描述

更新一条参考线:UpdateReferenceLine

判断新参考线各线段是否与原参考线对应线段相同,若相同则忽略,否则更新。

结束线程:Stop

将线程停止标志is_stop_置为true,判断当前线程是否完成,若未完,则调用thread_->join()强制完成线程任务。

获取所有参考线:ReferenceLineProvider::GetReferenceLines

通过GetReferenceLines来获取参考线。实际上并发模式和不是并发模式执行的函数都是一样,只不过并发模式下另外的线程已经计算好了,因此可以直接赋值。

bool ReferenceLineProvider::GetReferenceLines(
    std::list<ReferenceLine> *reference_lines,
    std::list<hdmap::RouteSegments> *segments) {
  ...
  // 1. 如果有单独的线程,则直接赋值 
  if (FLAGS_enable_reference_line_provider_thread) {
    std::lock_guard<std::mutex> 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();
    // 2. 否则,创建并且更新参考线
    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 << "Failed to use reference line latest history";
    return false;
  }
  // 3. 如果失败,则采用上一次的规划轨迹
  reference_lines->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;
}

从上面代码可以得出,参考线的生成主要集中在2个函数中CreateReferenceLine和UpdateReferenceLine。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值