PID介绍 PID参数调节 串级PID

 2024-01-29 02:01:48  阅读 0

鉴于级联PID在系统中的重要性,是否是误差补偿,比如姿态计算; 或者控制的实现,比如姿态控制、位置控制,都是依靠级联pid。 这里我们首先讨论级联pid。 我们先做一个介绍,然后继续分析、姿态控制、位置计算与控制。 他们的分析也将从原理框图和源代码注释中进行解释。 他们只是把自己平时的一些经验整理出来和大家分享。 也希望高手们能够帮助我飞翔。

本部分涵盖三个部分:

1.pid简介

2.pid参数调整

3.级联pid

4、pid和过滤的关系也是一个很有趣的问题。 一种是从控制的角度来理解,另一种是从过滤的角度来理解。 我对此只了解一点点,所以我在这里简单说几句。 在pid中,i相当于一个低通滤波器。 极端情况下理解:直流信号肯定会继续积分,但是高频噪声的正负叠加被屏蔽了,所以i是低通滤波器。 D是高通滤波器。 同样极端情况下,可以理解为直流信号微分为0,但高频噪声微分有值,因此D是高通滤波器。 我们通常说,如果D太大,很容易放大噪声并引起振动。 相等的。

1.pid简介

在工业应用中,PID及其衍生算法是应用最广泛的算法之一,是当之无愧的通用算法。 如果能掌握PID算法的设计和实现过程,对于普通研发人员来说应该足以应付一般的研发。 问题,而且难能可贵的是,在我接触过的控制算法中,PID控制算法是最简单的,也是最能体现反馈思想的控制算法。 可以说是经典中的经典。 经典不一定复杂。 经典的东西往往是简单的,而且是最简单的。 简单不是原始,简单不是落后,简单到了美。 虽然已经进化出很多智能算法,比如蚁群、神经网络等,如果有兴趣可以看一下刘金坤的《高级PID控制》。 但在实际应用中,串级PID仍然是主要方法,因为它可靠。

我们先看一下PID算法的一般形式:

PID过程再简单不过了。 通过误差信号来控制被控变量,控制器本身就是比例、积分、微分三个环节的和。 这里我们规定(在时间t):

1、输入量为rin(t);

2、输出为rout(t);

3、偏差为err(t)=rin(t)-rout(t);

pid的控制规则为

1.解释反馈控制的原理。 从上面的框图中不难看出,PID控制实际上是一个控制偏差的过程;

2、如果偏差为0,则比例联动不起作用。 比例连杆仅在存在偏差时起作用。

3、积分环节主要用于消除静误差。 所谓静态误差就是系统稳定后输出值与设定值之间的差值。 积分环节实际上就是偏差积累的过程。 将累积误差添加到原始值中。 系统来抵消系统引起的静差。

4、微分信号反映了偏差信号的变化规律或趋势,并根据偏差信号的变化趋势进行提前调整,从而提高了系统的速度。

接下来,PID连续系统将被离散化,以便于在处理器上实现。 让我们再次粘贴连续状态的公式:

假设采样间隔为T,则在第KT时刻:

偏差err(K)=rin(K)-rout(K);

积分环节以求和的形式表示,即err(K)+err(K+1)+……;

差分环节以斜率的形式表示,即[err(K)-err(K-1)]/T;

这导致 PID 的离散表示如下:

则u(K)可表示为:

至于Kp、Ki、Kd这三个参数的具体表达式,我想是很容易推导出来的。 为了节省时间,我不会在这里详细描述它们。

事实上,到目前为止,PID的基本离散表示形式已经发布了。 当前的表达式是位置式PID,另一个表达式是增量式PID,由上面的U表达式可以很容易得到:

所以:

这就是离散PID的增量表达式。 从公式中可以看出,增量表达结果与最近3次的偏差有关,大大提高了系统的稳定性。需要注意的是,最终的输出结果应为

u(K)+增量调整值;

PID离散化过程的基本思想是这样的。 下面是将离散化公式转换成C语言,实现单片机的控制功能。

那么用c语言怎么表达呢? 下面将介绍C语言中pid的一种常见形式,关注它们的演变过程,同时也会使用一些注意事项,比如积分分离等。

位置PID的C语言实现:

第一步:定义PID变量结构体,代码如下:

_pid{

float;//定义设置值

float;//定义实际值

浮动错误; //定义偏差值

float;//定义之前的偏差值

浮动Kp,Ki,Kd; //定义比例、积分、微分系数

float;//定义电压值(控制执行器的变量)

float;//定义积分值

}pid;

将控制算法中需要的参数统一定义在一个结构体中,方便后续使用。

第二部分:初始化变量,代码如下:

空白 (){

(“开始\n”);

pid.=0.0;

pid.=0.0;

pid.err=0.0;

pid.=0.0;

pid.=0.0;

pid.=0.0;

pid.Kp=0.2;

pid.Ki=0.015;

pid.Kd=0.2;

(“结束\n”);

统一初始化变量,特别是Kp、Ki、Kd这三个参数。 调试过程中,可以直接通过调节这三个量来调节所需的控制效果。

第三步:编写控制算法,代码如下:

浮动(浮动速度){

pid.=速度;

pid.err=pid.-pid.;

pid.+=pid.err;//位置pid是积分的不断累加,很容易造成积分饱和,是系统超调。

pid.=pid.Kp*pid.err+pid.Ki*pid.+pid.Kd*(pid.err-pid.);

pid.=pid.err;

pid.=pid.*1.0;

PID。;

注:这里使用的是最基本的算法实现形式。 没有考虑死区问题,没有设置上下限。 这只是公式的直接实现。 这一点将在后面的介绍中逐步完善。

至此,PID的基本实现部分已经初步完成。 这是测试代码:

int main(){

(“开始\n”);

();

整数计数=0;

而(计数{

漂浮速度=(200.0);

("%f\n",速度);

计数++;

0;

增量PID的C语言实现:

实现过程仍然分为四个部分:定义变量、初始化变量、实现控制算法功能、算法测试。

#

#

_pid{

float;//定义设置值

float;//定义实际值

浮动错误; //定义偏差值

float;//定义之前的偏差值

float;//定义顶偏差值

浮动Kp,Ki,Kd; //定义比例、积分、微分系数

}pid;

空白 (){

pid.=0.0;

pid.=0.0;

pid.err=0.0;

pid.=0.0;

pid.=0.0;

pid.Kp=0.2;

pid.Ki=0.015;

pid.Kd=0.2;

浮动(浮动速度){

pid.=速度;

pid.err=pid.-pid.;

float =pid.Kp*(pid.err-pid.)+pid.Ki*pid.err+pid.Kd*(pid.err-2*pid.+pid.);//只对错误值求和​​前后三个时间相关,方便计算

pid.+=;

pid.=pid.;

pid.=pid.err;

PID。;

int main(){

();

整数计数=0;

而(计数{

漂浮速度=(200.0);

("%f\n",速度);

计数++;

0;

积分分离PID控制算法的C语言实现:

在普通PID控制中,引入积分环节的目的主要是为了消除静差,提高控制精度。 但在启动、结束或大幅增减设定时,系统输出在短时间内出现较大偏差,会造成PID运算时积分累积,导致控制量超过极限控制量对应执行机构的最大允许动作范围。 这会造成较大的超调甚至振荡,这是绝对不允许的。

为了克服这个问题,引入了积分分离的概念。 其基本思想是:当被控变量偏离设定值较大时,积分效应取消; 当被控量接近给定值时,引入积分控制,消除静差,提高精度。 具体实现代码如下:

pid.Kp=0.2;

pid.Ki=0.04;

pid.Kd=0.2;//初始化过程

if(abs(pid.err)>200)

索引=0;

}别的{

索引=1;

pid.+=pid.err;

pid.=pid.Kp*pid.err+index*pid.Ki*pid.+pid.Kd*(pid.err-pid.);

//算法具体实现过程可以参考上面

对抗积分饱和的PID控制算法的C语言实现:

所谓积分饱和现象是指如果系统在一个方向上存在偏差,PID控制器的输出由于积分效应的不断积累而增大,导致执行器达到极限位置。 如果控制器输出U(k)继续增加,则执行器开度不能再增加。 此时,计算机输出控制量超出正常工作范围,进入饱和区。 一旦系统出现反向偏差,u(k)逐渐退出饱和区。 进入饱和区越深,离开饱和区所需的时间就越长。 在此期间,执行器仍停留在极限位置,没有立即随偏差反转而做出相应变化。 此时系统似乎失控,导致控制性能恶化。 这种现象称为积分饱和或积分失控。 现象。

防止积分饱和的方法之一是反积分饱和法。 该方法的思想是在计算u(k)时首先判断前一时刻的控制变量u(k-1)是否超出了限制范围:如果u(k-1)>umax,则只有负偏差被积累; 如果 u(k-1)

浮动(浮动速度){

整数索引;

pid.=速度;

pid.err=pid.-pid.;

if(pid.>pid.umax)//灰色背景表示执行反积分饱和

if(abs(pid.err)>200)//蓝色标记为积分分离过程

索引=0;

}别的{

索引=1;

if(pid.err {//如果超过上限,要么加负值,要么不加,避免进入饱和区

pid.+=pid.err;

}否则如果(pid.

if(abs(pid.err)>200)//积分分离过程

索引=0;

}别的{

索引=1;

if(pid.err>0)

{//如果超过下限,要么加正值,要么不加,避免进入饱和区。

pid.+=pid.err;

}别的{

if(abs(pid.err)>200)//积分分离过程

索引=0;

}别的{

索引=1;

pid.+=pid.err;

pid.=pid.Kp*pid.err+index*pid.Ki*pid.+pid.Kd*(pid.err-pid.);

pid.=pid.err;

pid.=pid.*1.0;

PID。;

变积分PID控制算法C语言实现:

变积分PID可以看作积分分离PID算法的更通用形式。 在普通PID控制算法中,由于积分系数ki是常数,因此在整个控制过程中积分增量保持不变。 但系统对积分项的要求是,当系统偏差较大时,应削弱甚至消除积分作用,当偏差较小时,应加强积分作用。 如果积分系数太大,会导致超调,甚至积分饱和。 如果太小,静态误差不能在短时间内消除。 因此,需要根据系统的偏差来改变积分速度。

变积分PID的基本思想是试图改变积分项的累积速度,使其与偏差的大小相对应:偏差越大,积分越慢; 偏差越小,积分速度越快。

这里,在积分系数前添加比例值索引:

当abs(错误)时

当180

当abs(err)>200时,index=0;

最终比例环节的比例系数值为ki*index;

浮动(浮动速度){

浮动指数;

pid.=速度;

pid.err=pid.-pid.;

if(abs(pid.err)>200)//变量积分过程

索引=0.0;

}否则 if(abs(pid.err) 索引=1.0;

pid.+=pid.err;

}别的{

索引=(200-abs(pid.err))/20;

pid.+=pid.err;

pid.=pid.Kp*pid.err+index*pid.Ki*pid.+pid.Kd*(pid.err-pid.);

pid.=pid.err;

pid.=pid.*1.0;

PID。;

最后给大家带来专家系统中的控制体验,大家可以自行理解。

反映系统性能的两个参数是系统误差e和误差变化规律ec。

首先,我们指定误差的极限值,假设为Mmax; 指定一个比较大的误差值,假设为Mmid; 指定较小的误差值,假设为Mmin;

e*ec>0 误差沿误差绝对值增大的方向变化(可以理解为速度和加速度)

如果此时abs(e)>Mmid:误差较大,需要强控制

如果此时abs(e)

欧洲经济共同体

如果此时e*err(k-1)>0或e=0:误差的绝对值向减小的方向变化,或者已经达到平衡状态,

此时,只需保持控制器输出不变即可。

如果此时使用e*err(k-1)min,则强控制(调节幅度比较大)。 如果此时误差的绝对值较小,则可以考虑弱控制。

当abs(e)>Mmax时,说明误差的绝对值已经很大。 应考虑控制器的输入应以最大(或最小)输出,以达到快速调节误差的效果,使误差的绝对值最大。 速度降低。

当abs(e) 2.您对pid参数调整有何看法?

1)。 PID调试的一般原理

A。 当输出不振荡时,增大比例增益P。

b. 当输出不振荡时,减小积分时间常数Ti。

C。 当输出不振荡时,增大微分时间常数Td。

(三者中任何一个太大都会导致系统震荡。)

2).一般步骤

A。 确定比例增益P:确定比例增益P时,首先去掉PID的积分项和微分项。 一般情况下Ti=0,Td=0(详见PID参数设置说明),这样PID为纯比例调节。 。 输入设定为系统允许最大值的60%~70%,比例增益P从0逐渐增大,直至系统振荡; 反之,从此时开始逐渐减小比例增益P,直至系统振荡消失,并记录此时比例增益P设置为当前值的60%~70%。 比例增益P调试完成。

b. 确定积分时间常数Ti。 比例增益P确定后,设置较大的积分时间常数Ti初始值,然后逐渐减小Ti,直至系统出现振荡,然后依次逐渐增大Ti,直至系统振荡消失。 记录此时的Ti,并将PID积分时间常数Ti设置为当前值的150%~180%。 积分时间常数Ti调试完成。

C。 确定积分时间常数Td。 积分时间常数Td一般不需要设置,设置为0即可。设置方法与确定P、Ti相同,取无振荡时值的30%。

d. 系统空载和带载联合调节,然后对PID参数进行微调,直至满足要求:理想时刻两波,前高后低4个比例。

增量式pid算法c_增量式pid算法程序_增量式pid算式

增量式pid算法c_增量式pid算式_增量式pid算法程序

增量式pid算式_增量式pid算法程序_增量式pid算法c

3.级联pid介绍

级联pid的内循环和外循环是并行调整的。 这样做的好处是增加系统的稳定性和抗干扰能力。 同时,调整制度缓慢且过度。 请注意,外环是其自身的误差,内环是速度。 例如位置控制的外环是位置,内环是速度。 这是因为位置变化是通过对三个方向的速度进行积分来实现的。 同样,在姿态控制中,外环是角度差,内环是加速度,因为角度的实现是通过角速度的转变来实现的。 都是这样一个过渡的过程。 实际中,如果追求快速反应,也可以直接控制内环或者直接控制姿态。

级联PID是两种PID控制算法,但它们串在一起(更准确地说,它们是嵌套的)。 这样做有什么用呢? 答案是,它增强了系统的抗干扰能力(即增强了稳定性),因为有两个控制器控制飞行器,会比单个控制器控制更多的变量,使飞行器的适应性更强。 画出级联PID原理框图,

增量式pid算式_增量式pid算法程序_增量式pid算法c

串级PID整定的经验是:先整定内环PID,再整定外环P。由于内环靠近输出,所以效果很直接。

内圈P:从小到大,拉四轴越来越困难,你越来越感觉四轴抵抗你的拉动; 当达到比较大的值时,四轴本身就会产生高频振动,这是肉眼可见的。 这时,拉力会快速振荡几次,几秒钟后稳定下来; 如果没有人为干预,它会继续增加,并会自行分化和翻转。

特别说明:当只有内圈P时,四轴会向一个方向缓慢下降。 这是正常现象。 这是系统角速度的静态差。

内环I:从前面提到的PID原理可以看出,积分只是用来消除静差。 所以,我个人觉得没有必要把积分项的系数做得很大,因为这样做会降低系统的稳定性。 从小到大,四轴会保持在一个位置,不再掉落; 如果继续增大I的值,四轴就会变得不稳定,一拉就会自行发散。

特别说明:增大I值,四轴角度设定能力很强,拉起来也比较困难,看起来像钉钉子,但一旦有较强干扰,就会发散。 这是因为积分项太大。 拉积分速度快,补偿量很大,所以很难拉,给人稳定的假象。

内环D:这里的微分项D是标准PID原理下的微分项,即本次误差-上一次误差。 角速度环中的微分就是角加速度。 原来四轴振动比较强,导致陀螺仪的数值变化较大。 此时差速器更容易引入噪声。 因此,这里一般可以适当做一些滑动滤波或者IIR滤波。 从小到大,飞机的性能没有太大变化,只是回中心时更加稳定; 继续增大D值,肉眼即可看到平衡位置的四轴高频振动(或听到电机滋滋声)。 上面已经说过,D项是辅助项,所以如果机架振动较大,则可以忽略D项。

外环P:当所有内环PID整定完成后,飞行器可以稳定在某个位置而不移动。 此时内环P,由小到大,可以清晰地看到飞行器从倾斜位置慢慢回到中心。 用手拉一下,然后松开,它会慢慢回到中心,达到平衡位置; 继续增大P值,使用遥控器给定不同角度,可以看到飞行器的跟踪速度和响应越来越快; 继续增大P值,飞机变得非常灵敏,机动性越来越强,并且有发散的倾向。

4.最后我把关于pid的源码贴给大家。 位置类型非常简单。 请你自己理解一下。 需要注意的是,位置pid很容易导致积分饱和,所以对积分做了很多处理。 例如,在位置控制中,推力的积分量饱和。

__EXPORT float pid_calculate(PID_t *pid, float sp, float val, float val_dot, float dt)
{
    if (!isfinite(sp) || !isfinite(val) || !isfinite(val_dot) || !isfinite(dt)) {
        return pid->last_output;
    }
 
    float i, d;
 
    /* current error value */
    float error = sp - val;
 
    /* current error derivative */
    if (pid->mode == PID_MODE_DERIVATIV_CALC) {
        d = (error - pid->error_previous) / fmaxf(dt, pid->dt_min);
        pid->error_previous = error;
 
    } else if (pid->mode == PID_MODE_DERIVATIV_CALC_NO_SP) {
        d = (-val - pid->error_previous) / fmaxf(dt, pid->dt_min);
        pid->error_previous = -val;
 
    } else if (pid->mode == PID_MODE_DERIVATIV_SET) {
        d = -val_dot;
 
    } else {
        d = 0.0f;
    }
 
    if (!isfinite(d)) {
        d = 0.0f;
    }
 
    /* calculate PD output */
    float output = (error * pid->kp) + (d * pid->kd);
 
    if (pid->ki > SIGMA) {
        // Calculate the error integral and check for saturation
        i = pid->integral + (error * dt);
 
        /* check for saturation */
        if (isfinite(i)) {
            if ((pid->output_limit < SIGMA || (fabsf(output + (i * pid->ki)) <= pid->output_limit)) &&
                fabsf(i) <= pid->integral_limit) {
                /* not saturated, use new integral value */
                pid->integral = i;
            }
        }
 
        /* add I component to output */
        output += pid->integral * pid->ki;
    }
 
    /* limit output */
    if (isfinite(output)) {
        if (pid->output_limit > SIGMA) {
            if (output > pid->output_limit) {
                output = pid->output_limit;
 
            } else if (output < -pid->output_limit) {
                output = -pid->output_limit;
            }
        }
 
        pid->last_output = output;
    }
 
    return pid->last_output;
}
 
 
__EXPORT void pid_reset_integral(PID_t *pid)
{
    pid->integral = 0.0f;
}

标签: 积分 误差 算法

如本站内容信息有侵犯到您的权益请联系我们删除,谢谢!!


Copyright © 2020 All Rights Reserved 京ICP5741267-1号 统计代码