前言
具体啥是PID,我这里不做介绍,网上有大把的资料可查,以下我推荐几篇优秀文章以供大家参考:
- 史上最详细的PID教程——理解PID原理及优化算法 ---------- 【狂刀西瓜】
- 位置式PID与增量式PID区别浅析 ---------- 【Z小旋】
- 深入浅出PID控制算法 ---------- 【万般滋味皆生活】
一、整体框架
该篇以电机控速为例展开分析,假如你手上有一个编码器电机,其余配件若干,请你运用PID算法相关知识设计出一套完整的反馈路线。
相信大家最常用的设计路线是用定时器,那么这里我就以定时器来构思反馈路线。
- 编码器电机的变化源于所在ABZ三相的变化(一般编码器电机只有A相和B相,这里也以该俩相为例),所以先对该两项进行设计,可知定时器有输入捕获功能刚好可以用于捕获AB相的变化 【定时器一】。
- 每隔一定时间对电机速度进行一次检测,以及时响应未知变化 【定时器二】。
- 需对电机进行速度控制,也就是PWM设计 【定时器三】。
- 你需给定电机一个初速度,那么该怎么给呢,我的方法是你可以根据你检测电机的时间,也就是定时器二的时间所捕获到的AB相脉冲数做为初速度,PWM周期可根据实际脉冲数而设定。
简易框图如下:
二、PID算法
1. 位置式PID
位置式Pid就是位置闭环控制,位置闭环控制就是根据编码器的脉冲累加,测量电机的位置信息,并与目标值进行比较得到一个控制偏差,然后我们对偏差进行比例积分、微分的控制,使偏差趋近于0的一个过程。
-
优点:
位置式PID是一种非递推式算法,可直接控制执行机构(如平衡小车),u(k)的值和执行机构的实际位置(如小车当前角度)是一一对应的,因此在执行机构不带积分部件的对象中可以很好应用 -
缺点:
每次输出均与过去的状态有关,计算时要对e(k)进行累加,运算工作量大。
PID_VAR_TYPE Position_PID_Cal(PID * s_PID,PID_VAR_TYPE now_point)
{
s_PID->LastResult = s_PID->Result; // 简单赋值运算
//误差计算
s_PID->Error = s_PID->SetPoint - now_point;
s_PID->SumError += s_PID->Error; //积分误差累加
//积分限幅
PID_VAR_TYPE IOutValue = s_PID->SumError * s_PID->Integral;
if(IOutValue > s_PID->IntegralMax)IOutValue = s_PID->IntegralMax;
else if(IOutValue < s_PID->IntegralMin)IOutValue = s_PID->IntegralMin;
//PID计算
s_PID->Result = s_PID->Proportion * s_PID->Error // 比例项
+ IOutValue // 积分项
+ s_PID->Derivative * (s_PID->Error - s_PID->LastError); // 微分项
s_PID->PrevError = s_PID->LastError; // 简单赋值运算
s_PID->LastError = s_PID->Error; // 简单赋值运算
//输出限幅
if(s_PID->Result > s_PID->OutMax)s_PID->Result = s_PID->OutMax;
else if(s_PID->Result < s_PID->OutMin)s_PID->Result = s_PID->OutMin;
return s_PID->Result;
}
2. 增量式PID
增量式pid就是速度闭环控制,速度闭环控制是根据单位时间获取的脉冲数,测量电机的速度信息,并于目标值进行比较,得到了偏差。然后同样通过对偏差的比例、积分、微分进行控制,使偏差趋近于0的一个过程。
-
优点:
①误动作时影响小,必要时可用逻辑判断的方法去掉出错数据。
②手动/自动切换时冲击小,便于实现无扰动切换。当计算机故障时,仍能保持原值。
③算式中不需要累加。控制增量Δu(k)的确定仅与最近3次的采样值有关。 -
缺点:
①积分截断效应大,有稳态误差;
②溢出的影响大。有的被控对象用增量式则不太好;
PID_VAR_TYPE Increment_PID_Cal(PID * s_PID,PID_VAR_TYPE now_point)
{
s_PID->LastResult = s_PID->Result; // 简单赋值运算
//误差计算
s_PID->Error = s_PID->SetPoint - now_point;
//PID计算
s_PID->Result = s_PID->LastResult
+ s_PID->Proportion * (s_PID->Error - s_PID->LastError) // 比例项
+ s_PID->Integral * s_PID->Error // 积分项
+ s_PID->Derivative * (s_PID->Error - 2*(s_PID->LastError) + s_PID->PrevError); // 微分项
s_PID->PrevError = s_PID->LastError; // 简单赋值运算
s_PID->LastError = s_PID->Error; // 简单赋值运算
//输出限幅
if(s_PID->Result > s_PID->OutMax)s_PID->Result = s_PID->OutMax;
else if(s_PID->Result < s_PID->OutMin)s_PID->Result = s_PID->OutMin;
return s_PID->Result;
}
3. 比例外置式PID
此类运用相对较少,请自行查阅
PID_VAR_TYPE PID_Cal(PID * s_PID,PID_VAR_TYPE now_point)
{
s_PID->LastResult = s_PID->Result; // 简单赋值运算
//误差计算
s_PID->Error = s_PID->SetPoint - now_point;
s_PID->SumError += s_PID->Error; //积分误差累加
//积分限幅
PID_VAR_TYPE IOutValue = s_PID->SumError * s_PID->Integral;
if(IOutValue > s_PID->IntegralMax)IOutValue = s_PID->IntegralMax;
else if(IOutValue < s_PID->IntegralMin)IOutValue = s_PID->IntegralMin;
//PID计算
s_PID->Result = s_PID->Proportion *
(s_PID->Error + IOutValue + s_PID->Derivative * (s_PID->Error - s_PID->LastError) );
s_PID->PrevError = s_PID->LastError; // 简单赋值运算
s_PID->LastError = s_PID->Error; // 简单赋值运算
//输出限幅
if(s_PID->Result > s_PID->OutMax)s_PID->Result = s_PID->OutMax;
else if(s_PID->Result < s_PID->OutMin)s_PID->Result = s_PID->OutMin;
return s_PID->Result;
}
4. 积分限幅、输出限幅和PID参数整定
//设置PID输出范围
void PID_SetOutRange (PID * s_PID, PID_VAR_TYPE outMax,PID_VAR_TYPE outMin)
{
s_PID->OutMax = outMax;
s_PID->OutMin = outMin;
}
//设置PID积分范围
void PID_SetIntegralOutRange(PID * s_PID, PID_VAR_TYPE outMax,PID_VAR_TYPE outMin)
{
s_PID->IntegralMax = outMax;
s_PID->IntegralMin = outMin;
}
参数整定找最佳, 从小到大顺序查。
先是比例后积分, 最后再把微分加。
曲线振荡很频繁, 比例度盘要放大。
曲线漂浮绕大弯, 比例度盘往小扳。
曲线偏离回复慢, 积分时间往下降。
曲线波动周期长, 积分时间再加长。
曲线振荡频率快, 先把微分降下来。
动差大来波动慢, 微分时间应加长。
理想曲线两个波, 前高后低四比一。
一看二调多分析, 调节质量不会低。
5. 位置式PID和增量式PID的区别及抉择
- (1)区别
-
增量式算法不需要做累加,控制量增量的确定仅与最近几次偏差采样值有关,计算误差对控制 量计算的影响较小。而位置式算法要用到过去偏差的累加值,容易产生较大的累加误差。
-
增量式算法得出的是控制量的增量,例如在阀门控制中,只输出阀门开度的变化部分,误动作 影响小,必要时还可通过逻辑判断限制或禁止本次输出,不会严重影响系统的工作。 而位置式的输出直接对应对象的输出,因此对系统影响较大。
-
增量式PID控制输出的是控制量增量,并无积分作用,因此该方法适用于执行机构带积分部件的对象,如步进电机等,而位置式PID适用于执行机构不带积分部件的对象,如电液伺服阀。
-
在进行PID控制时,位置式PID需要有积分限幅和输出限幅,而增量式PID只需输出限幅
- (2)抉择
- 位置式PID控制的输出与整个过去的状态有关,用到了误差的累加值;而增量式PID的输出只与当前拍和前两拍的误差有关,因此位置式PID控制的累积误差相对更大;
- 增量式PID控制输出的是控制量增量,并无积分作用,因此该方法适用于执行机构带积分部件的对象,如步进电机等,而位置式PID适用于执行机构不带积分部件的对象,如电液伺服阀。
- 由于增量式PID输出的是控制量增量,如果计算机出现故障,误动作影响较小,而执行机构本身有记忆功能,可仍保持原位,不会严重影响系统的工作,而位置式的输出直接对应对象的输出,因此对系统影响较大。
三、初值获取
关于初值的设定可以根据以下3种方法获取。
1. 定时器输入捕获
定时器A0和A1开捕获模式(双边沿),分别接俩个电机的A/B相,每发生一个脉冲变化进一次捕获中断,中断里做计数操作。
void TIME()//配置编码电机接口
{
TA0CCTL1 = CM_3 | CCIS_0 | SCS | CAP | CCIE; // 捕获比较器1:双边沿捕获模式,捕获 TA0CLK 信号,启用捕获中断
TA0CTL = TASSEL_2 | ID_0 | MC_2 | TACLR; // P1OUT=BIT2;时钟源选择 SMCLK,分频系数为 1,计数器模式为连续计数,启用计数器清零
P1DIR &=~ BIT2; //初始化捕获IO口
P1SEL |= BIT2;
// 启用 Timer_A 中断和总中断
TA0CTL |= TAIE; // 启用 Timer_A 中断
__enable_interrupt(); // 启用总中断
}
#pragma vector=TIMER0_A1_VECTOR //定时器A中断处理
__interrupt void timer_A0(void)
{
switch(TA0IV) //向量查询,读取的话无需手动清零标志位
{
case 2: //捕获中断
count0++;
break;
case 10: //溢出中断
break;
default:
break;
}
}
2. 外部中断
将A/B相接外部中断引脚,设置触发模式,每发生一次跳变便进一次中断,中断内做计数操作。文章来源:https://www.toymoban.com/news/detail-578093.html
void init_encoders()
{
P1DIR &= ~BIT4; //设置P1.4口为输入
P1IN |= BIT4;
P1REN |= BIT4;
P1OUT |= BIT4; //配置P1.4上拉电阻
P1IE |= BIT4; //P1.4中断使能
P1IES |= BIT4; //P1.4下降沿触发中断
P1IFG &= ~BIT4; //清除中断标志位
_EINT();
}
#pragma vector = PORT1_VECTOR
__interrupt void P1_ISR(void)
{
_DINT(); //关总中断
if (P1IFG & BIT4)
{
count0++;
}
P1IFG &= ~ BIT4 ;
_EINT(); //开总中断
}
3. ADC采样
对电机的输出电压进行采样,可知 电机输出电压范围是 0~12V,所以是不能直接采集的,这时你需串联一个电阻进行分压,然后再将采集到的模拟信号转换为数字信号再根据PWM进行再次转化,最后将处理后的值当作初值运算。文章来源地址https://www.toymoban.com/news/detail-578093.html
void ADC_Init(void)
{
P6SEL |= BIT6;
ADC12CTL0 = ADC12ON + ADC12SHT0_8 + ADC12MSC;
ADC12CTL1 = ADC12SHP + ADC12CONSEQ_2;
ADC12MCTL0 = ADC12SREF_0 + ADC12INCH_6;
ADC12CTL0 |= ADC12ENC;
ADC12CTL0 |= ADC12SC;
_EINT();
}
//采样数据转换
float ADC_date()
{
float date;
date = ADC12MEM0*3.3/4065;
return date;
}
//采样中断服务函数
#pragma vector = ADC12_VECTOR
__interrupt void ADC12ISR(void)
{
......
}
到了这里,关于基于TI板MSP430 玩转PID的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!