运动学模型的前向递推-IDM与自行车
智能驾驶员模型(Intelligent Driver Model, IDM)
🚗 智能驾驶员模型 (IDM) 详解IDM 的核心目标是计算自车的期望加速度 a,这个加速度 a 会在两个极端情况之间取得平衡:
自由流驾驶(Free Driving): 当前方没有车辆时,车辆倾向于加速至其期望速度 v0 。
跟车驾驶(Car Following): 当与前车距离较近时,车辆必须减速以保持一个动态的安全距离 s∗ 。
aIDM=amax[1−(v0v)δ−(ss∗)2]
公式主要由三部分组成:
① 自由流加速度项(Free-Driving Term):amax[1−(v0v)δ]
- 目的: 描述车辆在没有前车阻碍时,如何加速到其目标速度 v0 。
- 行为:
当自车速度 v 远小于期望速度 v0 时,该项接近 amax(最大加速度)。
当 v 接近 v0 时,该项接近 0,加速度减小。
当 v 超过 v0 时,该项变为负值,车辆开始减速。
② 跟车制动项(Interaction/Braking Term):−amax(ss∗)2
当实际距离 s 远大于期望安全距离 s∗ 时,该项接近 0,跟车影响很小。
当 s 接近 s∗ 时,该项急剧减小(变为较大的负值),产生强大的制动力。
2. 动态期望安全距离 s∗
在 IDM 中,安全距离 s∗ 不是一个固定值,它会根据自车速度 v 和相对速度 vrel 动态调整,是 IDM 的关键所在。
s∗=s0+vT+2amaxbmaxv⋅vrel
其中:
| 符号 |
描述 |
组成部分 |
作用 |
| s0 |
静止安全距离 |
s0 |
车辆静止时与前车应保持的最小距离(防止追尾)。 |
| vT |
速度相关距离 |
vT |
确保在期望时距 T 内,前车突然停车,自车有时间反应并制动。 |
| ...v⋅vrel |
相对速度距离 |
2amaxbmaxv⋅vrel |
动态制动距离。如果 vrel>0(自车比前车快),需要更大的安全距离来缓冲制动。 |
3. 模型输入与参数定义
要实现 IDM,需要以下输入(来自传感器)和参数(模型标定):
| 类别 |
符号 |
含义 |
示例值 |
| 输入 |
v |
自车当前速度 |
15 m/s |
|
vfront |
前车当前速度 |
13 m/s |
|
s |
自车与前车的净距 |
20 m |
| 参数 |
v0 |
期望最大速度(目标速度) |
30 m/s |
|
amax |
最大舒适加速度 |
1.5 m/s2 |
|
bmax |
最大舒适减速度 |
3.0 m/s2 |
|
T |
期望时距(Time Headway) |
1.5 s |
|
s0 |
静止安全距离 |
2.0 m |
简易实现
步骤 1:计算相对速度
vrel=v−vfront
步骤 2:计算动态期望安全距离 s∗
使用 v, vrel, 和模型参数计算 s∗ 。
1 2 3 4 5 6 7 8
| # 计算 sqrt(a_max * b_max) denom = 2 * sqrt(a_max * b_max)
# 计算动态项 (相对速度项) dynamic_term = (v * v_rel) / denom
# 计算 s* s_star = s0 + v * T + dynamic_term
|
步骤 3:计算 IDM 加速度 aIDM
将 v0, v, s, 和 s∗ 代入主公式:
1 2 3 4 5 6 7 8
| # 1. 自由流项 free_flow_term = 1 - (v / v0)**delta
# 2. 跟车制动项 braking_term = -(s_star / s)**2
# 3. 最终加速度 (基础值) a_idm_base = a_max * (free_flow_term + braking_term)
|
步骤 4:限制输出加速度
计算出的 aIDM 必须限制在物理和舒适性范围之内。
afinal=clip(aIDM,−bmax,amax)
示例伪代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
| #include <cmath> #include <algorithm>
struct IDM_Parameters { double a_max; double v0; double delta; double s0; double T; double b_max; };
class IntelligentDriverModel { public: IntelligentDriverModel(const IDM_Parameters& params) : params_(params) {}
double calculate_acceleration(double v_ego, double v_front, double s_gap) const { v_ego = std::max(v_ego, 0.0); s_gap = std::max(s_gap, 0.1);
double v_rel = v_ego - v_front;
double denom = 2.0 * std::sqrt(params_.a_max * params_.b_max); double dynamic_term = (v_ego * v_rel) / denom;
double s_star = params_.s0 + params_.T * v_ego + dynamic_term;
double free_flow_term; if (params_.v0 > 1e-6) { free_flow_term = 1.0 - std::pow(v_ego / params_.v0, params_.delta); } else { free_flow_term = 1.0; }
double braking_term = -std::pow(s_star / s_gap, 2.0);
double a_idm_base = params_.a_max * (free_flow_term + braking_term);
double a_final = std::max(-params_.b_max, a_idm_base); a_final = std::min(params_.a_max, a_final); return a_final; }
private: IDM_Parameters params_; };
void main_example() { IDM_Parameters default_params = { 1.5, 30.0, 4.0, 2.0, 1.5, 3.0 };
IntelligentDriverModel idm(default_params);
double v_ego = 15.0; double v_front = 13.0; double s_gap = 20.0;
double acceleration = idm.calculate_acceleration(v_ego, v_front, s_gap);
}
|
运动学自行车模型的前向仿真
🚲 运动学自行车模型 (Kinematic Bicycle Model)
模型定义车辆状态 S 和控制输入 U:
状态 S:
S=[x,y,ψ,v]T
x,y: 后轴中心的世界坐标。
ψ (yaw): 车辆的航向角(相对于 x 轴)。
v: 车辆的纵向速度。
控制输入 U:
U=[a,δ]T
a (acceleration): 纵向加速度。
δ (steering_angle): 前轮转向角。
运动学方程
车辆状态随时间变化的一阶微分方程如下:
x˙y˙ψ˙v˙=vcos(ψ)=vsin(ψ)=Lvtan(δ)=a
其中 L 是轴距(Wheelbase)。
知道 xt,要得到 xt+1,怎么实现呢?
状态的导数方程我们已经知道S˙=[x˙,y˙,ψ˙,v˙]T
欧拉法前向积分
欧拉法的基本思想是利用泰勒级数展开的一阶近似,假设在很短的时间步长 Δt 内,状态的变化率(导数)S˙(tk) 保持不变。
此时S(tk+1)≈S(tk)+Slope⋅(tk+1−tk)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
| struct State { double x; double y; double yaw; double v; };
struct ControlInput { double acceleration; double steering_angle; };
class KinematicBicycleModel { public: const double L;
KinematicBicycleModel(double wheelbase) : L(wheelbase) {}
State predict_euler(const State& current_state, const ControlInput& input_u, double dt) const {
double x_dot = current_state.v * std::cos(current_state.yaw);
double y_dot = current_state.v * std::sin(current_state.yaw);
double yaw_dot = 0.0; if (std::abs(L) > 1e-6) { yaw_dot = (current_state.v / L) * std::tan(input_u.steering_angle); } double v_dot = input_u.acceleration;
State next_state;
next_state.x = current_state.x + x_dot * dt; next_state.y = current_state.y + y_dot * dt; next_state.yaw = current_state.yaw + yaw_dot * dt; next_state.v = current_state.v + v_dot * dt;
next_state.v = std::max(0.0, next_state.v);
next_state.yaw = normalize_angle(next_state.yaw);
return next_state; }
private:
double normalize_angle(double angle) const { angle = std::fmod(angle + M_PI, 2.0 * M_PI); if (angle < 0) { angle += 2.0 * M_PI; } return angle - M_PI; } };
void main_example() { KinematicBicycleModel model(2.8); double dt = 0.1;
State current_state = { 0.0, 0.0, M_PI / 4, 5.0 };
ControlInput input_u = { 0.5, 0.1745 };
std::cout << "初始状态: x=" << current_state.x << ", y=" << current_state.y << ", yaw=" << current_state.yaw << ", v=" << current_state.v << std::endl;
for (int i = 0; i < 10; ++i) { current_state = model.predict_euler(current_state, input_u, dt); }
std::cout << "1秒后状态: x=" << current_state.x << ", y=" << current_state.y << ", yaw=" << current_state.yaw << ", v=" << current_state.v << std::endl; }
|
四阶龙格-库塔法(RK4)积分
比欧拉法精度高得多。四阶方法,意味着其局部误差与 (Δt)5 成正比,全局误差与 (Δt)4 成正比。
积分步骤
1.算四个斜率 k1,k2,k3,k4k1k2k3k4=f(Sk,Uk)=f(Sk+k12Δt,Uk)=f(Sk+k22Δt,Uk)=f(Sk+k3Δt,Uk)
2.计算加权平均变化率
四个斜率按照 1:2:2:1 的比例加权平均:
S˙_avg=61(k_1+2k_2+2k_3+k_4)
3.更新状态
Sk+1=Sk+S˙avg⋅Δt
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
| #include <cmath> #include <algorithm> #include <iostream> #include <vector>
#ifndef M_PI #define M_PI 3.14159265358979323846 #endif
struct State { double x; double y; double yaw; double v; };
struct ControlInput { double acceleration; double steering_angle; };
struct StateDerivative { double x_dot; double y_dot; double yaw_dot; double v_dot; };
class KinematicBicycleModelRK4 { public: const double L;
KinematicBicycleModelRK4(double wheelbase) : L(wheelbase) {}
State predict_rk4(const State& current_state, const ControlInput& input_u, double dt) const { StateDerivative k1 = calculate_s_dot(current_state, input_u);
State s_temp1 = add_state_derivative(current_state, k1, dt / 2.0); StateDerivative k2 = calculate_s_dot(s_temp1, input_u);
State s_temp2 = add_state_derivative(current_state, k2, dt / 2.0); StateDerivative k3 = calculate_s_dot(s_temp2, input_u);
State s_temp3 = add_state_derivative(current_state, k3, dt); StateDerivative k4 = calculate_s_dot(s_temp3, input_u);
StateDerivative s_dot_avg; s_dot_avg.x_dot = (k1.x_dot + 2.0 * k2.x_dot + 2.0 * k3.x_dot + k4.x_dot) / 6.0; s_dot_avg.y_dot = (k1.y_dot + 2.0 * k2.y_dot + 2.0 * k3.y_dot + k4.y_dot) / 6.0; s_dot_avg.yaw_dot = (k1.yaw_dot + 2.0 * k2.yaw_dot + 2.0 * k3.yaw_dot + k4.yaw_dot) / 6.0; s_dot_avg.v_dot = (k1.v_dot + 2.0 * k2.v_dot + 2.0 * k3.v_dot + k4.v_dot) / 6.0;
State next_state = add_state_derivative(current_state, s_dot_avg, dt);
next_state.v = std::max(0.0, next_state.v); next_state.yaw = normalize_angle(next_state.yaw);
return next_state; }
private:
StateDerivative calculate_s_dot(const State& s, const ControlInput& u) const { StateDerivative s_dot; const double L_safe = (std::abs(L) > 1e-6) ? L : 1e-6;
s_dot.x_dot = s.v * std::cos(s.yaw);
s_dot.y_dot = s.v * std::sin(s.yaw);
s_dot.yaw_dot = (s.v / L_safe) * std::tan(u.steering_angle); s_dot.v_dot = u.acceleration;
return s_dot; }
State add_state_derivative(const State& s, const StateDerivative& s_dot, double delta_t) const { State s_new; s_new.x = s.x + s_dot.x_dot * delta_t; s_new.y = s.y + s_dot.y_dot * delta_t; s_new.yaw = s.yaw + s_dot.yaw_dot * delta_t; s_new.v = s.v + s_dot.v_dot * delta_t; s_new.v = std::max(0.0, s_new.v); return s_new; }
double normalize_angle(double angle) const { angle = std::fmod(angle + M_PI, 2.0 * M_PI); if (angle < 0) { angle += 2.0 * M_PI; } return angle - M_PI; } };
int main() { KinematicBicycleModelRK4 model(2.8); double dt = 0.1;
State current_state = { 0.0, 0.0, M_PI / 4, 5.0 };
ControlInput input_u = { 0.5, 0.1745 };
std::cout << "--- RK4 运动学模型仿真 ---" << std::endl; std::cout << "初始状态: x=" << current_state.x << ", y=" << current_state.y << ", yaw=" << current_state.yaw << " rad, v=" << current_state.v << " m/s" << std::endl;
for (int i = 0; i < 10; ++i) { current_state = model.predict_rk4(current_state, input_u, dt); }
std::cout << "\n1秒后状态 (RK4):" << std::endl; std::cout << "x=" << current_state.x << " m, y=" << current_state.y << " m" << std::endl; std::cout << "yaw=" << current_state.yaw << " rad (" << current_state.yaw * 180.0 / M_PI << " deg)" << std::endl; std::cout << "v=" << current_state.v << " m/s" << std::endl;
return 0; }
|