一篇教会你 位置式PID 在写码中的应用。

                          前言:编写不易,仅供学习,参考,谢谢理解,请勿转载。

#位置式|增量式PID区别

        本系列的前两篇讲的是位置式PID  没有增量式  PID ,PID的变种有很多,常见的有  位置式PID  增量式PID   PI   PD  抗饱和PID  微分先行PID  自适应PID  模糊PID 这些都是PID算法的类型。

       位置式PID;这种PID算法应用在闭环系统中,输出影响下得到的值是新的输入值,这个新的输入值就是对整个闭环系统总共的作用量

                                公式:PID=Kp*e(k)+Ki*∑e(k)+Kd[e(k)-e(k-1)]

        增量式PID:顾名思义,增量式PID计算得出的值,是增量,是系统输入量的基础上再增加的量,增量并不是直接作用在闭环系统的值,这个值需要加上闭环系统原本的输入量,才是作用于闭环系统的输入值。

                                公式:PID=Kp[e(k)-e(k-1)]+Ki*e(k)+Kd[e(k)-2e(k-1)+e(k-2)]

        这两个公式Kp  还有Kd  是不一样的,如果在代码里面看到,计算相同的代码,就知道是增量式PID  还是位置式PID。

#位置式PID相关变量命名

         首先在闭环控制系统中,有期望值  目前值  还有差值,声明  期望值   和  目前值  差值   还有给 PID中的  P算法   I算法  D算法  先声明三个变量。

extern float Velcity_Kp,Velcity_Ki,Velcity_Kd;

          这里只讲位置式PID的代码,在位置式PID函数的作用下是一个闭环控制系统,也就是输出对输入有影响, CurrentVelocity 就是输出,那么这个值对输入有影响, CurrentVelocity 这个值要写到PID函数里面才能有影响,然后这个控制系统根据与 TargetVelocity 的差值,会产生一个新的输入值是 Control_Velocity,同理重复循环,形成了一个闭环控制系统,结论,TargetVelocity  Control_Velocity   是PID的参数之一。

int Control_Velocity;//  经过PID系统,新的作用系统的输出值。
 int CurrentVelocity ; //实际目前速度
int TargetVelocity;//目标速度

        同时 TargetVelocity  这个值,与 CurrentVelocity  进行比较的,计算出差值,这个差值经过PID算法后产生新的 Control_Velocity ,也就是说Error。这个参数也是PID控制系统所需要的。 

int Error;
Error = TargetVelocity - CurrentVelocity;//期望速度与目前速度的差值。

  

       

        同时 Kp  Ki  Kd 这三个变量因为组成了PID算法函数,是必须给数值的,同时调节PID参数也是调节这三个值的参数。从而达到更好的控制系统表现。

//定义PID参数
#define Kp  1.0
#define Ki  0.0
#define Kd  0.0

        前两篇讲解了,纯理论公式,同时也知道了,PID算法 由P算法(Kp)    比例   I算法(Ki)  积分  D算法(Kd)   微分   组成,实际应用中,更多的是使用这三种算法的组合形式,PI  PD  PID  。

        由于 D算法(Kd),是两次误差的值,如果差值过大,Kd也就越大对Kp的抑制也就越大,需要有三个参数,上次误差Last_Error,和Error,还有 derivate

        由于Ki算法,是对误差的累加算法,需要对其进行限制幅,这里需要两个参数  Ki_Max Ki*integral    因为是位置式PID 需要对Ki进行限幅度 ,如果是增量式PID 需要对输出限幅,同时Ki也就是积分是累加的,是用 integral(积分),进行命名。

        同时Kp算法,使用参数比较少,只需要Error,前面已经声明过了,到了这里,已经讲解了,位置式PID,需要用到的参数,如果像上面一个一个声明,太麻烦了,直接定义结构体,更好一点。下面定义结构体。

typedef struct //定义结构体参数
{
    float Velcity_Kp;
    float Velcity_Ki;
    float Velcity_Kd;
    float Error;
    float Last_Error;
    float integral;
    float derivate;
	int Control_Velocity;
}PID;

#相关PID组合函数进行编写

PID初始化函数编写

void PID_Init(PID*pid,float Velcity_Kp ,float Velcity_Ki,float Velcity_Kd)
{
    pid->Velcity_Kp = Velcity_Kp;
    pid->Velcity_Ki = Velcity_Ki;
    pid->Velcity_Kd = Velcity_Kd;
    pid->Error = 0;
    pid->Last_Error = 0;
    pid->integral = 0;
    pid->Control_Velocity = 0;
    pid->derivate = 0 ; 
}
//这里声明一个指针,然后对一个结构体 取地址& 代表要初始化的实例 

        首先定义初始化函数,用来对PID结构体里面的所有成员变量进行初始化,同时传入#define  kp | ki  | kd  的值,

        到这里将,前面所有讲解的代码整合,应该是这个样子的。

PI组合函数

        到了这一步还需要再声明一个函数,用来运行PID返回计算结果。

float   PID_Calculate (PID*pid,float Velcity_Kp ,float Velcity_Ki ,float Velcity_Kd )
{

    pid->Error    = pid->Current_Velocity  - pid->TargetVelocity;
    pid->integral +=pid->Error;
    pid->Control_Velocity  = pid->Velcity_Kp*pid->Error + pid->Velcity_Ki*pid->integral;     
    pid->Last_Error = pid->Error; 

    return pid->Control_Velocity;

}

PD组合函数

float   PID_Calculate (PID*pid,float Velcity_Kp ,float Velcity_Ki ,float Velcity_Kd )
{

    pid->Error    = pid->Current_Velocity  - pid->TargetVelocity;
    pid->derivate = pid->Error - pid->Last_Error;
    pid->Control_Velocity  = pid->Velcity_Kp*pid->Error  +pid->Velcity_Kd*pid->derivate;     
    pid->Last_Error = pid->Error; 

    return pid->Control_Velocity;

}

PID组合函数

float   PID_Calculate (PID*pid,float Velcity_Kp ,float Velcity_Ki ,float Velcity_Kd )
{

    pid->Error    = pid->Current_Velocity  - pid->TargetVelocity;
    pid->integral +=pid->Error;
    pid->derivate = pid->Error - pid->Last_Error;
    pid->Control_Velocity  = pid->Velcity_Kp*pid->Error + pid->Velcity_Ki*pid->integral +pid->Velcity_Kd*pid->derivate;     
    pid->Last_Error = pid->Error; 

    return pid->Control_Velocity;

}

        PID本身就是一个应用在 云台  编码电机上的东西,单讲PID不讲应用在云台或者电机,意义不大,本篇今天收藏过30,两天内立即更  PID应用在舵机云台,编码电机,附带调试细节,附带源码。

        最后整体程序是下图这个样子

//定义PID参数
#define Kp  1.0
#define Ki  0.0
#define Kd  0.0


typedef struct //定义结构体参数
{
    float Velcity_Kp;
    float Velcity_Ki;
    float Velcity_Kd;
    float Error;
    float Last_Error;
    float integral;
    float derivate;
	  int Control_Velocity;
}PID;


void PID_Init(PID*pid,float Velcity_Kp ,float Velcity_Ki,float Velcity_Kd);

int main()
{
    PID  servo;//声明PID 结构体 变量
    PID_Init(&servo,Kp,Ki,Kd);//这几个宏定义在PID.h文件里面。
while (1){
        int output = PID_Calculate(&servo,0,180);
        setAngle(0,output);
    }
}

void PID_Init(PID*pid,float Velcity_Kp ,float Velcity_Ki,float Velcity_Kd)
{
    pid->Velcity_Kp = Velcity_Kp;
    pid->Velcity_Ki = Velcity_Ki;
    pid->Velcity_Kd = Velcity_Kd;
    pid->Error = 0;
    pid->Last_Error = 0;
    pid->integral = 0;
    pid->Control_Velocity = 0;
    pid->derivate = 0 ; 
}

                欢迎指正,希望对你,有所帮助!!!

评论 66
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

看,是大狗

创作不易,感谢支持

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值