Apollo规划模块代码学习(1): 算法架构原理、运行机制一文详解

这篇具有很好参考价值的文章主要介绍了Apollo规划模块代码学习(1): 算法架构原理、运行机制一文详解。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1、Apllo算法框架原理

Apollo开源自动驾驶平台中,高清地图模块提供了每个在线模块都可以访问的高清地图。感知和定位模块提供了必要的动态环境信息,可以在预测模块中进一步用于预测未来的环境状态。运动规划模块考虑所有信息,以生成安全平滑的轨迹,并将其输入车辆控制模块。
apollo planning模块源代码分析,Apollo自动驾驶代码系统学习,学习,算法,人工智能
目前Apollo官方最新版本Apollo 7.0在感知和预测模块集成了3个全新的深度学习模型。该版本引入了Apollo Studio,并与数据管道相结合,以提供一站式在线开发平台。Apollo 7.0还发布了基于先前模拟服务的PnC强化学习模型培训和模拟评估服务。在我们的专栏里将会重点介绍PnC模块

2、Apollo规划模块概述

Apollo 规划模块功能的实现是基于多个场景(scenario-based)实现的,不同的场景分成多个阶段(stage),每一阶段执行多个任务(task)来完成轨迹规划。其功能是规划出实时的轨迹,并保证轨迹的安全、避障、遵守交通规则、舒适度等。

规划模块代码架构如下,输入包括Routing信息、感知预测信息(障碍物、交通灯)以及车辆地盘信息、高精地图和定位信息。在Apollo的CyberRT框架中,输入输出是由Reder和Writer组成,在planning_component.h里。其为消息触发。

bool Proc(const std::shared_ptr<prediction::PredictionObstacles>&
                prediction_obstacles,
            const std::shared_ptr<canbus::Chassis>& chassis,
            const std::shared_ptr<localization::LocalizationEstimate>&
                localization_estimate) override;

输出 :ADCTrajectory即轨迹的相关信息,时间、路径长度、轨迹点。代码在planning.proto中。

planning_writer_->Write(std::make_shared<ADCTrajectory>(adc_trajectory_pb));

Planning类实现两个线程:ReferenceLineProvider启动了一个单独的线程,每隔50ms执行一次,和Planning主流程并行执行。
apollo planning模块源代码分析,Apollo自动驾驶代码系统学习,学习,算法,人工智能

3、规划模块代码框架

1、重要数据结构

LocalView: 包含规划模块所有上游输入数据。
(预测障碍物、底盘信息、定位信息、交通灯信息、routing信息、相对地图)

ReferenceLine: 规划的参考线。(地图原始中线,参考线优化前的初始轨迹点)

**ReferenceLineInfo:**对ReferenceLine进行封装还包括参考线算法中其他信息。

Frame: 包括规划模块一次循环中用到的所有信息。(地图、规划初始点、车辆状态、参考线、障碍物、交通灯等信息)

三种规划器:
OnLanePlanning(车道规划,可用于城区及高速公路各种复杂道路)
NaviPlanning(导航规划,主要用于高速公路)
OpenSpacePlanning (自主泊车和狭窄路段的掉头)

四种规划算法:
PublicRoadPlanner(默认规划器)
LatticePlanner、NaviPlanner(主要用于高速公路场景)
RTKPlanner(循迹算法,一般不用)

2、运行机制

apollo planning模块源代码分析,Apollo自动驾驶代码系统学习,学习,算法,人工智能

(1) 入口函数PlanningComponent::Proc(),在cyber中注册模块。

bool Proc(const std::shared_ptr<prediction::PredictionObstacles>&
                prediction_obstacles,
            const std::shared_ptr<canbus::Chassis>& chassis,
            const std::shared_ptr<localization::LocalizationEstimate>&
                localization_estimate) override;

过程:模块注册(planning_component.h)-> 模块初始化(OnLanePlanning::Plan(和proc)-> 模块运行(OnLanePlanning::RunOnce() )

(2) 选择Planning模式:
OnLanePlanning(车道规划,用于城区及高速公路各种复杂道路)
NaviPlanning(导航规划,用于高速公路)
OpenSpacePlanning (自主泊车和狭窄路段掉头)

注: Planning类实现两个线程:ReferenceLineProvider启动了一个单独的线程,每隔50ms执行一次,和Planning主流程并行执行。

(3) 根据不同的Dispatcher,选择Planner。
PublicRoadPlanner(默认规划器)
LatticePlanner、NaviPlanner(用于高速公路场景)
RTKPlanner(循迹算法,一般不用)

// 配置文件
standard_planning_config {
  planner_type: PUBLIC_ROAD
  planner_type: OPEN_SPACE
  ...
}

// OnLanePlannerDispatcher具体实现
std::unique_ptr<Planner> OnLanePlannerDispatcher::DispatchPlanner() {
  PlanningConfig planning_config;
  apollo::cyber::common::GetProtoFromFile(FLAGS_planning_config_file,
                                          &planning_config);
  if (FLAGS_open_space_planner_switchable) {
    return planner_factory_.CreateObject(
        // OPEN_SPACE规划器
        planning_config.standard_planning_config().planner_type(1));
  }
  return planner_factory_.CreateObject(
      // PUBLIC_ROAD规划器
      planning_config.standard_planning_config().planner_type(0));
}

(4) OnLanePlanning的主要逻辑在"RunOnce()"中,调用具体的Planer实现轨迹规划算法(scenario->stage->task),实现在Init和Plan中

void OnLanePlanning::RunOnce(const LocalView& local_view,
                             ADCTrajectory* const ptr_trajectory_pb) {
  
  // 初始化Frame
  status = InitFrame(frame_num, stitching_trajectory.back(), vehicle_state);
  ...
  // 判断是否符合交通规则
  for (auto& ref_line_info : *frame_->mutable_reference_line_info()) {
    TrafficDecider traffic_decider;
    traffic_decider.Init(traffic_rule_configs_);
    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";
      continue;
    }
  }
  // 执行计划
  status = Plan(start_timestamp, stitching_trajectory, ptr_trajectory_pb);
  ...
}

Status OnLanePlanning::Plan(
    const double current_time_stamp,
    const std::vector<TrajectoryPoint>& stitching_trajectory,
    ADCTrajectory* const ptr_trajectory_pb) {
  ...
  // 调用具体的(PUBLIC_ROAD)Planner执行
  auto status = planner_->Plan(stitching_trajectory.back(), frame_.get(),
                               ptr_trajectory_pb);
  ...
}

(5) 具体的轨迹规划过程PublicRoadPlanner(类似Em planer算法):scenario->stage->task

场景注册:

Status PublicRoadPlanner::Init(const PlanningConfig& config) {
  // 读取public Road配置
  const auto& public_road_config =
      config_.standard_planning_config().planner_public_road_config();

  // 根据配置注册不同的场景
  for (int i = 0; i < public_road_config.scenario_type_size(); ++i) {
    const ScenarioConfig::ScenarioType scenario =
        public_road_config.scenario_type(i);
    supported_scenarios.insert(scenario);
  }
  scenario_manager_.Init(supported_scenarios);
}

场景运行:

Status PublicRoadPlanner::Plan(const TrajectoryPoint& planning_start_point,
                               Frame* frame,
                               ADCTrajectory* ptr_computed_trajectory) {
  DCHECK_NOTNULL(frame);
  // 更新场景,决策当前应该执行什么场景
  scenario_manager_.Update(planning_start_point, *frame);
  // 获取当前场景
  scenario_ = scenario_manager_.mutable_scenario();
  // 执行当前场景的任务
  auto result = scenario_->Process(planning_start_point, frame);


  // 当前场景完成
  if (result == scenario::Scenario::STATUS_DONE) {
    // only updates scenario manager when previous scenario's status is
    // STATUS_DONE
    scenario_manager_.Update(planning_start_point, *frame);
  } else if (result == scenario::Scenario::STATUS_UNKNOWN) {
    // 当前场景失败
    return Status(common::PLANNING_ERROR, "scenario returned unknown");
  }
  return Status::OK();
}

场景更新

bool ScenarioManager::Init(
    const std::set<ScenarioConfig::ScenarioType>& supported_scenarios) {
  // 注册场景
  RegisterScenarios();
  default_scenario_type_ = ScenarioConfig::LANE_FOLLOW;
  supported_scenarios_ = supported_scenarios;
  // 创建场景,默认为lane_follow
  current_scenario_ = CreateScenario(default_scenario_type_);
  return true;
}

// 更新场景
void ScenarioManager::Update(const common::TrajectoryPoint& ego_point,
                             const Frame& frame) {
  CHECK(!frame.reference_line_info().empty());
  // 保留当前帧
  Observe(frame);
  // 场景分发
  ScenarioDispatch(ego_point, frame);
}

// 通过一个有限状态机,决定当前的场景
void ScenarioManager::ScenarioDispatch(const common::TrajectoryPoint& ego_point,
                                       const Frame& frame) {
  ...
}

运行场景

/ Scenario对应的Stage
scenario_type: SIDE_PASS
stage_type: SIDE_PASS_APPROACH_OBSTACLE
stage_type: SIDE_PASS_GENERATE_PATH
stage_type: SIDE_PASS_STOP_ON_WAITPOINT
stage_type: SIDE_PASS_DETECT_SAFETY
stage_type: SIDE_PASS_PASS_OBSTACLE
stage_type: SIDE_PASS_BACKUP

// Stage对应的Task
stage_type: SIDE_PASS_APPROACH_OBSTACLE
enabled: true
task_type: DP_POLY_PATH_OPTIMIZER
task_type: PATH_DECIDER
task_type: SPEED_BOUNDS_PRIORI_DECIDER
task_type: DP_ST_SPEED_OPTIMIZER
task_type: SPEED_DECIDER
task_type: SPEED_BOUNDS_FINAL_DECIDER
task_type: QP_SPLINE_ST_SPEED_OPTIMIZER

执行阶段:

Stage::StageStatus LaneFollowStage::Process(
    const TrajectoryPoint& planning_start_point, Frame* frame) {
    ...
    // 根据参考线规划
    auto cur_status =
        PlanOnReferenceLine(planning_start_point, frame, &reference_line_info);
    ...
}

// LANE_FOLLOW中的PlanOnReferenceLine
Status LaneFollowStage::PlanOnReferenceLine(
    const TrajectoryPoint& planning_start_point, Frame* frame,
    ReferenceLineInfo* reference_line_info) {
  
  // 顺序执行stage中的任务
  for (auto* optimizer : task_list_) {
    const double start_timestamp = Clock::NowInSeconds();
    // 任务
    ret = optimizer->Execute(frame, reference_line_info);
  }

  // 增加障碍物的代价
  for (const auto* obstacle :
       reference_line_info->path_decision()->obstacles().Items()) {
    if (obstacle->IsVirtual()) {
      continue;
    }
    if (!obstacle->IsStatic()) {
      continue;
    }
    if (obstacle->LongitudinalDecision().has_stop()) {
      ...
    }
  }

  // 返回参考线
  reference_line_info->SetTrajectory(trajectory);
  reference_line_info->SetDrivable(true);
  return Status::OK();
}

接下来就是执行各个task,执行具体的轨迹规划过程(DP+QP),在之后的博文中,我们继续学习。

深入学习上述每一步具体地过程可看相关函数:
(1) 模块注册(planning_component.h)-> 模块初始化(OnLanePlanning::Plan(和proc)-> 模块运行(OnLanePlanning::RunOnce() )
(2) 默认OnLanePlanning,其输入:Planning上下文信息、Frame结构体。-> 初始化:分配具体planer、参考线生成(Init)-> RunOnce消息触发

(3) Planner注册 -> PublicRoadPlanner默认规划器(Init和Plan中实现) -> init(注册场景) - >plan(运行场景scenario.cc)-> 状态机实现场景转换(主要Scenario_Manager.cc中)

(4) 执行场景(planning/conf/scenario中Process函数))-> 执行stage(planning/conf/stage中Process函数)->任务 task (决策器decider和优化器optimizer:动态规划DP和二次规划QP)。

整理不易,欢迎点赞订阅,一起学习交流!

参考链接
Apollo官网源码
Apollo规划模块代码详解
apollo介绍之planning模块(四)
图片来源于网络和参考链接,侵权联系删文章来源地址https://www.toymoban.com/news/detail-824817.html

到了这里,关于Apollo规划模块代码学习(1): 算法架构原理、运行机制一文详解的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包赞助服务器费用

相关文章

  • 【Apollo学习笔记】——规划模块TASK之PATH_BOUNDS_DECIDER

    【Apollo学习笔记】——规划模块TASK之PATH_BOUNDS_DECIDER

    1.【Apollo学习笔记】——规划模块TASK之LANE_CHANGE_DECIDER 2.【Apollo学习笔记】——规划模块TASK之PATH_REUSE_DECIDER 3.【Apollo学习笔记】——规划模块TASK之PATH_BORROW_DECIDER 4.【Apollo学习笔记】——规划模块TASK之PATH_BOUNDS_DECIDER 5.【Apollo学习笔记】——规划模块TASK之PIECEWISE_JERK_PATH_OPTIMI

    2024年02月11日
    浏览(11)
  • 百度Apollo规划算法——OBB障碍物检测代码解析

    百度Apollo规划算法——OBB障碍物检测代码解析

    本文主要分析Apollo代码中函数 bool Box::HasOverlap(const Box2d box) const {} 的数学原理。 在阅读此部分代码时,第一遍没看懂return的一堆什么意思,百度之后说是采用OBB原理,所以就去了解下OBB原理,回来看还是没太明白,直到看到了博客[1],通过博主的图解才有了进一步的了解,但

    2024年02月14日
    浏览(12)
  • 【Apollo学习笔记】——规划模块TASK之PIECEWISE_JERK_PATH_OPTIMIZER

    【Apollo学习笔记】——规划模块TASK之PIECEWISE_JERK_PATH_OPTIMIZER

    1.【Apollo学习笔记】——规划模块TASK之LANE_CHANGE_DECIDER 2.【Apollo学习笔记】——规划模块TASK之PATH_REUSE_DECIDER 3.【Apollo学习笔记】——规划模块TASK之PATH_BORROW_DECIDER 4.【Apollo学习笔记】——规划模块TASK之PATH_BOUNDS_DECIDER 5.【Apollo学习笔记】——规划模块TASK之PIECEWISE_JERK_PATH_OPTIMI

    2024年02月10日
    浏览(10)
  • 【Apollo学习笔记】——规划模块TASK之RULE_BASED_STOP_DECIDER

    【Apollo学习笔记】——规划模块TASK之RULE_BASED_STOP_DECIDER

    1.【Apollo学习笔记】——规划模块TASK之LANE_CHANGE_DECIDER 2.【Apollo学习笔记】——规划模块TASK之PATH_REUSE_DECIDER 3.【Apollo学习笔记】——规划模块TASK之PATH_BORROW_DECIDER 4.【Apollo学习笔记】——规划模块TASK之PATH_BOUNDS_DECIDER 5.【Apollo学习笔记】——规划模块TASK之PIECEWISE_JERK_PATH_OPTIMI

    2024年02月10日
    浏览(12)
  • Apollo和autoware规划算法代码ros移植-路径规划可跑工程分享

    Apollo和autoware规划算法代码ros移植-路径规划可跑工程分享

    之前出了: Apollo规划代码ros移植-Lattcie的二次规划. Apollo规划代码ros移植-Lattice规划框架. 规划代码ros移植-POMDP预测规划(一). Apollo规划代码ros移植-Em planner. Apollo规划代码ros移植-混合A*. Apollo规划代码ros移植-动态障碍物处理(一). 适合人群: 1.想移植Apollo,autoware等流行规划算法到

    2024年02月12日
    浏览(13)
  • 【Apollo学习笔记】——规划模块TASK之PIECEWISE_JERK_NONLINEAR_SPEED_OPTIMIZER(二)

    【Apollo学习笔记】——规划模块TASK之PIECEWISE_JERK_NONLINEAR_SPEED_OPTIMIZER(二)

    1.【Apollo学习笔记】——规划模块TASK之LANE_CHANGE_DECIDER 2.【Apollo学习笔记】——规划模块TASK之PATH_REUSE_DECIDER 3.【Apollo学习笔记】——规划模块TASK之PATH_BORROW_DECIDER 4.【Apollo学习笔记】——规划模块TASK之PATH_BOUNDS_DECIDER 5.【Apollo学习笔记】——规划模块TASK之PIECEWISE_JERK_PATH_OPTIMI

    2024年02月09日
    浏览(9)
  • 自动驾驶路径规划控制ros移植Apollo和autoware规控算法可跑工程(适合入门学习和实战)

    自动驾驶路径规划控制ros移植Apollo和autoware规控算法可跑工程(适合入门学习和实战)

    自动驾驶路径规划控制ros1和ros2移植Apollo和autoware规控算法可跑工程(适合入门学习,科研和实战),不仅包括移植Apollo和autoware规划算法,还包括其他规划算法,与carla联合仿真实现规划控制,autoware-carla联合仿真,Lanelet高精度地图构建,强化学习等等,基本涵盖了公司算法

    2024年02月10日
    浏览(22)
  • 自动驾驶路径规划控制ros移植Apollo和autoware规控算法可跑工程(适合入门学习,科研和实战)

    自动驾驶路径规划控制ros移植Apollo和autoware规控算法可跑工程(适合入门学习,科研和实战)

    自动驾驶路径规划控制ros1和ros2移植Apollo和autoware规控算法可跑工程(适合入门学习,科研和实战),不仅包括移植Apollo和autoware规划算法,还包括其他规划算法,与carla联合仿真实现规划控制,autoware-carla联合仿真,Lanelet高精度地图构建,强化学习等等,基本涵盖了公司算法

    2024年02月08日
    浏览(13)
  • Apollo 轨迹规划算法解析

    Apollo 轨迹规划算法解析

    这篇文章主要整理一下前段时间学习的轨迹规划算法,关于轨迹规划问题可以查到的相关资料很多,但能把轨迹规划问题详细说清楚的并不太多,这导致我在学习过程中出现很多疑惑。这里我把Apollo的各个版本轨迹规划算法进行简单总结和汇总。 主要参考资料: 1.b站大佬详

    2023年04月21日
    浏览(5)
  • 【动态规划】动态规划算法基本概念,原理应用和示例代码

             动态规划(Dynamic Programming,简称DP)是一种解决多阶段决策问题的数学优化方法。它将原问题分解成若干个子问题,通过解决子问题只需解决一次并将结果保存下来,从而避免了重复计算,提高了算法效率。         通俗来讲,动态规划算法是解决一类具有重叠

    2024年01月21日
    浏览(11)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包