PID算法库

日期作者版本说明
2020.10.29TaoV1.0Release as V1.0

PID算法介绍

PID即:Proportional(比例)Integral(积分)、**Differential(微分)**的缩写。顾名思义,PID控制算法是结合比例、积分和微分三种环节于一体的控制算法,它是连续系统中技术最为成熟、应用最为广泛的一种控制算法,该控制算法出现于20世纪30至40年代,适用于对被控对象模型了解不清楚的场合。实际运行的经验和理论的分析都表明,运用这种控制规律对许多工业过程进行控制时,都能得到比较满意的效果。在理论上可以证明,对于过程控制的典型对象——“一阶滞后+纯滞后”与“二阶滞后+纯滞后”的控制对象,PID控制器是一种最优控制。PID控制的实质就是根据输入的偏差值,按照比例、积分、微分的函数关系进行运算,运算结果用以控制输出。

  • PID的控制过程:
    PID的控制过程
  • PID的计算公式:
    PID理论计算公式

源码

头文件

#ifndef __PID_H__
#define __PID_H__

#include "stm32f10x_conf.h"
#include "stm32f10x.h"

typedef struct
{
	float sv;
	float pv;
	float kp;
	float ki;
	float kd;
	float error;
	float error_last;
	float integral;
	float differential;
	float output;

	float upThres;			//PID启动上阈值
	float downThres;		//PID启动下阈值

	float maxInteg;			//最大积分限幅值(正值)
	float minInteg;			//最小积分限幅值(负值)
	float maxDiff;			//最大微分限幅值
	float minDiff;			//最小微分限幅值
}PID_TypeDef;

#define PID_DEFAULT_P						0.1
#define PID_DEFAULT_I							0.001
#define PID_DEFAULT_D						0.0

#define PID_DEFAULT_UPTHRES			3.0
#define PID_DEFAULT_DOWNTHRES		3.0

#define PID_DEFAULT_MAXINTEG			10.0
#define PID_DEFAULT_MININTEG			-10.0
#define PID_DEFAULT_MAXDIFF			10.0
#define PID_DEFAULT_MINDIFF				-10.0

void PID_SetPIDPara(PID_TypeDef *PID_InitStruct, float KP, float KI, float KD);
void PID_SetThresPara(PID_TypeDef *PID_InitStruct, float upThres, float downThres);
void PID_SetIntegLimiting(PID_TypeDef *PID_InitStruct, float maxInteg, float minInteg);
void PID_SetDiffLimiting(PID_TypeDef *PID_InitStruct, float maxDiff, float minDiff);

void PID_Init(PID_TypeDef *PID_InitStruct);
float PID_Update(PID_TypeDef *PID_InitStruct,  float SV, float PV);
void PID_Reset(PID_TypeDef *PID_InitStruct);
float PID_GetOutput(PID_TypeDef *PID_InitStruct);
float PID_GetError(PID_TypeDef *PID_InitStruct);
float PID_GetIntegral(PID_TypeDef *PID_InitStruct);
float PID_GetDifferential(PID_TypeDef *PID_InitStruct);

#endif // __PID__H

源文件

#include "pid.h"

void PID_SetPIDPara(PID_TypeDef *PID_InitStruct, float KP, float KI, float KD)
{
	PID_InitStruct->kp = KP;
	PID_InitStruct->ki = KI;
	PID_InitStruct->kd = KD;
}


void PID_SetThresPara(PID_TypeDef *PID_InitStruct, float upThres, float downThres)
{
	PID_InitStruct->upThres = upThres;
	PID_InitStruct->downThres = downThres;
}


void PID_SetIntegLimiting(PID_TypeDef *PID_InitStruct, float maxInteg, float minInteg)
{
	PID_InitStruct->maxInteg = maxInteg;
	PID_InitStruct->minInteg = minInteg;
}


void PID_SetDiffLimiting(PID_TypeDef *PID_InitStruct, float maxDiff, float minDiff)
{
	PID_InitStruct->maxInteg = maxDiff;
	PID_InitStruct->minInteg = minDiff;
}


void PID_Init(PID_TypeDef *PID_InitStruct)
{
	PID_InitStruct->error = 0.0;
	PID_InitStruct->error_last = 0.0;
	PID_InitStruct->integral = 0.0;
	PID_InitStruct->differential = 0.0;
	PID_InitStruct->output = 0.0;

	//将PID参数初始化为宏定义确定的默认通用参数
	PID_SetPIDPara(PID_InitStruct, PID_DEFAULT_P, PID_DEFAULT_I, PID_DEFAULT_D);
	PID_SetThresPara(PID_InitStruct, PID_DEFAULT_UPTHRES, PID_DEFAULT_DOWNTHRES);
	PID_SetIntegLimiting(PID_InitStruct, PID_DEFAULT_MAXINTEG, PID_DEFAULT_MININTEG);
	PID_SetDiffLimiting(PID_InitStruct, PID_DEFAULT_MAXDIFF, PID_DEFAULT_MINDIFF);
}


/**
 * @brief 静态函数,用来计算一次P值,I值,D值
 * @param PID_InitStruct: 传入的PID类型定义的结构体指针
 * @return 计算的结果,经过限幅处理,范围为0~1
 */
static float PID_Calculate(PID_TypeDef *PID_InitStruct)
{
	float pid_output = 0;

	///当输出限幅的时候,积分累加部分也应同时进行限幅,以防输出不变而积分项继续累加,也即所谓的积分饱和过深。
	PID_InitStruct->integral += PID_InitStruct->error;
	//积分量限幅
	if(PID_InitStruct->integral >PID_InitStruct->maxInteg)
	{
		PID_InitStruct->integral = PID_InitStruct->maxInteg ;
	}
	else if(PID_InitStruct->integral < PID_InitStruct->minInteg)
	{
		PID_InitStruct->integral = PID_InitStruct->minInteg ;
	}
	else
	{

	}

	PID_InitStruct->differential = PID_InitStruct->error - PID_InitStruct->error_last;
	//微分量限幅限制
	if(PID_InitStruct->differential > PID_InitStruct->maxDiff)
	{
		PID_InitStruct->differential = PID_InitStruct->maxDiff;
	}
	else if(PID_InitStruct->differential < PID_InitStruct->minDiff)
	{
		PID_InitStruct->differential = PID_InitStruct->minDiff;
	}
	else
	{

	}

	pid_output = PID_InitStruct->kp * PID_InitStruct->error + PID_InitStruct->ki * PID_InitStruct->integral
			+ PID_InitStruct->kd * PID_InitStruct->differential;

	if (pid_output > 1)
	{
		pid_output = 1;
	}
	else if (pid_output < 0)
	{
		pid_output = 0;
	}
	else
	{

	}

	return pid_output;
}


float PID_Update(PID_TypeDef *PID_InitStruct,  float SV, float PV)
{
	PID_InitStruct->sv = SV;
	PID_InitStruct->pv = PV;

	PID_InitStruct->error_last = PID_InitStruct->error;
	PID_InitStruct->error = PID_InitStruct->sv - PID_InitStruct->pv;

	///PV < SV - PIDDownThres. PID use full power.
	if(PID_InitStruct->error > PID_InitStruct->downThres)
	{
		PID_InitStruct->output = 1;
	}
	///PV < SV + PIDUpThres. PID use calculated data.
	else if(PID_InitStruct->error > 0 - PID_InitStruct->upThres)
	{
		PID_InitStruct->output = PID_Calculate(PID_InitStruct);
	}
	///PV >= SV + PIDUpThres. PID use zero power.
	else
	{
		PID_InitStruct->output = 0;
	}

	return PID_InitStruct->output;
}


void PID_Reset(PID_TypeDef *PID_InitStruct)
{
	PID_InitStruct->sv = 0;
	PID_InitStruct->pv = 0;
	PID_InitStruct->kp = 0;
	PID_InitStruct->ki = 0;
	PID_InitStruct->kd = 0;
	PID_InitStruct->error = 0;
	PID_InitStruct->error_last = 0;
	PID_InitStruct->integral = 0;
	PID_InitStruct->differential = 0;
	PID_InitStruct->output = 0;
}


float PID_GetOutput(PID_TypeDef *PID_InitStruct)
{
	return PID_InitStruct->output;
}


float PID_GetError(PID_TypeDef *PID_InitStruct)
{
	return PID_InitStruct->error;
}


float PID_GetIntegral(PID_TypeDef *PID_InitStruct)
{
	return PID_InitStruct->integral;
}


float PID_GetDifferential(PID_TypeDef *PID_InitStruct)
{
	return PID_InitStruct->differential;
}

使用指南

直接使用

声明并定义PID类型数据(或数组)

声明并定义PID类型数据(或数组)。可以在声明的时候直接初始化变量,也可以利用void PID_Init(PID_TypeDef *PID_InitStruct)将PID成员参数初始化为宏定义设定的默认参数

#define PID_DEFAULT_P				0.1
#define PID_DEFAULT_I				0.001
#define PID_DEFAULT_D				0.0

#define PID_DEFAULT_UPTHRES			3.0
#define PID_DEFAULT_DOWNTHRES		3.0

#define PID_DEFAULT_MAXINTEG		10.0
#define PID_DEFAULT_MININTEG		-10.0
#define PID_DEFAULT_MAXDIFF			10.0
#define PID_DEFAULT_MINDIFF			-10.0

根据需要修改PID参数

使用库函数提供的参数修改接口,在需要的地方对PID进行修改(程序初始化时、轮询PID控制动作时):

  • void PID_SetPIDPara(PID_TypeDef *PID_InitStruct, float KP, float KI, float KD):设置P(Proportional), I(Integral), D(Differential)参数。
  • void PID_SetThresPara(PID_TypeDef *PID_InitStruct, float upThres, float downThres):设置PID作用的上下阈值(PV进入[SV-downThres, SV+upThres]区间,PID才起作用)。
  • void PID_SetIntegLimiting(PID_TypeDef *PID_InitStruct, float maxInteg, float minInteg):设置PID算法的最大、最小积分量(防止PID进入积分过饱和)。
  • void PID_SetDiffLimiting(PID_TypeDef *PID_InitStruct, float maxDiff, float minDiff):设置PID算法的最大、最小微分量(防止PID进入微分过饱和)。

对于不需要支持动态修改的参数(修改后重启生效),可以在程序初始化的时候(根据相应保持寄存器的值)设置参数。对于需要实时修改的参数(修改后立即生效),可以在轮询PID控制动作的时候(调用PID_Update进行输出计算之前)进行修改。

	//Set PID
	PID_SetPara(&this->PidData, HoldingReg_GetData(11), HoldingReg_GetData(12), HoldingReg_GetData(13));
	//Set threshold
	PID_SetThresPara(&this->PidData, HoldingReg_GetData(14), HoldingReg_GetData(15));

计算PID输出值

在定时器更新中断服务函数或者RTOS的一个轮询任务中,周期性的调用float PID_Update(PID_TypeDef *PID_InitStruct, float SV, float PV)函数计算PID的输出值(返回值)。执行器根据输出值调整一次动作(例如加热器根据输出值调整PWM的占空比以实现功率调节)。

间接使用

PID数据已经被封装为一个结构体类型,可以直接声明并定义PID类型的变量作为其他结构体封装的成员。通过PID算法库提供的一套PID操作函数,可以在需要的地方调用并传入需要操作的PID变量。具体的例子可以参考C语言模块化设计控温器的实现

  • 6
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

全能骑士涛锅锅

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值