【转】位置式、增量式PID算法C语言实现
位置式、增量式PID算法C语言实现
芯片:STM32F107VC
编译器:KEIL4
作者:SY
日期:2017-9-21 15:29:19
概述
PID 算法是一种工控领域常见的控制算法,用于闭环反馈控制。有以下两种分类:
增量式
每次周期性计算出的
PID为增量值,是在上一次控制量的基础上进行的调整。位置式
每次周期性计算出的
PID为绝对的数值,是执行机构实际的位置。
我们使用高级语言的思想去实现两种 PID ,做到对于用户来说,调用相同的接口,内部实现不同的 PID 算法。
代码
pid.h
enum PID_MODE {
PID_INC = , //增量式
PID_POS, //位置式
};
struct PID {
enum PID_MODE mode;
float kp; //比例系数
float ki; //积分系数
float kd; //微分系数
double targetPoint; //目标点
double lastError; //Error[-1]
double prevError; //Error[-2]
void (*init)(struct PID *this, double targetPoint); //PID初始化
double (*outputLimit)(struct PID *this, double output); //PID输出限制
void (*setParameter)(struct PID *this, \
float kp, float ki, float kd); //设置PID参数
double (*calculate)(struct PID *this, double samplePoint); //计算PID
};
/* 增量式PID */
struct PID_INC {
struct PID pid;
};
/* 位置式PID */
struct PID_POS {
struct PID pid;
double iSum; //积分和
};
其中 struct PID 就是我们提供给用户的接口,可以理解为 抽象类 ,增量式和位置式 PID 都去继承该抽象类,然后实现其中的抽象方法。
对于位置式 PID 拥有自己的成员 iSum 。
pid.c
/*
*********************************************************************************************************
* PID
*********************************************************************************************************
*/
/*
*********************************************************************************************************
* Function Name : PID_Init
* Description : PID初始化
* Input : None
* Output : None
* Return : None
*********************************************************************************************************
*/
static void PID_Init(struct PID *this, double targetPoint)
{
this->targetPoint = targetPoint;
this->lastError = ;
this->prevError = ;
} /*
*********************************************************************************************************
* Function Name : PID_OutputLimit
* Description : PID输出限制
* Input : None
* Output : None
* Return : None
*********************************************************************************************************
*/
static double PID_OutputLimit(struct PID *this, double output)
{
if (output < ) {
output = ;
} else if (output > DIGITAL_THROTTLE_VALVE_MAX_DEGREE) {
output = DIGITAL_THROTTLE_VALVE_MAX_DEGREE;
}
return output;
} /*
*********************************************************************************************************
* Function Name : PID_SetParameter
* Description : PID设置参数
* Input : None
* Output : None
* Return : None
*********************************************************************************************************
*/
static void PID_SetParameter(struct PID *this, float kp, float ki, float kd)
{
this->kp = kp;
this->ki = ki;
this->kd = kd;
} /*
*********************************************************************************************************
* Function Name : PID_SetTargetValue
* Description : PID设置目标值
* Input : None
* Output : None
* Return : None
*********************************************************************************************************
*/
void PID_SetTargetValue(struct PID *this, double targetPoint)
{
this->targetPoint = targetPoint;
} /*
*********************************************************************************************************
* Function Name : PID_GetTargetValue
* Description : PID获取目标值
* Input : None
* Output : None
* Return : None
*********************************************************************************************************
*/
double PID_GetTargetValue(struct PID *this)
{
return this->targetPoint;
} /*
*********************************************************************************************************
* 增量式PID
*********************************************************************************************************
*/
static double PID_IncCalculate(struct PID *this, double samplePoint); struct PID_INC g_PID_Inc = {
.pid = {
.mode = PID_INC,
.init = PID_Init,
.outputLimit = PID_OutputLimit,
.setParameter = PID_SetParameter,
.calculate = PID_IncCalculate,
},
}; /*
*********************************************************************************************************
* Function Name : PID_IncCalculate
* Description : 增量式PID计算
* Input : None
* Output : None
* Return : None
*********************************************************************************************************
*/
static double PID_IncCalculate(struct PID *this, double samplePoint)
{
double nowError = this->targetPoint - samplePoint;
double out = this->kp * nowError +\
this->ki * this->lastError +\
this->kd * this->prevError;
this->prevError = this->lastError;
this->lastError = nowError; if (this->outputLimit) {
out = this->outputLimit(this, out);
} return out;
} /*
*********************************************************************************************************
* 位置式PID
*********************************************************************************************************
*/
static double PID_PosCalculate(struct PID *this, double samplePoint);
static void PID_PosInit(struct PID *this, double targetPoint); struct PID_POS g_PID_Pos = {
.pid = {
.mode = PID_POS,
.init = PID_PosInit,
.outputLimit = PID_OutputLimit,
.setParameter = PID_SetParameter,
.calculate = PID_PosCalculate,
},
}; /*
*********************************************************************************************************
* Function Name : PID_PosInit
* Description : 位置式PID初始化
* Input : None
* Output : None
* Return : None
*********************************************************************************************************
*/
static void PID_PosInit(struct PID *this, double targetPoint)
{
PID_Init(this, targetPoint);
struct PID_POS *pid_Handle = (struct PID_POS *)this;
pid_Handle->iSum = ;
} /*
*********************************************************************************************************
* Function Name : PID_PosCalculate
* Description : 位置式PID计算
* Input : None
* Output : None
* Return : None
*********************************************************************************************************
*/
static double PID_PosCalculate(struct PID *this, double samplePoint)
{
struct PID_POS *pid_Handle = (struct PID_POS *)this; double nowError = this->targetPoint - samplePoint;
this->lastError = nowError;
//积分累计误差
pid_Handle->iSum += nowError;
double out = this->kp * nowError +\
this->ki * pid_Handle->iSum +\
this->kd * (nowError - this->prevError);
this->prevError = nowError; if (this->outputLimit) {
out = this->outputLimit(this, out);
} return out;
}
对于上述内容:最关键的是两个变量 struct PID_INC g_PID_Inc 和 struct PID_POS g_PID_Pos ,他们针对抽象类实现了各自的算法。
其中有一个很重要的小技巧,举例:
static double PID_PosCalculate(struct PID *this, double samplePoint)
{
struct PID_POS *pid_Handle = (struct PID_POS *)this;
}
该函数的接口是 struct PID *this ,但是我们内部将他强制转换为 struct PID_POS *pid_Handle ,这是两种不同的数据类型,为什么可以进行转换呢?而且转换后的数据是正确的?
因为对于 C 语言来说,结构体内部的第一个成员的地址和该结构体变量的地址是一样的,所以可以相互转换,实现向下转型,这就是 C 语言的强大之处。
测试
app.c
struct KernelCtrl {
struct DTV dtv;
struct PID *dtvPid;
};
static struct KernelCtrl g_kernelCtrl;
/*
*********************************************************************************************************
* Function Name : Kernel_Ctrl_Init
* Description : 内核控制初始化
* Input : None
* Output : None
* Return : None
*********************************************************************************************************
*/
void Kernel_Ctrl_Init(void)
{
#if 1
/* 增量式 */
g_kernelCtrl.dtvPid = &g_PID_Inc.pid;
#else
/* 位置式 */
g_kernelCtrl.dtvPid = &g_PID_Pos.pid;
#endif
}
只要在初始化时,指定使用哪一种 PID 模式,在调用时两种方式可以使用同一个接口,这样对于用户来说就屏蔽了内部细节。
参考
【来源】
【转】位置式、增量式PID算法C语言实现的更多相关文章
- PID算法(C语言)
/************ PID算法(C语言) ************/ #include <stdio.h> #include<math.h> struct _pid { ...
- PID控制算法的C语言实现四 增量型PID的C语言实现
/*------------------------------------------- 2 位置型PID C实现(控制电机转速) --------------------------------- ...
- 023_STM32之PID算法原理及应用
(O)关于程序BUG说明,看最后面的红色字体,视频和源代码中都没有说明 (一)PID控制算法(P:比例 I:积分 D:微分) (二)首先先说明原理,使用的是数字PID算法,模拟PID算法在计算机这样的 ...
- PID控制器开发笔记之一:PID算法原理及基本实现
在自动控制中,PID及其衍生出来的算法是应用最广的算法之一.各个做自动控制的厂家基本都有会实现这一经典算法.我们在做项目的过程中,也时常会遇到类似的需求,所以就想实现这一算法以适用于更多的应用场景. ...
- PID算法的C语言实现
1.根据我控制算法类文章中关于PID的理论的一些描述,同时也根据网络上一些其他的PID文章,以及自己最近一个项目的实践后,总结了几套基于C语言的PID算法,由于网络中很少有人进行分享完整的PID算法实 ...
- 位置式PID与增量式PID算法
位置式PID与增量式PID算法 PID控制是一个二阶线性控制器 定义:通过调整比例.积分和微分三项参数,使得大多数的工业控制系统获得良好的闭环控制性能. 优点 ...
- T12焊台控制器制作教程 | T12烙铁 | PID增量式算法恒温控制 | 运算放大器-热电偶电压采集 | OLED屏幕显示-SPI通信 | 旋转编码器EC11用户操作
前言 购买T12烙铁的相关配件已经1年多了,期间也尝试了一些开源的T12控制器,但都没有成功,要么是配套资料少,要么是英文的,其中51和arduino的居多,STM32的较少.求人不如求己,索性自己开 ...
- 位置式PID与增量式PID
//位置式PID float Kp; float Ki; float Kd; float eSum,e0,e1; float pid_control(float now,float target) { ...
- 增量式pid和位置式PID参数整定过程对比
//增量式PID float IncPIDCalc(PID_Typedef* PIDx,float SetValue,float MeaValue)//err»ý·Ö·ÖÀë³£Êý { PIDx-& ...
随机推荐
- Ionic项目的建立
Ionic建立android项目的过程 1.cmd到目标盘文件,此处为D:\Dev\sourcecode\IonicApp\FlexApp\CaseStudy,执行ionic start CaseSt ...
- [Spark][Python]DataFrame where 操作例子
[Spark][Python]DataFrame中取出有限个记录的例子 的 继续 [15]: myDF=peopleDF.where("age>21") In [16]: m ...
- PHP实现验证码制作
captcha.php(PHP产生验证码并储存Session): <?php //开启Session session_start(); //绘制底图 $image = imagecreatetr ...
- markdown操作手册
**1.标题** # h1 h1自带分割线 ## h2 ### h3 #### h4 ##### h5 ###### h6 **2.圆点** - 圆点 **3.分割线,-和*都可以** --- *** ...
- 百度之星-1002-list应用
用stl的list即可,注意...代码的简洁性(被debug伤痛)注意合并时可以手动pop,或者用splice进行合并,不能用merge!!!merge合并是自带排序!!! #include<b ...
- vue element-ui 动态上传
上传填写完毕的幼儿及体测数据文件,上传成功后会自动导入该文件的数据 <el-upload :action="UploadUrl()" :on-success="Up ...
- React++ node.js ++SQL Sever ++MySQL++ python ++ php ++ java ++ c++ c#++ java ++ android ++ ios ++Linux+
"C语言在它诞生的那个年代,是非常不错的语言,可惜没有OOP.当项目臃肿到一定程度,人类就不可控了. 为了弥补这个缺陷,C++诞生了.而为了应对各种情况,C++设计的大而全,太多复杂的特性, ...
- M1/M2项目阶段总结
1.M1/M2总结 我们这学期完成了学霸项目. 在M1阶段,我们首先进行了分工,完成了一个系统的计划,然后是对学长代码的移植和优化.在优化代码的过程中,我们遇到了不少问题,比如一些代码的冗余以及指向性 ...
- BugPhobia终章篇章:学霸在线系统Beta阶段展示
0x00 :序言 1 universe, 9 planets, 204 countries,809 islands, 7 seas, and i had the privilege to meet y ...
- github链接
github链接:https://github.com/bjing123 test1:https://github.com/bjing123/test-/blob/master/test1.t ...