【【自动驾驶】车辆运动学模型】
【自动驾驶】车辆运动学模型
- 1. 引言
- 2. 以车辆重心为中心的单车模型
- 2.1 模型介绍
- 2.2 滑移角 β \beta β 的推导
- 2.3 Python代码实现
- 2.4 C++代码实现
- 3. 前轮驱动的单车模型
- 3.1 模型介绍
- 3.2 滑移角 β \beta β 的推导
- 3.3 Python代码实现
- 3.4 C++代码实现
- 4. 以后轴中心为车辆中心的单车模型
- 4.1 模型介绍
- 4.2 滑移角 β \beta β 的推导
- 4.3 Python代码实现
- 4.4 C++代码实现
- 5. 阿克曼转向几何
- 5.1 模型介绍
- 5.2 滑移角 β \beta β 的推导
- 5.3 Python代码实现
- 5.4 C++代码实现
- 6. 总结
- 参考资料
1. 引言
在自动驾驶技术的发展过程中,对车辆运动的理解和建模至关重要。车辆运动学模型用于描述车辆的运动特性,尤其是在低速条件下,通过控制输入来预测车辆的未来状态。本文将详细介绍几种常见的车辆运动学模型,并提供Python和C++的代码实现。
好的,我们将详细推导并更新其他模型中的侧滑角 β \beta β。以下是每个模型的详细推导和代码实现。
2. 以车辆重心为中心的单车模型
2.1 模型介绍
在自动驾驶领域,通常采用单车模型来简化实际车辆的复杂性。此模型将车辆视为具有两个转动轴的刚体,即前轮和后轮,每个轴上的左右轮合并为一个轮子来考虑。模型的关键参数包括:
- 车辆重心:点C,代表车辆的质量中心。
- 前后轮距离: l f l_f lf 和 l r l_r lr 分别从前轮中心到重心的距离和从后轮中心到重心的距离。
- 轴距: L = l f + l r L = l_f + l_r L=lf+lr。
- 速度: V V V,表示车辆重心的速度。
- 滑移角: β \beta β,车辆速度矢量与车辆纵向轴之间的夹角。
- 航向角: ψ \psi ψ,车身与X轴的夹角。
- 转向角: δ f \delta_f δf 和 δ r \delta_r δr,分别表示前轮和后轮的转向角。对于大多数车辆, δ r \delta_r δr 可以设置为0。
2.2 滑移角 β \beta β 的推导
-
几何关系:
- 假设车辆的重心位于点C,前轮中心位于点F,后轮中心位于点R。
- 前轮的转向角 δ f \delta_f δf 导致前轮的行驶方向与车辆纵向轴之间有一个夹角。
- 后轮的转向角 δ r \delta_r δr 导致后轮的行驶方向与车辆纵向轴之间有一个夹角。
-
滑移角 β \beta β 的定义:
- 滑移角 β \beta β 定义为车辆速度矢量与车辆纵向轴之间的夹角。
- 当车辆转弯时,前轮和后轮的速度矢量会有所不同,导致车辆重心的速度矢量与车辆纵向轴之间有一个夹角。
-
推导过程:
- 考虑车辆重心的速度矢量 V ⃗ \vec{V} V,它可以分解为沿车辆纵向轴的分量和横向轴的分量。
- 前轮的速度矢量
V
f
⃗
\vec{V_f}
Vf 可以表示为:
V f ⃗ = V cos ( δ f ) i ^ + V sin ( δ f ) j ^ \vec{V_f} = V \cos(\delta_f) \hat{i} + V \sin(\delta_f) \hat{j} Vf=Vcos(δf)i^+Vsin(δf)j^ - 后轮的速度矢量
V
r
⃗
\vec{V_r}
Vr 可以表示为:
V r ⃗ = V cos ( δ r ) i ^ + V sin ( δ r ) j ^ \vec{V_r} = V \cos(\delta_r) \hat{i} + V \sin(\delta_r) \hat{j} Vr=Vcos(δr)i^+Vsin(δr)j^
-
重心速度矢量:
- 由于重心位于前后轮之间,重心的速度矢量
V
c
⃗
\vec{V_c}
Vc 可以表示为前后轮速度矢量的加权平均:
V c ⃗ = l r V f ⃗ + l f V r ⃗ l f + l r \vec{V_c} = \frac{l_r \vec{V_f} + l_f \vec{V_r}}{l_f + l_r} Vc=lf+lrlrVf+lfVr - 将前后轮的速度矢量代入上式:
V c ⃗ = l r ( V cos ( δ f ) i ^ + V sin ( δ f ) j ^ ) + l f ( V cos ( δ r ) i ^ + V sin ( δ r ) j ^ ) l f + l r \vec{V_c} = \frac{l_r (V \cos(\delta_f) \hat{i} + V \sin(\delta_f) \hat{j}) + l_f (V \cos(\delta_r) \hat{i} + V \sin(\delta_r) \hat{j})}{l_f + l_r} Vc=lf+lrlr(Vcos(δf)i^+Vsin(δf)j^)+lf(Vcos(δr)i^+Vsin(δr)j^) - 整理得:
V c ⃗ = V ( l r cos ( δ f ) + l f cos ( δ r ) l f + l r ) i ^ + V ( l r sin ( δ f ) + l f sin ( δ r ) l f + l r ) j ^ \vec{V_c} = V \left( \frac{l_r \cos(\delta_f) + l_f \cos(\delta_r)}{l_f + l_r} \right) \hat{i} + V \left( \frac{l_r \sin(\delta_f) + l_f \sin(\delta_r)}{l_f + l_r} \right) \hat{j} Vc=V(lf+lrlrcos(δf)+lfcos(δr))i^+V(lf+lrlrsin(δf)+lfsin(δr))j^
- 由于重心位于前后轮之间,重心的速度矢量
V
c
⃗
\vec{V_c}
Vc 可以表示为前后轮速度矢量的加权平均:
-
滑移角 β \beta β 的计算:
- 滑移角
β
\beta
β 是重心速度矢量
V
c
⃗
\vec{V_c}
Vc 与车辆纵向轴之间的夹角,可以通过以下公式计算:
tan ( β ) = 横向分量 纵向分量 = l r sin ( δ f ) + l f sin ( δ r ) l f + l r l r cos ( δ f ) + l f cos ( δ r ) l f + l r \tan(\beta) = \frac{\text{横向分量}}{\text{纵向分量}} = \frac{\frac{l_r \sin(\delta_f) + l_f \sin(\delta_r)}{l_f + l_r}}{\frac{l_r \cos(\delta_f) + l_f \cos(\delta_r)}{l_f + l_r}} tan(β)=纵向分量横向分量=lf+lrlrcos(δf)+lfcos(δr)lf+lrlrsin(δf)+lfsin(δr) - 简化得:
tan ( β ) = l r sin ( δ f ) + l f sin ( δ r ) l r cos ( δ f ) + l f cos ( δ r ) \tan(\beta) = \frac{l_r \sin(\delta_f) + l_f \sin(\delta_r)}{l_r \cos(\delta_f) + l_f \cos(\delta_r)} tan(β)=lrcos(δf)+lfcos(δr)lrsin(δf)+lfsin(δr) - 因此,滑移角
β
\beta
β 可以表示为:
β = arctan ( l r sin ( δ f ) + l f sin ( δ r ) l r cos ( δ f ) + l f cos ( δ r ) ) \beta = \arctan \left( \frac{l_r \sin(\delta_f) + l_f \sin(\delta_r)}{l_r \cos(\delta_f) + l_f \cos(\delta_r)} \right) β=arctan(lrcos(δf)+lfcos(δr)lrsin(δf)+lfsin(δr))
- 滑移角
β
\beta
β 是重心速度矢量
V
c
⃗
\vec{V_c}
Vc 与车辆纵向轴之间的夹角,可以通过以下公式计算:
2.3 Python代码实现
import math
class KinematicModel_1:
def __init__(self, x, y, psi, v, l_r, l_f, dt):
self.x = x
self.y = y
self.psi = psi
self.v = v
self.l_f = l_f
self.l_r = l_r
self.dt = dt
def update_state(self, a, delta_f, delta_r=0):
# 计算滑移角 β
beta = math.atan2(self.l_r * math.sin(delta_f) + self.l_f * math.sin(delta_r),
self.l_r * math.cos(delta_f) + self.l_f * math.cos(delta_r))
# 更新状态
self.x += self.v * math.cos(self.psi + beta) * self.dt
self.y += self.v * math.sin(self.psi + beta) * self.dt
self.psi += (self.v / (self.l_f + self.l_r)) * (math.tan(delta_f) - math.tan(delta_r)) * math.cos(beta) * self.dt
self.v += a * self.dt
def get_state(self):
return self.x, self.y, self.psi, self.v
2.4 C++代码实现
#include <cmath>
#include <iostream>
class KinematicModel_1 {
public:
KinematicModel_1(double x, double y, double psi, double v, double l_r, double l_f, double dt) :
x(x), y(y), psi(psi), v(v), l_f(l_f), l_r(l_r), dt(dt) {}
void update_state(double a, double delta_f, double delta_r = 0) {
// 计算滑移角 β
double beta = atan2(l_r * sin(delta_f) + l_f * sin(delta_r),
l_r * cos(delta_f) + l_f * cos(delta_r));
// 更新状态
x += v * cos(psi + beta) * dt;
y += v * sin(psi + beta) * dt;
psi += (v / (l_f + l_r)) * (tan(delta_f) - tan(delta_r)) * cos(beta) * dt;
v += a * dt;
}
void get_state() const {
std::cout << "x: " << x << ", y: " << y << ", psi: " << psi << ", v: " << v << std::endl;
}
private:
double x, y, psi, v, l_f, l_r, dt;
};
3. 前轮驱动的单车模型
3.1 模型介绍
当仅考虑前轮转向时,模型可以简化为:
{ x ˙ = V cos ( ψ + β ) y ˙ = V sin ( ψ + β ) ψ ˙ = V sin β l r \left\{ \begin{array}{l} \dot{x} = V \cos (\psi + \beta) \\ \dot{y} = V \sin (\psi + \beta) \\ \dot{\psi} = \frac{V \sin \beta}{l_r} \end{array} \right. ⎩ ⎨ ⎧x˙=Vcos(ψ+β)y˙=Vsin(ψ+β)ψ˙=lrVsinβ
其中, β = arctan ( l r l f + l r tan δ f ) \beta = \arctan \left(\frac{l_r}{l_f + l_r} \tan \delta_f\right) β=arctan(lf+lrlrtanδf)。
3.2 滑移角 β \beta β 的推导
-
几何关系:
- 假设后轮没有转向角( δ r = 0 \delta_r = 0 δr=0),前轮的转向角为 δ f \delta_f δf。
- 前轮的速度矢量
V
f
⃗
\vec{V_f}
Vf 可以表示为:
V f ⃗ = V cos ( δ f ) i ^ + V sin ( δ f ) j ^ \vec{V_f} = V \cos(\delta_f) \hat{i} + V \sin(\delta_f) \hat{j} Vf=Vcos(δf)i^+Vsin(δf)j^
-
重心速度矢量:
- 由于重心位于前后轮之间,重心的速度矢量
V
c
⃗
\vec{V_c}
Vc 可以表示为前后轮速度矢量的加权平均:
V c ⃗ = l r V f ⃗ l f + l r \vec{V_c} = \frac{l_r \vec{V_f}}{l_f + l_r} Vc=lf+lrlrVf - 将前轮的速度矢量代入上式:
V c ⃗ = V ( l r cos ( δ f ) l f + l r ) i ^ + V ( l r sin ( δ f ) l f + l r ) j ^ \vec{V_c} = V \left( \frac{l_r \cos(\delta_f)}{l_f + l_r} \right) \hat{i} + V \left( \frac{l_r \sin(\delta_f)}{l_f + l_r} \right) \hat{j} Vc=V(lf+lrlrcos(δf))i^+V(lf+lrlrsin(δf))j^
- 由于重心位于前后轮之间,重心的速度矢量
V
c
⃗
\vec{V_c}
Vc 可以表示为前后轮速度矢量的加权平均:
-
滑移角 β \beta β 的计算:
- 滑移角
β
\beta
β 是重心速度矢量
V
c
⃗
\vec{V_c}
Vc 与车辆纵向轴之间的夹角,可以通过以下公式计算:
tan ( β ) = 横向分量 纵向分量 = l r sin ( δ f ) l f + l r l r cos ( δ f ) l f + l r \tan(\beta) = \frac{\text{横向分量}}{\text{纵向分量}} = \frac{\frac{l_r \sin(\delta_f)}{l_f + l_r}}{\frac{l_r \cos(\delta_f)}{l_f + l_r}} tan(β)=纵向分量横向分量=lf+lrlrcos(δf)lf+lrlrsin(δf) - 简化得:
tan ( β ) = l r sin ( δ f ) l r cos ( δ f ) = tan ( δ f ) ⋅ l r l f + l r \tan(\beta) = \frac{l_r \sin(\delta_f)}{l_r \cos(\delta_f)} = \tan(\delta_f) \cdot \frac{l_r}{l_f + l_r} tan(β)=lrcos(δf)lrsin(δf)=tan(δf)⋅lf+lrlr - 因此,滑移角
β
\beta
β 可以表示为:
β = arctan ( l r l f + l r tan ( δ f ) ) \beta = \arctan \left( \frac{l_r}{l_f + l_r} \tan(\delta_f) \right) β=arctan(lf+lrlrtan(δf))
- 滑移角
β
\beta
β 是重心速度矢量
V
c
⃗
\vec{V_c}
Vc 与车辆纵向轴之间的夹角,可以通过以下公式计算:
3.3 Python代码实现
class KinematicModel_2:
def __init__(self, x, y, psi, v, l_r, l_f, dt):
self.x = x
self.y = y
self.psi = psi
self.v = v
self.l_f = l_f
self.l_r = l_r
self.dt = dt
def update_state(self, a, delta_f):
# 计算滑移角 β
beta = math.atan((self.l_r / (self.l_f + self.l_r)) * math.tan(delta_f))
# 更新状态
self.x += self.v * math.cos(self.psi + beta) * self.dt
self.y += self.v * math.sin(self.psi + beta) * self.dt
self.psi += (self.v * math.sin(beta) / self.l_r) * self.dt
self.v += a * self.dt
def get_state(self):
return self.x, self.y, self.psi, self.v
3.4 C++代码实现
class KinematicModel_2 {
public:
KinematicModel_2(double x, double y, double psi, double v, double l_r, double l_f, double dt) :
x(x), y(y), psi(psi), v(v), l_f(l_f), l_r(l_r), dt(dt) {}
void update_state(double a, double delta_f) {
// 计算滑移角 β
double beta = atan((l_r / (l_f + l_r)) * tan(delta_f));
// 更新状态
x += v * cos(psi + beta) * dt;
y += v * sin(psi + beta) * dt;
psi += (v * sin(beta) / l_r) * dt;
v += a * dt;
}
void get_state() const {
std::cout << "x: " << x << ", y: " << y << ", psi: " << psi << ", v: " << v << std::endl;
}
private:
double x, y, psi, v, l_f, l_r, dt;
};
4. 以后轴中心为车辆中心的单车模型
4.1 模型介绍
当以车辆后轴中心为参考点时,模型可以进一步简化。假设后轮没有转向角(
δ
r
=
0
\delta_r = 0
δr=0),模型可以表示为:
{ x ˙ = V cos ( ψ ) y ˙ = V sin ( ψ ) ψ ˙ = V L tan δ f \left\{ \begin{array}{l} \dot{x} = V \cos (\psi) \\ \dot{y} = V \sin (\psi) \\ \dot{\psi} = \frac{V}{L} \tan \delta_f \end{array} \right. ⎩ ⎨ ⎧x˙=Vcos(ψ)y˙=Vsin(ψ)ψ˙=LVtanδf
其中, L L L 是轴距, δ f \delta_f δf 是前轮转向角。
4.2 滑移角 β \beta β 的推导
-
几何关系:
- 假设后轮没有转向角( δ r = 0 \delta_r = 0 δr=0),前轮的转向角为 δ f \delta_f δf。
- 车辆的重心位于后轴中心,因此重心的速度矢量
V
c
⃗
\vec{V_c}
Vc 可以表示为:
V c ⃗ = V cos ( ψ ) i ^ + V sin ( ψ ) j ^ \vec{V_c} = V \cos(\psi) \hat{i} + V \sin(\psi) \hat{j} Vc=Vcos(ψ)i^+Vsin(ψ)j^
-
滑移角 β \beta β 的计算:
- 在这种模型中,滑移角 β \beta β 可以近似为0,因为重心位于后轴中心,且后轮没有转向角。
- 因此,滑移角
β
\beta
β 可以表示为:
β ≈ 0 \beta \approx 0 β≈0
4.3 Python代码实现
class KinematicModel_3:
def __init__(self, x, y, psi, v, L, dt):
self.x = x
self.y = y
self.psi = psi
self.v = v
self.L = L
self.dt = dt
def update_state(self, a, delta_f):
# 更新状态
self.x += self.v * math.cos(self.psi) * self.dt
self.y += self.v * math.sin(self.psi) * self.dt
self.psi += (self.v / self.L) * math.tan(delta_f) * self.dt
self.v += a * self.dt
def get_state(self):
return self.x, self.y, self.psi, self.v
4.4 C++代码实现
class KinematicModel_3 {
public:
KinematicModel_3(double x, double y, double psi, double v, double L, double dt) :
x(x), y(y), psi(psi), v(v), L(L), dt(dt) {}
void update_state(double a, double delta_f) {
// 更新状态
x += v * cos(psi) * dt;
y += v * sin(psi) * dt;
psi += (v / L) * tan(delta_f) * dt;
v += a * dt;
}
void get_state() const {
std::cout << "x: " << x << ", y: " << y << ", psi: " << psi << ", v: " << v << std::endl;
}
private:
double x, y, psi, v, L, dt;
};
5. 阿克曼转向几何
5.1 模型介绍
阿克曼转向几何(Ackerman Turning Geometry)是一种为了解决交通工具转弯时,内外转向轮路径指向的圆心不同的几何学。在单车模型中,将转向时左、右前轮偏角假设为同一角度
δ
f
\delta_f
δf,虽然通常两个角度大致相等,但实际并不是,通常情况下,内侧轮胎转角更大。
- 外轮转角: δ o = L R + l w 2 \delta_o = \frac{L}{R + \frac{l_w}{2}} δo=R+2lwL
- 内轮转角: δ i = L R − l w 2 \delta_i = \frac{L}{R - \frac{l_w}{2}} δi=R−2lwL
其中, l w l_w lw 为轮距, R R R 为轨迹半径。
5.2 滑移角 β \beta β 的推导
-
几何关系:
- 车辆转弯时,内外轮的轨迹半径不同。
- 外轮的轨迹半径为 R + l w 2 R + \frac{l_w}{2} R+2lw。
- 内轮的轨迹半径为 R − l w 2 R - \frac{l_w}{2} R−2lw。
-
转向角计算:
- 外轮转角
δ
o
\delta_o
δo 可以表示为:
δ o = L R + l w 2 \delta_o = \frac{L}{R + \frac{l_w}{2}} δo=R+2lwL - 内轮转角
δ
i
\delta_i
δi 可以表示为:
δ i = L R − l w 2 \delta_i = \frac{L}{R - \frac{l_w}{2}} δi=R−2lwL
- 外轮转角
δ
o
\delta_o
δo 可以表示为:
-
滑移角 β \beta β 的计算:
- 在阿克曼转向几何中,滑移角 β \beta β 主要取决于车辆的几何参数和转向角。
- 通常情况下,滑移角 β \beta β 可以近似为0,因为阿克曼转向几何设计使得内外轮的转向角能够很好地匹配车辆的转弯半径。
5.3 Python代码实现
class AckermannSteering:
def __init__(self, L, l_w, R):
self.L = L
self.l_w = l_w
self.R = R
def calculate_steering_angles(self, delta_f):
delta_o = self.L / (self.R + self.l_w / 2)
delta_i = self.L / (self.R - self.l_w / 2)
return delta_o, delta_i
5.4 C++代码实现
#include <cmath>
#include <iostream>
class AckermannSteering {
public:
AckermannSteering(double L, double l_w, double R) : L(L), l_w(l_w), R(R) {}
std::pair<double, double> calculate_steering_angles(double delta_f) {
double delta_o = L / (R + l_w / 2);
double delta_i = L / (R - l_w / 2);
return {delta_o, delta_i};
}
private:
double L, l_w, R;
};
6. 总结
本文详细介绍了车辆运动学模型的基本概念,并提供了Python和C++的实现代码。通过这些模型,我们可以更好地理解车辆在不同控制输入下的运动行为,这对于开发自动驾驶系统的控制策略至关重要。希望本文能够为自动驾驶领域的研究者和开发者提供有价值的参考。
参考资料
- 【自动驾驶】车辆运动学模型 - CSDN博客
以上就是《【自动驾驶】车辆运动学模型》的全部内容,希望能够帮助到你。如果你有任何疑问或者建议,欢迎留言交流!