【Apollo学习笔记】—— Planning模块

news2024/12/23 13:46:12

在这里插入图片描述

前言

本文记录学习planning模块时的一些笔记,总体流程参照https://zhuanlan.zhihu.com/p/61982682中的流程图,如上图所示。

planning_component

modules/planning/planning_component.cc
在这里插入图片描述

PlanningComponent::Init部分首先完成规划模式的选择:

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

再完成相应的消息订阅

routing_reader_ = node_->CreateReader<RoutingResponse>(
traffic_light_reader_ = node_->CreateReader<TrafficLightDetection>(
pad_msg_reader_ = node_->CreateReader<PadMessage>(
story_telling_reader_ = node_->CreateReader<Stories>(
relative_map_reader_ = node_->CreateReader<MapMsg>(

最后消息发布

  planning_writer_ = node_->CreateWriter<ADCTrajectory>(
  rerouting_writer_ = node_->CreateWriter<RoutingRequest>(
  planning_learning_data_writer_ = node_->CreateWriter<PlanningLearningData>(

PlanningComponent::Proc的主要是检查数据,并且执行注册好的Planning,生成路线并且发布。

bool PlanningComponent::Proc(...) {
  // 1. 检查是否需要重新规划线路。
  CheckRerouting();
  // 2. 数据放入local_view_中,并且检查输入数据。
  ...
  // 3. 执行注册好的Planning,生成线路。
  planning_base_->RunOnce(local_view_, &adc_trajectory_pb);
  // 4. 发布消息
  planning_writer_->Write(std::make_shared<ADCTrajectory>(adc_trajectory_pb));
  // 5. 最后记录
  history->Add(adc_trajectory_pb);
}

RunOnce在NaviPlanning和OnLanePlanning都有,本文以常用的OnLanePlanning为例。

PS1

  • prediction_obstacles 从channel中获得的指针,类型为 PredictionObstacles,代码文件在 modules/prediction/proto/prediction_obstacle.proto 中,该类型的消息来自预测模块,包含了以下信息:
    • Header 头结构:包含了这条消息发布的时刻(以秒为单位),目前位置的模块名,该消息的序列号(每个模块各自维护的)等,几乎每个消息都包含有这个头结构,下面就不提及了。
    • PredictionObstacle 预测模块中的若干个障碍物行为:有感知模块中的障碍物(PerceptionObstacle),它包括障碍物的 id,它的三维坐标、速度加速度、边界大小(长高宽)、特殊的形状、类型(行人、非机动车、机动车)、运动轨迹等;还有时间戳,记录 GPS 给出的时刻;还有预测的时间长度;多种可能的运动轨迹;障碍物的运动趋势、优先级等。
    • 开始的时间戳:记录预测开始的时刻
    • 结束时间戳:预测结束的时刻
    • 自动驾驶车辆的运动趋势,停止、正常行驶还是正在变道等
    • Scenery 现在的场景
  • chassis 从channel获得的指针,类型为 Chassis,这条消息直接来自总线 CanBus,代码文件在 modules/canbus/proto/chassis.proto 中,该类包含了很多信息,主要是汽车底盘所给出的机械状态信息,比如:
    • 驾驶模式,有手动驾驶、自动驾驶、仅控制方向、仅控制速度以及紧急模式
    • 档位情况、引擎转速、车辆速度、里程表、燃油情况、电池电量等
    • 刹车、油门踏板的力度,方向盘的旋转角度,车轮转速
    • 转向灯、雾灯、大灯的工作情况
  • localization_estimate 从channel中获得的指针,类型为 LocalizationEstimate,代码文件在 modules/localization/proto/localization.proto 中,这条消息来自定位模块,该类主要包含了:
    • Pose 位置姿势,包括车头朝向,在地图上的线速度、线加速度和相对位置,角速度、仰角度等
    • 测量上述姿势的时刻
    • 车辆已经经过的轨迹点列
    • MSF 定位状态与质量

PS2

std::mutex是C++11标准中提供的一种互斥锁机制用于保护共享资源的访问。当多个线程需要同时访问共享资源时,为了避免出现数据竞争等问题,需要使用互斥锁进行同步控制。

std::mutex是一种基本的互斥锁类型,可以通过lock()函数锁定互斥锁,通过unlock()函数释放互斥锁。当一个线程持有互斥锁时,其他线程想要获取该互斥锁将会被阻塞,直到持有该互斥锁的线程将锁释放。

例如,当多个线程需要同时访问同一个共享变量时,可以在访问之前使用std::mutex进行锁定,保证每个线程都可以安全地访问该变量。例如:

#include <mutex>
#include <thread>
#include <iostream>

int shared_data = 0;
std::mutex mutex;

void work(int id) {
    for (int i = 0; i < 10000; ++i) {
        mutex.lock();
        shared_data++;
        mutex.unlock();
    }
    std::cout << "Thread " << id << " finished." << std::endl;
}

int main() {
    std::thread t1(work, 1);
    std::thread t2(work, 2);
    t1.join();
    t2.join();
    std::cout << "Shared data: " << shared_data << std::endl;
    return 0;
}

在上述例子中,两个线程都会对shared_data变量进行10000次的自增操作,为了避免出现数据竞争,我们在对shared_data进行访问之前都使用了std::mutex进行了锁定,保证了线程的安全性。

on_lane_planning

modules/planning/on_lane_planning.cc
在这里插入图片描述

OnLanePlanning::Init主要实现分配具体的Planner,启动参考线提供器(reference_line_provider_)。启动参考线提供器,会另启动一个线程,执行一个定时任务,每隔50ms提供一次参考线。注意:分配Planner的部分在OnLanePlanning实例化时就已经完成。

分配Planner的实现部分

modules/planning/planner/on_lane_planner_dispatcher.cc
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);
}

可以在modules/planning/conf/planning_config.pb.txt配置文件中看到配置Planner的类型:

standard_planning_config {
  planner_type: PUBLIC_ROAD
  planner_public_road_config {
  }
}

OnLanePlanning 的主逻辑在OnLanePlanning::RunOnce中,内容比较多,有些还没仔细看,大致完成了一下的内容:

void OnLanePlanning::RunOnce(const LocalView& local_view,
                             ADCTrajectory* const ptr_trajectory_pb) {
    //  更新汽车状态和参考线的状态,如果状态无效,直接返回
    //  ...  
    // 是否为出现导航路线变换,如果是 初始化 planner
    //  加上预估的规划触发的周期 得到 stitchingTrajectory
  // planning is triggered by prediction data, but we can still use an estimated
  // cycle time for stitching
  status = InitFrame(frame_num, stitching_trajectory.back(), vehicle_state);
    //  判断是否符合交通规则
    //  开始正在的规划 planner 开始规划
  status = Plan(start_timestamp, stitching_trajectory, ptr_trajectory_pb);
    //  记录规划所花费的时间
    //  ...
}

status = Plan(start_timestamp, stitching_trajectory, ptr_trajectory_pb);中有如下代码,此部分的Plan是指分配的planner的Plan()函数

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

PS1

make_unique是一个C++11中的函数模板,用于创建并返回一个独占指针(unique_ptr)。它的作用是将一个裸指针封装成一个unique_ptr对象,并确保该对象是唯一持有它所指向的对象。这可以有效避免内存泄漏和多个指针指向同一个对象的问题

public_road_planner

modules/planning/planner/public_road/public_road_planner.cc
接着来看public_road_planner的实现。

在这里插入图片描述

PublicRoadPlanner::Init实例化一个全局的scenario_manager_对象来进行场景管理。

Status PublicRoadPlanner::Init(const PlanningConfig& config) {
  config_ = config;
  scenario_manager_.Init(config);
  return Status::OK();
}

PublicRoadPlanner::Plan主要完成以下工作

Status PublicRoadPlanner::Plan(const TrajectoryPoint& planning_start_point,
                               Frame* frame,
                               ADCTrajectory* ptr_computed_trajectory) {
  // 更新场景,决策当前应该执行什么场景
  scenario_manager_.Update(planning_start_point, *frame);
  // 获取当前场景
  scenario_ = scenario_manager_.mutable_scenario();
  // 调用Scenario的Process函数,对具体的场景进行处理
  auto result = scenario_->Process(planning_start_point, frame);

  if (FLAGS_enable_record_debug) {
    auto scenario_debug = ptr_computed_trajectory->mutable_debug()
                              ->mutable_planning_data()
                              ->mutable_scenario();
    scenario_debug->set_scenario_type(scenario_->scenario_type());
    scenario_debug->set_stage_type(scenario_->GetStage());
    scenario_debug->set_msg(scenario_->GetMsg());
  }
  // 当前场景完成
  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();
}

scenario部分见Apollo星火计划学习笔记——Apollo决策规划技术详解及实现(以交通灯场景检测为例)、Apollo星火计划学习笔记——第七讲自动驾驶规划技术原理1以及后续文章

参考文章

[1] apollo介绍之planning模块(四)
[2] Apollo Planning 模块

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

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

相关文章

ArcGIS 利用cartogram插件制作变形地图

成果图 注&#xff1a;本图数据并不完全对&#xff0c;只做为测试用例 操作 首先需要下载一个插件cartogram 下载地址在这里 https://www.arcgis.com/home/item.html?idd348614c97264ae19b0311019a5f2276 下载完毕之后解压将Cartograms\HelpFiles下的所有文件复制到ArcGIS…

LeetCode(力扣)257. 二叉树的所有路径Python

LeetCode257. 二叉树的所有路径 题目链接代码 题目链接 https://leetcode.cn/problems/binary-tree-paths/ 代码 # Definition for a binary tree node. # class TreeNode: # def __init__(self, val0, leftNone, rightNone): # self.val val # self.…

ChatGPT成为工作工具,具体都应用在哪些地方?

Verified Market Research估计&#xff0c;到2030年&#xff0c;人工智能写作辅助软件市场将达到约65亿美元&#xff0c;复合年增长率为27%。生成式人工智能的浪潮正在席卷世界各地的营销部门。 Botco对美国1000名工作人员进行的调查发现&#xff0c;73%的人表示他们会利用生成…

IO流 详细介绍

一、IO流概述 1.IO&#xff1a;输入(Input读取数据)/输出(Output写数据) 2.流&#xff1a;是一种抽象概念&#xff0c;是对数据传输的总称,也就是说数据在设备间的传输称为流&#xff0c;流的本质是数据传输IO流就是用来处理设备间数据传输问题的。 3.常见的应用&#xff1a…

SQL两张表数据对比

表1&#xff1a; 表2&#xff1a; 1、查询两表的数据差异&#xff1a; # 查询表1中有但表2没有的数据 SELECT DATA FROM data1 WHERE ( DATA ) NOT IN ( SELECT DATA FROM data2 );# 查询表2中有但表…

MySQL系统变量 会话变量,用户变量

系统变量 分类 全局系统变量需要添加 global 关键字&#xff0c;有时把全局系统变量简称 全局变量 会话系统变量需要添加 session 关键字&#xff0c;有时也把会话系统变量称为 local 变量 局部变量 如果不写&#xff08;global、session&#xff09;默认会话级别。 静态变量在…

LeetCode[56]合并区间

难度&#xff1a;Medium 题目&#xff1a; 以数组 intervals 表示若干个区间的集合&#xff0c;其中单个区间为 intervals[i] [starti, endi] 。请你合并所有重叠的区间&#xff0c;并返回 一个不重叠的区间数组&#xff0c;该数组需恰好覆盖输入中的所有区间 。 示例 1&…

Practices11|41. 缺失的第一个正数(数组)、73. 矩阵置零(矩阵)

41. 缺失的第一个正数(数组) 1.题目&#xff1a; 给你一个未排序的整数数组 nums &#xff0c;请你找出其中没有出现的最小的正整数。 请你实现时间复杂度为 O(n) 并且只使用常数级别额外空间的解决方案。 示例 1&#xff1a; 输入&#xff1a;nums [1,2,0] 输出&#xf…

用于智能图像处理的计算机视觉和 NLP

莫斯科&#xff0c;神秘之城...&#xff08;这张照片由伊戈尔沙巴林提供&#xff09; 一、说明 如今&#xff0c;每个拥有智能手机的人都可能成为摄影师。因此&#xff0c;每天都有大量新照片出现在社交媒体、网站、博客和个人照片库中。尽管拍照的过程可能非常令人兴奋&#x…

在ubuntu+cpolar+rabbitMQ环境下,实现mq服务端远程访问

文章目录 前言1.安装erlang 语言2.安装rabbitMQ3. 内网穿透3.1 安装cpolar内网穿透(支持一键自动安装脚本)3.2 创建HTTP隧道 4. 公网远程连接5.固定公网TCP地址5.1 保留一个固定的公网TCP端口地址5.2 配置固定公网TCP端口地址 前言 RabbitMQ是一个在 AMQP(高级消息队列协议)基…

零信任架构演进与实践:探讨零信任安全模型在不断发展的背景下的最新趋势和实际应用案例

随着信息技术的迅猛发展&#xff0c;企业的网络安全面临着日益复杂的挑战。传统的网络安全模型已经不再适用于如今的威胁环境&#xff0c;因此&#xff0c;零信任架构应运而生。零信任安全模型基于"从内部出发&#xff0c;不信任网络&#xff0c;不信任用户"的理念&a…

FirmAE 工具安装(解决克隆失败 网络问题解决)

FirmAE官方推荐使用Ubuntu 18.04系统进行安装部署&#xff0c;FirmAE工具的安装部署十分简单&#xff0c;只需要拉取工具仓库后执行安装脚本即可。 首先运行git clone --recursive https://kgithub.com/pr0v3rbs/FirmAE命令 拉取FirmAE工具仓库&#xff0c;因为网络的问题&…

非常详细的 Ceph 介绍、原理、架构

1. Ceph架构简介及使用场景介绍 1.1 Ceph简介 Ceph是一个统一的分布式存储系统&#xff0c;设计初衷是提供较好的性能、可靠性和可扩展性。 Ceph项目最早起源于Sage就读博士期间的工作&#xff08;最早的成果于2004年发表&#xff09;&#xff0c;并随后贡献给开源社区。在经过…

排序链表00

题目链接 排序链表 题目描述 注意点 在 O(n log n) 时间复杂度和常数级空间复杂度下&#xff0c;对链表进行排序 解答思路 使用归并排序对链表进行排序&#xff0c;保证时间复杂度为 O(n log n)相对于数组的归并排序&#xff0c;链表的中间节点需要遍历才能找到&#xff0…

idea快速生成Serializable序列化UID的方法

①在idea的File–>Settings–>Editor–>Inspections里搜索 Serializable class without serialVersionUID 记得点Apply和OK

opencv进阶08-K 均值聚类cv2.kmeans()介绍及示例

K均值聚类是一种常用的无监督学习算法&#xff0c;用于将一组数据点分成不同的簇&#xff08;clusters&#xff09;&#xff0c;以便数据点在同一簇内更相似&#xff0c;而不同簇之间差异较大。K均值聚类的目标是通过最小化数据点与所属簇中心之间的距离来形成簇。 当我们要预测…

re学习(34)攻防世界-csaw2013reversing2(修改汇编顺序)

参考文章&#xff1a; re学习笔记&#xff08;27&#xff09;攻防世界-re-csaw2013reversing2_Forgo7ten的博客-CSDN博客攻防世界逆向入门题之csaw2013reversing2_沐一 林的博客-CSDN博客 三种做法 1、ida静态分析修改指令 main函数反编译的代码 由于运行之后的是乱码&…

【C++ 记忆站】缺省参数

文章目录 缺省参数的概念缺省参数的分类1、全缺省参数2、半缺省参数 缺省参数实际应用场景 缺省参数的概念 缺省参数是声明或定义函数时为函数的参数指定一个缺省值。在调用该函数时&#xff0c;如果没有指定实参则采用该形参的缺省值&#xff0c;否则使用指定的实参 正常调用一…

MySQL 安装 audit 日志审计插件

下载 我的MySQL版本是 5.7.37的&#xff0c;用的是日志审计插件&#xff08;audit-plugin&#xff09;是1.1.10的&#xff0c;大家可以对应自己版本去下载。 https://github.com/trellix-enterprise/mysql-audit/releases 配置 1、进入到/opt目录下载 audit&#xff0c;可以…

《Zookeeper》源码分析(十三)之 投票管理器

目录 QuorumVerifier数据结构构造函数containsQuorum() SyncedLearnerTracker功能 QuorumVerifier QuorumVerifier用于保存集群选举服务器信息以及选举期间判断投票是否过半&#xff0c;它的创建过程如下&#xff1a; 默认创建的是它的实现类QuorumMaj 数据结构 构造函数 从…