LQR軌跡跟蹤算法Python算法實現3

根據LQR軌跡跟蹤算法Python/Matlab算法實現2的代碼,我們轉化成Python,後續上車使用。代碼僅開源到這,可以進行仿真,函數都可以直接使用。工程代碼就不開源了。

from numpy import *
from math import *
import matplotlib.pyplot as plt
import scipy.linalg as la
import time
Kp = 1
dt = 0.1
L = 2.9
Q = eye(4)
Q[0,0] = 19.7
Q[1,1] =0.01
Q[2,2] = 18.3
Q[3,3] = 7.3
R = 1
max_steer =60 * pi/180#in rad
target_v =10.0 / 3.6


cx = linspace(0,200,2000)
cy = zeros(len(cx))
pd= zeros(len(cx))
pdd = zeros(len(cx))
ck = zeros(len(cx))
cyaw = zeros(len(cx))
for i in range(len(cx)):
    cy[i] = -sin(cx[i]/10) * cx[i]/8

for i in range (len(cx)-1):
    pd[i] = (cy[i+1]-cy[i])/(cx[i+1]-cx[i])

for i in range (len(cx)-1):
    pdd[i] = (cy[i+1]-2*cy[i] + cy[i-1])/(0.5* (cx[i+1]- cx[i-1]))**2

for i in range(len(cx)-1):
    ck[i] = pdd[i]/((1+pd[i]**2)**1.5)

for i in range(len(pd)):
    cyaw[i] = atan(pd[i])

pe = 0
pth_e = 0
i = 1
x = 0
y = -0.1
yaw = 0
v = 0
ind =0

class State:

    def __init__(self, x=0.0, y=0.0, yaw=0.0, v=0.0):
        self.x = x
        self.y = y
        self.yaw = yaw
        self.v = v

def update(state, a, delta):
    if delta >= max_steer:
        delta = max_steer
    if delta <= - max_steer:
        delta = - max_steer
    state.x = state.x + state.v * cos(state.yaw) * dt
    state.y = state.y + state.v * sin(state.yaw) * dt
    state.yaw = state.yaw + state.v / L * tan(delta) * dt
    state.v = state.v + a * dt

    return state

def PIDControl(target, current):
    a = Kp * (target - current)
    return a
#
# def pi_2_pi(angle):  # the unit of angle is in rad;
#     while (angle > pi):
#         angle = angle - 2.0 * pi
#
#     while (angle < -pi):
#         angle = angle + 2.0 * pi
#
#     return angle

def solve_DARE(A, B, Q, R):
    """
    solve a discrete time_Algebraic Riccati equation (DARE)
    """
    X = Q
    maxiter = 500
    eps = 0.01

    for i in range(maxiter):
        Xn = A.T * X * A - A.T * X * B * la.pinv(R + B.T * X * B) * B.T * X * A + Q
        if (abs(Xn - X)).max()  < eps:
            X = Xn
            break
        X = Xn

    return Xn

def dlqr(A, B, Q, R):
    """Solve the discrete time lqr controller.
    x[k+1] = A x[k] + B u[k]
    cost = sum x[k].T*Q*x[k] + u[k].T*R*u[k]
    # ref Bertsekas, p.151
    """

    # first, try to solve the ricatti equation
    X = solve_DARE(A, B, Q, R)

    # compute the LQR gain
    K = la.pinv(B.T * X * B + R) * (B.T * X * A)

    return K

def calc_nearest_index(state, cx, cy):
    dx = [state.x - icx for icx in cx]
    dy = [state.y - icy for icy in cy]

    d = [abs(sqrt(idx ** 2 + idy ** 2)) for (idx, idy) in zip(dx, dy)]

    error = min(d)

    ind = d.index(error)

    dy = cy[ind] - state.y
    if dy > 0:
        error = -error

    return ind, error

def lqr_steering_control(state, cx, cy, cyaw, ck, pe, pth_e):
    ind, e = calc_nearest_index(state, cx, cy)

    k = ck[ind]
    v = state.v
    th_e = (state.yaw - cyaw[ind])

    A = mat(zeros((4, 4)))
    A[0, 0] = 1.0
    A[0, 1] = dt
    A[1, 2] = v
    A[2, 2] = 1.0
    A[2, 3] = dt
    # print(A)

    B = mat(zeros((4, 1)))
    B[3, 0] = v / L

    K = dlqr(A, B, Q, R)
    print('K is', K)
    x =mat(zeros((4, 1)))

    x[0, 0] = e
    x[1, 0] = (e - pe) / dt
    x[2, 0] = th_e
    x[3, 0] = (th_e - pth_e) / dt

    ff = atan(L * k)
    fb = (-K * x)
    print(ff,fb)
    delta = 1*ff + 1 * fb
    print(delta)
    return delta, ind, e, th_e

state = State(x=0.0, y= -0.5, yaw=0.0, v=0.0)
x = state.x
y = state.y
yaw = state.yaw
v = state.v
i = 0
x_pos = zeros(len(cx))
y_pos = zeros(len(cx))

while ind < len(cx):
    delta,ind, e, th_e = lqr_steering_control(state, cx, cy, cyaw, ck, pe, pth_e)
    pth_e = th_e
    pe = e
    print('lateral error is ',e)
    v = state.v
    print("v is",v)
    #print('Index is ', ind)
    if abs(e) > 4:
       print('too far from reference!\n')
       break
    a = PIDControl(target_v, v)

    state = update(state, a, delta)
    x = state.x
    y = state.y
    x_pos[i] = x
    y_pos[i] = y
    i = i + 1


plt.plot(cx, cy,"-b")

for i in range(len(x_pos)):
    plt.plot(x_pos[i],y_pos[i],".r",markersize = 1)

plt.grid(True)
plt.axis("equal")
plt.xlabel("x[m]")
plt.ylabel("y[m]")
plt.show()
print(cyaw[0:20])

效果如圖:
在這裏插入圖片描述

發佈了74 篇原創文章 · 獲贊 22 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章