网上有许多dubins曲线的介绍,但我看了都迷迷糊糊的,所以我还是参考一些博客和论文自己再手推一遍,加深理解。
为了更好地阐述Dubins 曲线,这里我们简单地介绍一种车辆简化运动学模型。关于详细的车辆运动学模型介绍可以参考前文。
设车辆的转弯半径为:
R = L tan δ f R=\frac{L}{\tan {\delta_{f}}} R=tanδfL
其中 L L L 为前轴到后轴的长度, δ f \delta_{f} δf 为最大前轮转角。
而简化的运动学模型方程可以表示为:
x ˙ = v cos θ y ˙ = v sin θ θ ˙ = ω = v R \begin{aligned} &\dot{x}=v \cos {\theta} \\ &\dot{y}=v \sin {\theta} \\ &\dot{\theta}=\omega=\frac{v}{R} \end{aligned} x˙=vcosθy˙=vsinθθ˙=ω=Rv
其中 θ \theta θ 为偏航角, v v v为纵向速度, ω \omega ω为角速度。
将上述运动学方程离散化,取采样时间为 d t dt dt,则有
x new = x p r e v + v ⋅ cos ( θ ) ⋅ d t y new = y p r e v + v ⋅ sin ( θ ) ⋅ d t θ new = θ p r e v + v R ⋅ d t \begin{aligned} &x_{\text {new }}=x_{\mathrm{prev}}+v \cdot \cos(\theta) \cdot dt \\ &y_{\text {new }}=y_{\mathrm{prev}}+v \cdot \sin(\theta) \cdot dt \\ &\theta_{\text {new }}=\theta_{\mathrm{prev}}+\frac{v}{R}\cdot dt \end{aligned} xnew =xprev+v⋅cos(θ)⋅dtynew =yprev+v⋅sin(θ)⋅dtθnew =θprev+Rv⋅dt
显然,取 d t dt dt越小,得到的离散点坐标越多。令 Δ s = v d t \Delta s=v dt Δs=vdt ,则有:
x new = x p r e v + Δ s ⋅ cos ( θ ) y new = y p r e v + Δ s ⋅ sin ( θ ) θ new = θ p r e v + Δ s R \begin{aligned} &x_{\text {new }}=x_{\mathrm{prev}}+\Delta s \cdot \cos (\theta) \\ &y_{\text {new }}=y_{\mathrm{prev}}+\Delta s \cdot \sin (\theta) \\ &\theta_{\text {new }}=\theta_{\mathrm{prev}}+\frac{\Delta s}{R} \end{aligned} xnew =xprev+Δs⋅cos(θ)ynew =yprev+Δs⋅sin(θ)θnew =θprev+RΔs
Dubins 曲线不考虑车辆后退(汽车只能朝前开),且不允许出现尖瓣。Dubins曲线是在满足曲率约束和规定的始端和末端的切线方向的条件下,连接两个二维平面(即X-Y平面)的最短路径。Dubins曲线如下图所示。
Dubins曲线可以表示成3个运动基本动作的组合(即左转 L L L、右转 R R R、直行 S S S),一般将一种组合称之为一种word
。
符号 | 含义 | 绕单位圆 |
---|---|---|
L | 左转 | 逆时针 |
R | 右转 | 顺时针 |
S | 直走 | 直走 |
Dubins 给出了充分的路径集合,该集合里所包含的曲线叫做最佳路径。但是这个充分集合很小,对于每种特定终点情况下的集合中,最多只有6条可选曲线,分别表示如下:
{ L R L L S L L S R R L R R S R R S L } (1) \tag{1} \left\{\begin{array}{lllllll} L R L & L S L & L S R & R L R & R S R & R S L \end{array}\right\} {LRLLSLLSRRLRRSRRSL}(1)
为什么是6条可选的曲线?
由于连续两次做同一种基本运动和做一次基本运动是等效的,所以 word
经过排列组合后的有效种类有12个(除了上述6个还有其余6个: S L S , S R S , S L R , S R L , R L S , L R S SLS, SRS, SLR, SRL, RLS, LRS SLS,SRS,SLR,SRL,RLS,LRS)。论文又证明最短路径只在12种中的6种word中即公式(1)去选取。
Dubins 证明了,一个最优路径一定是由分段圆弧 (单位圆) 和线段组成的平滑曲线,且最多 3 部分组成。可以进一步简化表示为如下形式:
C C C → { L R L R L R } C S C → { L S L R S R L S R R S L } (2) \tag{2} \begin{array}{llllllll} C C C & \rightarrow & \{ & L R L & R L R & \}\\ C S C & \rightarrow & \{ & L S L & R S R & L S R & R S L & \} \end{array} CCCCSC→→{{LRLLSLRLRRSR}LSRRSL}(2)
等式 (2) 中符号含义如下:
符号 | 含义 |
---|---|
C | 单位圆弧 |
S | 一条直线段 |
一个word
表示相应的一类路径,对于 L L L和 R R R,其下标表示旋转的角度;对于 S S S,其下标表示行驶的直线距离。比如下图的 ( R α S d L γ ) (R_{\alpha}S_{d}L_{\gamma}) (RαSdLγ) 。
综上,Dubins曲线路径被定义为:
在最大曲率限制下,平面内两个有方向的点间的最短可行路径是 C L C CLC CLC路径或 C C C CCC CCC路径,或是他们的子集,其中 C C C表示圆弧段, L L L表示与 C C C相切的直线段。
可能的疑惑:
两点之间不是直线最短吗,为什么要加入圆弧?
因为这是在带有方向的初始位置 (起始位姿点)和终止位置 (终止位姿点)间寻找最短路径,所以这是两个位姿点间的最短路径,而不是单纯的两个坐标点间的最短路径。
最短路径在最小半径的时候取到的前提是在无障碍的情况下
对于 C S C CSC CSC轨迹来说,它包括: R S R , L S R , R S L , 和 L S R RSR, LSR, RSL, 和 LSR RSR,LSR,RSL,和LSR四种情况,下图是 R S R RSR RSR的轨迹情况:
对于四组圆的组合: R R , L L , R L , L R RR, LL, RL, LR RR,LL,RL,LR,他们之间的切线如下图所示,其中蓝色箭头表示开始的运动方向,绿色箭头表示结束时的运动方向。
C C C CCC CCC轨迹是另一组完全不同的轨迹,包括 L R L 和 R L R L R L 和R L R LRL和RLR。它们由一个方向的转弯组成,然后朝相反的方向组成,然后再进行另一个转弯,如下图所示的RLR轨迹。
计算的关键
对于给定的两个圆的圆心位置,如何计算切点位置。
对于 C S C CSC CSC类型的组合,其关键是根据起终点出发的两个圆,计算出一条切线,由于起终点的方向性,这条切线唯一。
对于 C C C CCC CCC类型的组合,其关键是计算过渡切圆的位置。
如图, L S L LSL LSL和 R S R RSR RSR的示意图如下:
|
|
由于 L S L LSL LSL和 R S R RSR RSR的推导是完全一致的,因此以上面任意一幅图为例进行推导都行。
为了推导方便,我们这里将起点圆和终点圆的最小转弯半径分别用了两个符号表示,并且画出的起点和终点圆的大小不同,但实际上最小转弯半径是一样的。
假设两个最小转弯半径构成的圆,半径大小分别为 r 1 r_1 r1和 r 2 r_2 r2,圆心分别为 o 1 o_1 o1和 o 2 o_2 o2,两个切点分别为 t 1 t_1 t1和 t 2 t_2 t2。两个圆心间的连线构成向量 V 1 V_1 V1,两个切点之间的连线(即切线)构成向量 V 2 V_2 V2,切线的单位法向量为 n n n,他们的方向分别如图所示。
显然,单位法向量 n n n与两圆心到切点的连线(即 o 1 t 1 o_1t_1 o1t1, o 2 t 2 o_2t_2 o2t2)是平行的。
我们需要求解的问题是:已知圆心位置和半径的前提下,求切点。
根据已知条件, V 2 ⊥ n V_2 \perp n V2⊥n,显然有
V 2 ⋅ n = 0 V_2 \cdot n =0 V2⋅n=0
在四边形 o 1 o 2 t 2 t 1 o_1o_2t_2t_1 o1o2t2t1中,根据向量的几何关系(注意向量定义的方向)有
V 2 = − o 1 t 1 ⃗ + V 1 + o 2 t 2 ⃗ (3) \tag{3} V_2=-\vec{o_1t_1}+V_1+\vec{o_2t_2} V2=−o1t1+V1+o2t2(3)
由图几何关系可知
o 1 t 1 ⃗ = r 1 ⋅ n o 2 t 2 ⃗ = r 2 ⋅ n (4) \tag{4} \vec{o_1t_1}=r_1\cdot n\\ \vec{o_2t_2}=r_2\cdot n o1t1=r1⋅no2t2=r2⋅n(4)
所以
V 2 = V 1 + ( r 2 − r 1 ) ⋅ n (5) \tag{5} V_2=V_1+(r_2-r_1)\cdot n V2=V1+(r2−r1)⋅n(5)
等式(5)两边右乘单位法向量 n n n,得
V 2 ⋅ n = ( V 1 + ( r 2 − r 1 ) ⋅ n ) ⋅ n ⇓ 0 = ( V 1 + ( r 2 − r 1 ) ⋅ n ) ⋅ n ⇓ 0 = V 1 ⋅ n + r 2 − r 1 ⇓ V 1 ⋅ n = r 1 − r 2 (6) \tag{6} \begin{aligned} V_2\cdot n &=(V_1+(r_2-r_1)\cdot n)\cdot n\\ & \Downarrow\\ 0 &=(V_1+(r_2-r_1)\cdot n)\cdot n\\ & \Downarrow\\ 0 &=V_1\cdot n+r_2-r_1\\ & \Downarrow\\ V_1\cdot n &=r_1-r_2 \end{aligned} V2⋅n00V1⋅n=(V1+(r2−r1)⋅n)⋅n⇓=(V1+(r2−r1)⋅n)⋅n⇓=V1⋅n+r2−r1⇓=r1−r2(6)
进一步地,记 V 1 V_1 V1模长为 D D D,将单位化后的 V 1 V_1 V1记为 V 1 D = V 1 n \frac{V_1}{D}=V_{1n} DV1=V1n,将等式(6)两边同除以 D D D,由于 V 1 n V_{1n} V1n和 n n n都是单位向量,故得
V 1 ⋅ n D = r 1 − r 2 D ⇓ V 1 n ⋅ n = r 1 − r 2 D ⇓ V 1 n ⋅ n = c ⇓ V 1 n ⋅ n = ∣ ∣ V 1 n ∣ ∣ ⋅ ∣ ∣ n ∣ ∣ ⋅ cos θ = cos θ = c (7) \tag{7} \begin{aligned} \frac{V_1\cdot n}{D} &=\frac{r_1-r_2}{D}\\ & \Downarrow\\ V_{1n}\cdot n&=\frac{r_1-r_2}{D}\\ & \Downarrow\\ V_{1n}\cdot n&=c\\ & \Downarrow\\ V_{1n}\cdot n&=||V_{1n}||\cdot||n||\cdot \cos{\theta}=\cos{\theta}=c\\ \end{aligned} DV1⋅nV1n⋅nV1n⋅nV1n⋅n=Dr1−r2⇓=Dr1−r2⇓=c⇓=∣∣V1n∣∣⋅∣∣n∣∣⋅cosθ=cosθ=c(7)
式中 c = r 1 − r 2 D = cos θ c=\frac{r_1-r_2}{D}=\cos{\theta} c=Dr1−r2=cosθ, θ \theta θ是 V 1 V_1 V1和 n n n的夹角,显然 sin θ = 1 − c 2 \sin{\theta}=\sqrt{1-c^2} sinθ=1−c2。
假设 V 1 n = ( v 1 n x , v 1 n y ) V_{1n}=(v_{1nx},v_{1ny}) V1n=(v1nx,v1ny), n = ( n x , n y ) n=(n_{x},n_{y}) n=(nx,ny),将之代入公式(7),化简后可求出 n n n:
{ n x = v 1 n x ∗ c − v 1 n y ∗ 1 − c 2 n y = v 1 n y ∗ c + v 1 n x ∗ 1 − c 2 (8-1) \tag{8-1} \left\{\begin{array}{l} n_{x}=v_{1 {nx}} * c-v_{1 {ny}} * \sqrt{1-c^{2}} \\ n_{y}=v_{1 {ny}} * c+v_{1 {nx}} * \sqrt{1-c^{2}} \end{array} \right. {nx=v1nx∗c−v1ny∗1−c2ny=v1ny∗c+v1nx∗1−c2(8-1)
因为向量 V 1 n V_{1n} V1n旋转角度 θ \theta θ就得到了向量 n n n,所以根据向量旋转的数学计算也可得出。
计算出 n n n之后,就可以很方便的计算出两个切点:从圆心 o 1 o_1 o1出发,沿着向量 n n n的方向,走过半径 r 1 r_1 r1的距离即为切点 t 1 t_1 t1; t 2 t_2 t2同理。
即起点圆的切点坐标 ( x t 1 , y t 1 ) (x_{t1},y_{t1}) (xt1,yt1)为:
x t 1 = x o 1 + r 1 ∗ n x y t 1 = y o 1 + r 1 ∗ n y (8-2) \tag{8-2} x_{t1}=x_{o1}+r_1*n_x\\ y_{t1}=y_{o1}+r_1*n_y\\ xt1=xo1+r1∗nxyt1=yo1+r1∗ny(8-2)
终点圆的切点坐标 ( x t 2 , y t 2 ) (x_{t2},y_{t2}) (xt2,yt2)为:
x t 2 = x o 2 + r 2 ∗ n x y t 2 = y o 2 + r 2 ∗ n y (8-3) \tag{8-3} x_{t2}=x_{o2}+r_2*n_x\\ y_{t2}=y_{o2}+r_2*n_y\\ xt2=xo2+r2∗nxyt2=yo2+r2∗ny(8-3)
R S L RSL RSL和 L S R LSR LSR的推导过程与上一小节完全类似。
|
|
由于 R S L RSL RSL和 L S R LSR LSR的推导是完全一致的,因此以上面任意一幅图为例进行推导。在四边形 o 1 t 1 t 2 o 2 o_1t_1t_2o_2 o1t1t2o2中,根据向量的几何关系有
V 2 = − o 1 t 1 ⃗ + V 1 + o 2 t 2 ⃗ V_2=-\vec{o_1t_1}+V_1+\vec{o_2t_2} V2=−o1t1+V1+o2t2
由图中几何关系可知
o 1 t 1 ⃗ = − r 1 ⋅ n o 2 t 2 ⃗ = r 2 ⋅ n \vec{o_1t_1}=-r_1\cdot n\\ \vec{o_2t_2}=r_2\cdot n o1t1=−r1⋅no2t2=r2⋅n
所以
V 2 = V 1 + ( r 2 + r 1 ) ⋅ n (9) \tag{9} V_2=V_1+(r_2+r_1)\cdot n V2=V1+(r2+r1)⋅n(9)
等式(9)两边右乘 n n n,得
V 2 ⋅ n = ( V 1 + ( r 2 + r 1 ) ⋅ n ) ⋅ n ⇓ 0 = ( V 1 + ( r 2 + r 1 ) ⋅ n ) ⋅ n ⇓ 0 = V 1 ⋅ n + r 2 + r 1 ⇓ V 1 ⋅ n = − r 1 − r 2 (10) \tag{10} \begin{aligned} V_2\cdot n &=(V_1+(r_2+r_1)\cdot n)\cdot n\\ & \Downarrow\\ 0 &=(V_1+(r_2+r_1)\cdot n)\cdot n\\ & \Downarrow\\ 0 &=V_1\cdot n+r_2+r_1\\ & \Downarrow\\ V_1\cdot n &=-r_1-r_2 \end{aligned} V2⋅n00V1⋅n=(V1+(r2+r1)⋅n)⋅n⇓=(V1+(r2+r1)⋅n)⋅n⇓=V1⋅n+r2+r1⇓=−r1−r2(10)
进一步地,记 V 1 V_1 V1模长为 D D D,将单位化后的 V 1 V_1 V1记为 V 1 D = V 1 n \frac{V_1}{D}=V_{1n} DV1=V1n,将等式(10)两边同除以 D D D,由于 V 1 n V_{1n} V1n和 n n n都是单位向量,故得
V 1 ⋅ n D = − r 1 − r 2 D ⇓ V 1 n ⋅ n = − r 1 − r 2 D ⇓ V 1 n ⋅ n = c ⇓ V 1 n ⋅ n = ∣ ∣ V 1 n ∣ ∣ ⋅ ∣ ∣ n ∣ ∣ ⋅ cos θ = cos θ = c (11) \tag{11} \begin{aligned} \frac{V_1\cdot n}{D} &=\frac{-r_1-r_2}{D}\\ & \Downarrow\\ V_{1n}\cdot n&=\frac{-r_1-r_2}{D}\\ & \Downarrow\\ V_{1n}\cdot n&=c\\ & \Downarrow\\ V_{1n}\cdot n&=||V_{1n}||\cdot||n||\cdot \cos{\theta}=\cos{\theta}=c\\ \end{aligned} DV1⋅nV1n⋅nV1n⋅nV1n⋅n=D−r1−r2⇓=D−r1−r2⇓=c⇓=∣∣V1n∣∣⋅∣∣n∣∣⋅cosθ=cosθ=c(11)
式中 c = − r 1 − r 2 D < 0 c=\frac{-r_1-r_2}{D}<0 c=D−r1−r2<0, θ \theta θ是 V 1 V_1 V1和 n n n的夹角,显然 sin θ = 1 − c 2 \sin{\theta}=\sqrt{1-c^2} sinθ=1−c2,且 θ \theta θ大于90°。
假设 V 1 n = ( v 1 n x , v 1 n y ) V_{1n}=(v_{1nx},v_{1ny}) V1n=(v1nx,v1ny), n = ( n x , n y ) n=(n_{x},n_{y}) n=(nx,ny),将之代入公式(11),化简后可求出 n n n:
{ n x = v 1 n x ∗ c + v 1 n y ∗ 1 − c 2 n y = v 1 n y ∗ c − v 1 n x ∗ 1 − c 2 (12-1) \tag{12-1} \left\{\begin{array}{l} n_{x}=v_{1 {nx}} * c+v_{1 {ny}} * \sqrt{1-c^{2}} \\ n_{y}=v_{1 {ny}} * c-v_{1 {nx}} * \sqrt{1-c^{2}} \end{array}\right. {nx=v1nx∗c+v1ny∗1−c2ny=v1ny∗c−v1nx∗1−c2(12-1)
因为向量 V 1 n V_{1n} V1n旋转角度 θ \theta θ就得到了向量 n n n,所以根据向量旋转的数学计算也可得出。
计算出 n n n之后,就可以很方便的计算出两个切点:从圆心 o 1 o_1 o1出发,沿着向量 o 1 t 1 ⃗ \vec{o_1t_1} o1t1的方向(即 n n n的反方向),走过半径 r 1 r_1 r1的距离即为切点 t 1 t_1 t1; t 2 t_2 t2同理。
即起点圆的切点坐标 ( x t 1 , y t 1 ) (x_{t1},y_{t1}) (xt1,yt1)为:
x t 1 = x o 1 − r 1 ∗ n x y t 1 = y o 1 − r 1 ∗ n y (12-2) \tag{12-2} x_{t1}=x_{o1}-r_1*n_x\\ y_{t1}=y_{o1}-r_1*n_y\\ xt1=xo1−r1∗nxyt1=yo1−r1∗ny(12-2)
终点圆的切点坐标 ( x t 2 , y t 2 ) (x_{t2},y_{t2}) (xt2,yt2)为:
x t 2 = x o 2 + r 2 ∗ n x y t 2 = y o 2 + r 2 ∗ n y (12-3) \tag{12-3} x_{t2}=x_{o2}+r_2*n_x\\ y_{t2}=y_{o2}+r_2*n_y\\ xt2=xo2+r2∗nxyt2=yo2+r2∗ny(12-3)
假设已知起点 s = ( x 1 , y 1 , θ 1 ) s=\left(x_{1}, y_{1}, \theta_{1}\right) s=(x1,y1,θ1) 和终点 g = ( x 2 , y 2 , θ 2 ) g=\left(x_{2}, y_{2}, \theta_{2}\right) g=(x2,y2,θ2) , θ 1 , θ 2 \theta_1,\theta_2 θ1,θ2表示航向角。然后我们计算起点圆和终点圆的圆心。
(1) 当车辆右转时
如上图所示,根据几何关系,圆心 o 1 o_1 o1的坐标 ( x o 1 , y o 1 ) (x_{o1},y_{o1}) (xo1,yo1)可以表示为
{ x o 1 = x 1 + r 1 ∗ cos ( 180 ° − α 1 ) y o 1 = y 1 − r 1 ∗ s i n ( 180 ° − α 1 ) (13) \tag{13} \left\{\begin{array}{l} x_{o1}=x_1+r_1*\cos{(180°-\alpha_1)} \\ y_{o1}=y_1-r_1*sin{(180°-\alpha_1)} \end{array}\right. {xo1=x1+r1∗cos(180°−α1)yo1=y1−r1∗sin(180°−α1)(13)
而 α 1 \alpha_1 α1和 θ 1 \theta_1 θ1的关系为
90 ° − θ 1 + α 1 = 180 ° 90°-\theta_1+\alpha_1=180° 90°−θ1+α1=180°
即
α 1 = 90 ° + θ 1 (14) \tag{14} \alpha_1=90°+\theta_1 α1=90°+θ1(14)
将公式(14)代入公式(13),使用三角函数公式化简后得到起点圆的圆心为:
o 1 = ( x 1 + r 1 ∗ sin θ 1 , y 1 − r 1 ∗ cos θ 1 ) (15) \tag{15} o_{1}=\left(x_{1}+r_{1} * \sin{\theta_1}, y_{1}-r_{1} * \cos{\theta_1}\right) o1=(x1+r1∗sinθ1,y1−r1∗cosθ1)(15)
同理可得,终点圆的圆心为:
o 2 = ( x 2 + r 2 ∗ sin θ 2 , y 2 − r 2 ∗ cos θ 2 ) (16) \tag{16} o_{2}=\left(x_{2}+r_{2} * \sin{\theta_2}, y_{2}-r_{2} * \cos{\theta_2}\right) o2=(x2+r2∗sinθ2,y2−r2∗cosθ2)(16)
(2) 当车辆左转时
类似的分析,如上图所示,根据几何关系,圆心 o 1 o_1 o1的坐标 ( x o 1 , y o 1 ) (x_{o1},y_{o1}) (xo1,yo1)可以表示为
{ x o 1 = x 1 + r 1 ∗ cos ( 180 ° − α 1 ) y o 1 = y 1 − r 1 ∗ s i n ( 180 ° − α 1 ) (17) \tag{17} \left\{\begin{array}{l} x_{o1}=x_1+r_1*\cos{(180°-\alpha_1)} \\ y_{o1}=y_1-r_1*sin{(180°-\alpha_1)} \end{array}\right. {xo1=x1+r1∗cos(180°−α1)yo1=y1−r1∗sin(180°−α1)(17)
而 α 1 \alpha_1 α1和 θ 1 \theta_1 θ1的关系为
360 ° − 90 ° − θ 1 + α 1 = 180 ° 360°-90°-\theta_1+\alpha_1=180° 360°−90°−θ1+α1=180°
即
θ 1 = 90 ° + α 1 (18) \tag{18} \theta_1=90°+\alpha_1 θ1=90°+α1(18)
将公式(18)代入公式(17),化简后得到起点圆的圆心为:
o 1 = ( x 1 − r 1 ∗ sin θ 1 , y 1 + r 1 ∗ cos θ 1 ) (19) \tag{19} o_{1}=\left(x_{1}-r_{1} * \sin{\theta_1}, y_{1}+r_{1} * \cos{\theta_1}\right) o1=(x1−r1∗sinθ1,y1+r1∗cosθ1)(19)
同理可得,终点圆的圆心为:
o 2 = ( x 2 − r 2 ∗ sin θ 2 , y 2 + r 2 ∗ cos θ 2 ) (20) \tag{20} o_{2}=\left(x_{2}-r_{2} * \sin{\theta_2}, y_{2}+r_{2} * \cos{\theta_2}\right) o2=(x2−r2∗sinθ2,y2+r2∗cosθ2)(20)
C S C CSC CSC类型曲线轨迹求解流程:
首先得到起点圆和终点圆的圆心,然后计算出两个圆的切点,计算出切点后,车辆便可以沿着最小转弯半径构成的圆周行驶到第一个圆的切点,然后直行到第二个圆的切点,再沿着最小转弯半径构成的圆周行驶到目的地。
通过2.1.2小节计算得到起点和终点圆的圆心之后,利用2.1.1小节的切点计算方法,便可以得到切点。然后就可以得到车辆的行驶轨迹,该轨迹分为三段:start到切点 t 1 t_1 t1的圆周弧; t 1 t_1 t1和 t 2 t_2 t2的直线距离; t 2 t_2 t2到End的圆周弧。至此我们便得到了 C S C CSC CSC的行驶曲线。
下面参考资料2的matlab程序,写了python代码,并没有考虑最优路径。
import numpy as np
import matplotlib.pyplot as plt
"""Dubins Curve CSC型
"""
#目标定义
#定义起终点[x y dir]
S = np.array([1, 1, 7 * np.pi / 4])
G = np.array([6, 8, 3 * np.pi / 4])
#定义转弯半径
ri = 1
rg = 1
#组合
i = -1 # 1:右转,-1:左转 ---起点圆
j = 1 # 1:右转,-1:左转 ---终点圆
k = i*j # 1:RSR/LSL, -1: RSL/LSR
"""计算首尾圆心坐标"""
xi = S[0] + ri * i * np.sin(S[2])
yi = S[1] - ri * i * np.cos(S[2])
xg = G[0] + rg * j * np.sin(G[2])
yg = G[1] - rg * j * np.cos(G[2])
"""计算法向量"""
#起终点圆圆心之间的向量V1=[v1x,v1y]
v1x = xg - xi
v1y = yg - yi
# V1模长
D = np.sqrt(v1x * v1x + v1y * v1y)
# 单位化
v1x = v1x / D
v1y = v1y / D
#计算法向量n
c = (k * ri - rg) / D
nx = v1x * c - j * v1y * np.sqrt(1 - c * c)
ny = v1y * c + j * v1x * np.sqrt(1 - c * c)
"""计算起终点圆的切点"""
xit = xi + k * ri * nx
yit = yi + k * ri * ny
xgt = xg + rg * nx
ygt = yg + rg * ny
# print(xgt-xg,ygt-yg)
# print(nx,ny)
"""绘图"""
# # 画起终点的初始方向
xiDir = np.array([S[0], S[0]+ri*np.cos(S[2])])
yiDir = np.array([S[1], S[1]+ri*np.sin(S[2])])
xgDir = np.array([G[0], G[0]+rg*np.cos(G[2])])
ygDir = np.array([G[1], G[1]+rg*np.sin(G[2])])
#切点连线即切线
tangent_x = np.array([xit, xgt])
tangent_y = np.array([yit, ygt])
# 画出首尾圆
t = np.arange(0, 2 * np.pi+0.01, 0.01)
# t = np.arange(S[2] - np.pi / 2, 3 * np.pi / 2 - np.arctan(ny / nx)+0.01, 0.01)
circle_xi = xi + ri * np.cos(t)
circle_yi = yi + ri * np.sin(t)
# t = np.arange(- np.pi / 2 - np.arctan(ny / nx),G[2] - np.pi / 2+0.01,0.01)
circle_xg = xg + rg * np.cos(t)
circle_yg = yg + rg * np.sin(t)
plt.plot(S[0], S[1], 'go', G[0], G[1], 'go', xiDir, yiDir, '-g', xgDir, ygDir, '-g', xi, yi,
'k*', xg, yg, 'k*', circle_xi, circle_yi, '-r', circle_xg, circle_yg, '-r', [xi,xit], [yi,yit], '-b', [xg,xgt],[yg,ygt], '-b', tangent_x, tangent_y, '-r')
plt.axis('equal')
plt.show()
这是 L S R LSR LSR曲线的效果:
|
|
C C C CCC CCC轨迹的推导比较纯几何,假设圆心 o 1 , o 2 o_1,o_2 o1,o2和三个圆的半径已知,则表明三角形 Δ o 1 o 3 o 2 \Delta o_1o_3o_2 Δo1o3o2的边长均已知,首先先求出 V 12 V_{12} V12与水平方向的夹角 β \beta β,然后通过余弦定理可以求出 θ \theta θ,继而根据三角关系,用 o 1 o_1 o1坐标计算 o 3 o_3 o3坐标。
我们假设 o 1 , o 2 , o 3 o_1,o_2,o_3 o1,o2,o3的半径分别为 r 1 , r 2 , r m i d r_{1},r_{2},r_{mid} r1,r2,rmid。
根据数学关系,可得到:
{ ∣ o 1 o 2 ‾ ∣ = D = ( x o 2 − x o 1 ) 2 + ( y o 2 − y o 1 ) 2 ∣ o 1 o 3 ‾ ∣ = r 1 + r m i d ∣ o 2 o 3 ‾ ∣ = r 2 + r m i d (21) \tag{21} \left\{\begin{array}{l} \left|\overline{o_{1} o_{2}}\right|=D=\sqrt{\left(x_{o2}-x_{o1}\right)^{2}+\left(y_{o2}-y_{o1}\right)^{2}} \\ \left|\overline{o_{1} o_{3}}\right|=r_{1 }+r_{mid } \\ \left|\overline{o_{2} o_{3}}\right|=r_{2}+r_{mid} \end{array}\right. ⎩⎪⎨⎪⎧∣o1o2∣=D=(xo2−xo1)2+(yo2−yo1)2∣o1o3∣=r1+rmid∣o2o3∣=r2+rmid(21)
根据余弦定理有:
θ = cos − 1 ( ∣ o 1 o 3 ‾ ∣ 2 + ∣ o 1 o 2 ‾ ∣ 2 − ∣ o 2 o 3 ‾ ∣ 2 2 ⋅ ∣ o 1 o 3 ‾ ∣ ⋅ ∣ o 1 o 2 ‾ ∣ ) (22) \tag{22} \theta=\cos ^{-1}\left( \frac{\left|\overline{o_{1} o_{3}}\right|^2+\left|\overline{o_{1} o_{2}}\right|^2-\left|\overline{o_{2} o_{3}}\right|^2}{2\cdot \left|\overline{o_{1} o_{3}}\right| \cdot \left|\overline{o_{1} o_{2}}\right|}\right) θ=cos−1(2⋅∣o1o3∣⋅∣o1o2∣∣o1o3∣2+∣o1o2∣2−∣o2o3∣2)(22)
最终可得到:
o 3 = ( x 1 + ∣ o 1 o 3 ‾ ∣ ⋅ cos ( β − θ ) , y 1 + ∣ o 1 o 3 ‾ ∣ ⋅ sin ( β − θ ) ) (23) \tag{23} o_{3}=\left(x_{1}+ \left|\overline{o_{1} o_{3}}\right| \cdot \cos (\beta-\theta), y_{1}+\left|\overline{o_{1} o_{3}}\right| \cdot \sin (\beta-\theta)\right) o3=(x1+∣o1o3∣⋅cos(β−θ),y1+∣o1o3∣⋅sin(β−θ))(23)
解出 o 3 o_3 o3坐标后,只需从 o 1 o_1 o1出发,沿 V 13 V_{13} V13( V 13 = o 3 − o 1 V_{13}=o_3-o_1 V13=o3−o1,其他同理)走过半径 r 1 r_1 r1的距离,即可得到第一个切点,同理沿 V 32 V_{32} V32方向,可得第二个切点位置。
定义向量 V 13 = o 3 − o 1 V_{13}=o_{3}-o_{1} V13=o3−o1 ,则切点 t 1 t_1 t1的坐标为 。
t 1 = o 1 + V 13 ∥ V 13 ∥ ∗ r 1 (24) \tag{24} t_1=o_{1}+\frac{V_{13}}{\left\|V_{13}\right\|} * r_{1} t1=o1+∥V13∥V13∗r1(24)
按照同样的过程可以计算得到 t 2 t_2 t2 。然后就可以得到起点到切点 t 1 t_1 t1的圆周弧; t 1 t_1 t1和 t 2 t_2 t2之间的圆周弧; t 2 t_2 t2到终点的圆周弧的三段轨迹组成的行驶曲线。
说明
一般地,对于最优情况来说,我们假设 o 1 , o 2 , o 3 o_1,o_2,o_3 o1,o2,o3具有最小转弯半径 r m i n r_{min} rmin。
根据数学关系,可得到:
{ ∣ o 1 o 2 ‾ ∣ = D = ( x o 2 − x o 1 ) 2 + ( y o 2 − y o 1 ) 2 ∣ o 1 o 3 ‾ ∣ = 2 r min ∣ o 2 o 3 ‾ ∣ = 2 r min (25) \tag{25} \left\{\begin{array}{l} \left|\overline{o_{1} o_{2}}\right|=D=\sqrt{\left(x_{o2}-x_{o1}\right)^{2}+\left(y_{o2}-y_{o1}\right)^{2}} \\ \left|\overline{o_{1} o_{3}}\right|=2 r_{\min } \\ \left|\overline{o_{2} o_{3}}\right|=2 r_{\min } \end{array}\right. ⎩⎪⎨⎪⎧∣o1o2∣=D=(xo2−xo1)2+(yo2−yo1)2∣o1o3∣=2rmin∣o2o3∣=2rmin(25)
此时三角形 Δ o 1 o 3 o 2 \Delta o_1o_3o_2 Δo1o3o2为等腰三角形,根据余弦定理,有:
θ = cos − 1 ( D 2 2 r min ) = cos − 1 ( D 4 r min ) (26) \tag{26} \theta=\cos ^{-1}\left(\frac{\frac{D}{2}}{2 r_{\min }}\right)=\cos ^{-1}\left(\frac{D}{4 r_{\min }}\right) θ=cos−1(2rmin2D)=cos−1(4rminD)(26)
最终可得到:
o 3 = ( x 1 + 2 r min cos ( β − θ ) , y 1 + 2 r min sin ( β − θ ) ) (27) \tag{27} o_{3}=\left(x_{1}+2 r_{\min } \cos (\beta-\theta), y_{1}+2 r_{\min } \sin (\beta-\theta)\right) o3=(x1+2rmincos(β−θ),y1+2rminsin(β−θ))(27)
参考资料A Comprehensive, Step-by-Step Tutorial to Computing Dubin’s Paths 中的这一段没理解,先放在这,有知道的朋友们欢迎帮忙解释一下。
下面参考资料2的matlab程序,写了python代码,并没有考虑最优路径。
import numpy as np
import matplotlib.pyplot as plt
"""
Dubins Curve CCC型
"""
#目标定义
#定义起终点[x y psi]
S = np.array([1, 1, 7 * np.pi / 4])
G = np.array([4, 5, 3 * np.pi / 4])
#定义转弯半径
ri = 1
rg = 1
rmid = 1
i = -1 # 1:右转,-1:左转
"""计算首尾圆心坐标及其连线向量V12"""
xi = S[0] + ri * i * np.sin(S[2])
yi = S[1] - ri * i * np.cos(S[2])
xg = G[0] + rg * i * np.sin(G[2])
yg = G[1] - rg * i * np.cos(G[2])
V12 = np.array([xg - xi,yg - yi])
angleV12 = np.arctan(V12[1] / V12[0])
"""计算中间圆坐标及三圆心连线向量V13、V32"""
d12 = np.sqrt((xg - xi) ** 2 + (yg - yi) ** 2)
rmid = np.max(np.array([rmid, (d12 - ri - rg) * 0.5]))
d13 = ri + rmid
d32 = rmid + rg
angleP213 = np.arccos((d12 ** 2 + d13 ** 2 - d32 ** 2) / (2 * d12 * d13)) # 余弦定理
xmid = xi + d13 * np.cos(angleV12 - angleP213)
ymid = yi + d13 * np.sin(angleV12 - angleP213)
V13 = np.array([xmid - xi,ymid - yi])
V32 = np.array([xg - xmid,yg - ymid])
Vn13 = V13 / d13 # 归一化
Vn32 = V32 / d32
"""计算切点坐标"""
xt1 = xi + ri * Vn13[0]
yt1 = yi + ri * Vn13[1]
xt2 = xmid + rmid * Vn32[0]
yt2 = ymid + rmid * Vn32[1]
"""绘图"""
# # 画起终点的初始方向
xiDir = np.array([S[0], S[0]+ri*np.cos(S[2])])
yiDir = np.array([S[1], S[1]+ri*np.sin(S[2])])
xgDir = np.array([G[0], G[0]+rg*np.cos(G[2])])
ygDir = np.array([G[1], G[1]+rg*np.sin(G[2])])
# 画出首尾圆
t = np.arange(0, 2 * np.pi+0.01, 0.01)
circle_xi = xi + ri * np.cos(t)
circle_yi = yi + ri * np.sin(t)
circle_xg = xg + rg * np.cos(t)
circle_yg = yg + rg * np.sin(t)
circle_xmid = xmid + rmid * np.cos(t)
circle_ymid = ymid + rmid * np.sin(t)
#绘图
plt.plot(S[0],S[1],'go',G[0],G[1],'go',xiDir,yiDir,'-g',xgDir,ygDir,'-g',xi,yi,'k*',xg,yg,'k*',xmid,ymid,'k*',xt1,yt1,'bo',xt2,yt2,'bo',circle_xi,circle_yi,'-r',circle_xg,circle_yg,'-r',circle_xmid,circle_ymid,'-r')
plt.axis('equal')
plt.show()
这是 L R L LRL LRL曲线的实现效果: