大家经常会用到PID算法,虽然算法简单,但实际应用中往往要考虑很多细节,而且往往普通的PID算法不能很好的应对大家的需求,为了能在打代码的时候节省点时间,这里作者提供一个自己写好的PID模块,可以让各位在工程中应用。
下载地址:
百度云:链接:https://pan.baidu.com/s/1PI6EuMif5Y_67c4VWE1x7A 提取码:yhmi
Github:连接:https://github.com/diceTZ/pid.git
PID模块除了普通PID还加入了常用的几个改进PID算法:
1、积分分离PID
2、抗积分饱和PID
3、变速积分PID – 由于需求不一样,这个需要用户自行修改
4、不完全微分PID
5、微分先行PID
注:该PID模块为位置型PID
以下为.h代码和例程代码
pid.h(由于篇幅过长pid.c在上述下载地址中存放)
//@作者 :tou_zi
//@编写时间 :2019年4月6日
//@修改时间 :2019年4月6日
//@文件名 :pid.h
//@描述 :pid模块库,可实现pid的计算
#ifndef _PID_H
#define _PID_H
#ifndef u8
#define u8 unsigned char
#endif
#define INTEGRAL_NORMAL 0 //普通积分
#define INTEGRAL_SEPARATION 1 //积分分离
#define INTEGRAL_SATURATION 2 //抗饱和积分
#define INTEGRAL_SPEED 3 //变速积分
#define DIFFERENTIAL_COMPLETE 0 //完全微分
#define DIFFERENTIAL_PART 1 //不完全微分
#define DIFFERENTIAL_PREVIOUS 2 //微分先行
//PID标志
typedef struct PID_Position_Flag
{
u8 run;
u8 integral_way;
u8 differential_way;
u8 use_predict;
}PID_Position_Flag;
//PID数据接口
typedef struct PID_Position_DInterface
{
float *target;
float *present;
float *predict;
}PID_Position_DInterface;
//PID接口
typedef struct PID_Position_Interface
{
PID_Position_DInterface data;
}PID_Position_Interface;
//PID参数
typedef struct PID_Position_Parameter
{
float kp; //比例系数
float ki; //积分系数
float kd; //微分系数
float kf; //前馈系数
float kd_lpf; //不完全微分系数
float kd_pre; //微分先行系数
float k_pre; //预测系数
float target_limit; //目标值限幅
float bias_limit; //误差限幅
float bias_dead_zone; //小于这个值将不进行PID操作
float bias_for_integral; //开始积分的误差 -- 用于积分分离
float integral_limit; //积分限幅 -- 用于抗积分饱和
float out_limit; //输出限幅
}PID_Position_Parameter;
//PID数据
typedef struct PID_Position_Data
{
float out;
}PID_Position_Data;
//PID过程变量
typedef struct PID_Position_Process
{
float bias;
float integral_bias;
float differential_bias;
float lpf_differential_bias;
float feedforward;
float predict;
float last_target;
float last_bias;
}PID_Position_Process;
//PID模块
typedef struct PID_Position_Module
{
PID_Position_Flag flag;
PID_Position_Interface interface;
PID_Position_Parameter parameter;
PID_Position_Data data;
PID_Position_Process process;
}PID_Position_Module;
//PID API
void initPID_Position_Module(PID_Position_Module *pid);
void calculatePID_Position_Module(PID_Position_Module *pid, float cycle);
模块分为五个子模块:标志模块,接口模块,参数模块,数据模块以及过程变量模块
****标志模块:(控制模块运行和运行方法)
****接口模块:分为数据接口(变量指针)和方法接口 (函数指针)
********数据接口:target 目标值, present 当前值
****参数模块:设定PID的相关参数
****数据模块:用户感兴趣的数据的存放点
****过程变量模块:用户不敢兴趣的数据的存放点,但调试时可能会用得上
例程代码:
#include "stdlib.h"
#include "pid.h"
PID_Position_Module my_pid;
int main(void)
{
float target = 0, present = 1;
initPID_Position_Module(&my_pid); //初始化pid结构体
//设置标志位
my_pid.flag.run = 1; //运行PID
my_pid.flag.differential_way = DIFFERENTIAL_COMPLETE; //设置微分方法--完全微分
my_pid.flag.integral_way = INTEGRAL_SATURATION; //设置积分方法--抗积分饱和
//设置接口
my_pid.interface.data.target = (float *)malloc(sizeof(float)); //设置目标值接口
my_pid.interface.data.present = (float *)malloc(sizeof(float)); //设置当前值接口
// my_pid.interface.data.target = ⌖ //设置目标值接口
// my_pid.interface.data.present = &present; //设置当前值接口
//设置参数
my_pid.parameter.kp = 0; //设置比例系数
my_pid.parameter.ki = 0; //设置积分系数
my_pid.parameter.kd = 0; //设置微分系数
my_pid.parameter.kf = 0; //设置前馈系数
my_pid.parameter.integral_limit = 25.0f; //积分限制
my_pid.parameter.bias_dead_zone = 0; //误差死区
my_pid.parameter.target_limit = 50.0f; //期望限幅
my_pid.parameter.bias_limit = 50.0f; //误差限幅
my_pid.parameter.out_limit = 50.0f; //输出限幅
while(1)
{
calculatePID_Position_Module(&my_pid, 0.01f); //计算pid,0.01 = 0.01秒(计算周期)
}
}
“望小小的举动,能够改变世界”