在一个控制系统中,需要闭环控制就势必会有采样,而采样就必然有采样周期。我在学校的时候做过智能车和四旋翼。智能车是根据摄像头或者电磁信号来判断车子位置和中线位置的偏差来用舵机校准,而四旋翼的平衡是根据MPU6050和HMC5883共同采集到俯仰角、横滚角和航偏角,然后将他们和设定角度比较,最后用四个电机不同速度进行校准。在这个校准的过程中,就要用到PID了,不同的是,智能车的方向校准是单级PID,四旋翼的角度校准是串级PID。
在以上的控制中,一般我会采用PIT中断来模拟确切的采样周期来采集外部的信号,然后通过PID控制器对偏差校准,最终保持设定值。在有较短的控制周期中,可以近似用一阶差分代替一阶微分。
离散PID的积分球和:
离散PID的差分近似微分:
PID公式:
将(1)(2)带入(3)得到:
根据上面式子,我们重新定义参数:
所以基于上述公式,我们可以用C语言写一个PID控制器,来实现多个闭环的输入输出,这样会有更加合理的参数传递并且可以极大地简化代码。(因为之前我看好多代码中,每多一个闭环就会重新写一套PID控制代码)。
首先,就是写一个结构体,将PID所有的有关量保存在结构体内,并且顶一个PID结构体。
接下来,我们来写一个PID初始化函数。
PID初始化结束后就需要对PID数据进行更新,让控制系统始终能够校准。
这样一个PID控制器就完成了。
我们使用简单的codeblock进行初步调试:
codeblock中的程序,根据这张图片可以得知上面的PID控制器如何使用。
------------------------------------------------------程序----------------------------------------------------------------------
#include
#include
#include
typedef struct
{
float pGain; //P
float iGain; //I
float dGain; //D
float ilimit; //积分限幅
float istate; //积分量
float perr; //一次偏差
float errdat; //两次偏差
unsigned int pidout; //PID控制器输出
}PIDP;
PIDP test1={1.3,0.01,-0.1,10,0,0,0};
PIDP test2={1.1,0,-0.08,10,0,0,0};
void pid_init(PIDP* pid)
{
pid->istate=0;
pid->perr=0;
pid->errdat=0;
pid->pidout=0;
}
void updat_pid(PIDP* pid)
{
float ilimit1; //下偏差
ilimit1 = -1 * pid->ilimit;
pid->istate += ((pid->iGain)*(pid->errdat));
if((pid->istate)>(pid->ilimit))
pid->istate = pid->ilimit;
if((pid->istate)<(ilimit1))
pid->istate = ilimit1;
pid->pidout = pid->pGain * pid->errdat + pid->istate + ((pid->errdat)-(pid->perr)) * pid->dGain;
pid->perr=pid->errdat;
}
void main()
{
int target = 80;
int now = 0;
int now1 = now;
int now2 = now;
int i;
pid_init(&test1);
pid_init(&test2);
//test.errdat = target - now;
printf("目前量 PID控制器输出量 目前量 PID控制器输出量");
for(i = 0;i < 10;i++)
{
test1.errdat = target - now1;
updat_pid(&test1);
now1 += test1.pidout; //now = now + out
test2.errdat = target - now2;
updat_pid(&test2);
now2 += test2.pidout;
printf("\n%2d %2d %2d %2d",now1,test1.pidout,now2,test2.pidout);
}
}
------------------------------------------------------程序----------------------------------------------------------------------
可以直接复制运行查看结果,这里给出运行后的截图(以80位目标进行控制校准):
那么我们如何在智能车中使用呢?以摄像头读取赛道两边黑线并且相加除以二得到中线,和设定中线进行比较,经过控制器后进行校准。
首先是定义一个舵机PID的结构体并且赋初值:
然后是初始化舵机和初始化PID控制器:
为了满足公式(2),我们需要用PIT中断来模拟离散采样,在PIT中断服务函数中进行更新。
具体的控制:
由于舵机sd5的特性,给450占空比时为中位,±100都会达到最大值。
以上便是PID控制器的一种简单用法,一套控制器可以满足多个闭环的需求。如果我们需要加一个速度环,则只需要:
第一步:PIDP speed = {P,I,D,积分限幅,积分量,一次偏差,两次偏差,输出量}; //根据自己的需求填入参数
第二步:pid_init(&speed); //控制器初始化
第三步:在PIT中断服务函数下
speed.errdat = 传感器采集的数值 - 期望数值;
updat_pid(&speed); //更新控制器
这样就实现了速度的闭环控制,如果控制不如预期则需要调整P I D三个数值。
控制器说明:
1.舵机实验使用恩智浦公司MK60FN系列芯片,使用的库是山外的库。
2.舵机为飞思卡尔智能车竞赛专用B车模舵机,型号SD5。
博客说明:
1.本人邮箱:[email protected],如果文章内有什么不合适或者错误,请发送给我,我将万分感谢,并且会修改博客中错误的地方,修改后不会删除先前错误但是会重点指出错在哪里,是谁找出,为什么我会有这样的错误,以儆效尤。
2.转载无需过问我,但是请注明。
3.如果有侵权行为请及时联系并提出要求:允许继续使用我将注明来源,不允许使用我会第一时间道歉并删除侵权内容。