AD_车辆运动无模型横向控制_前后轮反馈控制
·
车辆横向控制(Lateral Vehicle Control)是自动驾驶和高级驾驶辅助系统(ADAS)中的关键技术之一,其目标是使车辆沿期望路径行驶。在实现这一目标时,常采用前轮反馈控制(Front-wheel Feedback Control)和后轮反馈控制(Rear-wheel Feedback Control)两种策略。下面将从原理、建模、控制律设计、优缺点等方面对二者进行详细说明。
一、基本概念
- 前轮反馈控制:以车辆前轮(转向轮)为控制输入,通过调节前轮转角来跟踪期望路径。
- 后轮反馈控制:以车辆后轮为参考点,通过调节前轮转角使后轮轨迹跟踪期望路径。
注:虽然实际控制量仍是前轮转角(因为绝大多数乘用车只能前轮转向),但“后轮反馈”指的是控制器的误差计算基于后轮位置而非前轮或质心。
二、车辆运动学模型(简化自行车模型)
为便于分析,通常采用单车模型(Bicycle Model):
-
车辆简化为前后两个轮子,前轮可转向,后轮固定。
-
状态变量包括:



-
控制输入:前轮转角 δδ
运动学方程(以后轴中心为参考点):

其中 L 为轴距。
三、前轮反馈控制(Front-wheel Feedback Control)
1. 误差定义
将前轮位置作为跟踪点。
前轮坐标:



2. 控制律设计(典型方法:几何法或线性化反馈)
一种常用形式(基于小角度近似):

其中:
- RR 是期望路径的曲率半径(由路径规划给出),
- k1,k2 为反馈增益。
或在线性化后使用状态反馈:

3. 特点
- 优点:
- 直观,符合驾驶员直觉(看车头方向)。
- 对高速场景响应较快。
- 缺点:
- 在低速或大曲率路径下,前轮可能“冲出”路径外侧。
- 对路径曲率变化敏感。
四、后轮反馈控制(Rear-wheel Feedback Control)
1. 误差定义



2. 控制律设计(经典:Stanley 控制器 或 线性状态反馈)
方法一:线性状态反馈(适用于小曲率路径)
对误差动态线性化后得到:

设计控制律:

方法二:Stanley 控制器(非线性,广泛用于自动驾驶)


3. 特点
- 优点:
- 后轮轨迹更贴近路径,适合泊车、窄道等场景。
- 系统稳定性更好,尤其在低速时。
- 更容易保证整个车身不偏离路径。
- 缺点:
- 响应略滞后(因控制目标在后方)。
- 高速大曲率时可能转向不足。
五、对比总结
| 项目 | 前轮反馈控制 | 后轮反馈控制 |
|---|---|---|
| 参考点 | 前轮位置 | 后轮位置 |
| 适用场景 | 高速巡航、高速公路 | 低速、狭窄道路、自动泊车 |
| 路径跟踪精度 | 前轮贴合好,车身可能偏移 | 后轮贴合好,整体车身居中 |
| 稳定性 | 对曲率突变敏感 | 更鲁棒,尤其低速 |
| 典型算法 | 几何预瞄、纯追踪(Pure Pursuit)前轮版 | 前轮版 Stanley、后轮纯追踪 |
| 实际应用 | 较少单独使用 | 广泛用于自动驾驶(如Stanley) |
注:Pure Pursuit(纯追踪)算法本质上是一种前轮反馈方法,因为它根据前视点计算前轮转角,使前轮指向目标点。
六、实际工程选择建议
- 城市低速自动驾驶(<30 km/h):推荐后轮反馈(如Stanley),确保车身不压线。
- 高速公路场景(>60 km/h):可结合前轮反馈与模型预测控制(MPC),兼顾响应与舒适性。
- 高精度路径跟踪(如矿区、港口AGV):常以后轮或质心为参考,使用后轮反馈+MPC。
七、扩展:质心反馈控制
除前后轮外,也可选择车辆质心作为反馈点,此时需引入质心位置动力学,适用于高动态或四轮转向车辆。
八、前后轮反馈控制代码
码基于单车运动学模型(Bicycle Kinematic Model),并包含路径跟踪仿真。共同设定(适用于两种语言):
- 车辆模型:后轴中心为参考点
- 控制输入:前轮转角 delta
- 路径:正弦曲线 y = 2 * sin(x / 10)
- 初始状态:x=0, y=-1, psi=0
- 纵向速度恒定:v = 2.0 m/s
- 仿真时间:30 秒,步长 0.1 秒
python
- 切换 use_rear_feedback = False 可测试前轮反馈。
- 前轮反馈此处为简化实现(实际更常用 Pure Pursuit 或 MPC)。
import numpy as np
import matplotlib.pyplot as plt
from scipy.interpolate import interp1d
# ---------- 参数设置 ----------
L = 2.9 # 轴距 (m)
v = 2.0 # 纵向速度 (m/s)
dt = 0.1 # 时间步长 (s)
T = 30 # 总时间 (s)
N = int(T / dt)
# 路径定义:y = 2 * sin(x / 10)
x_ref = np.linspace(0, 50, 500)
y_ref = 2.0 * np.sin(x_ref / 10.0)
# 插值函数(用于计算任意 x 处的 y 和 dy/dx)
f_y = interp1d(x_ref, y_ref, kind='cubic', fill_value="extrapolate")
f_dy = lambda x: (2.0 / 10.0) * np.cos(x / 10.0) # 解析导数
# ---------- 初始状态 ----------
x, y, psi = 0.0, -1.0, 0.0
# 存储轨迹
x_hist = [x]
y_hist = [y]
psi_hist = [psi]
delta_hist = []
# ---------- 控制增益 ----------
k_e = 1.0 # Stanley 增益(后轮反馈)
k_front = 1.0 # 前轮反馈增益(简化版)
use_rear_feedback = True # 切换:True 用 Stanley(后轮),False 用前轮反馈
# ---------- 仿真循环 ----------
for i in range(N):
# 当前位置
current_x, current_y = x, y
# 找到路径上最近点(简化:按 x 投影)
if current_x < x_ref[0]:
idx = 0
elif current_x > x_ref[-1]:
idx = -1
else:
idx = np.argmin(np.abs(x_ref - current_x))
x_closest = x_ref[idx]
y_closest = y_ref[idx]
dy_dx = f_dy(x_closest)
psi_path = np.arctan2(dy_dx, 1.0) # 路径切线角
if use_rear_feedback:
# ===== 后轮反馈:Stanley 控制器 =====
# 横向误差:从后轮到路径的垂直距离(简化为 y 方向投影)
e_lat = -(current_y - y_closest) * np.cos(psi_path) + (current_x - x_closest) * np.sin(psi_path)
# 航向误差
e_psi = psi - psi_path
# Stanley 控制律
delta = e_psi + np.arctan2(k_e * e_lat, v + 1e-5)
else:
# ===== 前轮反馈控制(简化几何法)=====
# 前轮位置
x_f = x + L * np.cos(psi)
y_f = y + L * np.sin(psi)
# 前轮到路径的横向误差(简化)
e_lat_f = -(y_f - f_y(x_f))
e_psi = psi - psi_path
# 控制律(近似)
delta = np.arctan2(L * dy_dx, 1.0) + k_front * e_lat_f
# 限制转向角(±30度)
delta = np.clip(delta, -np.pi/6, np.pi/6)
# 更新车辆状态(运动学模型)
x += v * np.cos(psi) * dt
y += v * np.sin(psi) * dt
psi += (v / L) * np.tan(delta) * dt
# 存储
x_hist.append(x)
y_hist.append(y)
psi_hist.append(psi)
delta_hist.append(delta)
# ---------- 绘图 ----------
plt.figure(figsize=(10, 6))
plt.plot(x_ref, y_ref, 'k--', label='Reference Path')
plt.plot(x_hist, y_hist, 'b-', linewidth=2, label='Vehicle Trajectory')
plt.xlabel('X (m)')
plt.ylabel('Y (m)')
plt.title('Lateral Control: {} Feedback'.format('Rear-wheel (Stanley)' if use_rear_feedback else 'Front-wheel'))
plt.legend()
plt.grid(True)
plt.axis('equal')
plt.show()
# 转向角随时间变化
t = np.arange(0, T, dt)
plt.figure()
plt.plot(t, np.array(delta_hist) * 180 / np.pi)
plt.xlabel('Time (s)')
plt.ylabel('Steering Angle (deg)')
plt.title('Steering Command')
plt.grid(True)
plt.show()
matlab
- 若 MATLAB 版本 ≥ R2016b,可直接用 string 或逻辑索引替代 ternary。
- interp1 使用 ‘pchip’ 保证平滑导数。
%% 车辆横向控制:前轮 vs 后轮反馈
clear; clc; close all;
% ---------- 参数 ----------
L = 2.9; % 轴距 (m)
v = 2.0; % 纵向速度 (m/s)
dt = 0.1; % 时间步长
T = 30; % 总时间
N = T / dt;
% 路径:y = 2*sin(x/10)
x_ref = linspace(0, 50, 500);
y_ref = 2 * sin(x_ref / 10);
% 插值函数
f_y = @(x) interp1(x_ref, y_ref, x, 'pchip', 'extrap');
f_dy = @(x) (2/10) * cos(x / 10); % 解析导数
% 初始状态
x = 0; y = -1; psi = 0;
% 存储
x_hist = zeros(1, N+1); y_hist = zeros(1, N+1); psi_hist = zeros(1, N+1);
delta_hist = zeros(1, N);
x_hist(1) = x; y_hist(1) = y; psi_hist(1) = psi;
% 控制参数
k_e = 1.0; % Stanley 增益
k_front = 1.0; % 前轮反馈增益
useRearFeedback = true; % true: Stanley (后轮), false: 前轮反馈
% ---------- 仿真 ----------
for i = 1:N
% 找最近点(按 x 投影)
[~, idx] = min(abs(x_ref - x));
x_c = x_ref(idx);
y_c = y_ref(idx);
dy_dx = f_dy(x_c);
psi_path = atan2(dy_dx, 1);
if useRearFeedback
% ----- 后轮反馈:Stanley -----
e_lat = -(y - y_c)*cos(psi_path) + (x - x_c)*sin(psi_path);
e_psi = psi - psi_path;
delta = e_psi + atan(k_e * e_lat / (v + 1e-5));
else
% ----- 前轮反馈(简化)-----
x_f = x + L * cos(psi);
y_f = y + L * sin(psi);
e_lat_f = -(y_f - f_y(x_f));
e_psi = psi - psi_path;
delta = atan(L * dy_dx) + k_front * e_lat_f;
end
% 限幅 ±30度
delta = max(min(delta, pi/6), -pi/6);
% 更新状态
x = x + v * cos(psi) * dt;
y = y + v * sin(psi) * dt;
psi = psi + (v / L) * tan(delta) * dt;
% 存储
x_hist(i+1) = x;
y_hist(i+1) = y;
psi_hist(i+1) = psi;
delta_hist(i) = delta;
end
% ---------- 绘图 ----------
figure;
plot(x_ref, y_ref, 'k--', 'LineWidth', 1.5); hold on;
plot(x_hist, y_hist, 'b-', 'LineWidth', 2);
xlabel('X (m)'); ylabel('Y (m)');
title(sprintf('Lateral Control: %s Feedback', ...
ternary(useRearFeedback, 'Rear-wheel (Stanley)', 'Front-wheel')));
legend('Reference Path', 'Vehicle Trajectory');
grid on; axis equal;
% 转向角
t = (0:N-1)*dt;
figure;
plot(t, rad2deg(delta_hist), 'r-', 'LineWidth', 1.5);
xlabel('Time (s)'); ylabel('Steering Angle (deg)');
title('Steering Command');
grid on;
% 辅助函数(MATLAB R2016b 以下需定义 ternary)
function out = ternary(condition, a, b)
if condition, out = a; else, out = b; end
end
代码说明
| 模块 | 说明 |
|---|---|
| 路径表示 | 使用解析函数 + 插值,避免查表误差 |
| 误差计算 | 后轮反馈采用垂直距离投影(更准确);前轮反馈简化处理 |
| Stanley 控制器 | 经典后轮反馈方法,含航向误差 + 横向误差耦合 |
| 前轮反馈 | 此处为教学简化版,实际工程多用 Pure Pursuit 或 MPC |
| 转向限幅 | ±30°(典型乘用车极限) |
更多推荐
所有评论(0)