前言:编写不易,仅供学习,参考,谢谢理解,请勿转载。
#位置式|增量式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.0typedef 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 ;
}