2.11 PID控制算法(三)

您所在的位置:网站首页 脉冲反馈文件怎么做出来的 2.11 PID控制算法(三)

2.11 PID控制算法(三)

2024-07-10 13:55| 来源: 网络整理| 查看: 265

文章目录 1、讲解2、举例13、举例24、举例35、调试PID参数

1、讲解

1、AD采样,经过PID计算的值,怎么和PWM对应起来? 2、电机编码采样,经过PID计算的值,怎么与速度对应起来?

这个简单,PID控制原理就是输出一个控制量,然后检测反馈,由反馈得到的数据计算当前实际输出是多少,由这个实际输出和目标输出得到差值,最后由这个差值计算一个新的输出控制量。 举例(数据都是乱拟的,只为好计算):假设你的PWM是用来控制电机速度的,0%占空比对应的电机速度是0r,100%占空比对应的电机速度是100r。你目标电机速度是50r,那么调控步骤如下:

输出50%占空比的PWMAD采样并计算当前电机速度,假设计算得到的当前实际电机速度是40r,比目标速度50r差10r,这个10r送到PID计算得到一个增量结果,假设结果是5r由5r计算对应的PWM占空比,即5%更新PWM输出占空比,就是:50%+5%=55%,返回到第1步 我个人理解,它们之间实际上就是一个比例关系。 2、举例1

我们来分析一个例子:步进电机PID速度闭环控制,它原理:预先设置好需要达到的速度,然后每隔一段时间读取编码器的值反馈当前速度,经过PID计算慢慢到达设定的速度。

#define FEEDBACK_CONST (SPR/ENCODER_SPR) //编码器和步进电机驱动器的比值 typedef struct { __IO float SetPoint; // 目标值 单位:mm/s __IO int LastError; // 前一次误差 __IO int PrevError; // 前两次误差 __IO long SumError; // 累计误差 __IO double Proportion; // Kp系数 __IO double Integral; // Ki系数 __IO double Derivative; // Kd系数 }PID_Typedef; __IO PID_Typedef vPID; Vel_Target = (vPID.SetPoint*P_PERIOD);//每单位采样周期内的脉冲数(频率) /** * 函数功能:增量式PID速度环计算 * 输入参数:NextPoint 由编码器得到的速度值 * TargetVal 目标值 * 返 回 值:经过PID运算得到的增量值 * 说 明:增量式 PID 速度环控制设计,计算得到的结果仍然是速度值 */ float IncPIDCalc(__IO float NextPoint,__IO float TargetVal) //临时变量,期望值 { __IO float iError = 0,iIncpid = 0; //当前误差 iError = TargetVal - NextPoint; // 增量计算 // if((iError-0.5f)) // iError = 0; // |e| < 0.5,不做调整 iIncpid=(vPID.Proportion * iError) // E[k]项 -(vPID.Integral * vPID.LastError) // E[k-1]项 +(vPID.Derivative * vPID.PrevError); // E[k-2]项 vPID.PrevError=vPID.LastError; // 存储误差,用于下次计算 vPID.LastError = iError; return(iIncpid); // 返回增量值 } /** * 函数功能: 系统滴答定时器中断回调函数 * 输入参数: 无 * 返 回 值: 无 * 说 明: 每发生一次滴答定时器中断进入该回调函数一次 */ void HAL_SYSTICK_Callback(void) { __IO static uint16_t time_count = 0; // 时间计数,每1ms增加一(与滴答定时器频率有关) __IO static int32_t Last_CaptureNumber=0; // 上一次捕获值 // 每1ms自动增一 time_count++; if(Start_Flag == ENABLE) { if(time_count >= SAMPLING_PERIOD)// 20ms控制周期 { time_count = 0; //获得编码器的脉冲值 CaptureNumber = OverflowCount*65536 + __HAL_TIM_GET_COUNTER(&htimx_Encoder); //M法 测速度 MSF = CaptureNumber - Last_CaptureNumber; Last_CaptureNumber = CaptureNumber; MSF = abs(MSF); Exp_Val += IncPIDCalc((float)MSF,Vel_Target); //编码器输出期望值 Exp_Val = abs(Exp_Val); /* 经过PID计算得到的结果是编码器的输出期望值的增量, 需要转换为步进电机的控制量(频率值),这里乘上一个系数6400/2400 */ //乘上一个系数,6400/2400,将PID计算结果转换为步进电机的频率(速度) STEPMOTOR_Motion_Ctrl(MotorDir,Exp_Val*FEEDBACK_CONST); } } } /** * 函数功能: 步进电机运动控制 * 输入参数: Dir:步进电机运动方向 0:反转 1正转 * Frequency:步进电机频率,0:停止 * 返 回 值: void * 说 明: 无 */ void STEPMOTOR_Motion_Ctrl(uint8_t Dir , float Frequency) { uint16_t Step_Delay = 0; //步进延时 if(Frequency == 0) STEPMOTOR_OUTPUT_DISABLE(); else { if(Dir==MOTOR_DIR_CCW) { STEPMOTOR_DIR_REVERSAL(); } else STEPMOTOR_DIR_FORWARD();//方向控制 /* 步进电机速度由定时器输出脉冲频率(f)决定, f = c/F;c是计数器的计数值,F是定时器频率 推导过程:(T是定时器输出脉冲周期) T=c*t => T=c*F => f = 1/T = F/c; */ Step_Delay = (uint16_t)(FREQ_UINT/Frequency); Toggle_Pulse = Step_Delay>>1;//算出来的结果是周期,这里除以2,半周期翻转一次 } }

我们来分析一下它PID是怎么PID输出结果与速度量的关系: 从上面我可以知道,PID算法 输入参数: 1、MSF :单位采样周期内(20mS)编码器的值。 2、Vel_Target:每单位采样周期内编码器的脉冲数(频率);它由SetPoint(标 值 单位:mm/s),经过一定的计算而来。 输出参数: 1、编码器的输出期望值

步进电机的频率(速度)与PID结果的关系:Exp_Val*FEEDBACK_CONST ;从整个公式我们可发现,它们仅仅一个比例系数而已。

3、举例2

再举一例PWM控制温度

int iDataSigma void PIDCalc(uint32_t Channel,int16_t set_temp,int16_t actualTemp)//温度放大100倍 { int En,out_temp,controlOut; En= set_temp-actualTemp; //本次偏差 if(abs(En) > 500) //积分分离 { index=0; } else { index=1; iDataSigma += En*iData; //历史偏差总和 } // out_temp = Kp*En+index*Ki*iDataSigma; //P+I out_temp = Kp*En+index*Ki*iDataSigma+Kd(En-En_1);//P+I+D En_1 = En; controlOut=_TIM3_ARR/500*out_temp; if (controlOut feedback = feedback; pid->e_0 = target - feedback; #if 0 if(pid->Ki*pid->ei + pid->Kp*pid->e_0 Uplimit)//限制累积值 pid->ei += pid->e_0; else if(pid->e_0 ei += pid->e_0; else; #endif pid->ei += pid->e_0; if(pid->Ki*pid->ei > 500)//限制累积值 { pid->ei = 500/pid->Ki; } if(pid->ei ei = (-100); } #if 0 pid->ed = pid->e_0 - 2*pid->e_1 + pid->e_2; #else pid->ed = pid->e_1 - pid->e_0; //个人以为这个才是对的 #endif pid->Out = pid->Kp*pid->e_0 + pid->Ki*pid->ei + pid->Kd*pid->ed; if(pid->Out > pid->Uplimit) { pid->Out = pid->Uplimit; } else if(pid->Out Downlimit) { pid->Out = pid->Downlimit; } else {} pid->e_2 = pid->e_1; pid->e_1 = pid->e_0; return (u32)pid->Out; } pid_calc(&spid1,(float)TempCtrler[PURE_TEMP_LYSIS].target,(float)TempForCal[PURE_TEMP_LYSIS]); __HAL_TIM_SET_COMPARE(&htim1,TIM_CHANNEL_2,spid1.Out); 5、调试PID参数

调试PID参数链接 在这里插入图片描述

3.1 PID参数的整定原则

U(t)=P*[e(t)+ 1/Ti∫0te(t)dt+Tdde(t)/dt] a.在输出不振荡时,增大比例增益P。(即增开Kp) b.在输出不振荡时,减小积分时间常数Ti。(即增大Ki) c.在输出不振荡时,增大微分时间常数Td。(即减小Kd)

P环很好理解,我们将误差乘以P值加在执行机构上面,当误差越小时P环所得值也就越小,给到执行机构的值也就越小,执行机构反应也就越慢,很符合这种闭环反馈的思想。但是当有一种情况,误差很小的时候P环得出的值给到执行机构上面不足以驱动执行机构工作,这时系统距离期望值仍有一段距离,该距离便被称为静差。

I环的作用是对过去状态的累加,本质上是对误差的积分,当系统存在静差时,I环会持续累加静差值,直到累加值大到足以驱动执行机构工作。这是I环的优点,可以有效地处理静差。但是I环本质上是对过去状态的处理,所以加上I环以后整个系统会变得有些不可控制,这里可以采用积分分离式的思想,只有当误差小于一定范围才开始进行进行误差的累加。如果是对稳定性要求比较高的系统,比如平衡小车直立环,就尽量不要用I环,单PD控制器控制即可。

D环,这个环比较的神奇,它可以预测将来,本质上是对误差的微分。也可以理解成对系统的阻尼,打个比方,在一个理想的环境下有个单摆一直在摆动,它摆动的波形是个正弦波形。如果不加阻尼那么它便可以一直摆动,但是现实中总会有各种各样的阻尼作用迫使单摆运动停下来。D环起的就是这个作用。D环一般运用在角度环比较多,因为你不可以进入弯道才想到转弯,而是在进入弯道之前就要有这个转弯的意识。做智能车的小伙伴们注意了!!

下面式复制别人图片,讲的挺好的,链接如下: PID参数整定

在这里插入图片描述



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3