车辆动力学模型是描述汽车运动规律的微分方程,一般用于分析汽车的平顺性和操纵稳定性。二自由度的车辆动力学模型基于单车模型假设,只考虑轮胎侧偏特性,其应用前提是
由于车辆动力学模型忽略了空气动力学和地面坡度等因素,因此汽车受到的外力均来自轮胎受到的地面力,其模型的几何结构和受力分析如下图所示:
其中:
忽略地面坡度,沿着车身
y
y
y轴(横向)应用牛顿第二定律可得
m
a
y
=
F
y
f
+
F
y
r
(1)
ma_y=F_{yf}+F_{yr} \tag{1}
may?=Fyf?+Fyr?(1)
m
m
m为车辆的质量,
a
y
a_y
ay?为车辆在质心
C
C
C处横向的惯性加速度,其主要由横向加速度
y
¨
\ddot{y}
y¨?和向心加速度
v
x
φ
˙
v_x\dot{\varphi}
vx?φ˙?组成,即
a
y
=
y
¨
+
v
x
φ
˙
(2)
a_y=\ddot{y}+v_x\dot{\varphi} \tag{2}
ay?=y¨?+vx?φ˙?(2)
将(2)代入(1)可得
m
(
y
¨
+
v
x
φ
˙
)
=
F
y
f
+
F
y
r
(3)
m(\ddot{y}+v_x\dot{\varphi} ) = F_{yf}+F_{yr} \tag{3}
m(y¨?+vx?φ˙?)=Fyf?+Fyr?(3)
同理,沿着车身
x
x
x轴(纵向)可得
a
x
=
v
x
˙
?
v
y
φ
˙
(4)
a_x = \dot{v_x}-v_y\dot{\varphi} \tag{4}
ax?=vx?˙??vy?φ˙?(4)
m ( v x ˙ ? v y φ ˙ ) = F a ? F x f (5) m(\dot{v_x}-v_y\dot{\varphi} )= F_a- F_{xf} \tag{5} m(vx?˙??vy?φ˙?)=Fa??Fxf?(5)
其中 F a F_a Fa?为车辆动力系统提供的纵向力。
车辆的横向运动并不是完全的侧向平移,而是需要通过一定程度的转向来完成,也就是横摆运动,由车辆绕
z
z
z轴的旋转平衡可以得到车辆的的横摆动力学方程
I
z
φ
¨
=
L
f
F
y
f
?
L
r
F
y
r
(6)
I_z\ddot{\varphi}=L_fF_{yf}-L_rF_{yr} \tag{6}
Iz?φ¨?=Lf?Fyf??Lr?Fyr?(6)
其中
I
z
I_z
Iz?为车辆绕
z
z
z轴的转动惯量,
φ
¨
\ddot{\varphi}
φ¨?为横摆角的加速度。
由图中角的几何关系,可得前轮侧偏角
α
f
=
δ
f
?
θ
v
f
(7)
\alpha_f = \delta_f - \theta_{vf} \tag{7}
αf?=δf??θvf?(7)
后轮侧偏角
α
r
=
?
θ
v
r
(8)
\alpha_r=-\theta_{vr} \tag{8}
αr?=?θvr?(8)
由于轮胎在侧偏角较小的时候,轮胎的侧向力与侧偏角近似成正比,因此有
F
c
f
=
C
α
f
(
δ
f
?
θ
v
f
)
(9)
F_{cf}=C_{\alpha f}(\delta_f-\theta_{vf})\tag{9}
Fcf?=Cαf?(δf??θvf?)(9)
F c r = C α r ( ? θ v r ) (10) F_{cr} = C_{\alpha r}(-\theta_{vr}) \tag{10} Fcr?=Cαr?(?θvr?)(10)
C α f C_{\alpha f} Cαf?为前轮侧向力与前轮侧偏角的比例系数,称为前轮轮胎的侧扁刚度, C α r C_{\alpha r} Cαr?为后轮侧向力与后轮侧偏角的比例系数,即后轮轮胎的侧扁刚度。
注:这里推导没有乘以2,是因为我们是将车辆看作是一个两轮的自行车模型, C α f C_{\alpha f} Cαf?和 C α r C_{\alpha r} Cαr?分别可以理解为两个前轮的侧扁刚度和,以及两个后轮的侧扁刚度和,在实际应用中,需要根据车辆的实际情况作适当的调整。后面的代码仿真中,我们在设置 C α f C_{\alpha f} Cαf?和 C α r C_{\alpha r} Cαr?的时候,会自动将其乘以2,来表示两个前轮侧扁刚度和和两个后轮侧扁刚度和。
由图中力的几何关系可得
F
x
f
=
F
c
f
s
i
n
δ
f
=
C
α
f
(
δ
f
?
θ
v
f
)
s
i
n
δ
f
(11)
F_{xf} = F_{cf}sin\delta_f=C_{\alpha f}(\delta_f-\theta_{vf})sin\delta_f \tag{11}
Fxf?=Fcf?sinδf?=Cαf?(δf??θvf?)sinδf?(11)
F y f = F c f c o s δ f = C α f ( δ f ? θ v f ) c o s δ f (12) F_{yf} = F_{cf}cos\delta_f=C_{\alpha f}(\delta_f-\theta_{vf})cos\delta_f \tag{12} Fyf?=Fcf?cosδf?=Cαf?(δf??θvf?)cosδf?(12)
F y r = F c r = C α r ( ? θ v r ) (13) F_{yr} = F_{cr} = C_{\alpha r}(-\theta_{vr}) \tag{13} Fyr?=Fcr?=Cαr?(?θvr?)(13)
由于前后轮的横向速度由车辆自身横向速度和绕质心的转动速度组成,因此
v
f
y
=
y
˙
+
L
f
φ
˙
(14)
v_{fy}=\dot{y}+L_f\dot{\varphi} \tag{14}
vfy?=y˙?+Lf?φ˙?(14)
v r y = y ˙ ? L r φ ˙ (15) v_{ry}=\dot{y}-L_r \dot{\varphi} \tag{15} vry?=y˙??Lr?φ˙?(15)
其中 y ˙ \dot{y} y˙?为车辆横向速度, φ ˙ \dot{\varphi} φ˙?为车辆的向心速度。
由于前后轮的纵向速度和车辆自身的纵向速度相等,即
v
f
x
=
v
r
x
=
v
x
v_{fx} = v_{rx} = v_x
vfx?=vrx?=vx?,结合图中的几何关系可得
t
a
n
θ
v
f
=
v
f
y
v
f
x
=
y
˙
+
L
f
φ
˙
v
x
(16)
tan\theta_{vf} = \frac{v_{fy}}{v_{fx}}= \frac{\dot{y}+L_f\dot{\varphi}}{v_{x}} \tag{16}
tanθvf?=vfx?vfy??=vx?y˙?+Lf?φ˙??(16)
t a n θ v r = v r y v r x = y ˙ ? L r φ ˙ v x (17) tan\theta_{vr} = \frac{v_{ry}}{v_{rx}}= \frac{\dot{y}-L_r \dot{\varphi}}{v_{x}} \tag{17} tanθvr?=vrx?vry??=vx?y˙??Lr?φ˙??(17)
由(16)和(17)可得
θ
v
f
=
a
r
c
t
a
n
y
˙
+
L
f
φ
˙
v
x
(18)
\theta_{vf} = arctan{\frac{\dot{y}+L_f\dot{\varphi}}{v_{x}}} \tag{18}
θvf?=arctanvx?y˙?+Lf?φ˙??(18)
θ v r = a r c t a n y ˙ ? L r φ ˙ v x (19) \theta_{vr} = arctan{\frac{\dot{y}-L_r \dot{\varphi}}{v_{x}}} \tag{19} θvr?=arctanvx?y˙??Lr?φ˙??(19)
将(18)和(19)代入到(11)、(12)和(13)可得
F
x
f
=
C
α
f
(
δ
f
?
a
r
c
t
a
n
y
˙
+
L
f
φ
˙
v
x
)
s
i
n
δ
f
(20)
F_{xf} = C_{\alpha f}(\delta_f-arctan{\frac{\dot{y}+L_f\dot{\varphi}}{v_{x}}})sin\delta_f \tag{20}
Fxf?=Cαf?(δf??arctanvx?y˙?+Lf?φ˙??)sinδf?(20)
F y f = C α f ( δ f ? a r c t a n y ˙ + L f φ ˙ v x ) c o s δ f (21) F_{yf}=C_{\alpha f}(\delta_f-arctan{\frac{\dot{y}+L_f\dot{\varphi}}{v_{x}}})cos\delta_f \tag{21} Fyf?=Cαf?(δf??arctanvx?y˙?+Lf?φ˙??)cosδf?(21)
F y r = C α r ( ? a r c t a n y ˙ ? L r φ ˙ v x ) (22) F_{yr}= C_{\alpha r}(-arctan{\frac{\dot{y}-L_r \dot{\varphi}}{v_{x}}}) \tag{22} Fyr?=Cαr?(?arctanvx?y˙??Lr?φ˙??)(22)
由(5)可得纵向加速度
v
x
˙
\dot{v_x}
vx?˙?等于
v
x
˙
=
F
a
?
F
x
f
m
+
v
y
φ
˙
(23)
\dot{v_x}=\frac{F_a- F_{xf}}{m}+v_y\dot{\varphi} \tag{23}
vx?˙?=mFa??Fxf??+vy?φ˙?(23)
由(3)可得横向加速度
v
y
˙
\dot{v_y}
vy?˙?等于
v
y
˙
=
y
¨
=
F
y
f
+
F
y
r
m
?
v
x
φ
˙
(24)
\dot{v_y}=\ddot{y}=\frac{F_{yf}+F_{yr}}{m}-v_x \dot{\varphi} \tag{24}
vy?˙?=y¨?=mFyf?+Fyr???vx?φ˙?(24)
由(6)可得
φ
¨
=
L
f
F
y
f
?
L
r
F
y
r
I
z
(25)
\ddot{\varphi}=\frac{L_fF_{yf}-L_rF_{yr}}{I_z} \tag{25}
φ¨?=Iz?Lf?Fyf??Lr?Fyr??(25)
另外对于全局坐标
X
˙
\dot{X}
X˙和
Y
˙
\dot{Y}
Y˙类似坐标的旋转,所以有
X
˙
=
v
x
c
o
s
φ
?
v
y
s
i
n
φ
(26)
\dot{X}=v_xcos\varphi-v_ysin\varphi \tag{26}
X˙=vx?cosφ?vy?sinφ(26)
Y ˙ = v x s i n φ + v y c o s φ (27) \dot{Y}=v_xsin\varphi+v_ycos\varphi \tag{27} Y˙=vx?sinφ+vy?cosφ(27)
综上可得
{
v
x
˙
=
a
?
F
x
f
m
+
v
y
φ
˙
v
y
˙
=
F
y
f
+
F
y
r
m
?
v
x
φ
˙
φ
¨
=
L
f
F
y
f
?
L
r
F
y
r
I
z
X
˙
=
v
x
c
o
s
φ
?
v
y
s
i
n
φ
Y
˙
=
v
x
s
i
n
φ
+
v
y
c
o
s
φ
(28)
\begin{cases} \dot{v_x}=a-\frac{ F_{xf}}{m}+v_y\dot{\varphi}\\ \dot{v_y}=\frac{F_{yf}+F_{yr}}{m}-v_x \dot{\varphi}\\ \ddot{\varphi}=\frac{L_fF_{yf}-L_rF_{yr}}{I_z}\\ \dot{X}=v_xcos\varphi-v_ysin\varphi \\ \dot{Y}=v_xsin\varphi+v_ycos\varphi \end{cases} \tag{28}
?
?
??vx?˙?=a?mFxf??+vy?φ˙?vy?˙?=mFyf?+Fyr???vx?φ˙?φ¨?=Iz?Lf?Fyf??Lr?Fyr??X˙=vx?cosφ?vy?sinφY˙=vx?sinφ+vy?cosφ?(28)
其中
{
F
x
f
=
C
α
f
(
δ
f
?
θ
v
f
)
s
i
n
δ
f
F
y
f
=
C
α
f
(
δ
f
?
a
r
c
t
a
n
y
˙
+
L
f
φ
˙
v
x
)
c
o
s
δ
f
F
y
r
=
C
α
r
(
?
a
r
c
t
a
n
y
˙
?
L
r
φ
˙
v
x
)
(29)
\begin{cases} F_{xf} = C_{\alpha f}(\delta_f-\theta_{vf})sin\delta_f \\ F_{yf}=C_{\alpha f}(\delta_f-arctan{\frac{\dot{y}+L_f\dot{\varphi}}{v_{x}}})cos\delta_f\\ F_{yr}= C_{\alpha r}(-arctan{\frac{\dot{y}-L_r \dot{\varphi}}{v_{x}}}) \end{cases} \tag{29}
?
?
??Fxf?=Cαf?(δf??θvf?)sinδf?Fyf?=Cαf?(δf??arctanvx?y˙?+Lf?φ˙??)cosδf?Fyr?=Cαr?(?arctanvx?y˙??Lr?φ˙??)?(29)
import math
import matplotlib.pyplot as plt
import numpy as np
# import imageio
# 车辆参数信息
L = 2.9 # 轴距[m]
Lf = L / 2.0 # 车辆中心点到前轴的距离[m]
Lr = L - Lf # 车辆终点到后轴的距离[m]
W = 2.0 # 宽度[m]
LF = 3.8 # 后轴中心到车头距离[m]
LB = 0.8 # 后轴中心到车尾距离[m]
TR = 0.5 # 轮子半径[m]
TW = 0.5 # 轮子宽度[m]
WD = W # 轮距[m]
Iz = 2250.0 # 车辆绕z轴的转动惯量[kg/m2]
Cf = 1600.0 * 2.0 # 前轮侧偏刚度[N/rad]
Cr = 1700.0 * 2.0 # 后轮侧偏刚度[N/rad]
m = 1500.0 # 车身质量[kg]
LENGTH = LB + LF # 车辆长度[m]
MWA = np.radians(30.0) # 最大轮转角(Max Wheel Angle)[rad]
def normalize_angle(angle):
a = math.fmod(angle + np.pi, 2 * np.pi)
if a < 0.0:
a += (2.0 * np.pi)
return a - np.pi
class DynamicBicycleModel:
def __init__(self, x=0.0, y=0.0, yaw=0.0, vx=0.01, vy=0.0, omega=0.0):
self.x = x
self.y = y
self.yaw = yaw
self.vx = vx
self.vy = vy
self.omega = omega
self.delta = 0.0
def update(self, a, delta, dt=0.1):
self.delta = np.clip(delta, -MWA, MWA)
self.x = self.x + self.vx * math.cos(self.yaw) * dt - self.vy * math.sin(self.yaw) * dt
self.y = self.y + self.vx * math.sin(self.yaw) * dt + self.vy * math.cos(self.yaw) * dt
self.yaw = self.yaw + self.omega * dt
self.yaw = normalize_angle(self.yaw)
f_cf = Cf * normalize_angle(self.delta - math.atan2((self.vy + Lf * self.omega) / self.vx, 1.0))
f_cr = Cr * math.atan2((Lr * self.omega-self.vy) / self.vx, 1.0)
f_xf = f_cf * math.sin(self.delta)
f_yf = f_cf * math.cos(self.delta)
f_yr = f_cr
self.vx = self.vx + (a - f_xf / m + self.vy * self.omega) * dt
self.vy = self.vy + ((f_yr + f_yf) / m - self.vx * self.omega) * dt
self.omega = self.omega + (Lf * f_yf - f_yr * Lr) / Iz * dt
def draw_vehicle(x, y, yaw, delta, ax, color='black'):
vehicle_outline = np.array(
[[-LB, LF, LF, -LB, -LB],
[W / 2, W / 2, -W / 2, -W / 2, W / 2]])
wheel = np.array([[-TR, TR, TR, -TR, -TR],
[TW / 2, TW / 2, -TW / 2, -TW / 2, TW / 2]])
rr_wheel = wheel.copy() # 右后轮
rl_wheel = wheel.copy() # 左后轮
fr_wheel = wheel.copy() # 右前轮
fl_wheel = wheel.copy() # 左前轮
rr_wheel[1, :] += WD/2
rl_wheel[1, :] -= WD/2
# 方向盘旋转
rot1 = np.array([[np.cos(delta), -np.sin(delta)],
[np.sin(delta), np.cos(delta)]])
# yaw旋转矩阵
rot2 = np.array([[np.cos(yaw), -np.sin(yaw)],
[np.sin(yaw), np.cos(yaw)]])
fr_wheel = np.dot(rot1, fr_wheel)
fl_wheel = np.dot(rot1, fl_wheel)
fr_wheel += np.array([[L], [-WD / 2]])
fl_wheel += np.array([[L], [WD / 2]])
fr_wheel = np.dot(rot2, fr_wheel)
fr_wheel[0, :] += x
fr_wheel[1, :] += y
fl_wheel = np.dot(rot2, fl_wheel)
fl_wheel[0, :] += x
fl_wheel[1, :] += y
rr_wheel = np.dot(rot2, rr_wheel)
rr_wheel[0, :] += x
rr_wheel[1, :] += y
rl_wheel = np.dot(rot2, rl_wheel)
rl_wheel[0, :] += x
rl_wheel[1, :] += y
vehicle_outline = np.dot(rot2, vehicle_outline)
vehicle_outline[0, :] += x
vehicle_outline[1, :] += y
ax.plot(fr_wheel[0, :], fr_wheel[1, :], color)
ax.plot(rr_wheel[0, :], rr_wheel[1, :], color)
ax.plot(fl_wheel[0, :], fl_wheel[1, :], color)
ax.plot(rl_wheel[0, :], rl_wheel[1, :], color)
ax.plot(vehicle_outline[0, :], vehicle_outline[1, :], color)
# ax.axis('equal')
if __name__ == "__main__":
vehicle = DynamicBicycleModel(0.0, 0.0, 0.0, 1.0, 1.0, 0.0)
trajectory_x = []
trajectory_y = []
fig = plt.figure()
# 保存动图用
# i = 0
# image_list = [] # 存储图片
plt.figure(1)
for i in range(500):
plt.cla()
plt.gca().set_aspect('equal', adjustable='box')
vehicle.update(0, np.pi / 10)
draw_vehicle(vehicle.x, vehicle.y, vehicle.yaw, vehicle.delta, plt)
trajectory_x.append(vehicle.x)
trajectory_y.append(vehicle.y)
plt.plot(trajectory_x, trajectory_y, 'blue')
plt.xlim(-15, 12)
plt.ylim(-2.5, 21)
plt.pause(0.001)
# i += 1
# if (i % 50) > 0:
# plt.savefig("temp.png")
# image_list.append(imageio.imread("temp.png"))
#
# imageio.mimsave("display.gif", image_list, duration=0.1)
运行效果:
文章首发公众号:iDoitnow如果喜欢话,可以关注一下