1.1任务
采用28335DSC设计一个直流伺服电机的伺服控制系统,利用电机上光电编码器所提供的位置脉冲信号,通过合适的计算方法、提取速度或转角位置信号,并选择恰当的控制算法,实现对转速或位置的准确控制。设计完成后需进行实验演示,并提交一份实验报告,其中包含的主要内容:总体设计思路,转速或位置测量的计算方法,控制算法的选择,系统工作流程(包括人机交互),实验测试结果,分析讨论,程序源代码(附录)。
1.2系统参数
(1) 28335DSC开发板:利用DSC的EQEP模块来捕捉电机的光电编码器脉冲、并估算速度/位置信号;利用EPWM模块来产生电机驱动所需的占空比信号、实现调速或位置控制;
(2) L298N电机驱动模块;
(3) 直流伺服电机(三选一):
a. 美国Pittman伺服电机8214C113-R8(双路QEP,512线光电编码器,可做位置和速度控制);
(4) 直流稳压电源(可提供12V输出);
(5) 连接线:杜邦线,鳄鱼夹线,等。
二、总体设计思路
2.1硬件结构
系统的硬件结构:
三、转速或位置测量的计算方法
TMS28335芯片将常用的转速测量电路集成于芯片内部,组成了增强型正交编码模块eQEP。当工作在正交计数模式下,正交解码单元可对正交信号进行4倍频处理,为位置计数器寄存器的计数提供时钟频率。
增量式编码器是将设备运动时的位移信息变成连续的脉冲信号,脉冲个数表示位移量的大小。只有当设备运动的时候增量式编码器才会输出信号。编码器一般会把这些信号分为通道A和通道B 两组输出,并且这两组信号间有90° 的相位差。同时采集这两组信号就可以知道设备的运动和方向。除了通道A、通道B 以外,很多增量式编码器还会设置一个额外的通道Z 输出信号,用来表示编码器特定的参考位置,传感器转一圈Z 轴信号才会输出一个脉冲。增量式编码器只输出设备的位置变化和运动方向,不会输出设备的绝对位置。
增量式编码器都有A、B 两通道信号输出,这是因为增量式编码器的码盘上有两圈线槽,两圈线槽的之间会错开一定的角度,这个角度会使得光电检测装置输出的两相信号相差1/4 周期(90°)。码盘的具体工作方式如下图所示。图中黑色代表透光,白色代表遮光。当码盘转动时,内圈和外圈的线槽会依次透过光线,光电检测装置检测到光线通断的变化,就会相应的输出脉冲信号,因为内外圈遮光和透光时候存在时间差,所以也就有了A、B 两通道信号的相位差。
分辨率:指编码器能够分辨的最小单位。对于增量式编码器,其分辨率表示为编码器转轴旋转一圈所产生的脉冲数,即脉冲数/转(Pulse Per Revolution 或PPR)。码盘上透光线槽的数目其实就等于分辨率,也叫多少线,较为常见的有5-6000线。
精度:精度是指编码器每个读数与转轴实际位置间的最大误差,通常用角度、角分或角秒来表示。
最大响应频率:指编码器每秒输出的脉冲数,单位是Hz。计算公式:最大响应频率= 分辨率* 轴转速/60。
3.1转速测量方法
M法又称之为测频法,其原理是先设定一定的时间,然后在这段时间TC内,对光电码盘输出的信号的个数进行计数。在测量过程中,计取的脉冲数M1不一定正好是整数,M1可能存在±1的误差。计取的M1的值越大,所得的误差越小,因此M法适用于高速转速的测量。
T法又称之为测周法,此测量原理是在一个脉冲周期内对高频脉冲数进行计数。为了减小误差,计得的高频脉冲M2应尽量大,因此T法测量适用于低速测量。
M/T法是将M法和T法两种方法结合起来,即在一定的时间范围TC内,计取光电码盘输出的脉冲数M1的同时,也对高频脉冲M2进行计数。TC时间到来后,再计取T时间内的高频脉冲数m,T是时间TC结束后到码盘信号下一个脉冲上升沿的时间间隔。
二阶Lagrange插值多项式估值法。
其关于时间t的导数如下:
式中:t 0,t1,t 2,f (t0),f (t1),f (t2)分别为离当前时刻t最近的3个位置事件对应的时间和位置。假定在t0,t1,t2这3个时间点对应的位置增量相等,即
其中N为一个位置事件所对应的编码器脉冲数。令△t1 = t1 - t0,△t2 = t2 - t1,△t3 = t - t2,则可利用式(17)来估计当前时刻t的瞬时转速(rad/s):
3.2具体参数计算
M法:
T法:
控制算法的选择
4.1PID算法(位置式与增量式)
4.1.1位置式PID算法
位置式PID
在控制信号幅值受限、且给定目标出现大跳变的情况下,积分控制容易产生积分器饱和(integrator windup)的现象,使系统出现大超调和低频震荡,甚至导致不稳定。
课上所学两种抗积分饱和方法:遇限消弱积分法,反馈抑制抗饱和PID。
4.1.2增量式PID算法
增量式PID
• 增量式算法不需要对积分项累加,控制量增量只与近几次的误差有关,计算误差对控制量计算的影响较小。而位置式算法要对近几次的偏差的进行积分累加,容易产生较大的累加误差;
• 增量式算法得出的是控制量的增量,例如在阀门控制中,只输出阀门开度的变化部分,误动作影响小,必要时还可通过逻辑判断限制或禁止本次输出,不会严重影响系统的工作;而位置式的输出直接对应对象的输出,因此对系统影响较大;
• 增量式算法控制输出的是控制量增量,并无积分作用,因此该方法适用于执行机构带积分部件的对象,如步进电机等,而位置式算法适用于执行机构不带积分部件的对象,如电液伺服阀;
• 积分饱和现象是位置式PID 算法应用常见的一种现象,因此对于位置式PID 算法除了需要对输出进行限幅外还需要对积分输出进行限幅,而增量式算法很好地避免了积分饱和现象,因此在增量式PID 控制算法中只需要对输出限幅,而无需积分限幅。
4.2专家PID算法
专家PID 控制主要是利用受控对象和控制规律的知识进行控制,对被控制的对象不需要精确的模型,使用专家经验来对系统模型进行设计控制。对于系统模型的控制专家PID 具有灵活性、适应性和鲁棒性。可根据系统的工作状态及误差情况去灵活的选择相应的控制规律去控制,并根据专家知识和经验,能动性的去调整控制器的参数,适应对象特性及环境的变化,通过利用专家规则,控制系统模型可以在非线性、大偏差下进行可靠地工作。
专家PID 主要由五个控制律组成,通过工作状态及误差去选择相应的控制律去稳定数据,并对参数进行调节达到对控制系统稳定的作用。其控制结构如图 所示。
设定偏差的一个极大值,记为Mmax;设定一个偏差较大的中间值,记为Mmid;设定一个偏差的极小值,记为Mmin。根据以上偏差、偏差增量以及偏差极值的设定,我们分析如下:
(1)如果|e(k)|>Mmax (规则一)
这种情况说明偏差的绝对值已经很大了,不论偏差变化趋势如何,都应该考虑控制器的输入应按最大(或最小)输出,以达到迅速调整偏差的效果,使偏差绝对值以最大的速度减小。同时避免超调,此时相当于开环控制。
(2)当e(k)*∆e(k)>0或者∆e(k)=0时(规则二)
这种情况说明偏差在朝向偏差绝对值增大的方向变化,或者偏差为某一固定值,此时我们再判断偏差的绝对值与偏差的中间值Mmid之间的关系。
(2.1)此时如果|e(k)|>Mmid
说明偏差也较大,可考虑由控制器实施较强的控制作用,以达到扭转偏差绝对值向减小的方向变化,并迅速减小偏差的绝对值。
(2.2)此时如果|e(k)|≤Mmid
说明尽管偏差是向绝对值增大的方向变化,但是偏差绝对值本身并不是很大,可以考虑控制器实施一般的控制作用,只需要扭转偏差的变化趋势,使其向偏差绝对值减小的方向变化即可。
(3)当e(k)*∆e(k)<0且∆e(k)*∆e(k-1)>0或者e(k)=0时
说明偏差的绝对值向减小的方向变化,或者已经达到平衡状态,此时保持控制器输出不变即可。
(4)当e(k)*∆e(k)<0且∆e(k)*∆e(k-1)<0时
说明偏差处于极限状态。
(4.1)如果此时偏差的绝对值较大,|e(k)|>Mmid
可以考虑实施较强控制作用。
(4.2)如果此时偏差绝对值较小,|e(k)|<Mmid
可以考虑实施较弱控制作用。
其中,k1为增益放大系数,k1取大于1的值;k2为增益抑制系数,取大于0而小于1的值。
(5)如果|e(k)|<Mmin
这种情况实际上说明偏差绝对值很小,这种偏差有可能是系统静差引起的,此时必须要引入积分作用,减小系统的稳态误差。
五、系统工作流程
采用TMS320F28335DSC 作为控制的主芯片,伺服系统采用基于L298N 的功率驱动模块和12V 稳压直流电源。伺服电动机的双路正交脉冲信号由DSC 的eQEP 模块进行使用M法户主T法等方法解码处理,计算出角位置\就速度; 位置\速度控制器输出的控制量转换为对应占空比的PWM 信号,去驱动L298N 的功率开关,从而控制电机转速。
为方便实验的连续进行,把目标转速设置为每隔1.5s在2500 r/min与3600 r/min之间阶跃跳变的方波信号。
六、实验测试结果
增量式PID控制电压曲线
增量式PID误差曲线
专家PID控制曲线
专家PID误差曲线
七、分析讨论
从图中可以看出,当给定速度发生大范围阶跃跳变时,各种控制方案下电机都能够快速、准确、平稳、无超调地跟踪给定速度。
与增量式PID相比,专家PID的控制曲线更加平稳,上升时间更短,超调量更少,调节时间更短,鲁棒性更好,当然专家PID的知识库的设计显得尤为重要,知识库设计不当,很可能效果不如增量式PID,所以设计更加繁琐,另外专家PID需要推理,推理消耗的计算资源远大于增量式PID。
增量式PID | 专家PID | |
鲁棒性 | 略差 | 更优 |
参数整定(规则设计) | 方便 | 繁琐 |
计算资源 | 小 | 大 |
时域指标 | 略差 | 更优 |
表 增量式PID与专家PID对比
所以,在小型嵌入式系统,计算资源比较紧缺的单片机(C51、Arduino、MSP430等),可以采用增量式PID,在计算资源比较强的嵌入式系统(如STM32、C2000系列的DSP等)可以采用专家PID从而获得更好的性能。此外还要考虑经济效益的问题,当控制器的成本在项目中成本占用不高是,应当选用更优的方案去获得更鲁棒的性能。
八、总结
8.1总结
在此次课程实践当中,我运用了计算机控制所学的增量式PID与智能控制所学的专家PID,给出PID控制方案的具体设计,并应用于直流伺服电机的转速调节,利用TMS320F2808DSP进行了实验研究。结果表明,用这2种PID的方案设计的速度控制系统都可以在大的目标转速范围内实现快速、平稳和无静差的伺服跟踪,相比较之下专家PID的效果更好。从控制算法实现和参数整定的复杂度来看,专家PID参数整定更加繁琐,增量式PID参数整定简单。但对实际系统而言,要考虑经济效益,确定控制方案。
附录
- #ifndef EH_PID_H_
- #define EH_PID_H_
- typedef struct {
- float32 Ref; // 输入:参考输入 Input: Reference input
- float32 Fdb; // 输入:反馈输入 Input: Feedback input、
- float32 Err; //变量:误差信号e(k)
- float32 Err_1; // 变量:误差信号e(k-1) Variable: Error
- float32 Err_2; // 变量:误差信号e(k-2) Variable: Error
- float32 umax; // 参数:控制量的饱和限幅值
- float32 Ts; // 控制周期
- float32 Kp; // 参数:比例增益 Parameter: Proportional gain
- float32 Ki; // 参数:积分增益 Parameter: Integral gain
- float32 Kd; // 参数:微分增益Parameter: Derivative gain
- float32 OutPreSat; // 变量:饱和输出 Variable: Pre-saturated output
- float32 OutMax; // 参数:最大输出 Parameter: Maximum output
- float32 OutMin; // 参数:最小输出 Parameter: Minimum output
- float32 Out; // 输出:SP_PID输出 Output: SP_PID output
- void (*calc)(); // 计算函数指针 Pointer to calculation function
- } EH_PID;
- typedef EH_PID* EH_PID_handle;
- #define EH_PID_DEFAULTS { 0, 0, 0, 0, 0, 0, 0,\
- 0, 0, 0, \
- 0, 0, 0, 0, \
- (void (*)(Uint32)) eh_pid_calc }
- void eh_pid_calc(EH_PID_handle);
- #endif /* EH_PID_H_ */
eh_pid.c
- #include "dmctype.h"
- #include "eh_pid.h"
- void eh_pid_calc(EH_PID * v)
- {
- float32 Delta_Err; //e(k)-e(k-1)
- float32 Last_Delta_Err; //e(k-1)-e(k-2)
- float32 uk; //本次调节输出值
- v->Err = v->Ref - v->Fdb;
- Delta_Err=v->Err-v->Err_1;
- Last_Delta_Err=v->Err_1-v->Err_2;
- uk=v->Out+v->Kp*Delta_Err+v->Ki* v->Err +v->Kd*(Delta_Err-Last_Delta_Err);
- v->OutPreSat = uk;
- if (v->OutPreSat > v->OutMax)
- v->Out = v->OutMax;
- else if (v->OutPreSat < v->OutMin)
- v->Out = v->OutMin;
- else
- v->Out = v->OutPreSat;
- v->Err_2=v->Err_1;
- v->Err_1= v->Err ;
- }
sp_pid.h
- #ifndef INCLUDE_SP_PID_H_
- #define INCLUDE_SP_PID_H_
- typedef struct {
- float32 Ref; // 输入:参考输入 Input: Reference input
- float32 Fdb; // 输入:反馈输入 Input: Feedback input
- float32 Err; //偏差
- float32 Err_1; // 变量:误差信号e(k-1) Variable: Error
- float32 Err_2; // 变量:误差信号e(k-2) Variable: Error
- float32 Ts; // 控制周期
- float32 Kp; // 参数:比例增益 Parameter: Proportional gain
- float32 Ki; // 参数:积分增益 Parameter: Integral gain
- float32 Kd; // 参数:微分增益Parameter: Derivative gain
- float32 ErrorAbsMax; /*偏差绝对值最大值*/
- float32 ErrorAbsMid; /*偏差绝对值中位值*/
- float32 ErrorAbsMin; /*偏差绝对值最小值*/
- float32 OutPreSat; // 变量:饱和输出 Variable: Pre-saturated output
- float32 OutMax; // 参数:最大输出 Parameter: Maximum output
- float32 OutMin; // 参数:最小输出 Parameter: Minimum output
- float32 Out; // 输出:SP_PID输出 Output: SP_PID output
- void (*init)(); // Pointer to the init funcion
- void (*calc)(); // 计算函数指针 Pointer to calculation function
- } SP_PID;
- typedef SP_PID* SP_PID_handle;
- #define SP_PID_DEFAULTS { 0, 0, 0, 0, 0, 0,\
- 0, 0, 0, \
- 0, 0, 0,\
- 0, 0, 0, 0, \
- (void (*)(Uint32)) sp_pid_init,\
- (void (*)(Uint32)) sp_pid_calc }
- void sp_pid_init(SP_PID_handle);
- void sp_pid_calc(SP_PID_handle);
- #endif /* INCLUDE_SP_PID_H_ */
sp_pid.c
- #include "dmctype.h"
- #include "sp_pid.h"
- void sp_pid_init(SP_PID * v){
- //以下初始化时针对阶跃输入而言
- v->ErrorAbsMax = v->Ref *0.30;
- v->ErrorAbsMid = v->Ref *0.15;
- v->ErrorAbsMin = v->Ref *0.08;
- }
- void sp_pid_calc(SP_PID * v){
- float32 Delta_Err; //e(k)-e(k-1)
- float32 Last_Delta_Err; //e(k-1)-e(k-2)
- float32 uk; //本次调节输出值
- v->Err = v->Ref - v->Fdb;
- Delta_Err=v->Err-v->Err_1;
- Last_Delta_Err=v->Err_1-v->Err_2;
- if(abs(v->Err)>=v->ErrorAbsMax){
- /*执行规则1*/
- if(v->Err>0){
- uk=v->OutMax;
- }
- if(v->Err<0){
- uk=v->OutMin;
- }
- }
- if((v->Err*Delta_Err>0)||(Delta_Err==0)){
- /*执行规则2*/
- if(abs(v->Err)>=v->ErrorAbsMid){
- uk=v->Out+1.5*(v->Kp*Delta_Err+v->Ki*v->Err+v->Kd*(Delta_Err-Last_Delta_Err));
- }
- else{
- uk=v->Out+0.3*(v->Kp*Delta_Err+v->Ki*v->Err+v->Kd*(Delta_Err-Last_Delta_Err));
- }
- }
- if(((v->Err*Delta_Err<0)&&(Delta_Err*Last_Delta_Err>0))||(v->Err==0)){
- /*执行规则3*/
- uk=v->Out;
- }
- if((v->Err*Delta_Err<0)&&(Delta_Err*Last_Delta_Err<0)){
- /*执行规则4*/
- if(abs(v->Err)>=v->ErrorAbsMid){
- uk=v->Out+1.5*v->Kp*v->Err;
- }
- else{
- uk=v->Out+0.4*v->Kp*v->Err;
- }
- }
- if((abs(v->Err)<=v->ErrorAbsMin)&&(abs(v->Err)>0)){
- /*执行规则5*/
- uk=v->Out+0.5*v->Kp*Delta_Err+0.3*v->Ki*v->Err;
- }
- v->OutPreSat = uk;
- if (v->OutPreSat > v->OutMax)
- v->Out = v->OutMax;
- else if (v->OutPreSat < v->OutMin)
- v->Out = v->OutMin;
- else
- v->Out = v->OutPreSat;
- v->Err_2=v->Err_1;
- v->Err_1=v->Err;
- }