文章目录
前言
一、PID控制器是什么?
PID 控制器是一种反馈控制机制,用于将系统的实际输出与期望输出之间的误差最小化。它由三部分组成:比例(P)、积分(I)和微分(D)控制。
PID 控制器公式
PID 控制器的基本公式如下:
u ( t ) = K p e ( t ) + K i ∫ 0 t e ( τ ) d τ + K d d d t e ( t ) u(t) = K_p e(t) + K_i \int_0^t e(\tau) \, d\tau + K_d \frac{d}{dt} e(t) u(t)=Kpe(t)+Ki∫0te(τ)dτ+Kddtde(t)
其中:
- ( u(t) ) 是控制输出
- ( e(t) ) 是误差,即设定点与过程变量之间的差值
- ( K_p ) 是比例增益
- ( K_i ) 是积分增益
- ( K_d ) 是微分增益
具体分量解释:
- 比例项:( K_p e(t) )
- 积分项:( K_i \int_0^t e(\tau) , d\tau )
- 微分项:( K_d \frac{d}{dt} e(t) )
每个项的作用如下:
- 比例项用于快速响应并减小误差。
- 积分项用于消除稳态误差。
- 微分项用于预测误差的变化趋势,从而提高系统的稳定性。
二、代码解释
1.代码
代码如下(示例):
class PidController
{
public:
PidController() = default;
explicit PidController(float _p, float _i, float _d, float _ramp, float _limit) :
p(_p), i(_i), d(_d), outputRamp(_ramp), limit(_limit)
{
timeStamp = micros();
}
float operator()(float error);
float p = 0;
float i = 0;
float d = 0;
float outputRamp = 0;
float limit = 0;
protected:
float errorLast = 0;
float outputLast = 0;
float integralLast = 0;
unsigned long timeStamp = 0;
};
float PidController::operator()(float error)
{
auto time = micros(); // 获取当前时间(以微秒为单位)
float dt = (float) (time - timeStamp) * 1e-6f; // 计算时间间隔(秒)
// Quick fix for strange cases (micros overflow)
if (dt <= 0 || dt > 0.5f) dt = 1e-3f; // 时间间隔的合理性检查
// 比例项计算
float pTerm = p * error;
// 积分项计算(梯形积分)
float iTerm = integralLast + i * dt * 0.5f * (error + errorLast);
iTerm = CONSTRAINT(iTerm, -limit, limit); // 限制积分项在范围内
// 微分项计算
float dTerm = d * (error - errorLast) / dt;
// 总输出计算
float output = pTerm + iTerm + dTerm;
output = CONSTRAINT(output, -limit, limit); // 限制输出在范围内
// 如果定义了输出斜坡
if (outputRamp > 0)
{
// 限制输出的加速度(斜坡限制)
float outputRate = (output - outputLast) / dt;
if (outputRate > outputRamp)
output = outputLast + outputRamp * dt;
else if (outputRate < -outputRamp)
output = outputLast - outputRamp * dt;
}
// 更新状态
integralLast = iTerm;
outputLast = output;
errorLast = error;
timeStamp = time;
return output; // 返回控制器的输出值
}
这段代码实现了一个典型的 PID 控制器
2.详细解释
2.1.时间计算和合理性检查
auto time = micros(); // 获取当前时间
float dt = (float) (time - timeStamp) * 1e-6f; // 计算时间间隔(微秒)
if (dt <= 0 || dt > 0.5f) dt = 1e-3f; // 处理时间间隔异常
- 使用 micros() 函数获取当前时间(单位是微秒)。
- 计算当前时间和上次更新时间之间的时间间隔 dt。
- 处理 dt 的异常情况,比如时间溢出或异常值,将其设为默认值 1e-3f(1毫秒)。
2.1.比例项
float pTerm = p * error;
- 比例项是根据当前误差 error 计算的。比例增益 p 决定了比例控制的强度。
- p: 这是比例增益(Proportional Gain),一个调整系数,用于决定比例控制的强度。比例增益是一个常数,通常由用户根据具体系统的需求进行调整。
- error: 这是当前误差值,计算为系统的目标值(setpoint)与实际值(process variable)之间的差值。
- 比例控制的目标是减少误差。比例增益 p 通过与误差 error 相乘,生成一个控制信号,这个信号与误差成正比,通过调整比例增益 p,可以控制系统的响应速度和稳定性。
- 比例项是当前误差的线性函数。比例增益 p 决定了系统对误差的敏感度。较大的比例增益会使系统对误差更敏感,快速反应;较小的比例增益则会使系统反应较慢。
2.1.积分项
float iTerm = integralLast + i * dt * 0.5f * (error + errorLast);
iTerm = CONSTRAINT(iTerm, -limit, limit); // 限制积分项
- 使用梯形积分法来更新积分项 iTerm,梯形积分法使用当前误差和上一次误差的平均值来近似误差积分。
梯形积分法是一种数值积分方法,其基本原理如下:
将被积函数曲线下的面积近似为多个梯形的面积之和。
-
integralLast: 上一次计算的积分项值。这是前一次控制器状态保存的积分项,用于计算当前的积分项。
-
i: 积分增益(Integral Gain),一个常数,用于决定积分控制的强度。
-
dt: 当前时间间隔(秒),计算为当前时间与上次时间的差值。
-
error: 当前误差值,即目标值与实际值之间的差值。
-
errorLast: 上一次的误差值,用于计算积分的平均值。
-
CONSTRAINT 函数用于限制积分项在指定范围内,以防止积分饱和。
-
积分项的主要作用是消除系统中的稳态误差,即使误差很小,积分项会逐渐累积以使系统达到期望值。
在 PID 控制器中,通过计算误差的平均值并乘以时间间隔 dt,可以得到在这个时间间隔内的积分增量。这样做是为了在离散时间控制系统中近似积分的计算,同时避免直接计算积分的复杂性。
2.1.微分项
float dTerm = d * (error - errorLast) / dt;
- 微分项根据误差的变化率来计算。d 是微分增益,error - errorLast 是误差的变化量,dt 是时间间隔。误差的变化量除以时间间隔计算误差变化的速率,即误差的导数。
- 微分项考虑误差的变化率,有助于预测未来误差趋势。
- 通过对误差变化的响应,微分项可以帮助减少系统的振荡,提高系统稳定性。
- 增强对误差变化的响应,提高系统的动态性能。
2.1.总输出计算
float output = pTerm + iTerm + dTerm;
output = CONSTRAINT(output, -limit, limit); // 限制输出
#define CONSTRAINT(amt, low, high) ((amt)<(low)?(low):((amt)>(high)?(high):(amt)))
- 计算比例、积分和微分项的和,得到控制器的总输出。
- CONSTRAINT 函数用于限制输出在指定范围内,以防止超出控制范围。
2.1.输出斜坡(Ramp)
if (outputRamp > 0)
{
float outputRate = (output - outputLast) / dt;
if (outputRate > outputRamp)
output = outputLast + outputRamp * dt;
else if (outputRate < -outputRamp)
output = outputLast - outputRamp * dt;
}
- 如果定义了输出斜坡 outputRamp,则限制输出的变化速率,防止控制器输出变化过快。
- outputRate 计算输出的变化速率,并根据 outputRamp 限制输出的加速度。
- 正向限制: 如果当前输出变化率 outputRate 大于允许的最大斜坡 outputRamp,则将输出限制为上一个输出值加上最大斜坡限制乘以时间间隔
- 反向限制: 如果当前输出变化率 outputRate 小于负的最大斜坡限制 -outputRamp,则将输出限制为上一个输出值减去最大斜坡限制乘以时间间隔
- 这段代码的目的是为了防止输出信号的剧烈变化,从而减少控制系统的振荡和不稳定性。通过限制输出变化率,可以使控制信号在变动时更加平稳,避免突发性的大幅度调整。这种方法通常用于保护系统不受过大的瞬时变化影响,保持系统的稳定性。
2.1.更新状态
integralLast = iTerm;
outputLast = output;
errorLast = error;
timeStamp = time;
- 更新状态变量以便于下一次调用时使用。
2.1.返回控制器的输出控制量
return output;
总结
这段代码实现了一个功能全面的 PID 控制器,包括比例、积分、微分控制,时间间隔处理,积分饱和限制,输出范围限制,以及输出斜坡限制。它处理了时间间隔异常,确保积分项和输出在合理范围内,并通过斜坡限制防止输出剧烈变化。