IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Python知识库 -> Dubins路径的计算和Python&Julia实现 -> 正文阅读

[Python知识库]Dubins路径的计算和Python&Julia实现

w# DubinsPath

简介

Dubins曲线是在满足曲率约束和规定的始端和末端的切线的条件下,连接两个二维平面的最短路径,限制目标只能向前行进。

Dubins曲线的目的是规划一条满足转弯半径、前进方向、初始相对位置和速度方向的最短曲线。
在这里插入图片描述

Dubins曲线分类

在运动方向已知和转向半径最小的情况下,从初始向量到终止向量的最短的路径是由直线和最小半径转向圆弧组成的。

  • L:逆时针圆弧运动
  • R:顺时针圆弧运动
  • S:直线运动

计算

  • 输入参数

    出发点 P i : ( x 1 , y 1 , α ) P_i:(x_1,y_1,\alpha) Pi?:(x1?,y1?,α)

    终止点 P f : ( x 2 , y 2 , β ) P_f:(x_2,y_2,\beta) Pf?:(x2?,y2?,β)

    转弯半径 r r r

  • 输出

    Dubins路径的长度和路径点

  1. 坐标系转换

    P i P_i Pi?变为新坐标系的原点,旋转坐标系使 P f P_f Pf? X X X轴上。

    P i : ( x 1 , y 1 , α ) ? > P i ′ : ( 0 , 0 , α ? θ ( α ′ ) ) P_i:(x_1,y_1,\alpha)->P_i':(0,0,\alpha-\theta(\alpha')) Pi?:(x1?,y1?,α)?>Pi?:(0,0,α?θ(α))

    P f : ( x 2 , y 2 , β ) ? > P f ′ : ( d , 0 , β ? θ ( β ′ ) ) P_f:(x_2,y_2,\beta)->P_f':(d,0,\beta-\theta(\beta')) Pf?:(x2?,y2?,β)?>Pf?:(d,0,β?θ(β))
    其中:
    { θ = arctan ? [ ( y 2 ? y 1 ) / ( x 2 ? x 1 ) ] ∣ P i P f ? ∣ = ( x 1 ? x 2 ) 2 + ( y 1 ? y 2 ) 2 d = ∣ P i P f ? ∣ / r \begin{cases} \theta=\arctan{[(y_2-y_1)/(x_2-x_1)]}\\ |\vec{P_iP_f}|=\sqrt{(x_1-x_2)^2+(y_1-y_2)^2}\\ d=|\vec{P_iP_f}|/r\\ \end{cases} ??????θ=arctan[(y2??y1?)/(x2??x1?)]Pi?Pf? ?=(x1??x2?)2+(y1??y2?)2 ?d=Pi?Pf? ?/r?

    转弯半径被归一化为1,可以直接使用弧度来表示路径长度。

  2. 计算Dubins路径长度

  • RSR型路径

    1. 根据起始点的坐标和方向推算出圆心的坐标
    2. 找到两圆的公切线中满足逆时针方向的那一条
  • LSL型路径

  • LSR型路径

  1. 坐标系转换

python代码实现

文字部分后续补全,代码如下:

import numpy as np
import matplotlib.pyplot as plt
from math import pi, sin, cos, acos, atan2, sqrt

##########################################################
# 功能:
#   输入起止点的坐标,方向,转弯半径,曲线的种类,计算Dubins曲线
#
# 输入参数:
#   起点坐标:
#       Pi(x,y)
#   终点坐标:
#       Pf(x,y)
#   起点角度:
#       alpha(弧度)
#   终点角度:
#       beta(弧度)
#   转弯半径:
#       ratio
#   曲线类型:
#       tp "RSR","LSL","RSL","LSR"
#       ( R顺时针 L逆时针 S直线 default:"RSR" )
#   是否可视化结果:
#       show_path (default=True)
#
# 输出结果:三元组
#   切出点坐标posiA:[A_x,A_y]
#   切入点坐标posiB:[B_x,B_y]
#   三段距离dist lst:[dist1出发圆弧,dist2直线,dist3到达圆弧
#
# Author: jia-yf19@mails.tsinghua.edu.cn
# Date  : 2021.10.28
#
##########################################################
def Dubins_path(Pi, Pf, alpha, beta, ratio, tp="RSR", show_path=True):
    assert len(Pi) == 2 and len(Pf) == 2
    assert tp in ["RSR", "LSL", "RSL", "LSR"]
    assert ratio > 0.

    # 坐标变换
    Vec_Move = np.matrix([[1., 0., -Pi[0]], [0., 1., -Pi[1]], [0., 0., 1.]])  # 平移
    temp_theta = -(atan2(Pf[1] - Pi[1], Pf[0] - Pi[0]) + pi)
    alpha_ = alpha + temp_theta
    beta_ = beta + temp_theta
    Vec_Rotate = np.matrix([[cos(temp_theta), -sin(temp_theta), 0.],
                            [sin(temp_theta), cos(temp_theta), 0.], 
                            [0., 0., 1.]])  # 旋转
    Vec_Length = np.matrix([[1. / ratio, 0., 0.],
                            [0., 1. / ratio, 0.],
                            [0., 0., 1.]])  # 拉伸
    Vec_Trans = Vec_Length * Vec_Rotate * Vec_Move  # 变换矩阵

    temp_res = Vec_Trans * [[Pi[0]], [Pi[1]], [1]]
    Pi_ = [temp_res[0, 0], temp_res[1, 0]]
    temp_res = Vec_Trans * [[Pf[0]], [Pf[1]], [1]]
    Pf_ = [temp_res[0, 0], temp_res[1, 0]]

    # 曲线计算
    if tp == "RSR":  # 双逆时针路线
        O1_x, O1_y = sin(alpha_), -cos(alpha_)          # 起点圆
        O2_x, O2_y = Pf_[0] + sin(beta_), -cos(beta_)   # 终点圆
        theta = atan2(O2_y - O1_y, O2_x - O1_x)         # 圆心夹角
        pho1 = (theta - alpha_) % (2.0 * pi)            # 起点圆弧度
        pho2 = sqrt((O1_x - O2_x)**2 + (O1_y - O2_y)**2)    # 直线长度
        pho3 = (beta_ - pho1 - pho2 - alpha_) % (2.0 * pi)  # 终点圆弧度
        A_x, A_y = sin(alpha_) - sin(alpha_ + pho1), -cos(alpha_) + cos(alpha_ + pho1)          # 切出点
        B_x, B_y = Pf_[0] + sin(beta_) - sin(alpha_ + pho1), -cos(beta_) + cos(alpha_ + pho1)   # 切入点
    elif tp == "LSL":  # 双顺时针路线
        O1_x, O1_y = -sin(alpha_), cos(alpha_)          # 起点圆
        O2_x, O2_y = Pf_[0] - sin(beta_), cos(beta_)    # 终点圆
        theta = atan2(O2_y - O1_y, O2_x - O1_x)         # 圆心夹角
        pho1 = (theta - alpha_) % (2.0 * pi)            # 起点圆弧度
        pho2 = sqrt((O1_x - O2_x)**2 + (O1_y - O2_y)**2)    # 直线长度
        pho3 = (beta_ - pho1 - pho2 - alpha_) % (2.0 * pi)  # 终点圆弧度
        A_x, A_y = -sin(alpha_) + sin(alpha_ + pho1), cos(alpha_) - cos(alpha_ + pho1)          # 切出点
        B_x, B_y = Pf_[0] - sin(beta_) + sin(alpha_ + pho1), cos(beta_) - cos(alpha_ + pho1)    # 切入点
    elif tp == "RSL":  # 八字交叉路线
        O1_x, O1_y = sin(alpha_), -cos(alpha_)          # 起点圆
        O2_x, O2_y = Pf_[0] - sin(beta_), cos(beta_)    # 终点圆
        theta = atan2(O2_y - O1_y, O2_x - O1_x)         # 圆心夹角
        dis_O1O2 = sqrt((O2_y - O1_y)**2 + (O2_x - O1_x)**2)
        if dis_O1O2 < 2.0:
            print("The geometry constraint is not satisfied!")
            return None
        else:
            theta_O1A = acos(2. / dis_O1O2)             # 圆1圆心和A夹角
            A_x, A_y = sin(alpha_) + cos(theta + theta_O1A), -cos(alpha_) + sin(theta + theta_O1A)          # 切出点
            B_x, B_y = Pf_[0] - sin(beta_) - cos(theta + theta_O1A), cos(beta_) - sin( theta + theta_O1A)   # 切入点
    else:  # "LSR" # 另一种八字交叉路线
        O1_x, O1_y = -sin(alpha_), cos(alpha_)          # 起点圆
        O2_x, O2_y = Pf_[0] + sin(beta_), -cos(beta_)   # 终点圆
        theta = atan2(O2_y - O1_y, O2_x - O1_x)         # 圆心夹角
        dis_O1O2 = sqrt((O2_y - O1_y)**2 + (O2_x - O1_x)**2)
        if dis_O1O2 < 2.0:
            print("The geometry constraint is not satisfied!")
            return None
        else:
            theta_O1A = acos(2. / dis_O1O2)             # 圆1圆心和A夹角
            A_x, A_y = -sin(alpha_) + cos(theta - theta_O1A), cos(alpha_) + sin(theta - theta_O1A)          # 切出点
            B_x, B_y = Pf_[0] + sin(beta_) - cos(theta - theta_O1A), -cos(beta_) - sin(theta - theta_O1A)   # 切入点

    # 逆变换
    Vec_Trans_INV = Vec_Trans.I
    temp_res = Vec_Trans_INV * [[A_x], [A_y], [1]]
    A_x, A_y = (temp_res[0, 0], temp_res[1, 0])
    temp_res = Vec_Trans_INV * [[B_x], [B_y], [1]]
    B_x, B_y = (temp_res[0, 0], temp_res[1, 0])
    temp_res = Vec_Trans_INV * [[O1_x], [O1_y], [1]]
    O1_x, O1_y = (temp_res[0, 0], temp_res[1, 0])
    temp_res = Vec_Trans_INV * [[O2_x], [O2_y], [1]]
    O2_x, O2_y = (temp_res[0, 0], temp_res[1, 0])

    dis_lst = []  # 每一段的距离
    ati1, ati2 = atan2(Pi[1] - O1_y, Pi[0] - O1_x), atan2(A_y - O1_y, A_x - O1_x)
    if tp[0] == "R" and ati1 < ati2:
        ati1 += 2.0 * pi
    elif tp[0] == "L" and ati1 > ati2:
        ati1 -= 2.0 * pi
    dis_lst.append(ratio * abs(ati1 - ati2))  # 切出弧长度
    dis_lst.append(sqrt((A_x - B_x)**2 + (A_y - B_y)**2))  # 直线段距离
    atf1 = atan2(Pf[1] - O2_y, Pf[0] - O2_x)
    atf2 = atan2(B_y - O2_y, B_x - O2_x)
    if tp[2] == "R" and atf2 < atf1:
        atf2 += 2.0 * pi
    elif tp[2] == "L" and atf2 > atf1:
        atf2 -= 2.0 * pi
    dis_lst.append(ratio * abs(atf1 - atf2))  # 切入弧长度
    if show_path:
        plt.figure(figsize=(12, 12))
        arrow_length = 0.75
        # 出发向量
        plt.arrow(Pi[0],
                  Pi[1],
                  arrow_length * cos(alpha),
                  arrow_length * sin(alpha),
                  width=0.01,
                  length_includes_head=True,
                  head_width=0.05,
                  head_length=0.1,
                  fc='b',
                  ec='b')
        # 到达向量
        plt.arrow(Pf[0],
                  Pf[1],
                  arrow_length * cos(beta),
                  arrow_length * sin(beta),
                  width=0.01,
                  length_includes_head=True,
                  head_width=0.05,
                  head_length=0.1,
                  fc='r',
                  ec='r')
        plt.scatter(np.array([Pi[0], A_x, B_x, Pf[0]]), np.array([Pi[1], A_y, B_y, Pf[1]]))  # 起止点,切点
        plt.scatter(np.array([O1_x, O2_x]), np.array([O1_y, O2_y]), c='r')  # 圆心
        the = np.linspace(-pi, pi, 200)  # 完整圆形轮廓
        plt.scatter((O1_x + ratio * np.cos(the)), (O1_y + ratio * np.sin(the)), s=0.1, c='r')
        plt.scatter((O2_x + ratio * np.cos(the)), (O2_y + ratio * np.sin(the)), s=0.1, c='r')

        # 出发圆弧轨迹
        the = np.linspace(ati2, ati1, 200)
        plt.plot((O1_x + ratio * np.cos(the)), (O1_y + ratio * np.sin(the)), c='b')

        # 直线段
        plt.plot([A_x, B_x], [A_y, B_y], c='b')

        # 到达圆弧轨迹
        the = np.linspace(atf1, atf2, 200)
        plt.plot((O2_x + ratio * np.cos(the)), (O2_y + ratio * np.sin(the)), c='b')

        ax = plt.gca()  # 设置等比例
        ax.set_aspect(1)
        plt.title("Dubins Path")
        plt.grid(True)
        plt.show()

    return ([A_x, A_y], [B_x, B_y], dis_lst)  # 切出点,切入点,每一段的距离


if __name__ == "__main__":
    print("Dubins Path")
    path_point = Dubins_path(Pi=(-4., 1.), Pf=(5., -2.), alpha=-1, beta=1, ratio=2, tp="RSL")
    print(path_point)

效果

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

Julia代码实现



##########################################################
# 功能:
#   输入起止点的坐标,方向,转弯半径,曲线的种类,计算Dubins曲线
#
# 输入参数:
#   起点坐标:
#       Pi(x,y)
#   终点坐标:
#       Pf(x,y)
#   起点角度:
#       alpha(弧度)
#   终点角度:
#       beta(弧度)
#   转弯半径:
#       ratio
#   曲线类型:
#       tp "RSR","LSL","RSL","LSR"
#       ( R顺时针 L逆时针 S直线 default:"RSR" )
#
# 输出结果:三元组
#   切出点坐标posiA:[A_x,A_y]
#   切入点坐标posiB:[B_x,B_y]
#   三段距离dist lst:[dist1出发圆弧,dist2直线,dist3到达圆弧
#
# Author: jia-yf19@mails.tsinghua.edu.cn
# Date  : 2021.10.29
#
##########################################################
function Dubins_path(Pi,Pf,α,β,r,tp="SRS")
    # 坐标系变化
    Mtr_Move = [1. 0. -Pi[1]; 0. 1. -Pi[2]; 0. 0. 1.] # 平移
    temp_θ = -(atan(Pf[2] - Pi[2], Pf[1] - Pi[1]) + π)
    α_ = α + temp_θ
    β_ = β + temp_θ
    Mtr_Rotate = [cos(temp_θ) -sin(temp_θ) 0.; sin(temp_θ) cos(temp_θ) 0.; 0. 0. 1.] # 旋转
    Mtr_Length = [1. / r 0. 0.; 0. 1. / r 0.; 0. 0. 1.]  # 拉伸
    Mtr_Trans = Mtr_Length * Mtr_Rotate *Mtr_Move
    temp_res = Mtr_Trans * [Pi[1]; Pi[2]; 1]
    Pi_ = [temp_res[1, 1], temp_res[2, 1]]
    temp_res = Mtr_Trans * [Pf[1]; Pf[2]; 1]
    Pf_ = [temp_res[1, 1], temp_res[2, 1]]

    # 曲线计算
    if tp == "RSR"  # 双逆时针路线
        Φ1_x, Φ1_y = sin(α_), -cos(α_)          # 起点圆
        Φ2_x, Φ2_y = Pf_[1] + sin(β_), -cos(β_)   # 终点圆
        θ = atan(Φ2_y - Φ1_y, Φ2_x - Φ1_x)         # 圆心夹角
        ρ1 = (θ - α_) % (2.0 * π)            # 起点圆弧度
        ρ2 = hypot((Φ1_x - Φ2_x), (Φ1_y - Φ2_y))    # 直线长度
        ρ3 = (β_ - ρ1 - ρ2 - α_) % (2.0 * π)  # 终点圆弧度
        A_x, A_y = sin(α_) - sin(α_ + ρ1), -cos(α_) + cos(α_ + ρ1)          # 切出点
        B_x, B_y = Pf_[1] + sin(β_) - sin(α_ + ρ1), -cos(β_) + cos(α_ + ρ1)   # 切入点
    elseif tp == "LSL"  # 双顺时针路线
        Φ1_x, Φ1_y = -sin(α_), cos(α_)          # 起点圆
        Φ2_x, Φ2_y = Pf_[1] - sin(β_), cos(β_)    # 终点圆
        θ = atan(Φ2_y - Φ1_y, Φ2_x - Φ1_x)         # 圆心夹角
        ρ1 = (θ - α_) % (2.0 * π)            # 起点圆弧度
        ρ2 = hypot((Φ1_x - Φ2_x), (Φ1_y - Φ2_y))    # 直线长度
        ρ3 = (β_ - ρ1 - ρ2 - α_) % (2.0 * π)  # 终点圆弧度
        A_x, A_y = -sin(α_) + sin(α_ + ρ1), cos(α_) - cos(α_ + ρ1)          # 切出点
        B_x, B_y = Pf_[1] - sin(β_) + sin(α_ + ρ1), cos(β_) - cos(α_ + ρ1)    # 切入点
    elseif tp == "RSL"  # 八字交叉路线
        Φ1_x, Φ1_y = sin(α_), -cos(α_)          # 起点圆
        Φ2_x, Φ2_y = Pf_[1] - sin(β_), cos(β_)    # 终点圆
        θ = atan(Φ2_y - Φ1_y, Φ2_x - Φ1_x)         # 圆心夹角
        dis_Φ1Φ2 = hypot((Φ2_y - Φ1_y), (Φ2_x - Φ1_x))
        if dis_Φ1Φ2 < 2.0
            println("The geometry constraint is not satisfied!")
            return Nothing
        else
            θ_Φ1A = acos(2. / dis_Φ1Φ2)             # 圆1圆心和A夹角
            A_x, A_y = sin(α_) + cos(θ + θ_Φ1A), -cos(α_) + sin(θ + θ_Φ1A)          # 切出点
            B_x, B_y = Pf_[1] - sin(β_) - cos(θ + θ_Φ1A), cos(β_) - sin(θ + θ_Φ1A)   # 切入点
        end
    else  # "LSR" # 另一种八字交叉路线
        Φ1_x, Φ1_y = -sin(α_), cos(α_)          # 起点圆
        Φ2_x, Φ2_y = Pf_[1] + sin(β_), -cos(β_)   # 终点圆
        θ = atan(Φ2_y - Φ1_y, Φ2_x - Φ1_x)         # 圆心夹角
        dis_Φ1Φ2 = hypot((Φ2_y - Φ1_y), (Φ2_x - Φ1_x))
        if dis_Φ1Φ2 < 2.0
            println("The geometry constraint is not satisfied!")
            return Nothing
        else
            θ_Φ1A = acos(2. / dis_Φ1Φ2)             # 圆1圆心和A夹角
            A_x, A_y = -sin(α_) + cos(θ - θ_Φ1A), cos(α_) + sin(θ - θ_Φ1A)          # 切出点
            B_x, B_y = Pf_[1] + sin(β_) - cos(θ - θ_Φ1A), -cos(β_) - sin(θ - θ_Φ1A)   # 切入点
        end
    end

    # 逆变换
    Mtr_Trans_INV = inv(Mtr_Trans)
    temp_res = Mtr_Trans_INV * [A_x; A_y; 1]
    A_x, A_y = (temp_res[1, 1], temp_res[2, 1])
    temp_res = Mtr_Trans_INV * [B_x; B_y; 1]
    B_x, B_y = (temp_res[1, 1], temp_res[2, 1])
    temp_res = Mtr_Trans_INV * [Φ1_x; Φ1_y; 1]
    Φ1_x, Φ1_y = (temp_res[1, 1], temp_res[2, 1])
    temp_res = Mtr_Trans_INV * [Φ2_x; Φ2_y; 1]
    Φ2_x, Φ2_y = (temp_res[1, 1], temp_res[2, 1])

    dis_lst = [0., 0., 0.]  # 每一段的距离
    ati1, ati2 = atan(Pi[2] - Φ1_y, Pi[1] - Φ1_x), atan(A_y - Φ1_y, A_x - Φ1_x)
    if tp[1] == 'R' && ati1 < ati2
        ati1 += 2.0 * π
    elseif tp[1] == 'L' && ati1 > ati2
        ati1 -= 2.0 * π
    end
    dis_lst[1] = r * abs(ati1 - ati2)  # 切出弧长度
    dis_lst[2] = hypot((A_x - B_x), (A_y - B_y))  # 直线段距离
    atf1 = atan(Pf[2] - Φ2_y, Pf[1] - Φ2_x)
    atf2 = atan(B_y - Φ2_y, B_x - Φ2_x)
    if tp[end] == 'R' && atf2 < atf1
        atf2 += 2.0 * π
    elseif tp[end] == 'L' && atf2 > atf1
        atf2 -= 2.0 * π
    end
    dis_lst[3] = (r * abs(atf1 - atf2))  # 切入弧长度 

    return ([A_x, A_y], [B_x, B_y], dis_lst)  # 切出点,切入点,每一段的距离
end

@time path_point = Dubins_path((2., 1.), (3., 2.), -1, 1, 3, "RSL")
println(path_point)

相关链接

  Python知识库 最新文章
Python中String模块
【Python】 14-CVS文件操作
python的panda库读写文件
使用Nordic的nrf52840实现蓝牙DFU过程
【Python学习记录】numpy数组用法整理
Python学习笔记
python字符串和列表
python如何从txt文件中解析出有效的数据
Python编程从入门到实践自学/3.1-3.2
python变量
上一篇文章      下一篇文章      查看所有文章
加:2021-10-30 12:31:14  更:2021-10-30 12:33:21 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/15 23:18:58-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码