apollo规划架构

news2024/11/25 6:53:56

算法的基本架构

我们在最开始直接给出规划决策算法架构框图,然后一一介绍每个框图结构的细节:

在这里插入图片描述

  1. 模块的入口是 PlanningComponent,在 Cyber 中注册模块,订阅和发布消息,并且注册对应的 Planning 类。
  2. Planning 的过程之前是定时器触发,即每隔一段固定的时间执行一次,现已经改为事件触发,即只要收集完成对应 TOPIC 的消息,就会触发执行,这样的好处是提高的实时性。
  3. Planning 类主要实现了 2 个功能,一个是启动 ReferenceLineProvider 来提供参考线,后面生成的轨迹都是在参考线的基础上做优化,ReferenceLineProvider 启动了一个单独的线程,每隔 50ms 执行一次,和 Planning 主流程并行执行。Planning 类另外的一个功能是执行 Planning 主流程。
  4. Planning 主流程先是选择对应的 Planner,我们这里主要分析 PublicRoadPlanner,在配置文件中定义了 Planner 支持的场景(Scenario),把规划分为具体的几个场景来执行,每个场景又分为几个阶段(Stage),每个阶段会执行多个任务(Task),任务执行完成后,对应的场景就完成了。不同场景间的切换是由一个状态机(ScenarioDispatch)来控制的。规划控制器根据 ReferenceLineProvider 提供的参考线,在不同的场景下做切换,生成一条车辆可以行驶的轨迹,并且不断重复上述过程直到到达目的地。

PlanningComponent

规划模块的入口是 PlanningComponent。PlanningComponent 的两大核心函数是 Init 和 Proc.

在初始化中,我们可以看到如下的代码,FLAGS_use_navigation_mode 的标志位直接决定了我们等等实例化的 planning_base_ 的具体 planner,到底是 NaviPlanning 还是 OnLanePlanning:

if (FLAGS_use_navigation_mode) {
    planning_base_ = std::make_unique<NaviPlanning>(injector_);
  } else {
    planning_base_ = std::make_unique<OnLanePlanning>(injector_);
  }

其实在更早的版本中有更多选项,7.0 为什么简化了呢?

if (FLAGS_open_space_planner_switchable) {
    planning_base_ = std::make_unique<OpenSpacePlanning>();
  } else {
    if (FLAGS_use_navigation_mode) {
      planning_base_ = std::make_unique<NaviPlanning>();
    } else {
      planning_base_ = std::make_unique<OnLanePlanning>();
    }
  }

而在 Proc(…)函数中,最核心部分则是调用对应 planner 的 RunOnce 函数:

planning_base_->RunOnce(local_view_, &adc_trajectory_pb);

接下来的具体例子中我们都以这个 planing_base_被实例化为 OnLanePlanning 作为前提。

下图是几个规划器的结构。这里我们要讨论的是 PublicRoadPlanner,这里只是简单的给出结构,后面的对应小节会具体介绍函数中如何运行和管理。

在这里插入图片描述

OnLanePlanning

RunOnce 函数的三大重要函数是:

// 初始化frame
status = InitFrame(frame_num, stitching_trajectory.back(), vehicle_state);
......
//进行traffic decider
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, injector_);
    if (!traffic_status.ok() || !ref_line_info.IsDrivable()) {
      ref_line_info.SetDrivable(false);
      AWARN << "Reference line " << ref_line_info.Lanes().Id()
            << " traffic decider failed";
    }
  }
  ......
  //plan主函数
status = Plan(start_timestamp, stitching_trajectory, ptr_trajectory_pb);

Plan

这个 plan 函数中主要核心则是:

auto status = planner_->Plan(stitching_trajectory.back(), frame_.get(),
                               ptr_trajectory_pb);

而这个 planner_则是通过 DispatchPlanner 来指定:

// dispatch planner
  planner_ = planner_dispatcher_->DispatchPlanner(config_, injector_);

具体来说就是:

std::unique_ptr<Planner> OnLanePlannerDispatcher::DispatchPlanner(
    const PlanningConfig& planning_config,
    const std::shared_ptr<DependencyInjector>& injector) {
  return planner_factory_.CreateObject(
      planning_config.standard_planning_config().planner_type(0), injector);
}
//其中这个config是:
standard_planning_config {
  planner_type: PUBLIC_ROAD
  planner_public_road_config {
  }
}

Plan 函数中主要的几个步骤是:

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

  。。。。。。
}

Scenario 是 apollo 决策规划算法中的重要概念,apollo 可以应对自动驾驶所面临的不同道路场景,都是通过 Scenario 统一注册与管理;Scenario 通过一个有限状态机来选择不同场景。

更新当前的 scenario

scenario_manager_.Update(planning_start_point, *frame);

我们来看 Update,做了这么几件事:

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

这里能够提供的场景库包括:

enum ScenarioType {
    LANE_FOLLOW = 0;  // default scenario

    // intersection involved
    BARE_INTERSECTION_UNPROTECTED = 2;
    STOP_SIGN_PROTECTED = 3;
    STOP_SIGN_UNPROTECTED = 4;
    TRAFFIC_LIGHT_PROTECTED = 5;
    TRAFFIC_LIGHT_UNPROTECTED_LEFT_TURN = 6;
    TRAFFIC_LIGHT_UNPROTECTED_RIGHT_TURN = 7;
    YIELD_SIGN = 8;

    // parking
    PULL_OVER = 9;
    VALET_PARKING = 10;

    EMERGENCY_PULL_OVER = 11;
    EMERGENCY_STOP = 12;

    // misc
    NARROW_STREET_U_TURN = 13;
    PARK_AND_GO = 14;

    // learning model sample
    LEARNING_MODEL_SAMPLE = 15;
    // turn around
    DEADEND_TURNAROUND = 16;
}

获取当前场景

//获取当前场景
Scenario* mutable_scenario() { return current_scenario_.get(); }

执行当前场景的任务

//通过Process函数进行场景运行
Scenario::ScenarioStatus Scenario::Process(
    const common::TrajectoryPoint& planning_init_point, Frame* frame)

场景下有 stage, 运行 stage 的 Process 函数:

auto ret = current_stage_->Process(planning_init_point, frame);

我们拿 LaneFollowStage 为例,则运行他的每个 task:

//首先进入函数:
auto cur_status =
        PlanOnReferenceLine(planning_start_point, frame, &reference_line_info);
        
//然后是在PlanOnReferenceLine函数中遍历每个task
for (auto* task : task_list_) {
    const double start_timestamp = Clock::NowInSeconds();

    ret = task->Execute(frame, reference_line_info);
    。。。。。。
  }

以 lane follow 这个 stage 为例,这个 task list 包括:

scenario_type: LANE_FOLLOW
stage_type: LANE_FOLLOW_DEFAULT_STAGE
stage_config: {
  stage_type: LANE_FOLLOW_DEFAULT_STAGE
  enabled: true
  task_type: LANE_CHANGE_DECIDER
  task_type: PATH_REUSE_DECIDER
  task_type: PATH_LANE_BORROW_DECIDER
  task_type: PATH_BOUNDS_DECIDER
  task_type: PIECEWISE_JERK_PATH_OPTIMIZER
  task_type: PATH_ASSESSMENT_DECIDER
  task_type: PATH_DECIDER
  task_type: RULE_BASED_STOP_DECIDER
  task_type: SPEED_BOUNDS_PRIORI_DECIDER
  task_type: SPEED_HEURISTIC_OPTIMIZER
  task_type: SPEED_DECIDER
  task_type: SPEED_BOUNDS_FINAL_DECIDER
  task_type: PIECEWISE_JERK_SPEED_OPTIMIZER
  # task_type: PIECEWISE_JERK_NONLINEAR_SPEED_OPTIMIZER
  task_type: RSS_DECIDER

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1852664.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于SpringBoot+Vue教材订购系统设计和实现(源码+LW+调试文档+讲解等)

&#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN作者、博客专家、全栈领域优质创作者&#xff0c;博客之星、平台优质作者、专注于Java、小程序技术领域和毕业项目实战✌&#x1f497; &#x1f31f;文末获取源码数据库&#x1f31f; 感兴趣的可以先收藏起来&#xff0c;…

DNF手游攻略:云手机辅助流光星陨刀详细攻略大全!

DNF手游中&#xff0c;流光星陨刀是鬼剑士的专属神器之一&#xff0c;拥有快速的攻击速度和优秀的物理与法术攻击属性&#xff0c;因其出色的性能和未来升级的潜力&#xff0c;成为广大玩家关注的焦点。 流光星陨刀的背景与起源 流光星陨刀作为鬼剑士的标志性武器之一&#xf…

使用 Ubuntu x86_64 平台交叉编译适用于 Linux aarch64(arm64) 平台的 QT5(包含OpenGL支持) 库

使用 Ubuntu AMD64 平台交叉编译适用于 Linux ARM64 平台的 QT5(包含 OpenGL/WebEngine 支持) 库 目录 使用 Ubuntu AMD64 平台交叉编译适用于 Linux ARM64 平台的 QT5(包含 OpenGL/WebEngine 支持) 库写在前面前期准备编译全流程1. 环境搭建2. 复制源码包并解压&#xff0c;创…

论文《Universal Graph Convolutional Networks》笔记

【UGCN】论文提出一个基本问题&#xff0c;即是否不同的网络结构属性应该采用不同的传播机制。通过实验发现&#xff0c;对于完全同配性、完全异配性和随机性的网络&#xff0c;1-hop、2-hop和k-nearest neighbor&#xff08;kNN&#xff09;邻居分别更适合作为信息传播的邻域。…

stm32学习笔记---GPIO输出(理论部分)

目录 GPIO通用输入输出口 GPIO的基本结构 I/O端口位的基本结构 输入部分 输出部分 推挽模式 开漏模式 GPIO的8种工作模式 STM32手册GPIO和AFIO大致介绍 STM32外部的设备和电路 声明&#xff1a;本专栏是本人跟着B站江科大的视频的学习过程中记录下来的笔记&#xff0…

CISP-PTE综合靶机-WinServer2003

1.收集网站的地址和开放的端口,完成前期信息收集。10分 2.访问站点,找出站点的敏感文件,利用返回数据找到相关敏感信 息,完成网站结构的信息收集。10分 3.利用文件包含漏洞读取敏感文件,找出数据库连接凭证,利用此 凭证连接数据库。10分 4.网站后台提权:找出后台管理员登…

Attention系列总结-粘贴自知乎

1. 梦想做个翟老师&#xff1a;阿里&#xff1a;Behavior Sequence Transformer 解读48 赞同 7 评论文章 优点:捕捉用户行为历史序列中的顺序信息。w2v也是捕捉用户序列信息的,本质差异在于啥&#xff1f; 添加图片注释&#xff0c;不超过 140 字&#xff08;可选&#xff0…

STM32CubeIDE提示找不到头文件(No such file or directory)的解决办法

0 前言 最近在使用STM32CubeIDE时&#xff0c;发现为工程添加了头文件路径&#xff0c;但编译的时候还是报错&#xff0c;提示找不到头文件&#xff1a; 1 解决办法 1.1 为工程添加头文件路径 右键我们的工程&#xff0c;然后添加头文件路径&#xff08;最好是相对路径&am…

Vue3+TypeScript项目实战——打造雨雪交加的智慧城市

个人简介 &#x1f440;个人主页&#xff1a; 前端杂货铺 ⚡开源项目&#xff1a; rich-vue3 &#xff08;基于 Vue3 TS Pinia Element Plus Spring全家桶 MySQL&#xff09; &#x1f64b;‍♂️学习方向&#xff1a; 主攻前端方向&#xff0c;正逐渐往全干发展 &#x1…

C# SerialPort串口通讯

串口通信 在.NET平台下创建C#串口通信程序&#xff0c;.NET 2.0提供了串口通信的功能&#xff0c;其命名空间是System.IO.Ports。这个新的框架不但可以访问计算机上的串口&#xff0c;还可以和串口设备进行通信。 创建C#串口通信程序之命名空间 System.IO.Ports命名空间中最重…

【跟我学RISC-V】(三)openEuler特别篇

写在前面 这篇文章是跟我学RISC-V指令集的第三期&#xff0c;距离我上一次发文已经过去一个多月了&#xff0c;在这个月里我加入了oerv的实习项目组&#xff0c;并且还要准备期末考试&#xff0c;比较忙&#xff0c;所以更新频率不高&#xff0c;不过对于Linux kernel和RISC-V…

vue修改node_modules打补丁步骤和注意事项_node_modules 打补丁

1、vue-pdf问题解决及patch-package简介&#xff1a;https://www.jianshu.com/p/d1887e02f8d6 2、使用“黑魔法”优雅的修改第三方依赖包&#xff1a;https://zhuanlan.zhihu.com/p/412753695 3、使用patch-package定制node_modules中的依赖包&#xff1a;https://blog.csdn.…

macbook配置adb环境和用adb操作安卓手机

&#xff08;参考&#xff1a;ADB工具包的安装与使用_adb工具箱-CSDN博客&#xff09; 第一步&#xff1a;从Android开发者网站下载Android SDK&#xff08;软件开发工具包&#xff09;。下载地址为&#xff1a; 第二步&#xff1a;解压下载的SDK压缩文件到某个目录中。 进入解…

Python 数据可视化 多色散点图

Python 数据可视化 多色散点图 fig, ax plt.subplots() max_line max([max(merged_df[unif_ref_value]), max(merged_df[unif_rust_value])]) min_line min([max(merged_df[unif_ref_value]), max(merged_df[unif_rust_value])]) ax.plot([min_line, max_line], [min_line, …

基于JSP的教学质量评价系统

开头语&#xff1a; 你好&#xff0c;我是计算机学长猫哥。如果您对教学质量评价系统感兴趣或有相关需求&#xff0c;欢迎随时联系我。 开发语言&#xff1a; Java 数据库&#xff1a; MySQL 技术&#xff1a; JSP技术 Java语言 工具&#xff1a; MyEclipse、Tomcat服…

基于JSP的“塞纳河畔左岸”的咖啡馆管理系统

开头语&#xff1a; 塞纳河畔左岸的咖啡&#xff0c;我手一杯品尝的你美~ 哎哟&#xff0c;不错哦&#xff01;我们今天来介绍一下咖啡馆管理系统&#xff01; 你好呀&#xff0c;我是计算机学长猫哥&#xff01;如果你对咖啡馆管理系统感兴趣或有相关需求&#xff0c;欢迎联…

基于 GoLang 编写的 IOT 物联网在线直播抓娃娃企业级项目

大家好&#xff0c;我是码农先森。 引言 前几年&#xff0c;娱乐物联网的热度很高。我当时所在的公司启动了一个将线下娃娃机的玩法&#xff0c;迁移到线上的项目&#xff0c;因此公司决定开发一个在线直播抓娃娃的项目。近来&#xff0c;娱乐物联网的领域已经进入资本的寒冬…

小白学-WEBGL

第一天&#xff1a; 1.canvas和webgl的区别 Canvas 和 WebGL 都是用于在网页上绘制图形的技术&#xff0c;它们通过浏览器提供的 API 使开发者能够创建丰富的视觉内容&#xff0c;但它们的工作原理和用途有所不同。 Canvas Canvas API 提供了一个通过 JavaScript 和 HTML <…

家政预约小程序14权限配置

目录 1 创建用户2 创建角色3 启用登录4 实现退出总结 我们现在小程序端的功能基本开发好了&#xff0c;小程序开发好之后需要给运营人员提供管理后台&#xff0c;要分配账号、配置权限&#xff0c;我们本篇就介绍一下权限如何分配。 1 创建用户 在微搭中&#xff0c;用户分为内…

基于Pico和MicroPython点亮ws2812彩色灯带

基于Pico和MicroPython点亮ws2812彩色灯带 文章目录 基于Pico和MicroPython点亮ws2812彩色灯带IntroductionPracticeConclusion Introduction 点亮发光的LED灯是简单有趣的实验&#xff0c;点亮多个ws2812小灯串联起来的灯带&#xff0c;可对多个彩色小灯进行编程&#xff0c;…