这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » DIY与开源设计 » 电子DIY » Quadlator II--使用PID控制

共1条 1/1 1 跳转至

Quadlator II--使用PID控制

工程师
2011-03-15 14:34:06     打赏
Quadlator II--使用PID控制
写于: 星期六 29 四月 @ 13:33:08
 
智能机器人开发Quadlator II第六章

Quadlator II--使用PID控制 作者:baredog 六,使用PID控制

这几年来,每次做自我介绍时,总有非常尴尬的场面。有人问我:“你大学是学什么的?”如果我答:哦,我是学自动化的。”对方经常会一脸茫然,如果对方 是外国人,就更加不理解了,通常会接着问:“自动化是做什么的?”为了避免这样的局面,后来当别人问我大学的专 业时,我索性不照直回答,而说:“哦,我是学自动控制的。”对方听后,虽然还是不明所以,但是通常不会继续再追问了。

在控制理论中,PID是一种在很早就成熟起来的经典控制方法之一,并且在控制理论日新月异的高速发展的情况下,仍能在工业实际应用中,占据垄断的地位,的确是很值得思考。在Quadlator I和Quadlator II中,撇开上层控制算法不说,在电机控制这一局部,都使用了PID控制。

PID控制是任何学习自动控制理论课程的必讲内容,因此这些介绍也本着这样的原则:对于熟悉的读者,这些内容可以略去不管;对于已经忘记的差不多得读者,这些可以唤起你当初大学时得回忆;对于初学的爱好者,这个是比课本更加简略的介绍,不涉及太多的理论推导,而更重视实际效果和应用。所以将主要介绍以下内容:

  • PID的基本概念
  • 怎么使用PID控制,尤其在控制电机时如何实现

PID是比例,积分,微分的首字母缩写。为了不一上来就进行复杂的理论推导。这里用直观朴素的“问题-解答 ”方式加以介绍。

假设你要在房间的墙上张贴一幅年画,你站在椅子上,你的审美情趣严格的妻子站在远处告诉你画是否摆正了。她会说:“太偏了,向左 ”,于是你会把画向左移动很大一截;然后你妻子告诉你:过了,向右一点,于是你把画向右移动,但是这次不是很大一截,而是幅度小一些的移动;这时你妻子说:过了一点点,稍微向左一点,这时你会小心谨慎的只向左移动很小的一段距离。

上述过程,实际是一个比例控制系统的工作工程。可以用下面的图表示出来:

 

你们预先有一个目标位置Destination,例如房间墙的正中。你实际在墙上摆放的位置Output,被你妻子观察(measure)到后,作为反馈量和预期目标进行比较,这个比较的差值作为新的输出的指导,如果差距大,你就进行较大的调整,反之调整量就小。如果用数学公式表示,就是:

Output[下次]=P*(Destination-Output[本次])

这样的系统可以满足相当部分的控制要求了,但是有什么不足之处么?从直观上看,似乎发现不了,应用上述方法,几乎可以保证把图片摆到墙的基本中间位置。但是仔细分析上面的公式就会发现问题——永远也不可能100%达到指定位置。因为一旦Output和 Destination相等,也就是误差为0的时候,公式左侧就等于0,也就是说,下次的输出是0。但是目标位置Destination不是0,于是下下次就会产生新的误差,大小为Destination,于是就会有下下次的新调整……这个过程反复下去。直到达到某种平衡,这时

Output=Destination*P/(1+P)

然后系统达到稳定。这种误差永远不会为0的现象,术语上叫“残差”。这就是比例控制(P控制)的缺点,另外一个缺点,就是如果P的值太大,有可能造成下次的误差会大于本次的误差,系统会迅速崩溃。于是针对这些问题,积分控制(I控制)就被引入了进来。

现在回过头来从哲学的角度看,PID的思想非常朴素。他们体现了人类从今天,历史,未来三个角度来把握事务的思想。比例(P)控制是着眼于今天,“有错就改,过而改之,善莫大焉”;而积分控制在于分析历史,总结经验,把历史上的错误累计起来,加以考虑:

 

积分控制的直接含义,不是那么直观,从上面图上大概可以看出,针对误差Err=(Destination-Output),除了直接用比例(P)放大之外,还要考虑误差在时间上的累计效应,并且把这个累计结果也放大(乘以系数I)后,共同作为下次的输出,用数学公式表示就是:

Output[下次]=P*(Destination-Output[本次])+I*Σ(Destination -Output[本次])??t

积分控制的优点是,可以有效的消除残差,从而保证最后系统稳定时 Destination和Output正好相等。但是积分控制的缺点是“超调”问题。所谓超调,用通俗易懂的话解释就是“过犹不及 ”,比如本次的输出,距离目标输出相差5厘米,经过调整后,下次的输出超过目标3厘米,之后再反复几次后,达到目标。那么这个超过的3厘米就称为“超调”。超调会造成系统振荡,如果下次的误差甚至大于了本次的误差,系统就会越振越厉害,最终崩溃。因此积分控制虽然改善了比例控制中残差的问题,却没有解决稳定性的问题。要想解决稳定性的问题,微分(D)控制就被引入了进来。

最后说说微分(D)控制,如果说比例控制在于把握今天,积分控制在于总结历史经验,微分控制就在于预测未来了。微分控制考虑了本次调节误差的变化速度,然后根据这个变化速度加以预测,提前进行调节。用框图表示就是:

 

根据前面的描述,误差就是输出Output和目标Destination之间的差,所以误差的变化就是:

??Err = Err[本次]-Err[上次]
     = (Output[本次]-Destination)-(Output[上次]-Destination)
     = Output[本次]-Output[上次]
     = ??Output

微分控制考虑了误差的变化速度,并根据这个速度及时调整下次的输出,这样就提前抑制了过大的超调,也改善了系统的稳定性。

最后给出一个公式上的总结,综合采用了PID三种控制的控制系统可以表示如下:

Output[下次] = Kp*P分量+Ki*I分量+Kd*D分量
             = Kp*Err+Ki*Σ(Err*Δt)+Kd*ΔErr/Δt

其中,Err=Destination-Output。


以上大致介绍了一下PID控制的基本概念,我没有给出复杂的数学推导(包括拉普拉斯Laplace变换),和控制输出曲线图,这些可以在任何一本控制理论的教科书里看到。如果读者感兴趣,可以参考这些资料。我这里只是希望给出PID的直观意义——朴素的解决问题的思路。希望这种尝试对于初学者能够降低门槛,对于专业人员,这些则是我的一家之言。

下面,我给出一个应用PID实际控制电动机的实现。从而完成“理论-实践”的思路。经过前面几部分的铺垫,底层内核模块的电机驱动已经给出,PID就可以放在用户空间。结合机器人关节的控制,最直观的一种是控制关节的角度,本次四足12个关节的角度为θ[4][3],由于C 语言不支持希腊字母,因此用theta来表示,这些角度可以由光电码盘计数得到;上次的各关节角度为θ_old [4][3]。在上面的最后一个总结性公式中,最终输出等于P分量,I分量,D分量各自乘以系数后三者的和,针对每个关节用分别用P[4][3],I [4][3]和D[4][3]表示,上次和上上次的各分量值,如有必要分别加_old和_old_old后缀。两次控制运算的间隔时间用dt表示,上一次的时间间隔用dt_old表示。PID的系数(放大倍数或者增益)分别用Kp,Ki和Kd表示。这样定义后的ANSI C头文件如下:

#include "motor_ctrl.h"

//Run in user-space
typedef struct PIDCRTL{
     MotorDriver* p_motor; 

     //all use DEG
     double theta[4][3];                  //measured from Counter
     double theta_old[4][3]; 

     double err[4][3];
     double err_old[4][3]; 

     double P[4][3],I[4][3],D[4][3];
     double Kp,Ki,Kd;

     double t, t_old, dt;
}PIDCTRL;

void pid_ctrl_create(PIDCTRL* p_pid_ctrl);
void pid_position_ctrl(PIDCTRL* p_pid_ctrl, double th0[4][3], double da_value[4][3]);

头文件中最后给出了2个函数,一个是初始化函数pid_ctrl_create用于各个变量的初始化,基本就是各个变量初始化为0,系数预先设置好,如下:
void pid_ctrl_create(PIDCTRL* p_pid_ctrl){
     int i,j;
     for(i=0;i<4;i++){
           for(j=0;j<3;j++){
                p_pid_ctrl->theta[i][j]=0;
                p_pid_ctrl->theta_old[i][j]=0; 

                p_pid_ctrl->err[i][j]=0;
                p_pid_ctrl->err_old[i][j]=0; 

                p_pid_ctrl->P_old[i][j]=0;
                p_pid_ctrl->P[i][j]=0;
                p_pid_ctrl->I[i][j]=0;
                p_pid_ctrl->D[i][j]=0;
           }
     }

     p_pid_ctrl->Kd=0.01;
     p_pid_ctrl->Ki=0.01;
     p_pid_ctrl->Kp=2.0; 

     p_pid_ctrl->t=0;
     p_pid_ctrl->t_old=0;    

     p_pid_ctrl->dt=0;
}

另一个是核心算法函数,用PID实现对关节位置的控制。算法实现如下:

void pid_position_ctrl(PIDCTRL* p_pid_ctrl, double th0[4][3], double da_value[4][3]){
     int i,j; 

     for(i=0;i<4;i++){
           for(j=0;j<3;j++){
                p_pid_ctrl->err[i][j]=th0[i][j]-p_pid_ctrl->theta[i][j];
                p_pid_ctrl->P[i][j]=err[i][j];               

                //area of ladder shap
                p_pid_ctrl->I[i][j] += (p_pid_ctrl->err[i][j]+p_pid_ctrl->err_old[i][j])*
                        p_pid_ctrl->dt*0.5;

                if(p_pid_ctrl->dt >0.001)
                     p_pid_ctrl->D[i][j] = 
                        (p_pid_ctrl->theta[i][j]-p_pid_ctrl->theta_old[i][j])/p_pid_ctrl->dt;

                da_value[i][j] = p_pid_ctrl->Kp*p_pid_ctrl->P[i][j]+
                                 p_pid_ctrl->Ki*p_pid_ctrl->I[i][j]+
                                 p_pid_ctrl->Kd*p_pid_ctrl->D[i][j];     //-10 --- +10

                //DA out limit
                da_value[i][j] = da_value[i][j] >MAX_DA_OUT ? MAX_DA_OUT : da_value[i][j];
                da_value[i][j] = da_value[i][j] <-MAX_DA_OUT ? -MAX_DA_OUT : da_value[i][j];
           }
     }
     p_pid_ctrl->dt_old=p_pid_ctrl->dt;
     pid_update(p_pid_ctrl);
}

这个函数的参数有3个,一个是PID控制的结构体指针,一个是各个关节的本次的目标角度,最后一个参数是本次PID调节后,应该输出到DA转换器的电压。基本上比较直观,稍微值得解释的是积分的运算部分,积分运算采用了梯形面积计算法,说明如下图

积分的物理意义是曲线下方的面积,计算面积可以用矩形法,但是梯形法更加精确,就是把这个面积分隔成一个一个小的梯形,而梯形的面积可以用(上底+下底)*高/2来计算,这就是上面函数中:(Err[上次]+Err[本次])*dt/2的意义。

至此,本部分给出了PID控制的基本概念和简单实现,希望能够帮助读者对此能建立一个感性的认识,而不再对PID控制感到困难和不可理 解。

=====

回到总目录

返回ROBOTDIY主页




关键词: Quadlator     使用     控制     积分     一个     表示         

共1条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]