【转】位置式、增量式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 Cannot find module 'internal/fs'问题
最近升级了node.js到7.3.0之后,在用cordoval add plugin XXX 命令安装插件的时候报"Cannot find module 'internal/fs'" ...
- POJ Remmarguts' Date
题目链接-> 题解: 次短路模板. 代码: #include<cstdio> #include<iostream> using namespace std; #defin ...
- Caffe源码中syncedmem文件分析
Caffe源码(caffe version:09868ac , date: 2015.08.15)中有一些重要文件,这里介绍下syncedmem文件. 1. include文件: (1).& ...
- 事务,acid,cap,paxos随笔
事务ACID四个特性: A:原子性(Atomicity)C:一致性(Consistency)I:隔离性(Isolation)D:持久性(Durability) 原子性:语句要么全执行,要么全不执行,是 ...
- HBase最佳实践-管好你的操作系统
本文由 网易云发布. 作者:范欣欣 本篇文章仅限本站分享,如需转载,请联系网易获取授权. 操作系统这个话题其实很早就想拿出来和大家分享,拖到现在一方面是因为对其中各种理论理解并不十分透彻,怕讲不好: ...
- .net core实践系列之短信服务-Api的SDK的实现与测试
前言 上一篇<.net core实践系列之短信服务-Sikiro.SMS.Api服务的实现>讲解了API的设计与实现,本篇主要讲解编写接口的SDK编写还有API的测试. 或许有些人会认为, ...
- 支持自定义协议的虚拟仪器【winform版】
首先,这个程序的由来,额,工作以来,做的最久的就是上位机,对市面上的大部分组态软件都感到不满,不好用,LabView虽然用起来不错,但是入门还是不够简单,刚好现在工作比较闲(已经不再做上位机了),所以 ...
- Anaconda2和Anaconda3同时安装
转载于:https://www.cnblogs.com/zle1992/p/6720425.html 1.先从网站(国内的清华镜像:https://mirrors.tuna.tsinghua.edu. ...
- how-is-docker-different-from-a-normal-virtual-machine[Docker与VirtualMachine的区别]
https://stackoverflow.com/questions/16047306/how-is-docker-different-from-a-normal-virtual-machine 被 ...
- Java的Vector源码阅读
* The {@code Vector} class implements a growable array of * objects. Like an array, it contains comp ...