当前位置: 首页 > article >正文

Apollo学习——planning模块(3)之planning_base

planning_componentplanning_baseon_lane_planningnavi_planning 的关系


1. 模块关系总览

继承层次
  • PlanningComponent:Cyber RT 框架中的 入口组件,负责调度规划模块的输入输出和管理生命周期。
  • PlanningBase:规划算法的 抽象基类,定义通用接口(如 Init(), RunOnce())。
  • OnLanePlanningNaviPlanning:继承自 PlanningBase具体规划器实现,分别针对不同场景设计的动态多态子类。
调用关系
PlanningComponent → (通过指针调用) PlanningBase → OnLanaPlanning/NaviPlanning → 具体规划算法

2. 各模块作用详解

(1) PlanningComponent
  • 功能定位

    • 数据集成:接收上游模块的输入(如 PredictionObstacles 障碍物预测、LocalizationEstimate 定位数据、Chassis 底盘信息)。
    • 生命周期管理:通过 Init() 初始化规划器(选择 OnLanePlanningNaviPlanning),在 Proc() 中触发规划主流程。
    • 消息发布:输出规划轨迹 ADCTrajectory、路由请求 RoutingRequest 和学习数据 PlanningLearningData
  • 核心代码逻辑

    // 初始化时根据配置选择规划模式
    if (FLAGS_use_navigation_mode) {planning_base_ = std::make_unique<NaviPlanning>(injector_);
    } else {planning_base_ = std::make_unique<OnLanePlanning>(injector_);
    }
    
(2) PlanningBase
  • 功能定位

    • 抽象接口定义:提供规划算法的统一接口(如 RunOnce()Plan()),确保子类实现一致性。
    • 数据封装:管理 Frame 对象(包含车辆状态、环境信息)和 DependencyInjector(依赖注入容器,集成场景、车辆模型等)。
    • 多态支持:通过虚函数机制实现动态绑定,允许运行时切换 OnLanePlanningNaviPlanning
  • 关键成员

    • Frame:整合当前车辆状态、障碍物信息、参考线等上下文数据。
    • ReferenceLineInfo:存储参考线及其动态决策信息,供轨迹规划使用。
(3) OnLanePlanning
  • 功能定位

    • 高精地图规划:基于高精地图生成参考线,适用于 城市道路复杂交通场景(如红绿灯路口、人行道)。
    • 场景机制:内置双层状态机(Scenario + Stage),支持 LaneFollowScenario(车道保持)、TrafficLightProtectedScenario(交通灯路口)等场景。
    • 任务调度:调用 PublicRoadPlanner 等规划器,执行具体的路径优化算法(如 EM Planner、Lattice Planner)。
  • 典型流程

    1. 生成参考线(ReferenceLineProvider)。
    2. 场景切换判定(ScenarioManager::Update())。
    3. 执行场景内的多阶段任务(Stage + Task)。
(4) NaviPlanning
  • 功能定位

    • 相对地图规划:基于实时生成的相对地图(relative_map),适用于 高速公路 或其他 规则简单场景
    • 轻量化设计:简化参考线生成逻辑,依赖车道级导航信息而非全局高精地图。
    • 高效处理:优化算法复杂度,适合长距离、低动态障碍物的场景。
  • 与 OnLanePlanning 的差异

    特性OnLanePlanningNaviPlanning
    地图依赖高精地图相对地图(动态生成)
    适用场景城市道路、复杂交通高速公路、规则简单道路
    场景切换机制支持多场景状态机场景逻辑简化
    计算资源消耗较高较低

3. 数据流与功能协作

协作流程
  1. 输入触发
    • PlanningComponentProc() 由上游消息(如障碍物预测)触发,整合 LocalView 数据包。
  2. 规划执行
    • 调用 planning_base_->RunOnce(),由具体子类(OnLanePlanningNaviPlanning)实现规划逻辑。
  3. 场景与任务
    • OnLanePlanning 中通过 ScenarioManager 切换场景,执行阶段任务(如绕障、停车)。
    • NaviPlanning 直接生成参考线并规划轨迹,跳过复杂场景判定。
  4. 结果输出
    • 发布 ADCTrajectory 轨迹至控制模块,完成闭环。
关键交互点
  • DependencyInjector:注入全局依赖(如车辆状态、历史轨迹),供所有子类共享。
  • PlanningLearningData:在 RL_TEST 模式下收集强化学习训练数据。

总结

  • PlanningComponent 是入口,负责数据集成与调度。
  • PlanningBase 定义框架,实现多态支持。
  • OnLanePlanning 面向复杂场景,NaviPlanning 面向高速场景,二者通过继承实现功能差异化。

基类:planning_base

规划器(OnLanePlanning、NaviPlanning)需要重写的函数有

  //初始化virtual apollo::common::Status Init(const PlanningConfig& config);//可以不重写virtual std::string Name() const = 0;virtual void RunOnce(const LocalView& local_view, ADCTrajectory* const adc_trajectory) = 0;virtual apollo::common::Status Plan( const double current_time_stamp, const std::vector<common::TrajectoryPoint>& stitching_trajectory, ADCTrajectory* const trajectory) = 0;

不需要重写的有

  //判断规划是否完成bool IsPlanningFinished( const ADCTrajectory::TrajectoryType& current_trajectory_type) const;// 为轨迹添加设置路的左右边界bool GenerateWidthOfLane(const Vec2d& current_location, Vec2d& left_point, Vec2d& right_point);protected://规划模块生成轨迹数据时填充协议头信息(Header)的核心方法virtual void FillPlanningPb(const double timestamp, ADCTrajectory* const trajectory_pb);//加载规划器 默认使用apollo::planning::PublicRoadPlannervoid LoadPlanner();

代码解释

namespace apollo {
namespace planning {using apollo::common::Status;PlanningBase::PlanningBase(const std::shared_ptr<DependencyInjector>& injector): injector_(injector) {}PlanningBase::~PlanningBase() {}
//如果不重写,则使用基类Init,加载参数
Status PlanningBase::Init(const PlanningConfig& config) {injector_->planning_context()->Init();config_ = config;return Status::OK();
}
//判断规划状态是否完成
bool PlanningBase::IsPlanningFinished(const ADCTrajectory::TrajectoryType& current_trajectory_type) const {const auto frame = injector_->frame_history()->Latest();//判断当前轨迹类型是否为OPEN SPACE 泊车if (current_trajectory_type == apollo::planning::ADCTrajectory::OPEN_SPACE) {AINFO << "Current trajectory type is: OPEN SPACE";if (frame->open_space_info().openspace_planning_finish()) {AINFO << "OPEN SPACE: planning finished";return true;} else {AINFO << "OPEN SPACE: planning not finished";return false;}} else {// const auto frame = injector_->frame_history()->Latest();if (nullptr == frame || frame->reference_line_info().empty() ||nullptr == local_view_.planning_command) {AINFO << "Current reference point is empty;";return true;}const auto& reference_line_info = frame->reference_line_info().front();// Check if the ReferenceLineInfo is the last passage.const auto& reference_points =reference_line_info.reference_line().reference_points();if (reference_points.empty()) {AINFO << "Current reference points is empty;";return true;}const auto& last_reference_point = reference_points.back();const std::vector<hdmap::LaneWaypoint>& lane_way_points =last_reference_point.lane_waypoints();if (lane_way_points.empty()) {AINFO << "Last reference point is empty;";return true;}// Get the end lane way point.if (nullptr == frame->local_view().end_lane_way_point) {AINFO << "Current end lane way is empty;";return true;}bool is_has_passed_destination = injector_->planning_context()->planning_status().destination().has_passed_destination();AINFO << "Current passed destination:" << is_has_passed_destination;return is_has_passed_destination;}
}
// 规划模块生成轨迹数据时填充协议头信息(Header)的核心方法
// 时间戳同步:设置轨迹消息的全局时间戳
// 多传感器时间对齐:记录激光雷达、摄像头、雷达等传感器的原始数据时间戳
// 路由信息传递:复制当前路由请求的元数据
void PlanningBase::FillPlanningPb(const double timestamp,ADCTrajectory* const trajectory_pb) {trajectory_pb->mutable_header()->set_timestamp_sec(timestamp); // timestamp通常通过Clock::NowInSeconds()获取系统当前时间// 多传感器时间对齐if (local_view_.prediction_obstacles->has_header()) {trajectory_pb->mutable_header()->set_lidar_timestamp(local_view_.prediction_obstacles->header().lidar_timestamp());trajectory_pb->mutable_header()->set_camera_timestamp(local_view_.prediction_obstacles->header().camera_timestamp());trajectory_pb->mutable_header()->set_radar_timestamp(local_view_.prediction_obstacles->header().radar_timestamp());}// local_view_.planning_command包含来自Routing模块的全局路径请求trajectory_pb->mutable_routing_header()->CopyFrom(local_view_.planning_command->header());
}
//加载规划器默认apollo::planning::PublicRoadPlanner
void PlanningBase::LoadPlanner() {// Use PublicRoadPlanner as default Plannerstd::string planner_name = "apollo::planning::PublicRoadPlanner";if ("" != config_.planner()) {planner_name = config_.planner();planner_name = ConfigUtil::GetFullPlanningClassName(planner_name);}planner_ =cyber::plugin_manager::PluginManager::Instance()->CreateInstance<Planner>(planner_name);
}
//设置路的左右边界
bool PlanningBase::GenerateWidthOfLane(const Vec2d& current_location,Vec2d& left_point, Vec2d& right_point) {double left_width = 0, right_width = 0;const auto frame = injector_->frame_history()->Latest();if (nullptr == frame || frame->reference_line_info().empty()) {AINFO << "Reference lane is empty!";return false;}const auto& reference_line_info = frame->reference_line_info().front();// get current SLcommon::SLPoint current_sl;reference_line_info.reference_line().XYToSL(current_location, &current_sl);// Get the lane width of vehicle locationbool get_width_of_lane = reference_line_info.reference_line().GetLaneWidth(current_sl.s(), &left_width, &right_width);AINFO << "get_width_of_lane: " << get_width_of_lane<< ", left_width: " << left_width << ", right_width: " << right_width;if (get_width_of_lane && left_width != 0 && right_width != 0) {AINFO << "Get the width of lane successfully!";SLPoint sl_left_point, sl_right_point;sl_left_point.set_s(current_sl.s());sl_left_point.set_l(left_width);sl_right_point.set_s(current_sl.s());sl_right_point.set_l(-right_width);reference_line_info.reference_line().SLToXY(sl_left_point, &left_point);reference_line_info.reference_line().SLToXY(sl_right_point, &right_point);return true;} else {AINFO << "Failed to get the width of lane!";return false;}
}}  // namespace planning
}  // namespace apollo

相关文章:

Apollo学习——planning模块(3)之planning_base

planning_component、planning_base、on_lane_planning 和 navi_planning 的关系 1. 模块关系总览 继承层次 PlanningComponent&#xff1a;Cyber RT 框架中的 入口组件&#xff0c;负责调度规划模块的输入输出和管理生命周期。PlanningBase&#xff1a;规划算法的 抽象基类&…...

当 AI 邂逅丝路:揭秘「丝路智旅」,用 RAG 重塑中阿文化旅游体验

目录 系统命名:丝路智旅 (Silk Road Intelligent Travel)系统概述系统架构设计系统功能模块技术选型:为何是它们?系统优势与特点未来展望与扩展总结在数字浪潮席卷全球的今天,古老的丝绸之路正在以一种全新的方式焕发生机。当深厚的文化底蕴遇上尖端的人工智能技术,会碰撞…...

18.Excel数据透视表:第1部分创建数据透视表

一 什么是数据透视表 通过万花筒可以用不同的方式査看里面画面图像&#xff0c;在excel中可以将数据透视表看作是对准数据的万花筒&#xff0c;用不同角度去观察数据&#xff0c;也可以旋转数据&#xff0c;对数据进行重新排列&#xff0c;对大量的数据可以快速的汇总和建立交叉…...

CSS AI 通义灵码 VSCode插件安装与功能详解

简介 在前端开发领域&#xff0c;页面调试一直是个繁琐的过程&#xff0c;而传统开发中美工与前端的对接也常常出现问题。如今&#xff0c;阿里云技术团队推出的通义灵码智能编码助手&#xff0c;为前端开发者带来了新的解决方案&#xff0c;让开发者可以像指挥者一样&#xf…...

每日c/c++题 备战蓝桥杯(P1002 [NOIP 2002 普及组] 过河卒)

洛谷P1002 [NOIP 2002 普及组] 过河卒 题解 题目描述 过河卒是一道经典的动态规划题目。题目大意是&#xff1a;一个卒子从棋盘左上角(0,0)出发&#xff0c;要走到右下角(n,m)&#xff0c;棋盘上有一个马在(x,y)位置&#xff0c;卒子不能经过马所在位置及其周围8个位置。求卒…...

【Linux网络】TCP全连接队列

TCP 相关实验 理解 listen 的第二个参数 基于刚才封装的 TcpSocket 实现以下测试代码对于服务器, listen 的第二个参数设置为 1, 并且不调用 accept测试代码链接 test_server.cc #include "tcp_socket.hpp"int main(int argc, char* argv[]) {if (argc ! 3) {pri…...

HTML 颜色全解析:从命名规则到 RGBA/HSL 值,附透明度设置与场景应用指南

一、HTML 颜色系统详解 HTML 中的颜色可以通过多种方式定义&#xff0c;包括颜色名称、RGB 值、十六进制值、HSL 值等&#xff0c;同时支持透明度调整。以下是详细分类及应用场景&#xff1a; 1. 颜色名称&#xff08;预定义关键字&#xff09; HTML 预定义了 140 个标准颜色名…...

蓝桥杯12届国B 完全日期

题目描述。 如果一个日期中年月日的各位数字之和是完全平方数&#xff0c;则称为一个完全日期。 例如&#xff1a;2021 年 6 月 5 日的各位数字之和为 20216516&#xff0c;而 16 是一个完全平方数&#xff0c;它是 4 的平方。所以 2021 年 6 月 5 日是一个完全日期。 例如&…...

深度剖析多模态大模型中的视频编码器算法

写在前面 随着多模态大型语言模型(MLLM)的兴起,AI 理解世界的能力从静态的文本和图像,进一步拓展到了动态的、包含丰富时空信息的视频。视频作为一种承载了动作、交互、场景变化和声音(虽然本文主要聚焦视觉部分)的复杂数据形式,为 MLLM 提供了理解真实世界动态和因果关…...

游戏引擎学习第282天:Z轴移动与摄像机运动

运行游戏&#xff0c;展示目前进展 我们目前正在进行一个游戏开发项目。昨天&#xff0c;我们实现了基于房间的角色移动系统&#xff0c;并且加入了摄像机的跟随滚动功能。这是我们首次进入“游戏逻辑设计”阶段&#xff0c;也就是说&#xff0c;我们开始构建游戏本身的行为和…...

C++中的std::allocator

C中的std::allocator 文章目录 C中的std::allocator1.std::allocator1.1C中的placement new 和operator new1.2一个custom allocator的实现1.3使用std::allocator_traits实现allocator 1.std::allocator C中的std::allocator默默工作在CSTL中的所有容器的内存分配上&#xff0…...

Git/GitLab日常使用的命令指南来了!

在 GitLab 中拉取并合并代码的常见流程是通过 Git 命令来完成的。以下是一个标准的 Git 工作流&#xff0c;适用于从远程仓库&#xff08;如 GitLab&#xff09;拉取代码、切换分支、合并更新等操作。 &#x1f310; 一、基础命令&#xff1a;拉取最新代码 # 拉取远程仓库的所…...

aws 实践创建policy + Role

今天Cyber 通过image 来创建EC2 的时候,要添加policy, 虽然是administrator 的role, 参考Cyber 提供的link: Imageshttps://docs.cyberark.com/pam-self-hosted/14.2/en/content/pas%20cloud/images.htm#Bring 1 Step1:...

[Java实战]Spring Boot 解决跨域问题(十四)

[Java实战]Spring Boot 解决跨域问题&#xff08;十四&#xff09; 一、CORS 问题背景 什么是跨域问题&#xff1f; 当浏览器通过 JavaScript 发起跨域请求&#xff08;不同协议、域名、端口&#xff09;时&#xff0c;会触发同源策略限制&#xff0c;导致请求被拦截。 示例场…...

【HarmonyOS 5】鸿蒙星闪NearLink详解

【HarmonyOS 5】鸿蒙星闪NearLink详解 一、前言 鸿蒙星闪NearLink Kit 是 HarmonyOS 提供的短距离通信服务&#xff0c;支持星闪设备间的连接、数据交互。例如&#xff0c;手机可作为中心设备与外围设备&#xff08;如鼠标、手写笔、智能家电、车钥匙等&#xff09;通过星闪进…...

Python高级进阶:Vim与Vi使用指南

李升伟 整理 在 Python 高级进阶中&#xff0c;使用 Vim 或 Vi 作为代码编辑器可以显著提升开发效率&#xff0c;尤其是在远程服务器开发或快速脚本编辑时。以下是关于它们在 Python 开发中的高级应用详解&#xff1a; 1. Vim/Vi 简介 Vi&#xff1a;经典的 Unix 文本编辑器…...

【Python】对象生命周期全解析

Python对象生命周期全解析 在Python中&#xff0c;一个对象从创建到销毁会经历一系列过程&#xff0c;理解这些过程对于编写高效、可靠的Python代码非常重要。下面我将详细讲解Python对象的完整生命周期。 1. 对象创建阶段 (1) 内存分配 当使用类实例化时(obj MyClass())&…...

自然语言处理(NLP)在影评情感分析中的处理流程示例

自然语言处理&#xff08;NLP&#xff09;在影评情感分析中的处理流程示例 以影评情感分析为例&#xff0c;为你详细介绍自然语言处理的处理流程。在这个例子中&#xff0c;我们将使用 Python 和一些常用的 NLP 库&#xff0c;如nltk&#xff08;自然语言工具包&#xff09;和…...

WF24 wifi/蓝牙模块串口与手机蓝牙通信

usb-ttl ch340接线 打开串口工具SSCOM&#xff0c;端口号选择ch340接的那个口&#xff0c;波特率改成115200 DX-SMART_2.0.5.apk下载 手机打开DX-SMART软件 点击透传-搜索BLE-连接WF24-BLE 连接成功串口会收到消息 [14:37:10.591]收←◆ BLE_CONNECT_SUCCESS发送命令ATBLUFI…...

互联网大厂Java求职面试:优惠券服务架构设计与AI增强实践-3

互联网大厂Java求职面试&#xff1a;优惠券服务架构设计与AI增强实践-3 场景背景 面试场景设定在一家大型互联网公司&#xff0c;面试官为拥有10年以上经验的技术总监&#xff0c;专注于高并发、高可用系统的架构设计。候选人郑薪苦是一名技术潜力十足的程序员&#xff0c;擅…...

C++核心编程--1 内存分区模型

C程序执行时&#xff0c;内存可以划分为4部分 代码区&#xff1a;存放函数体的二进制代码 全局区&#xff1a;存放全局变量、静态变量、常量 栈区&#xff1a;局部变量、函数参数值&#xff0c;编译器自动分配和释放 堆区&#xff1a;程序员自己分配和释放 1.1 程序运行前…...

02_线性模型(回归分类模型)

用于分类的线性模型 线性模型也广泛应用于分类问题&#xff0c;可以利用下面的公式进行预测&#xff1a; $ \widehat y w[0]*x[0]w[1]*x[1]…w[p]*x[p]b > 0$ 公式看起来与线性回归的公式非常相似&#xff0c;但没有返回特征的加权求和&#xff0c;而是为预测设置了阈值…...

通义千问席卷日本!开源界“卷王”阿里通义千问成为日本AI发展新基石

据日本经济新闻&#xff08;NIKKEI&#xff09;报道&#xff0c;通义千问已成为日本AI开发的新基础&#xff0c;其影响力正逐步扩大&#xff0c;深刻改变着日本AI产业的格局。 同时&#xff0c;日本经济新闻将通义千问Qwen2.5-Max列为全球AI模型综合评测第六名&#xff0c;不仅…...

流程编辑器Bpmn与LogicFlow学习

工作流技术如何与用户交互结合&#xff08;如动态表单、任务分配&#xff09;处理过 XML 与 JSON 的转换自定义过 bpmn.js 的样式&#xff08;如修改节点颜色、形状、图标&#xff09;扩展过上下文菜单&#xff08;Palette&#xff09;或属性面板&#xff08;Properties Panel&…...

Figma 新手教程学习笔记

&#x1f4fa; 视频地址&#xff1a;Figma新手教程2025&#xff5c;30分钟高效掌握Figma基础操作与UI设计流程_哔哩哔哩_bilibili &#x1f9ed; 课程结构 Figma 简介&#xff08;00:38&#xff09; 熟悉工作环境&#xff08;01:49&#xff09; 操作界面介绍&#xff08;03:…...

RabbitMQ的工作队列模式和路由模式有什么区别?

RabbitMQ 的工作队列模式&#xff08;Work Queues&#xff09;和路由模式&#xff08;Routing&#xff09;是两种不同的消息传递模式&#xff0c;主要区别在于消息的分发逻辑和使用场景。以下是它们的核心差异&#xff1a; 1. 工作队列模式&#xff08;Work Queues&#xff09…...

什么是 ANR 如何避免它

一、什么是 ANR&#xff1f; ANR&#xff08;Application Not Responding&#xff09; 是 Android 系统在应用程序主线程&#xff08;UI 线程&#xff09;被阻塞超过一定时间后触发的错误机制。此时系统会弹出一个对话框提示用户“应用无响应”&#xff0c;用户可以选择等待或强…...

配置Spark环境

1.上传spark安装包到某一台机器&#xff08;自己在finaShell上的机器&#xff09;。 2.解压。 把第一步上传的安装包解压到/opt/module下&#xff08;也可以自己决定解压到哪里&#xff09;。对应的命令是&#xff1a;tar -zxvf 安装包 -C /opt/module 3.重命名。进入/opt/mo…...

嵌入式硬件篇---IIC

文章目录 前言1. IC协议基础1.1 物理层特性两根信号线SCLSDA支持多主多从 标准模式电平 1.2 通信流程起始条件&#xff08;Start Condition&#xff09;从机地址&#xff08;Slave Address&#xff09;应答&#xff08;ACK/NACK&#xff09;数据传输&#xff1a;停止条件&#…...

Window下Jmeter多机压测方法

1.概述 Jmeter多机压测的原理&#xff0c;是通过单个jmeter客户端&#xff0c;控制多个远程的jmeter服务器&#xff0c;使他们同步的对服务器进行压力测试。 以此方式收集测试数据的好处在于&#xff1a; 保存测试采样数据到本地机器通过单台机器管理多个jmeter执行引擎测试…...