【动手学运动规划】2.6 Reeds Shepp曲线

我出来打工,我不惦记钱,我惦记什么? — 武林外传 黄豆豆

代码及环境配置:请参考 环境配置和代码运行!


Reeds Shepp,通常简称为RS曲线,是一种用于路径规划的算法,由J.A.Reeds和L.A.Shepp在1990年的论文《Optimal Paths for a Car That Goes Both Forwards and Backwards》中提出。该算法主要用于描述机器人或车辆在平面上的运动轨迹,特别是在需要考虑车辆前进和后退的情况下,寻找从起点到终点的最短路径。

【动手学运动规划】2.6 Reeds Shepp曲线_第1张图片

2.4.1 Reeds Shepp曲线定义

简单的说, Reeds Shepp曲线在Dubins曲线的基础上,允许切换车辆行驶方向,这在某些情况下能够找到比Dubins曲线更短的路径。

Dubins曲线有6种组合方式, 以LSL为例, Reeds Shepp曲线为每一个运动基元都增加了前进( + + +)和后退( − - ), 就有了以下8种组合:

L + S + L + ,   L + S + L − ,   L + S − L + ,   L + S − L − , L − S − L + ,   L − S + L + ,   L − S + L − ,   L − S − L − ,   L^+S^+L^+,\ L^+S^+L^-,\ L^+S^-L^+,\ L^+S^-L^-,\\ L^-S^-L^+,\ L^-S^+L^+,\ L^-S^+L^-,\ L^-S^-L^-,\ L+S+L+, L+S+L, L+SL+, L+SL,LSL+, LS+L+, LS+L, LSL, 

如果用 ∣ | 表示车辆运动朝向反转, 可以简写成下表表示所有的组合:

 Base  α β γ d C α ∣ C β ∣ C γ [ 0 , π ] [ 0 , π ] [ 0 , π ] − C α ∣ C β C γ [ 0 , β ] [ 0 , π / 2 ] [ 0 , β ] − C α C β ∣ C γ [ 0 , β ] [ 0 , π / 2 ] [ 0 , β ] − C α S d C γ [ 0 , π / 2 ] − [ 0 , π / 2 ] ( 0 , ∞ ) C α C β ∣ C β C γ [ 0 , β ] [ 0 , π / 2 ] [ 0 , β ] − C α ∣ C β C β ∣ C γ [ 0 , β ] [ 0 , π / 2 ] [ 0 , β ] − C α ∣ C π / 2 S d C π / 2 ∣ C γ [ 0 , π / 2 ] − [ 0 , π / 2 ] ( 0 , ∞ ) C α ∣ C π / 2 S d C γ [ 0 , π / 2 ] − [ 0 , π / 2 ] ( 0 , ∞ ) C α S d C π / 2 C γ [ 0 , π / 2 ] − [ 0 , π / 2 ] ( 0 , ∞ ) \begin{array}{|l|l|l|l|l|}\hline \text { Base } & \alpha & \beta & \gamma & d \\\hline \hline C_\alpha\left|C_\beta\right| C_\gamma & {[0, \pi]} & {[0, \pi]} & {[0, \pi]} & - \\\hline C_\alpha \mid C_\beta C_\gamma & {[0, \beta]} & {[0, \pi / 2]} & {[0, \beta]} & - \\\hline C_\alpha C_\beta \mid C_\gamma & {[0, \beta]} & {[0, \pi / 2]} & {[0, \beta]} & - \\\hline C_\alpha S_d C_\gamma & {[0, \pi / 2]} & - & {[0, \pi / 2]} & (0, \infty) \\\hline C_\alpha C_\beta \mid C_\beta C_\gamma & {[0, \beta]} & {[0, \pi / 2]} & {[0, \beta]} & - \\\hline C_\alpha\left|C_\beta C_\beta\right| C_\gamma & {[0, \beta]} & {[0, \pi / 2]} & {[0, \beta]} & - \\\hline C_\alpha\left|C_{\pi / 2} S_d C_{\pi / 2}\right| C_\gamma & {[0, \pi / 2]} & - & {[0, \pi / 2]} & (0, \infty) \\\hline C_\alpha \mid C_{\pi / 2} S_d C_\gamma & {[0, \pi / 2]} & - & {[0, \pi / 2]} & (0, \infty) \\\hline C_\alpha S_d C_{\pi / 2} C_\gamma & {[0, \pi / 2]} & - & {[0, \pi / 2]} & (0, \infty) \\\hline\end{array}  Base CαCβCγCαCβCγCαCβCγCαSdCγCαCβCβCγCαCβCβCγCαCπ/2SdCπ/2CγCαCπ/2SdCγCαSdCπ/2Cγα[0,π][0,β][0,β][0,π/2][0,β][0,β][0,π/2][0,π/2][0,π/2]β[0,π][0,π/2][0,π/2][0,π/2][0,π/2]γ[0,π][0,β][0,β][0,π/2][0,β][0,β][0,π/2][0,π/2][0,π/2]d(0,)(0,)(0,)(0,)

弧线的下标代表旋转的角度, 直线S的下标代表距离.

C C C替换为 L L L,或者 R R R ,通过简单的变换,则共有 48 种字段组合

 Base word   Sequences of motion primitives  C ∣ C ∣ C ( L + R − L + ) ( L − R + L − ) ( R + L − R + ) ( R − L + R − ) C C ∣ C ( L + R + L − ) ( L − R − L + ) ( R + L + R − ) ( R − L − R + ) C ∣ C C ( L + R − L − ) ( L − R + L + ) ( R + L − R − ) ( R − L + R + ) C S C ( L + S + L + ) ( L − S − L − ) ( R + S + R + ) ( R − S − R − ) ( L + S + R + ) ( L − S − R − ) ( R + S + L + ) ( R − S − L − ) C C β ∣ C β C ( L + R β + L β − R − ) ( L − R β − L β + R + ) ( R + L β + R β − L − ) ( R − L β − R β + L + ) C ∣ C β C β ∣ C ( L + R β − L β − R + ) ( L − R β + L β + R − ) ( R + L β − R β − L + ) ( R − L β + R β + L − ) C ∣ C π / 2 S C ( L + R π / 2 − S − R − ) ( L − R π / 2 + S + R + ) ( R + L π / 2 − S − L − ) ( R − L π / 2 + S + L + ) ( L + R π / 2 − S − L − ) ( L − R π / 2 + S + L + ) ( R + L π / 2 − S − R − ) ( R − L π / 2 + S + R + ) C S C π / 2 ∣ C ( L + S + L π / 2 + R − ) ( L − S − L π / 2 − R + ) ( R + S + R π / 2 + L − ) ( R − S − R π / 2 − L + ) ( R + S + L π / 2 + R − ) ( R − S − L π / 2 − R + ) ( L + S + R π / 2 + L − ) ( L − S − R π / 2 − L + ) C ∣ C π / 2 S C π / 2 ∣ C ( L + R π / 2 − S − L π / 2 − R + ) ( L − R π / 2 + S + L π / 2 + R − ) ( R + L π / 2 − S − R π / 2 − L + ) ( R − L π / 2 + S + R π / 2 + L − ) \begin{array}{|l|l|}\hline \text { Base word } & \text { Sequences of motion primitives } \\\hline C|C| C & \left(L^{+} R^{-} L^{+}\right)\left(L^{-} R^{+} L^{-}\right)\left(R^{+} L^{-} R^{+}\right)\left(R^{-} L^{+} R^{-}\right) \\\hline C C \mid C & \left(L^{+} R^{+} L^{-}\right)\left(L^{-} R^{-} L^{+}\right)\left(R^{+} L^{+} R^{-}\right)\left(R^{-} L^{-} R^{+}\right) \\\hline C \mid C C & \left(L^{+} R^{-} L^{-}\right)\left(L^{-} R^{+} L^{+}\right)\left(R^{+} L^{-} R^{-}\right)\left(R^{-} L^{+} R^{+}\right) \\\hline C S C & \left(L^{+} S^{+} L^{+}\right)\left(L^{-} S^{-} L^{-}\right)\left(R^{+} S^{+} R^{+}\right)\left(R^{-} S^{-} R^{-}\right) \\& \left(L^{+} S^{+} R^{+}\right)\left(L^{-} S^{-} R^{-}\right)\left(R^{+} S^{+} L^{+}\right)\left(R^{-} S^{-} L^{-}\right) \\\hline C C_\beta \mid C_\beta C & \left(L^{+} R_\beta^{+} L_\beta^{-} R^{-}\right)\left(L^{-} R_\beta^{-} L_\beta^{+} R^{+}\right)\left(R^{+} L_\beta^{+} R_\beta^{-} L^{-}\right)\left(R^{-} L_\beta^{-} R_\beta^{+} L^{+}\right) \\\hline C\left|C_\beta C_\beta\right| C & \left(L^{+} R_\beta^{-} L_\beta^{-} R^{+}\right)\left(L^{-} R_\beta^{+} L_\beta^{+} R^{-}\right)\left(R^{+} L_\beta^{-} R_\beta^{-} L^{+}\right)\left(R^{-} L_\beta^{+} R_\beta^{+} L^{-}\right) \\\hline C \mid C_{\pi / 2} S C & \left(L^{+} R_{\pi / 2}^{-} S^{-} R^{-}\right)\left(L^{-} R_{\pi / 2}^{+} S^{+} R^{+}\right)\left(R^{+} L_{\pi / 2}^{-} S^{-} L^{-}\right)\left(R^{-} L_{\pi / 2}^{+} S^{+} L^{+}\right) \\& \left(L^{+} R_{\pi / 2}^{-} S^{-} L^{-}\right)\left(L^{-} R_{\pi / 2}^{+} S^{+} L^{+}\right)\left(R^{+} L_{\pi / 2}^{-} S^{-} R^{-}\right)\left(R^{-} L_{\pi / 2}^{+} S^{+} R^{+}\right) \\\hline C S C_{\pi / 2} \mid C & \left(L^{+} S^{+} L_{\pi / 2}^{+} R^{-}\right)\left(L^{-} S^{-} L_{\pi / 2}^{-} R^{+}\right)\left(R^{+} S^{+} R_{\pi / 2}^{+} L^{-}\right)\left(R^{-} S^{-} R_{\pi / 2}^{-} L^{+}\right) \\& \left(R^{+} S^{+} L_{\pi / 2}^{+} R^{-}\right)\left(R^{-} S^{-} L_{\pi / 2}^{-} R^{+}\right)\left(L^{+} S^{+} R_{\pi / 2}^{+} L^{-}\right)\left(L^{-} S^{-} R_{\pi / 2}^{-} L^{+}\right) \\\hline C\left|C_{\pi / 2} S C_{\pi / 2}\right| C & \left(L^{+} R_{\pi / 2}^{-} S^{-} L_{\pi / 2}^{-} R^{+}\right)\left(L^{-} R_{\pi / 2}^{+} S^{+} L_{\pi / 2}^{+} R^{-}\right) \\& \left(R^{+} L_{\pi / 2}^{-} S^{-} R_{\pi / 2}^{-} L^{+}\right)\left(R^{-} L_{\pi / 2}^{+} S^{+} R_{\pi / 2}^{+} L^{-}\right) \\\hline\end{array}  Base word CCCCCCCCCCSCCCβCβCCCβCβCCCπ/2SCCSCπ/2CCCπ/2SCπ/2C Sequences of motion primitives (L+RL+)(LR+L)(R+LR+)(RL+R)(L+R+L)(LRL+)(R+L+R)(RLR+)(L+RL)(LR+L+)(R+LR)(RL+R+)(L+S+L+)(LSL)(R+S+R+)(RSR)(L+S+R+)(LSR)(R+S+L+)(RSL)(L+Rβ+LβR)(LRβLβ+R+)(R+Lβ+RβL)(RLβRβ+L+)(L+RβLβR+)(LRβ+Lβ+R)(R+LβRβL+)(RLβ+Rβ+L)(L+Rπ/2SR)(LRπ/2+S+R+)(R+Lπ/2SL)(RLπ/2+S+L+)(L+Rπ/2SL)(LRπ/2+S+L+)(R+Lπ/2SR)(RLπ/2+S+R+)(L+S+Lπ/2+R)(LSLπ/2R+)(R+S+Rπ/2+L)(RSRπ/2L+)(R+S+Lπ/2+R)(RSLπ/2R+)(L+S+Rπ/2+L)(LSRπ/2L+)(L+Rπ/2SLπ/2R+)(LRπ/2+S+Lπ/2+R)(R+Lπ/2SRπ/2L+)(RLπ/2+S+Rπ/2+L)

2.4.2 Reeds Shepp曲线公式

由于公式推导与Dubins曲线大体一致, 不再赘述. 由于Reeds Shepp曲线的不同组合曲线之间存在镜像, 翻转的关系, 并不需要对每一种组合都一一计算. 可以只求解12种组合, 通过时间变换反射变换逆向变换 快速计算剩下的情况. 这里大体介绍一下, 具体公式见参考链接.

2.4.2.1 计算技巧

以下技巧都需要先进行上一节提到的, 转换坐标系和正则化.

(1) 时间翻转(timeflip)

将计算出的曲线按照其运动方向进行取反,得到的新的曲线为原曲线相反的曲线。

L + S + L + L^+S^+L^+ L+S+L+为例, 如果对其曲线沿着y轴翻转, 也就是x坐标取反, 则会得到 L − S − L − L^-S^-L^- LSL曲线.

(2) 反射(reflect)

将计算的曲线按照其沿圆周运动方向取反, 在转换后的坐标系下, 沿着x轴翻转, 也就是y坐标取反.

得到的结果是运动基元取反的组合, L不变.

L + S + L + L^+S^+L^+ L+S+L+为例, 如果对其曲线沿着y轴翻转, 也就是x坐标取反, 则会得到 R + S + R + R^+S^+R^+ R+S+R+曲线.

(3) 向后变换(backwards)

将原曲线的路径逆序转换,得到的曲线与原来的曲线长度相同的新曲线。

得到的结果是运动基元顺序颠倒的组合.

L + S + R + L^+S^+R^+ L+S+R+为例, 如果对其曲线沿着y轴翻转, 也就是x坐标取反, 则会得到 R + S + L + R^+S^+L^+ R+S+L+曲线.

2.4.2.2 不同技巧的组合方式

(1) C ∣ C ∣ C C|C| C CCC

即三段圆弧且每段圆弧两两圆弧方向相反, 基于此, 可以扩展出四种曲线形式:

L + R − L + 、 L − R + L − 、 R + L − R + 、 R − L + R − 。  L^{+} R^{-} L^{+} 、 L^{-} R^{+} L^{-} 、 R^{+} L^{-} R^{+} 、 R^{-} L^{+} R^{-} \text {。 } L+RL+LR+LR+LR+RL+R 

(2) C C ∣ C C C \mid C CCC

即三段圆弧且后两段圆弧的圆弧方向相反, 基于此, 可以扩展出四种曲线形式:

L + R + L − 、 L − R − L + 、 R + L + R − 、 R − L − R + 。  L^{+} R^{+} L^{-} 、 L^{-} R^{-} L^{+} 、 R^{+} L^{+} R^{-} 、 R^{-} L^{-} R^{+} \text {。 } L+R+LLRL+R+L+RRLR+ 

(3) C ∣ C C C \mid C C CCC,

即三段圆弧且前两段圆弧的圆弧方向相反, 基于此, 可以扩展出四种曲线形式:

L + R − L − 、 L − R + L + 、 R + L − R − 、 R − L + R + 。  L^{+} R^{-} L^{-} 、 L^{-} R^{+} L^{+} 、 R^{+} L^{-} R^{-} 、 R^{-} L^{+} R^{+} \text {。 } L+RLLR+L+R+LRRL+R+ 

2.6.c Reeds Shepp曲线代码解析

本节提供了Reeds Shepp曲线的代码测试

python3 tests/curves/reeds_shepp_path_test.py

【动手学运动规划】2.6 Reeds Shepp曲线_第2张图片

2.6.c.1 Reeds Shepp曲线代码实现

Reeds Shepp实现代码框架与上一节Dubins曲线整体类似, 仅做简要描述.

path_functions 中存储了完整的曲线组合接口:

  path_functions = [
      left_straight_left,
      left_straight_right,  # CSC
      left_x_right_x_left,
      left_x_right_left,
      left_right_x_left,  # CCC
      left_right_x_left_right,
      left_x_right_left_x_right,  # CCCC
      left_x_right90_straight_left,
      left_x_right90_straight_right,  # CCSC
      left_straight_right90_x_left,
      left_straight_left90_x_right,  # CSCC
      left_x_right90_straight_left90_x_right,
  ]  # CCSCC

left_straight_left为例, 返回该组合是否生成成功, 旋转角度1:t, 直线距离:u, 旋转角度2:v

def left_straight_left(x, y, phi):
    u, t = polar(x - math.sin(phi), y - 1.0 + math.cos(phi))
    if 0.0 <= t <= math.pi:
        v = mod2pi(phi - t)
        if 0.0 <= v <= math.pi:
            return True, [t, u, v], ["L", "S", "L"]

    return False, [], []

generate_path 中会将生成的有效的RS曲线放到paths 中, 最终在reeds_shepp_path_planning 中挑选总长度最短的组合.

2.6.c.2 Reeds Shepp曲线代码测试

main() 函数中, 生成了一组始末状态的随机数, 调用接口, 并可视化.

  for i in range(0, 5):
      start_x = random.uniform(-5, 5)  # [m]
      start_y = random.uniform(-5, 5)  # [m]
      start_yaw = np.deg2rad(random.uniform(-45, 45))  # [rad]

      end_x = random.uniform(-15, 15)  # [m]
      end_y = random.uniform(-15, 15)  # [m]
      end_yaw = np.deg2rad(random.uniform(145, 225))  # [rad]

      curvature = random.uniform(0.1, 0.3)
      step_size = 0.05

      xs, ys, yaws, modes, lengths = reeds_shepp_path_planning(
          start_x, start_y, start_yaw, end_x, end_y, end_yaw, curvature, step_size
      )

【动手学运动规划】2.6 Reeds Shepp曲线_第3张图片

参考链接

  • https://blog.csdn.net/weixin_42301220/article/details/125382518

️自动驾驶小白说官网:https://www.helloxiaobai.cn

你可能感兴趣的:(动手学运动规划,自动驾驶,算法,运动规划)