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

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

前言

本文主要分析Apollo代码中函数bool Box::HasOverlap(const Box2d &box) const {}的数学原理。

在阅读此部分代码时,第一遍没看懂return的一堆什么意思,百度之后说是采用OBB原理,所以就去了解下OBB原理,回来看还是没太明白,直到看到了博客[1],通过博主的图解才有了进一步的了解,但对照代码还是没能完全理解,后来结合向量的相关知识,才算彻底明白了HasOverlap()实现的具体数学原理。
下面,作者仅对代码进行数学解读。

代码

直接上代码,代码路径/self_driving/Optimization/Apollo-DL-IAPS/util/box2d.cc,作者在这里将代码划分为几个部分分别解读。Apollo对Box2d的碰撞检测分为两步进行,第一步使用AABB进行粗检测(f1部分)快速剔除非碰撞的box,第二部分使用OBB进行细检测(f2~f6部分),对f1检测到有碰撞的box进一步进行检测。

bool Box2d::HasOverlap(const Box2d &box) const {
  // f1
  if (box.max_x() < min_x() || box.min_x() > max_x() || box.max_y() < min_y() ||
      box.min_y() > max_y()) {
    return false;
  }

  //f2
  const double shift_x = box.center_x() - center_.x();
  const double shift_y = box.center_y() - center_.y();

  const double dx1 = cos_heading_ * half_length_;
  const double dy1 = sin_heading_ * half_length_;
  const double dx2 = sin_heading_ * half_width_;
  const double dy2 = -cos_heading_ * half_width_;
  const double dx3 = box.cos_heading() * box.half_length();
  const double dy3 = box.sin_heading() * box.half_length();
  const double dx4 = box.sin_heading() * box.half_width();
  const double dy4 = -box.cos_heading() * box.half_width();

  //f3
  return std::abs(shift_x * cos_heading_ + shift_y * sin_heading_) <=
             std::abs(dx3 * cos_heading_ + dy3 * sin_heading_) +
                 std::abs(dx4 * cos_heading_ + dy4 * sin_heading_) +
                 half_length_ &&
  //f4
         std::abs(shift_x * sin_heading_ - shift_y * cos_heading_) <=
             std::abs(dx3 * sin_heading_ - dy3 * cos_heading_) +
                 std::abs(dx4 * sin_heading_ - dy4 * cos_heading_) +
                 half_width_ &&
  //f5
         std::abs(shift_x * box.cos_heading() + shift_y * box.sin_heading()) <=
             std::abs(dx1 * box.cos_heading() + dy1 * box.sin_heading()) +
                 std::abs(dx2 * box.cos_heading() + dy2 * box.sin_heading()) +
                 box.half_length() &&
  //f6
         std::abs(shift_x * box.sin_heading() - shift_y * box.cos_heading()) <=
             std::abs(dx1 * box.sin_heading() - dy1 * box.cos_heading()) +
                 std::abs(dx2 * box.sin_heading() - dy2 * box.cos_heading()) +
                 box.half_width();
}

代码分析

f1

AABB检测用于粗检测,根据自车和障碍物的box角点构建两个长宽分别平行于坐标轴的box,查看这两个box(两个虚线box表示)是否有交集,可以直接根据新构建的box的角点的坐标值来判断。如下图所示,通过这种方式可以粗略检测到A、B有碰撞,但是是否真的有碰撞还需要通过OBB进一步检测。
AABB

f2

根据OBB检测原理,构建向量如下图所示:
分离轴投影
假设有两个Box类型的对象A和B,计算A.HasOverlap(B)的结果。
以下两行代码计算的时A的中心到B的中心的向量

  const double shift_x = box.center_x() - center_.x();
  const double shift_y = box.center_y() - center_.y();

转换为数学计算为:
a b ⃗ = ( x s h i f t , y s h i f t ) = ( B . x c e n t e r − A . x c e n t e r , B . y c e n t e r − A . y c e n t e r ) (1) \vec{ab}=(x_{shift},y_{shift})=(B.x_{center}-A.x_{center},B.y_{center}-A.y_{center})\tag{1} ab =(xshift,yshift)=(B.xcenterA.xcenter,B.ycenterA.ycenter)(1)
以下四行代码是分别计算A的纵向方向(指box的朝向)和横向方向的两个向量,其中纵向方向的向量模为 l e n g t h h a l f length_{half} lengthhalf,横向方向的向量模为 w i d t h h a l f width_{half} widthhalf

  const double dx1 = cos_heading_ * half_length_;
  const double dy1 = sin_heading_ * half_length_;
  const double dx2 = sin_heading_ * half_width_;
  const double dy2 = -cos_heading_ * half_width_;

纵向向量:
v 1 ⃗ = ( d x 1 , d y 1 ) = A . l e n g t h h a l f ⋅ ( cos ⁡ ( h e a d i n g A ) , sin ⁡ ( h e a d i n g A ) ) (2) \vec{v_1}=(dx1,dy1)=A.length_{half}\cdot(\cos(heading_A),\sin(heading_A))\tag{2} v1 =(dx1,dy1)=A.lengthhalf(cos(headingA),sin(headingA))(2)
横向向量:
v 2 ⃗ = ( d x 2 , d y 2 ) = A . w i d t h h a l f ⋅ ( sin ⁡ ( h e a d i n g A ) , − cos ⁡ ( h e a d i n g A ) ) (3) \vec{v_2}=(dx2,dy2)=A.width_{half}\cdot(\sin(heading_A),-\cos(heading_A))\tag{3} v2 =(dx2,dy2)=A.widthhalf(sin(headingA),cos(headingA))(3)
其中, h e a d i n g A heading_A headingA为A的方向角,则 ( cos ⁡ ( h e a d i n g A ) ,   s i n ( h e a d i n g A ) ) (\cos(heading_A),\ sin(heading_A)) (cos(headingA), sin(headingA))为A的单位方向向量, ( sin ⁡ ( h e a d i n g A ) , − cos ⁡ ( h e a d i n g A ) (\sin(heading_A),-\cos(heading_A) (sin(headingA),cos(headingA)为A的单位法向量(为啥单位法向量这样表示?可参考线性代数相关知识)。

同理,以下四行代码分别计算的是B的纵向方向和横向方向的两个向量,纵向方向向量和横向方向向量的模分别是B的半长 l e n g t h h a l f length_{half} lengthhalf,半宽 w i d t h h a l f width_{half} widthhalf

  const double dx3 = box.cos_heading() * box.half_length();
  const double dy3 = box.sin_heading() * box.half_length();
  const double dx4 = box.sin_heading() * box.half_width();
  const double dy4 = -box.cos_heading() * box.half_width();

纵向向量:
v 3 ⃗ = ( d x 3 , d y 3 ) = B . l e n g t h h a l f ⋅ ( cos ⁡ ( h e a d i n g B ) , sin ⁡ ( h e a d i n g B ) ) (4) \vec{v_3}=(dx3,dy3)=B.length_{half}\cdot(\cos(heading_B),\sin(heading_B))\tag{4} v3 =(dx3,dy3)=B.lengthhalf(cos(headingB),sin(headingB))(4)
横向向量:
v 4 ⃗ = ( d x 4 , d y 4 ) = B . w i d t h h a l f ⋅ ( sin ⁡ ( h e a d i n g B ) , − cos ⁡ ( h e a d i n g B ) ) (5) \vec{v_4}=(dx4,dy4)=B.width_{half}\cdot(\sin(heading_B),-\cos(heading_B))\tag{5} v4 =(dx4,dy4)=B.widthhalf(sin(headingB),cos(headingB))(5)
其中, h e a d i n g B heading_B headingB为B的方向角,则 ( cos ⁡ ( h e a d i n g B ) ,   s i n ( h e a d i n g B ) ) (\cos(heading_B),\ sin(heading_B)) (cos(headingB), sin(headingB))为B的单位方向向量, ( sin ⁡ ( h e a d i n g B ) , − cos ⁡ ( h e a d i n g B ) (\sin(heading_B),-\cos(heading_B) (sin(headingB),cos(headingB)为A的单位法向量。

f3

f 3 f3 f3表示的是计算往A纵轴上的投影

std::abs(shift_x * cos_heading_ + shift_y * sin_heading_) <=
             std::abs(dx3 * cos_heading_ + dy3 * sin_heading_) +
                 std::abs(dx4 * cos_heading_ + dy4 * sin_heading_) +
                 half_length_

如下图所示
往A纵轴方向投影
结合代码和图片一块分析:
(1)代码中std::abs(shift_x * cos_heading_ + shift_y * sin_heading_)所表示的是向量 a b ⃗ \vec{ab} ab 在A的纵轴上投影的模c,结合公式(1)可知:
c = ∣ a b ⃗ ⋅ ( cos ⁡ ( h e a d i n g A ) , sin ⁡ ( h e a d i n g A ) ) ∣ = ∣ x s h i f t ⋅ cos ⁡ ( h e a d i n g A ) + y s h i f t ⋅ sin ⁡ ( h e a d i n g A ) ∣ c=|\vec{ab}\cdot(\cos(heading_A),\sin(heading_A))|=|x_{shift}\cdot\cos(heading_A)+y_{shift}\cdot\sin(heading_A)| c=ab (cos(headingA),sin(headingA))=xshiftcos(headingA)+yshiftsin(headingA)
(2)代码中std::abs(dx3 * cos_heading_ + dy3 * sin_heading_)所表示的是向量 v 3 ⃗ \vec{v_3} v3 在A的纵轴上投影的模 b 1 b1 b1,结合公式(4)可知:
b 1 = ∣ v 3 ⃗ ⋅ ( cos ⁡ ( h e a d i n g A ) , sin ⁡ ( h e a d i n g A ) ) ∣ = ∣ d x 3 ⋅ cos ⁡ ( h e a d i n g A ) + d y 3 ⋅ sin ⁡ ( h e a d i n g A ) ∣ b1=|\vec{v_3}\cdot(\cos(heading_A),\sin(heading_A))|=|dx3\cdot\cos(heading_A)+dy3\cdot\sin(heading_A)| b1=v3 (cos(headingA),sin(headingA))=dx3cos(headingA)+dy3sin(headingA)
代码中std::abs(dx4 * cos_heading_ + dy4 * sin_heading_)所表示的是向量 v 4 ⃗ \vec{v_4} v4 在A的纵轴上投影的模 b 2 b2 b2,结合公式(5)可知:
b 2 = ∣ v 4 ⃗ ⋅ ( cos ⁡ ( h e a d i n g A ) , sin ⁡ ( h e a d i n g A ) ) ∣ = ∣ d x 4 ⋅ cos ⁡ ( h e a d i n g A ) + d y 4 ⋅ sin ⁡ ( h e a d i n g A ) ∣ b2=|\vec{v_4}\cdot(\cos(heading_A),\sin(heading_A))|=|dx4\cdot\cos(heading_A)+dy4\cdot\sin(heading_A)| b2=v4 (cos(headingA),sin(headingA))=dx4cos(headingA)+dy4sin(headingA)
由上图可知:
b = b 1 + b 2 b=b1+b2 b=b1+b2
(3)代码中half_length_是向量 v 1 ⃗ \vec{v_1} v1 在其纵轴上的投影的模,另外,向量 v 2 ⃗ \vec{v_2} v2 此时在其纵轴上投影的模为0。
c 1 = b + l e n g t h h a l f c1=b+length_{half} c1=b+lengthhalf

f4

f 4 f4 f4表示的是计算往A横轴上的投影

 std::abs(shift_x * sin_heading_ - shift_y * cos_heading_) <=
     std::abs(dx3 * sin_heading_ - dy3 * cos_heading_) +
         std::abs(dx4 * sin_heading_ - dy4 * cos_heading_) +
         half_width_

如下图所示
往A横轴方向投影
结合代码和图片一块分析:
(1)代码中std::abs(shift_x * sin_heading_ - shift_y * cos_heading_)所表示的是向量 a b ⃗ \vec{ab} ab 在A的横轴上投影的模c,结合公式(1)可知:
c = ∣ a b ⃗ ⋅ ( sin ⁡ ( h e a d i n g A ) , − cos ⁡ ( h e a d i n g A ) ) ∣ = ∣ x s h i f t ⋅ sin ⁡ ( h e a d i n g A ) − y s h i f t ⋅ cos ⁡ ( h e a d i n g A ) ∣ c=|\vec{ab}\cdot(\sin(heading_A),-\cos(heading_A))|=|x_{shift}\cdot\sin(heading_A)-y_{shift}\cdot\cos(heading_A)| c=ab (sin(headingA),cos(headingA))=xshiftsin(headingA)yshiftcos(headingA)
(2)代码中std::abs(dx3 * sin_heading_ - dy3 * cos_heading_)所表示的是向量 v 3 ⃗ \vec{v_3} v3 在A的横轴上投影的模 b 1 b1 b1,结合公式(4)可知:
b 1 = ∣ v 3 ⃗ ⋅ ( sin ⁡ ( h e a d i n g A ) , − cos ⁡ ( h e a d i n g A ) ) ∣ = ∣ d x 3 ⋅ sin ⁡ ( h e a d i n g A ) − d y 3 ⋅ cos ⁡ ( h e a d i n g A ) ∣ b1=|\vec{v_3}\cdot(\sin(heading_A),-\cos(heading_A))|=|dx3\cdot\sin(heading_A)-dy3\cdot\cos(heading_A)| b1=v3 (sin(headingA),cos(headingA))=dx3sin(headingA)dy3cos(headingA)
代码中std::abs(dx4 * sin_heading_ - dy4 * cos_heading_)所表示的是向量 v 4 ⃗ \vec{v_4} v4 在A的横轴上投影的模 b 2 b2 b2,结合公式(5)可知:
b 2 = ∣ v 4 ⃗ ⋅ ( sin ⁡ ( h e a d i n g A ) , − cos ⁡ ( h e a d i n g A ) ) ∣ = ∣ d x 4 ⋅ sin ⁡ ( h e a d i n g A ) − d y 4 ⋅ cos ⁡ ( h e a d i n g A ) ∣ b2=|\vec{v_4}\cdot(\sin(heading_A),-\cos(heading_A))|=|dx4\cdot\sin(heading_A)-dy4\cdot\cos(heading_A)| b2=v4 (sin(headingA),cos(headingA))=dx4sin(headingA)dy4cos(headingA)
由上图可知:
b = b 1 + b 2 b=b1+b2 b=b1+b2
(3)代码中half_width_是向量 v 2 ⃗ \vec{v_2} v2 在其横轴上的投影的模,另外,向量 v 1 ⃗ \vec{v_1} v1 此时在其横轴上投影的模为0。
c 1 = b + w i d t h h a l f c1=b+width_{half} c1=b+widthhalf

f5

f 5 f5 f5表示的是计算往B纵轴上的投影

std::abs(shift_x * box.cos_heading() + shift_y * box.sin_heading()) <=
    std::abs(dx1 * box.cos_heading() + dy1 * box.sin_heading()) +
        std::abs(dx2 * box.cos_heading() + dy2 * box.sin_heading()) +
        box.half_length()

如下图所示:
往B纵轴方向投影
结合代码和图片一块分析:
(1)代码中std::abs(shift_x * box.cos_heading() + shift_y * box.sin_heading())所表示的是向量 a b ⃗ \vec{ab} ab 在B的纵轴上投影的模c,结合公式(1)可知:
c = ∣ a b ⃗ ⋅ ( cos ⁡ ( h e a d i n g B ) , sin ⁡ ( h e a d i n g B ) ) ∣ = ∣ x s h i f t ⋅ cos ⁡ ( h e a d i n g B ) + y s h i f t ⋅ sin ⁡ ( h e a d i n g B ) ∣ c=|\vec{ab}\cdot(\cos(heading_B),\sin(heading_B))|=|x_{shift}\cdot\cos(heading_B)+y_{shift}\cdot\sin(heading_B)| c=ab (cos(headingB),sin(headingB))=xshiftcos(headingB)+yshiftsin(headingB)
(2)代码中std::abs(dx1 * box.cos_heading() + dy1 * box.sin_heading())所表示的是向量 v 1 ⃗ \vec{v_1} v1 在B的纵轴上投影的模 a 1 a1 a1,结合公式(2)可知:
a 1 = ∣ v 1 ⃗ ⋅ ( cos ⁡ ( h e a d i n g B ) , sin ⁡ ( h e a d i n g B ) ) ∣ = ∣ d x 1 ⋅ cos ⁡ ( h e a d i n g B ) + d y 1 ⋅ sin ⁡ ( h e a d i n g B ) ∣ a1=|\vec{v_1}\cdot(\cos(heading_B),\sin(heading_B))|=|dx1\cdot\cos(heading_B)+dy1\cdot\sin(heading_B)| a1=v1 (cos(headingB),sin(headingB))=dx1cos(headingB)+dy1sin(headingB)
代码中std::abs(dx2 * box.cos_heading() + dy2 * box.sin_heading())所表示的是向量 v 2 ⃗ \vec{v_2} v2 在B的纵轴上投影的模 a 2 a2 a2,结合公式(3)可知:
a 2 = ∣ v 2 ⃗ ⋅ ( cos ⁡ ( h e a d i n g B ) , sin ⁡ ( h e a d i n g B ) ) ∣ = ∣ d x 2 ⋅ cos ⁡ ( h e a d i n g B ) + d y 2 ⋅ sin ⁡ ( h e a d i n g B ) ∣ a2=|\vec{v_2}\cdot(\cos(heading_B),\sin(heading_B))|=|dx2\cdot\cos(heading_B)+dy2\cdot\sin(heading_B)| a2=v2 (cos(headingB),sin(headingB))=dx2cos(headingB)+dy2sin(headingB)
由上图可知:
a = a 1 + a 2 a=a1+a2 a=a1+a2
(3)代码中half_length是向量 v 3 ⃗ \vec{v_3} v3 在其纵轴上的投影的模,另外,向量 v 4 ⃗ \vec{v_4} v4 此时在其纵轴上投影的模为0。
c 1 = a + l e n g t h h a l f c1=a+length_{half} c1=a+lengthhalf

f6

f 6 f6 f6表示的是计算往B横轴上的投影

std::abs(shift_x * box.sin_heading() - shift_y * box.cos_heading()) <=
    std::abs(dx1 * box.sin_heading() - dy1 * box.cos_heading()) +
        std::abs(dx2 * box.sin_heading() - dy2 * box.cos_heading()) +
        box.half_width()

如下图所示:
往B横轴方向投影
结合代码和图片一块分析:
(1)代码中std::abs(shift_x * box.sin_heading() - shift_y * box.cos_heading())所表示的是向量 a b ⃗ \vec{ab} ab 在B的横轴上投影的模c,结合公式(1)可知:
c = ∣ a b ⃗ ⋅ ( sin ⁡ ( h e a d i n g B ) , − cos ⁡ ( h e a d i n g B ) ) ∣ = ∣ x s h i f t ⋅ sin ⁡ ( h e a d i n g B ) − y s h i f t ⋅ cos ⁡ ( h e a d i n g B ) ∣ c=|\vec{ab}\cdot(\sin(heading_B),-\cos(heading_B))|=|x_{shift}\cdot\sin(heading_B)-y_{shift}\cdot\cos(heading_B)| c=ab (sin(headingB),cos(headingB))=xshiftsin(headingB)yshiftcos(headingB)
(2)代码中std::abs(dx1 * box.sin_heading() - dy1 * box.cos_heading())所表示的是向量 v 1 ⃗ \vec{v_1} v1 在B的横轴上投影的模 a 1 a1 a1,结合公式(2)可知:
a 1 = ∣ v 1 ⃗ ⋅ ( sin ⁡ ( h e a d i n g B ) , − cos ⁡ ( h e a d i n g B ) ) ∣ = ∣ d x 1 ⋅ sin ⁡ ( h e a d i n g B ) − d y 1 ⋅ cos ⁡ ( h e a d i n g B ) ∣ a1=|\vec{v_1}\cdot(\sin(heading_B),-\cos(heading_B))|=|dx1\cdot\sin(heading_B)-dy1\cdot\cos(heading_B)| a1=v1 (sin(headingB),cos(headingB))=dx1sin(headingB)dy1cos(headingB)
代码中std::abs(dx2 * box.sin_heading() - dy2 * box.cos_heading())所表示的是向量 v 2 ⃗ \vec{v_2} v2 在B的横轴上投影的模 a 2 a2 a2,结合公式(3)可知:
a 2 = ∣ v 2 ⃗ ⋅ ( sin ⁡ ( h e a d i n g B ) , − cos ⁡ ( h e a d i n g B ) ) ∣ = ∣ d x 2 ⋅ sin ⁡ ( h e a d i n g B ) − d y 2 ⋅ cos ⁡ ( h e a d i n g B ) ∣ a2=|\vec{v_2}\cdot(\sin(heading_B),-\cos(heading_B))|=|dx2\cdot\sin(heading_B)-dy2\cdot\cos(heading_B)| a2=v2 (sin(headingB),cos(headingB))=dx2sin(headingB)dy2cos(headingB)
由上图可知:
a = a 1 + a 2 a=a1+a2 a=a1+a2
(3)代码中half_width是向量 v 4 ⃗ \vec{v_4} v4 在其横轴上的投影的模,另外,向量 v 3 ⃗ \vec{v_3} v3 此时在其横轴上投影的模为0。
c 1 = a + w i d t h h a l f c1=a+width_{half} c1=a+widthhalf

若步骤f3~f6均满足 c < = c 1 c<=c1 c<=c1,则可判定两个Box存在碰撞(具体原理可参考OBB原理)。

参考

[1] Apollo中Lattice轨迹碰撞检测
[2]自动驾驶运动规划中的碰撞检测

  • 5
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: Apollo Planning决策规划算法在无人驾驶领域中被广泛应用,在自动驾驶车辆中起着至关重要的作用。该算法主要通过对车辆周围环境的感知和分析,实现智能驾驶路线的规划和决策,确保车辆安全行驶。 该算法代码主要包含三个部分:感知模块、规划模块和控制模块。其中感知模块主要负责采集车辆周围的环境信息,包括车辆所处的位置、路况、障碍物等。规划模块通过对这些信息的分析,提出一系列可能的驾驶路线,并通过评估这些路线的优劣来选择最佳驾驶路线。控制模块负责实现规划模块中选择的最佳驾驶路线,并控制车辆按照路线行驶。 在Apollo Planning决策规划算法中,规划模块是实现驾驶决策的最重要模块,也是最具技术难度的模块。规划模块通过对车辆当前状态和环境信息的分析,提出一系列汽车驾驶路线。该算法采用在线生成路线方案的方法,路线生成的步骤如下: 1. 动态路径规划:根据车辆的位置和行驶状态,实时选择当前最佳的驾驶路线。 2. 静态路线生成:基于当前车辆所处的环境信息,生成固定的驾驶路线。 3. 组合路径规划:将动态路径规划和静态路线生成相结合,生成最终的驾驶路线。 除此之外,Apollo Planning决策规划算法还包括计算机视觉、机器学习、深度学习和人工智能等技术,这些技术的综合应用使得Apollo Planning决策规划算法成为无人驾驶领域中应用最广泛的决策规划算法。 ### 回答2: Apollo Planning决策规划算法是一种用于自动驾驶系统的规划算法。该算法的主要作用是实时生成安全、有效且符合路况的路径以实现自动驾驶功能。本文将对该算法进行详细解析Apollo Planning决策规划算法主要包括三个步骤:路线规划、运动规划和决策规划。具体代码如下: 1. 路线规划 ```c++ bool Planning::PlanOnReferenceLine() { std::vector<const hdmap::HDMap*> hdmap_vec; hdmap_vec.reserve(1); if (!GetHdmapOnRouting(current_routing_, &hdmap_vec)) { AERROR << "Failed to get hdmap on current routing with " << current_routing_.ShortDebugString(); return false; } const auto& reference_line_info = reference_line_infos_.front(); std::vector<ReferencePoint> ref_points; if (!CreateReferenceLineInfo(hdmap_vec.front(), reference_line_info, &ref_points)) { AERROR << "Failed to create reference line from routing"; return false; } // Smooth reference line Spline2d smoothed_ref_line; std::vector<double> s_refs; std::vector<double> l_refs; std::vector<double> headings; std::vector<double> kappas; std::vector<double> dkappas; if (!SmoothReferenceLine(ref_points, &smoothed_ref_line, &s_refs, &l_refs, &headings, &kappas, &dkappas)) { AERROR << "Failed to smooth reference line"; return false; } reference_line_info.SetTrajectory(&smoothed_ref_line); reference_line_info.SetReferenceLine(&ref_points); // set origin point if (!reference_line_info.SLToXY(s_refs.front(), 0.0, &origin_point_)) { AERROR << "Failed to get origin point on reference line"; return false; } return true; } ``` 在路线规划阶段中,Apollo Planning决策规划算法首先获取当前行驶路线和高精度地图数据。然后根据行驶路线和地图数据构建参考线,对参考线进行平滑处理,得到平滑后的参考线。此时我们可以得到平滑后的参考线的位置、方向和曲率等信息,这些信息将作为后面的运动和决策规划的输入。 2. 运动规划 ```c++ bool Planning::PlanOnPrediction() { PredictionObstacles prediction_obstacles; if (!GetPrediction(&prediction_obstacles)) { AERROR << "Prediction failed"; return false; } std::vector<Obstacle> obstacles; if (!BuildObstacle(prediction_obstacles, &obstacles)) { AERROR << "Unable to build obstacle"; return false; } const auto& reference_line_info = reference_line_infos_.front(); const auto& reference_line = reference_line_info.reference_line(); SpeedData speed_data; Cruiser::PlanningTarget planning_target; Status status = cruiser_->Plan(reference_line_info, obstacles, 0.0, reference_line.Length(), &speed_data, &planning_target); if (status != Status::OK()) { AERROR << "Failed to plan path with status: " << status; return false; } RecordDebugInfo(reference_line_info, obstacles, speed_data); return true; } ``` 运动规划主要用于生成车辆在参考线上的运行轨迹。在运动规划阶段,Apollo Planning决策规划算法首先获取预测障碍物信息,将预测的障碍物转化为Obstacle对象。然后根据当前平滑后的参考线、障碍物等信息进行运动规划。运动规划的目标是生成符合规划目标的速度曲线。最后,Apollo Planning决策规划算法记录调试信息,以便后续分析调试。 3. 决策规划 ```c++ bool Planning::MakeDecision() { const auto& reference_line_info = reference_line_infos_.front(); const auto& reference_line = reference_line_info.reference_line(); std::vector<const Obstacle*> obstacles; if (!Obstacle::CreateObstacleRegions(FLAGS_max_distance_obstacle, reference_line_info, &obstacles)) { AERROR << "Failed to create obstacle regions"; return false; } for (auto obstacle_ptr : obstacles) { const auto& obstacle = *obstacle_ptr; if (obstacle.IsVirtual()) { continue; } if (obstacle.IsStatic()) { continue; } if (obstacle.type() == PerceptionObstacle::BICYCLE || obstacle.type() == PerceptionObstacle::PEDESTRIAN) { continue; } const auto& nearest_path_point = obstacle.nearest_point(); const SLPoint obstacle_sl = reference_line_info.xy_to_sl(nearest_path_point); if (obstacle_sl.s() < -FLAGS_max_distance_obstacle || obstacle_sl.s() > reference_line.Length() + FLAGS_max_distance_obstacle) { continue; } ObjectDecisionType decision; decision.mutable_avoid(); decision.mutable_avoid()->set_distance_s(-obstacle_sl.s()); reference_line_info.AddCost(&obstacle, &decision); } std::vector<ObjectDecisionType> decisions; if (!traffic_rule_manager_.ApplyRule(reference_line_info, &decisions)) { AERROR << "Failed to apply traffic rule manager"; return false; } reference_line_info.SetDecision(decisions); return true; } ``` 决策规划是基于当前环境信息和规划的路径等输入信息,实时生成控制命令的过程。在Apollo Planning决策规划算法中,决策规划阶段根据当前参考线、障碍物等信息生成决策。该算法根据不同的规则和策略,生成不同的控制命令,以保证车辆安全、有效地运行。 综上,Apollo Planning决策规划算法自动驾驶系统中重要的规划算法之一,它通过路线规划、运动规划和决策规划三个步骤,实现了安全、有效和符合路况的路径规划,为自动驾驶车辆的控制提供了重要的支持。 ### 回答3: Apollo Planning(阿波罗规划)是百度自动驾驶平台Apollo中的一种决策规划算法,主要用于规划车辆的驾驶行为。该算法基于深度强化学习,使用了运动学模型和环境感知技术,可以根据车辆当前位置和目的地,生成一条最优的行驶路径,包括车辆的控制指令和行驶速度等。 该算法的核心技术是深度强化学习,它通过对驾驶过程进行大量的仿真,让计算机通过自我学习得到驾驶规则,使车辆能够根据不同的场景做出最优的决策。具体而言,算法先通过神经网络生成一系列潜在的行动策略,然后通过与环境进行交互、执行行动并接收环境反馈来评估每个策略的优劣,最终选取最优策略进行执行。 在实现上,Apollo Planning算法主要由四个模块构成:感知模块、规划模块、执行模块和控制模块。感知模块主要用于获取车辆周围环境的信息,包括车辆位置、速度、道路情况、交通灯等;规划模块根据感知模块提供的信息和车辆的目的地,生成一条最优的行驶路径;执行模块则根据规划模块生成的路径信息,实现车辆的自主驾驶;控制模块则根据执行模块生成的控制指令,控制车辆的加速、刹车、转向等行为。 在算法实现上,Apollo Planning采用了C++编程语言,结合ROS框架实现各模块之间的数据交互和代码复用,保证了算法的高效性和可维护性。算法代码实现方面还采用了许多优化技术,包括多线程并发执行、高效的数据结构和算法等,以提升算法的运行效率和稳定性。 总之,Apollo Planning是一种基于深度强化学习的决策规划算法,具有高效、自主、可靠等特点,在智能驾驶领域具有广泛应用前景。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值