巨人的肩膀:

Apollo planning 框架
Apollo Planning 代码学习(一)
apollo介绍之planning模块
Apollo Planning决策规划代码详细解析 (6):LaneChangeDecider

1

主要的函数流程如下:
PlanningComponent::Proc() -> OnLanePlanning::RunOnce() ->
OnLanePlanning::Plan()-> PublicRoadPlanner::Plan() ->
Scenario::Process() -> LaneFollowStage::Process() -> LaneFollowStage::PlanOnReferenceLine()

PlanningComponent::Proc()
Proc主要是检查数据,并且执行注册好的planning,生成路线并且发布。
OnLanePlanning::RunOnce()
该函数的实现主要分为三个部分:车辆状态更新、查看全局路径是否有更新、Planning模块运行需要时间
OnLanePlanning::Plan() PublicRoadPlanner::Plan()
依据decider和optimizer进行规划,调用具体的planner进行规划,更新场景,决策当前应该执行什么场景,获取当前场景
Scenario::Process()
执行当前场景的任务
LaneFollowStage::Process()
遍历所有的参考线,直到找到可用来规划的参考线后退出
LaneFollowStage::PlanOnReferenceLine()
//顺序执行stage中的任务

2

场景选择阶段:ScenarioDispatchNonLearning()函数默认从lanefollow场景开始判断,首先根据驾驶员的意图来安排场景,如果不是默认的lanefollow场景,直接输出当前场景;如果是lanefollow场景,会依次判断是否属于别的场景;即剩余场景之间的跳转必须经过lanefollow这个场景。

switch (current_scenario_->scenario_type()) {case ScenarioConfig::LANE_FOLLOW: 车道保持case ScenarioConfig::PULL_OVER: 靠边break;case ScenarioConfig::BARE_INTERSECTION_UNPROTECTED: 无保护十字路口case ScenarioConfig::EMERGENCY_PULL_OVER: 紧急靠边case ScenarioConfig::PARK_AND_GO: 停车和启动case ScenarioConfig::STOP_SIGN_PROTECTED: 停止标志case ScenarioConfig::STOP_SIGN_UNPROTECTED:case ScenarioConfig::TRAFFIC_LIGHT_PROTECTED: 信号灯case ScenarioConfig::TRAFFIC_LIGHT_UNPROTECTED_LEFT_TURN: 信号灯无保护左转case ScenarioConfig::TRAFFIC_LIGHT_UNPROTECTED_RIGHT_TURN:case ScenarioConfig::VALET_PARKING: 代客泊车case ScenarioConfig::DEADEND_TURNAROUND: 路端调头

3

lane_follow的task列表:

 stage_type: LANE_FOLLOW_DEFAULT_STAGEenabled: truetask_type: LANE_CHANGE_DECIDER 判断当前是否进行变道,以及变道的状态task_type: PATH_REUSE_DECIDER 换道时:根据横纵向跟踪偏差,来决策是否需要重新规划轨迹;如果横纵向跟踪偏差,则根据上一时刻的轨迹生成当前周期的轨迹,以尽量保持轨迹的一致性task_type: PATH_LANE_BORROW_DECIDER 只是判断是否满足借道条件,具体的轨迹是否借道,是由后面的task决定task_type: PATH_BOUNDS_DECIDER 根据借道信息、道路宽度生成FallbackPathBound根据借道信息、道路宽度生成、障碍物边界生成PullOverPathBound、LaneChangePathBound、        RegularPathBound中的一种将车道线和障碍物转为上图中的边界task_type: PIECEWISE_JERK_PATH_OPTIMIZER 根据之前decider决策的reference line和path bound,以及横向约束,将最优路径求解问题转化为二次型规划问题;调用osqp库求解最优路径;task_type: PATH_ASSESSMENT_DECIDER       选出之前规划的备选路径中排序最靠前的路径;添加一些必要信息到路径中task_type: PATH_DECIDER              在上一个任务中获得了最优的路径,PathDecider的功能是 根据静态障碍物做出自车的决策, 对于前方的静态障碍物是忽略、stop还是nudgetask_type: RULE_BASED_STOP_DECIDER    根据一些规则设定停止标志task_type: ST_BOUNDS_DECIDERtask_type: SPEED_BOUNDS_PRIORI_DECIDER  将规划路径上障碍物的st bounds加载到路径对应的st图上计算并生成路径上的限速信息task_type: SPEED_HEURISTIC_OPTIMIZER  使用DP求解一条最优路径task_type: SPEED_DECIDERtask_type: SPEED_BOUNDS_FINAL_DECIDER#task_type: PIECEWISE_JERK_SPEED_OPTIMIZERtask_type: PIECEWISE_JERK_NONLINEAR_SPEED_OPTIMIZERtask_type: RSS_DECIDER

LANE_CHANGE_DECIDER

它的作用主要有两点:

判断当前是否进行变道,以及变道的状态,并将结果存在变量lane_change_status中;
变道过程中将目标车道的reference line放置到首位,变道结束后将当前新车道的reference line放置到首位

静态障碍物的nudge是用的lane_change,至于lane_change和lane_borrow的区别目前还不懂,之后再补

补:lane_chage的触发条件是有一个以上的参考线,而lane_borrow的条件是只能有一条参考线

PathReuseDecider

它的作用主要是换道时:

根据横纵向跟踪偏差,来决策是否需要重新规划轨迹;
如果横纵向跟踪偏差,则根据上一时刻的轨迹生成当前周期的轨迹,以尽量保持轨迹的一致性

Path_Lane_Borrow_Decider

需要进入借道场景才可以触发绕行功能。

需要满足下面条件才能判断是否可以借道:

○ 只有一条参考线,才能借道
○ 起点速度小于最大借道允许速度
○ 阻塞障碍物必须远离路口
○ 阻塞障碍物会一直存在
○ 阻塞障碍物与终点位置满足要求
○ 为可侧面通过的障碍物

PathBoundsDecider

分四种情况对pathBound进行计算,按照处理顺序分别是fallback备用、pullover靠边停车、lanechange换道、regular常规,不同的boundary对应不同的应用场景,
其中fallback对应的path bound一定会生成,其余3个只有一个被激活,即按照顺序一旦有有效的boundary生成,就结束该task。

对于决策规划–超车任务来说,这里会生成三种path bound :fallback、regular/self、regular/left/forward

PathAssessmentDecider

它的作用主要是:

○ 选出之前规划的备选路径中排序最靠前的路径;
○ 添加一些必要信息到路径中。

在这里debug时候观察到,regular/self的路径被排到了最前面,发现是因为排序的ComparePathData中设置的规则:

if (lhs_on_selflane || rhs_on_selflane) {if (std::fabs(lhs_path_length - rhs_path_length) >kSelfPathLengthComparisonTolerance) {return lhs_path_length > rhs_path_length;} else {return lhs_on_selflane;}

log一下发现regular/self的路径长度和regular/left的路径长度竟然一样,这是因为啥呢,继续往前看。
来看看这个path_bound是怎么生成的
->PathBoundsDecider::GenerateRegularPathBound()

直到这时,在这里发现了apollo就没给动态障碍物写生成借道边界的逻辑:
看issue里面怎么说:

https://github.com/ApolloAuto/apollo/issues/8808
Hi,
Thanks for the question. The current path-decision can take care of slow-speed obstacles. Here are a few parameters that you can tune to achieve your goal:path_decider_obstacle_utils.cc line 40: Here you can modify it by deleting the "IsStatic()" check and increase the FLAGS_static_obstacle_speed_threhold to be the slow-speed threshold you want. The ADC will try to side-pass any obstacle below this given speed.path_lane_borrow_decider.cc line 103: The FLAGS_lane_borrow_max_speed is the speed for the ADC to start side-pass. If you want the ADC to be able to start side-pass at a faster speed, you can increase this value (at the cost of reduced safety so please be careful).path_lane_borrow_decider.cc line 110: Only when the ADC thinks the blocking obstacle is a long-term one, it will start side-pass. Here you can specify how many frames an obstacle is blocking can it be defined as a "long-term" blocking obstacle. For example, if you specify it to be 10, then only when the ADC sees a slow-car ahead for 10frames (1sec) will the ADC start to pass the slow-car.path_bounds_decider.cc line 270: Here you see that the boundary is determined by lane-width, if you want, you can replace it with the function GetBoundaryFromRoads, what that will do is to use the entire road (likely consisting multiple lanes) as the boundary, ADC will try to use any path that it can find on the road, without considering whether it needs to borrow neighbor lane or not, etc. Normally, we don't suggest use this because it might create some safety issues. But as you can see, at line 319, when the ADC needs to pull-over, especially in emergency situation, it will use this method to find a path.Hope this answers your questions. Thanks.

根据大神的指点开始调试
改变静态障碍物判定逻辑后发现小车可以变道,但是速度保持在和前车相同
这可以说明PATH_LANE_BORROW_DECIDER给的借道判断正确

根据SPEED_BOUNDS_PRIORI_DECIDER模块,我们先来看看是否受到了限速

curr_speed_limit = std::fmax(speed_bounds_config_.lowest_speed(),std::min({speed_limit_from_reference_line,speed_limit_from_centripetal_acc,speed_limit_from_nearby_obstacles}));

speed_limit_from_reference_line 是根据map得到的限制
speed_limit_from_centripetal_acc 路径曲率带来的速度限制
speed_limit_from_nearby_obstacles 根据障碍物得到的速度限制

speed decider 流程图

注:超车时,在ST图中障碍物上方采样,即自车速度大于障碍物车速度。

根据log,得到AINFO:ADC在ST图上位于障碍物下方。但是想overtake需要在障碍物上方。如图:

查看GetSTLocation()函数,该函数是根据路径决策、速度曲线、障碍物ST边界获取到STLocation。
动态障碍物的ST边界应该是平行四边形
先看看输入的路径决策、速度曲线分别为
reference_line_info->path_decision()
reference_line_info->speed_data()
回到上一个SPEED_BOUNDS_PRIORI_DECIDER,观察到给的speed_limit并不小。
判断还是路径规划有问题,主要看PATH_BOUNDS_DECIDER:

Task初始化,根据参考线建立frenet坐标系,计算自车在frenet坐标系中的位置(s,l,s’,l’),同时计算自车到车道中心线的距离以及左右车道宽度。

接下来生成path bound,每个path bound都会在后续生成一条轨迹。

生成RegularPathBound:

Status PathBoundsDecider::GenerateRegularPathBound(const ReferenceLineInfo& reference_line_info,const LaneBorrowInfo& lane_borrow_info, PathBound* const path_bound,std::string* const blocking_obstacle_id,std::string* const borrow_lane_type) {// 1. Initialize the path boundaries to be an indefinitely large area.//将路径边界初始化为一个无限大的区域。if (!InitPathBoundary(reference_line_info, path_bound)) {const std::string msg = "Failed to initialize path boundaries.";AERROR << msg;return Status(ErrorCode::PLANNING_ERROR, msg);}// PathBoundsDebugString(*path_bound);// 2. Decide a rough boundary based on lane info and ADC's position//基于道路信息和车辆生成粗略边界if (!GetBoundaryFromLanesAndADC(reference_line_info, lane_borrow_info, 0.1,path_bound, borrow_lane_type)) {const std::string msg ="Failed to decide a rough boundary based on ""road information.";AERROR << msg;return Status(ErrorCode::PLANNING_ERROR, msg);}// PathBoundsDebugString(*path_bound);// TODO(jiacheng): once ready, limit the path boundary based on the//                 actual road boundary to avoid getting off-road.// 3. Fine-tune the boundary based on static obstacles基于静态障碍微调边界PathBound temp_path_bound = *path_bound;if (!GetBoundaryFromStaticObstacles(reference_line_info.path_decision(),//将不是静态的排除path_bound, blocking_obstacle_id)) {const std::string msg ="Failed to decide fine tune the boundaries after ""taking into consideration all static obstacles.";AERROR << msg;return Status(ErrorCode::PLANNING_ERROR, msg);}// Append some extra path bound points to avoid zero-length path data.int counter = 0;while (!blocking_obstacle_id->empty() &&path_bound->size() < temp_path_bound.size() &&counter < kNumExtraTailBoundPoint) {path_bound->push_back(temp_path_bound[path_bound->size()]);counter++;}// PathBoundsDebugString(*path_bound);// 4. Adjust the boundary considering dynamic obstacles// TODO(all): may need to implement this in the future.ADEBUG << "Completed generating path boundaries.";return Status::OK();
}

根据车辆和障碍物以及道路信息生成bound,即下图:
由于障碍物是非静态的,所以障碍物的end_s会有一个延长,所以会造成s-ref被堵塞,故进行buffer的调整。
成功:

可以看到决策块也变成了overtake。

如果对您有参考价值。希望不吝点赞:)。

apollo决策规划学习--慢速障碍物超车相关推荐

  1. apollo决策规划学习--施工绕行

    这一场景的难点在于多静态障碍物的处理. 首先看看规划失败的场景,大佬已经给出示例,不再自己录制了,参考:自动驾驶player 由于设置的起点和终点在一条扯到线上,所以只生成了一条ReferenceLi ...

  2. Apollo星火计划学习笔记——Apollo决策规划技术详解及实现(以交通灯场景检测为例)

    文章目录 前言 1. Apollo决策技术详解 1.1 Planing模块运行机制 1.2 Apollo决策功能的设计与实现 1.2.1参考路径 Reference Line 1.2.2 交规决策 T ...

  3. Apollo路径规划学习

    Apollo路径规划入门 规划简介 路线规划 轨迹规划 将地图转为图形 路径查找算法:A* 轨迹生成 Frenet坐标系 路径-速度解耦规划 路径规划 速度规划 路径生成与选择 ST图 速度规划 优化 ...

  4. Apollo决策规划planning模块简要分析

    决策规划planning模块简要分析 入口 初始化 Planning模块的初始化见Planning::Init()(apollo/modules/planning/planning.cc). 业务逻辑 ...

  5. Apollo Planning决策规划算法代码详细解析 (1):Scenario选择

    本文重点讲解Apollo代码中怎样配置Scenario以及选择当前Scenario,Scenario场景决策是Apollo规划算法的第一步,本文会对代码进行详细解析,也会梳理整个决策流程,码字不易,喜 ...

  6. 自动驾驶决策规划算法概述

    一.自动驾驶级别分类 L0 系统无法控制横向或者纵向 L1 系统能控制横向或者纵向中的一个,但横纵向无法联合控制 L2 系统可以联合控制横向和纵向 L3 小部分场景不需要人负责监控环境 L4 大部分场 ...

  7. 自动驾驶算法详解(1) : Apollo路径规划 Piecewise Jerk Path Optimizer的python实现

    本文作为Apollo Planning决策规划代码详细解析系列文章的补充,将使用Python代码以及anaconda环境,来实现Apollo 决策规划Planning 模块里的 Piecewise J ...

  8. 学习百度Apollo中的决策规划

    学习视频链接 无人车的任务:定位(在哪里).感知(看到了什么).预测(环境下一步怎么变化).规划(我们应该怎么移动).控制(怎样控制车辆) 一.无人车规划问题与解决框架 1.定义: 无人车规划问题就是 ...

  9. 自动驾驶决策规划算法第二章——Apollo EM Planner实践篇

    前置学习内容:自动驾驶控制算法 [自动驾驶][零基础]基础自动驾驶控制算法笔记_免费教学录影带的博客-CSDN博客 自动驾驶决策规划第一章 自动驾驶决策规划算法第一章_免费教学录影带的博客-CSDN博 ...

  10. Apollo星火计划学习笔记——Apollo路径规划算法原理与实践

    文章目录 前言 1. 路径规划算法总体介绍 1.1 Task: LANE_CHANGE_DECIDER 1.2 Task: PATH_REUSE_DECIDER 1.3 Task: PATH_BORR ...

最新文章

  1. Zookeeper工作原理
  2. 文巾解题 1837. K 进制表示下的各位数字总和
  3. android imap开发,企业邮箱在Android(安卓)系统手机上POP3/IMAP协议如何设置
  4. Win7和Ubuntu14.10双系统
  5. VUE报错:Module build failed: Error: Cannot find module ‘node-sass‘
  6. Git如何创建本地分支并推送到远程仓库
  7. 高光谱和图像特征相融合的生菜病害识别
  8. mysql migration tool 64bit_Migration Tool支持MySQL业务SQL迁移
  9. 不同cpu服务器虚拟迁移,虚拟机迁移时,提示CPU不兼容问题求解,谢谢!
  10. python数据标注工具_使用Python实现简易的数据标注工具
  11. html360chromeURL无法编辑,关于近期360拦截本站以及部分网友无法用chrome打开本站问题...
  12. 用计算机计算的结构图怎么画,冯·诺依曼计算机结构图解析
  13. ABAP调用HTTP服务
  14. 跳槽 ,你跳的是工资,还是阶层?
  15. 全国计算机二级flash,教你如何在Flash当中制作插按钮动画
  16. 原来Mysql索引要这么设计才能起飞
  17. linux下虚拟安装cad,LeoCAD下载 LeoCAD(虚拟乐高模型创建工具) 32位/64位 Linux版 v18.01 官方英文安装版 下载-脚本之家...
  18. Android RSA加密解密的 工具类的使用
  19. the work directory /tmp/ oracle,Oracle升级问题总结
  20. php cpu占有率过高怎么办,system占用cpu过高怎么办

热门文章

  1. linux+聊天工具支持qq,linux 下怎样使用qq等聊天工具聊天
  2. Camera幻灯片参数设置
  3. 关于TOPCODER的所有挑战、任务和GIG工作机会
  4. 网页游戏常见外挂原理及防御
  5. 服务器虚拟化的主要特点,网络虚拟化的七大特征
  6. 基于百度AI开放平台及图灵机器人搭建的聊天机器人
  7. 《正在爆发的互联网革命》作者个人出资10000美金,面向全球征召六度分割理论实验对象!...
  8. 李沐动手学深度学习V2-BERT微调和代码实现
  9. zend studio 12.5 安装aptana
  10. 英语体系----词根词缀等----持续补充(词根词缀等,词汇,语法,简单句,长难句,写作)