控制/MCU
typedef struct
{
int setpoint;//设定目标
int sum_error;//误差累计
float proportion ;//比例常数
float integral ;//积分常数
float derivative;//微分常数
int last_error;//e[-1]
int prev_error;//e[-2]
}PIDtypedef;
复制代码
在文件中定义几个关键变量:
float Kp = 0.32 ; //比例常数
float Ti = 0.09 ; //积分时间常数
float Td = 0.0028 ; //微分时间常数
#define T 0.02 //采样周期
#define Ki Kp*(T/Ti) // Kp Ki Kd 三个主要参数
#define Kd Kp*(Td/T)
复制代码
PID.H里面主要的几个函数:
void PIDperiodinit(u16 arr,u16 psc); //PID 采样定时器设定
void incPIDinit(void); //初始化,参数清零清零
int incPIDcalc(PIDtypedef*PIDx,u16 nextpoint); //PID计算
void PID_setpoint(PIDtypedef*PIDx,u16 setvalue); //设定 PID预期值
void PID_set(float pp,float ii,float dd);//设定PID kp ki kd三个参数
void set_speed(float W1,float W2,float W3,float W4);//设定四个电机的目标转速
复制代码
int incPIDcalc(PIDtypedef *PIDx,u16 nextpoint)
{
int iError,iincpid;
iError=PIDx->setpoint-nextpoint; //当前误差
/*iincpid= //增量计算
PIDx->proportion*iError //e[k]项
-PIDx->integral*PIDx->last_error //e[k-1]
+PIDx->derivative*PIDx->prev_error;//e[k-2]
*/
iincpid= //增量计算
PIDx->proportion*(iError-PIDx->last_error)
+PIDx->integral*iError
+PIDx->derivative*(iError-2*PIDx->last_error+PIDx->prev_error);
PIDx->prev_error=PIDx->last_error; //存储误差,便于下次计算
PIDx->last_error=iError;
return(iincpid) ;
}
复制代码
注释掉的是第一种写法,没注释的是第二种以Kp KI kd为系数的写法,实际结果是一样的。
处理过程放在了TIM6,溢出周期时间就是是PID里面采样周期(区分于反馈信号的采样,反馈信号采样是1M的频率)
相关代码:
void TIM6_IRQHandler(void) // 采样时间到,中断处理函数
{
if (TIM_GetITStatus(TIM6, TIM_IT_Update) != RESET)//更新中断
{
frequency1=1000000/period_TIM4 ; //通过捕获的波形的周期算出频率
frequency2=1000000/period_TIM1 ;
frequency3=1000000/period_TIM2 ;
frequency4=1000000/period_TIM5 ;
/********PID1处理**********/
PID1.sum_error+=(incPIDcalc(&PID1,frequency1)); //计算增量并累加
pwm1=PID1.sum_error*4.6875 ; //pwm1 代表将要输出PWM的占空比
frequency1=0; //清零
period_TIM4=0;
/********PID2处理**********/
PID2.sum_error+=(incPIDcalc(&PID2,frequency2)); //计算增量并累加 Y=Y+Y'
pwm2=PID2.sum_error*4.6875 ; //将要输出PWM的占空比
frequency2=0;
period_TIM1=0;
/********PID3处理**********/
PID3.sum_error+=(incPIDcalc(&PID3,frequency3)); //常规PID控制
pwm3=PID3.sum_error*4.6875 ; //将要输出PWM的占空比
frequency3=0;
period_TIM2=0;
/********PID4处理**********/
PID4.sum_error+=(incPIDcalc(&PID4,frequency4)); //计算增量并累加
pwm4=PID4.sum_error*4.6875 ; //将要输出PWM的占空比
frequency4=0;
period_TIM5=0;
}
TIM_SetCompare(pwm1,pwm2,pwm3,pwm4); //重新设定PWM值
TIM_ClearITPendingBit(TIM6, TIM_IT_Update); //清除中断标志位
}
复制代码
上面几个代码是PID实现的关键部分
还有整定过程:
办法有不少,这里用的是先KP,再TI,再TD,在微调。其他的办法特别是有个尼古拉斯法我发现不适合我这个控制对象。
先Kp,就是消除积分和微分部分的影响,这里我纠结过到底是让Ti 等于一个很大的值让Ki=Kp*(T/Ti)里面的KI接近零,还是直接定义KI=0,TI=0.
然后发现前者没法找到KP使系统震荡的临界值,第二个办法可以得到预期的效果:即KP大了会产生震荡,小了会让系统稳定下来,当然这个时候是有稳态误差的。
随后把积分部分加进去,KI=Kp*(T/Ti)这个公式用起来,并且不断调节TI 。TI太大系统稳定时间比较长。
然后加上Kd =Kp*(Td/T),对于系统响应比较滞后的情况效果好像好一些,我这里的电机反映挺快的,所以Td值很小。
最后就是几个参数调节一下,让波形好看一点。这里的波形实际反映的是采集回来的转速值,用STM32的DAC功能输出和转速对应的电压,用示波器采集的。
最后的波形是这样的:
最近两天在考虑一般控制算法的C语言实现问题,发现网络上尚没有一套完整的比较体系的讲解。于是总结了几天,整理一套思路分享给大家。
在工业应用中PID及其衍生算法是应用最广泛的算法之一,是当之无愧的万能算法,如果能够熟练掌握PID算法的设计与实现过程,对于一般的研发人员来讲,应该是足够应对一般研发问题了,而难能可贵的是,在我所接触的控制算法当中,PID控制算法又是最简单,最能体现反馈思想的控制算法,可谓经典中的经典。经典的未必是复杂的,经典的东西常常是简单的,而且是最简单的,想想牛顿的力学三大定律吧,想想爱因斯坦的质能方程吧,何等的简单!简单的不是原始的,简单的也不是落后的,简单到了美的程度。先看看PID算法的一般形式:
PID的流程简单到了不能再简单的程度,通过误差信号控制被控量,而控制器本身就是比例、积分、微分三个环节的加和。这里我们规定(在t时刻):
1.输入量为rin(t);
2.输出量为rout(t);
3.偏差量为err(t)=rin(t)-rout(t);
pid的控制规律为
理解一下这个公式,主要从下面几个问题着手,为了便于理解,把控制环境具体一下:
1.规定这个流程是用来为直流电机调速的;
2.输入量rin(t)为电机转速预定值;
3.输出量rout(t)为电机转速实际值;
4.执行器为直流电机;
5.传感器为光电码盘,假设码盘为10线;
6.直流电机采用PWM调速 转速用单位 转/min 表示;
不难看出以下结论:
1.输入量rin(t)为电机转速预定值(转/min);
2. 输出量rout(t)为电机转速实际值(转/min);
3.偏差量为预定值和实际值之差(转/min);
那么以下几个问题需要弄清楚:
看到有不少人问到底如何让UK值与PWM占空比值对应,进而实现占空比输出和输出控制电压对应。
(注意,我这里讨论的前提是输出控制的是电压,不是PWM方波。PWM输出后要经过滤波整形再输出控制。)
前提条件:
输出电压控制电压范围是0-10V。
给定、反馈、输出电压采样输入电压范围是0-5V(经过运放)。
使用单片机AD为10位AD芯片。
那么10位AD芯片电压采集得到的数据范围就是0-1024。
PWM为 8位可调占空比方波,0对应输出占空比为0的方波,255对应输出占空比100%的方波,127对应输出50%的方波。
比如当前给定是2.5V,反馈电压是1V。(KP,KI,KD等系数略,关于PID算法的整数实现我在前文中有论述如何实现)。
那么经过AD采样
1、给定2.5V对应为 512
2、反馈1V对应为 205
假定经过PID计算得到的UK为400
也就意味着输出电压应当为(400*(UPWM峰值电压))/1024
那么UK对应的PWM占空比是多少呢?
我们知道,UK=1024对应占空比为100,也就是PWM的占空比系数为255。可知,PWM系数 = UK/4;
那么400就应当对应系数 400/4=100。
也就是输出电压=400*10/1024=3.9V
同时,由于采样精度以及PWM输出占空比精度控制的问题,将导致输出电压和期望值不是那么线性,所以,我在项目内加入了输出电压采样的控制。
采样AD输入为0-5V,所以,对于输出0-10V有一个缩小的比例。
输出10V则采样值对应为255
输出5V则采样之对应127
可知,3.9V对应AD结果为97
采样输出电压值,可以针对性的调整一下占空比输出,从而得到误差允许范围内的一个控制输出电压。
全部0条评论
快来发表一下你的评论吧 !