自动驾驶横纵向耦合控制:复现 Apollo 横纵向控制的奇妙之旅
自动驾驶横纵向耦合控制-复现Apollo横纵向控制 基于动力学误差模型,使用mpc算法,一个控制器同时控制横向和纵向,实现横纵向耦合控制 matlab与simulink联合仿真,纵向控制已经做好油门刹车标定表,跟踪五次多项式换道轨迹,效果完美。 内含三套代码,两套采用面向对象编程-一套只对控制量添加约束,一套对控制量和控制增量均添加约束,另外一套采用面向过程编程。

在自动驾驶领域,横纵向耦合控制一直是个关键且充满挑战的话题。最近我基于动力学误差模型,运用 MPC 算法,成功实现了用一个控制器同时搞定横向和纵向的控制,也就是横纵向耦合控制,还通过 Matlab 与 Simulink 联合仿真进行了验证,效果超棒,现在就来和大家分享分享。
实现思路:基于动力学误差模型与 MPC 算法
我们知道,动力学误差模型能够很好地描述车辆实际状态与期望状态之间的差异,而 MPC(模型预测控制)算法则凭借其在预测未来状态并据此优化控制量的强大能力,成为了实现横纵向耦合控制的理想选择。通过建立合适的动力学误差模型,MPC 算法可以在每个控制周期内计算出最优的横纵向控制量,使得车辆能够精准地跟踪期望轨迹。
Matlab 与 Simulink 联合仿真
这次仿真中,纵向控制部分已经预先做好了油门刹车标定表。在实际应用里,油门刹车标定表就像是车辆纵向运动的“操作指南”,它根据不同的车速、路况等信息,精准地指示出应该施加多大的油门或刹车力度。这就好比给车辆的纵向运动配备了一个贴心的“私人教练”,让车辆在纵向行驶过程中表现得稳如老狗。

自动驾驶横纵向耦合控制-复现Apollo横纵向控制 基于动力学误差模型,使用mpc算法,一个控制器同时控制横向和纵向,实现横纵向耦合控制 matlab与simulink联合仿真,纵向控制已经做好油门刹车标定表,跟踪五次多项式换道轨迹,效果完美。 内含三套代码,两套采用面向对象编程-一套只对控制量添加约束,一套对控制量和控制增量均添加约束,另外一套采用面向过程编程。

在跟踪五次多项式换道轨迹时,整个系统表现堪称完美。五次多项式换道轨迹能够为车辆提供平滑、连续的换道路径,这对于保证乘客的乘坐舒适性以及车辆行驶的安全性至关重要。就像是在高速公路上,车辆优雅地从一条车道切换到另一条车道,既不突兀,又高效精准。
三套代码大揭秘
面向对象编程的两套代码
只对控制量添加约束
先看看第一套基于面向对象编程且只对控制量添加约束的代码。面向对象编程的好处就在于它把相关的数据和操作封装在一起,形成一个个对象,就像一个个独立的小盒子,每个盒子都有自己的功能。
classdef ControllerWithControlConstraint
properties
% 定义一些属性,比如车辆参数、约束条件等
vehicleParams;
controlConstraints;
end
methods
function obj = ControllerWithControlConstraint(params, constraints)
% 构造函数,初始化属性
obj.vehicleParams = params;
obj.controlConstraints = constraints;
end
function controlInput = calculateControl(obj, state, desiredState)
% 根据当前状态和期望状态计算控制量
% 这里面会用到动力学误差模型和 MPC 算法的相关计算
controlInput = zeros(2, 1); % 假设横纵向控制量各一个
% 计算控制量
controlInput(1) = calculateLateralControl(state, desiredState, obj.vehicleParams);
controlInput(2) = calculateLongitudinalControl(state, desiredState, obj.vehicleParams);
% 添加控制量约束
controlInput(1) = max(min(controlInput(1), obj.controlConstraints.lateralMax), obj.controlConstraints.lateralMin);
controlInput(2) = max(min(controlInput(2), obj.controlConstraints.longitudinalMax), obj.controlConstraints.longitudinalMin);
return;
end
end
end
在这段代码里,我们定义了一个 ControllerWithControlConstraint 类,它有 vehicleParams 和 controlConstraints 两个属性,分别用来存储车辆参数和控制约束条件。calculateControl 方法就是根据当前车辆状态 state 和期望状态 desiredState 来计算控制量。先分别计算横纵向控制量,然后根据设定的约束条件,把控制量限制在合理范围内,避免出现不切实际的控制指令,就好比给车辆的行为划定了一个“安全区”。
对控制量和控制增量均添加约束
再瞧瞧第二套同样是面向对象编程,但对控制量和控制增量都添加约束的代码。
classdef ControllerWithBothConstraints
properties
vehicleParams;
controlConstraints;
controlIncrementConstraints;
end
methods
function obj = ControllerWithBothConstraints(params, controlCons, incrementCons)
% 构造函数,初始化属性
obj.vehicleParams = params;
obj.controlConstraints = controlCons;
obj.controlIncrementConstraints = incrementCons;
end
function controlInput = calculateControl(obj, state, desiredState, prevControl)
% 根据当前状态、期望状态和上一时刻控制量计算控制量
controlInput = zeros(2, 1); % 假设横纵向控制量各一个
% 计算控制量
controlInput(1) = calculateLateralControl(state, desiredState, obj.vehicleParams);
controlInput(2) = calculateLongitudinalControl(state, desiredState, obj.vehicleParams);
% 添加控制量约束
controlInput(1) = max(min(controlInput(1), obj.controlConstraints.lateralMax), obj.controlConstraints.lateralMin);
controlInput(2) = max(min(controlInput(2), obj.controlConstraints.longitudinalMax), obj.controlConstraints.longitudinalMin);
% 添加控制增量约束
controlIncrement(1) = controlInput(1) - prevControl(1);
controlIncrement(2) = controlInput(2) - prevControl(2);
controlIncrement(1) = max(min(controlIncrement(1), obj.controlIncrementConstraints.lateralMax), obj.controlIncrementConstraints.lateralMin);
controlIncrement(2) = max(min(controlIncrement(2), obj.controlIncrementConstraints.longitudinalMax), obj.controlIncrementConstraints.longitudinalMin);
controlInput(1) = prevControl(1) + controlIncrement(1);
controlInput(2) = prevControl(2) + controlIncrement(2);
return;
end
end
end
这个 ControllerWithBothConstraints 类比上一个类多了一个 controlIncrementConstraints 属性,用来存储控制增量的约束条件。在 calculateControl 方法里,除了像之前一样对控制量进行约束,还计算了控制增量,并把控制增量也限制在合理范围内。这样做的好处是可以让控制量的变化更加平滑,避免车辆出现突然的大幅动作,就像是给车辆的“动作幅度”也加上了一个限制,让车辆开起来更加平稳。
面向过程编程的代码
最后是面向过程编程的那套代码。面向过程编程更侧重于按照步骤来执行一系列操作。
function controlInput = processOrientedController(state, desiredState, vehicleParams, controlConstraints, controlIncrementConstraints, prevControl)
controlInput = zeros(2, 1); % 假设横纵向控制量各一个
% 计算控制量
controlInput(1) = calculateLateralControl(state, desiredState, vehicleParams);
controlInput(2) = calculateLongitudinalControl(state, desiredState, vehicleParams);
% 添加控制量约束
controlInput(1) = max(min(controlInput(1), controlConstraints.lateralMax), controlConstraints.lateralMin);
controlInput(2) = max(min(controlInput(2), controlConstraints.longitudinalMax), controlConstraints.longitudinalMin);
% 添加控制增量约束
controlIncrement(1) = controlInput(1) - prevControl(1);
controlIncrement(2) = controlInput(2) - prevControl(2);
controlIncrement(1) = max(min(controlIncrement(1), controlIncrementConstraints.lateralMax), controlIncrementConstraints.lateralMin);
controlIncrement(2) = max(min(controlIncrement(2), controlIncrementConstraints.longitudinalMax), controlIncrementConstraints.longitudinalMin);
controlInput(1) = prevControl(1) + controlIncrement(1);
controlInput(2) = prevControl(2) + controlIncrement(2);
return;
end
这段代码以函数的形式实现了同样的功能,通过传入各种参数,包括车辆状态、期望状态、车辆参数、控制约束和控制增量约束以及上一时刻的控制量,来计算出当前时刻的控制量。它没有像面向对象编程那样把数据和操作封装在类里,而是直接按照步骤进行计算和约束处理,也能很好地完成横纵向耦合控制的任务,就像是一个简洁直接的“操作手册”,一步一步指导车辆该怎么控制。

这次在自动驾驶横纵向耦合控制上的探索,通过基于动力学误差模型和 MPC 算法,结合 Matlab 与 Simulink 联合仿真,以及这三套不同风格的代码,让我对自动驾驶控制有了更深的理解,希望也能给大家带来一些启发。

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)