023_STM32之PID算法原理及应用
(O)关于程序BUG说明,看最后面的红色字体,视频和源代码中都没有说明
(一)PID控制算法(P:比例 I:积分 D:微分)
(二)首先先说明原理,使用的是数字PID算法,模拟PID算法在计算机这样的系统中是不能够直接使用的,数字PID算法又分为位置式PID控制算法和增量式PID控制算法,那么下面从原理上说明这两种算法
(三)原理分析如图
(四)从上面图中我们可以得到定义
定义变量
用户设定值: SV
当前值(实际值): PV
偏差: E = SV - PV
(五)如果我们在一段时间内就从传感器读取一个值,那么我们就可以得到一个实际值的数据序列,,那么我们也会得到一个偏差值的序列
读取时间: t(1) t(2) ------ t(k-1) t(k)
读取到的值: X(1) X(2) ------ X(k-1) X(k)
偏差值: E(1) E(2) ------ E(k-1) E(k) 那么我们从偏差值中可以知道: E(X) > 0 说明未达标
E(X) = 0 说明正好达标
E(X) < 0 说明超标
(六)比例控制(P),作用:对偏差起到及时反映的作用,一旦产生偏差,控制器立即做出反映.............
定义:
比例系数:Kp (根据系统进行调节)
比例输出:POUT = Kp * E(k)
POUT = Kp * E(k) + OUT0 OUT0说明:OUT0是防止E(K) = 0 时候比例控制不作用,所以添加个OUT0进去,OUT0可以根据系统定义大小
Kp说明:如果我们得到一个偏差之后,将偏差进行放大或者缩小来让控制器进行控制
(七)积分控制(I),作用:消除静差............
从上面我们得到偏差序列:
偏差值: E() E() ------ E(k-) E(k) 定义,历史偏差值之和:S(k) = E(1) + E(2) + .... + E(k-1) + E(K)
定义,积分输出: IOUT = Kp * S(k) + OUT0
(八)微分控制(D),作用:反映偏差信号的变化趋势.............
从上面我们得到偏差序列:
偏差值: E() E() ------ E(k-) E(k)
定义,偏差之差:D(k) = E(k) - E(k-1)
定义,微分输出:DOUT = Kp * D(k) + OUT0
(九)那么我们从上面就能得出PID的控制算法
PIDOUT = POUT + IOUT + DOUT
= (Kp * E(k) + OUT0) + (Kp * S(k) + OUT0) + (Kp * D(k) +OUT0)
= Kp * (E(k) + S(k) + D(k)) + OUT0 OUT0防止PIDOUT = 0 时候算法还有输出,防止失去控控制
比例(P):考虑当前
积分(I):考虑历史
微分(D):考虑未来
(十)位置式PID,上面只是简单的说明了一下原理,那么实际的数字PID控制算法中,额,那个变换公式打不出来,自行百度,这里就直接打出结果
Ti:积分常数
TD:微分常数
T:计算周期
上面两个是变化后的积分和微分的那个,那么我们把上面的两个替换到第九点中,我们就得到位置上PIDOUT的公式,两个式子是一样的
(十一)增量式PID,本次基础上加上多少偏差:△OUT
/**********************分割线************************/
(十二)上面的只是PID的原理说明,那么数字PID的公式是
(十三)那么我们将上面的公式通过通过C语言写出来
1. 位置式PID
#ifndef _pid_
#define _pid_
#include "stm32f10x_conf.h"
#define MODEL_P 1
#define MODEL_PI 2
#define MODEL_PID 3 typedef struct
{
u8 choose_model; //使用哪个模式调节 float Sv; //用户设定值
float Pv; //当前值,实际值 float Kp; //比例系数
float T; //PID计算周期--采样周期
u16 Tdata; //判断PID周期到没到
float Ti; //积分时间常数
float Td; //微分系数 float Ek; //本次偏差
float Ek_1; //上次偏差
float SEk; //历史偏差之和 float Iout; //积分输出
float Pout; //比例输出
float Dout; //微分输出 float OUT0; //一个维持的输出,防止失控 float OUT; //计数最终得到的值 u16 pwmcycle;//pwm周期 }PID; extern PID pid; //存放PID算法所需要的数据
void PID_Calc(void); //pid计算
void PID_Init(void); //PID初始化 #endif
#include "pid.h"
#include "PWM_Config.h"
#include "USART_Config.h" //USART设置 PID pid; //存放PID算法所需要的数据
void PID_Init()
{
pid.choose_model = MODEL_PID; pid.T=; //采样周期,定时器使用1ms,则最小执行PID的周期为330ms pid.Sv=; //用户设定值
pid.Kp=0.5; //比例系数
pid.Ti=; //积分时间
pid.Td=; //微分时间
pid.OUT0=; //一个维持的输出 pid.pwmcycle = ; //PWM的周期
} void PID_Calc() //pid计算
{
float DelEk; //本次和上次偏差,最近两次偏差之差
float ti,ki;
float td;
float kd;
float out; if(pid.Tdata < (pid.T)) //最小计算周期未到
{
return ;
}
pid.Tdata = ;
pid.Ek=pid.Sv-pid.Pv; //得到当前的偏差值
pid.Pout=pid.Kp*pid.Ek; //比例输出 pid.SEk+=pid.Ek; //历史偏差总和 DelEk=pid.Ek-pid.Ek_1; //最近两次偏差之差 ti=pid.T/pid.Ti;
ki=ti*pid.Kp; pid.Iout=ki*pid.SEk*pid.Kp; //积分输出
/*注意:上面程序中多了个pid.Kp,原程序中有,请自动删除,正确的应该是pid.Iout=ki*pid.SEK */ td=pid.Td/pid.T; kd=pid.Kp*td; pid.Dout=kd*DelEk; //微分输出 switch(pid.choose_model)
{
case MODEL_P: out= pid.Pout; printf("使用P运算\r\n") ;
break; case MODEL_PI: out= pid.Pout+ pid.Iout; printf("使用PI运算\r\n") ;
break; case MODEL_PID: out= pid.Pout+ pid.Iout+ pid.Dout; printf("使用PID运算\r\n") ;
break;
}
printf("PID算得的OUT:\t%d\r\n",(int)out) ; ////////////////////////////////////////////////////////// /*判断算出的数是否符合控制要求*/
if(out>pid.pwmcycle) //不能比PWM周期大,最大就是全高吗
{
pid.OUT=pid.pwmcycle;
}
else if(out<) //值不能为负数
{
pid.OUT=pid.OUT0;
}
else
{
pid.OUT=out;
}
printf("实际输出使用的pid.OUT:\t%d\r\n",(int)pid.OUT) ;
pid.Ek_1=pid.Ek; //更新偏差 Turn_Angle((int)pid.OUT); //输出PWM }
2.增量式PID
#ifndef _pid_
#define _pid_
#include "stm32f10x_conf.h"
#define MODEL_P 1
#define MODEL_PI 2
#define MODEL_PID 3 typedef struct
{
u8 choose_model; //使用哪个模式调节 float curr; //当前值
float set; //设定值 float En; //当前时刻
float En_1; //前一时刻
float En_2; //前二时刻 float Kp; //比例系数
float T; //采样周期---控制周期,每隔T控制器输出一次PID运算结果
u16 Tdata; //判断PID周期到没到
float Ti; //积分时间常数
float Td; //微分时间常数 float Dout; //增量PID计算本次应该输出的增量值--本次计算的结果
float OUT0; //一个维持的输出,防止失控 short currpwm; //当前的pwm宽度
u16 pwmcycle; //pwm周期 }PID; extern u8 STATUS;
extern PID pid;
void PIDParament_Init(void); /*增量式PID初始化*/
void pid_calc(void); /*pid计算 并输出*/ #endif
#include "pid.h"
#include "PWM_Config.h"
#include "USART_Config.h" //USART设置 PID pid; void PIDParament_Init() //
{
pid.choose_model = MODEL_PID;
pid.T=; //采样周期,定时器使用1ms,则最小执行PID的周期为330ms pid.set =; //用户设定值
pid.Kp=0.5; //比例系数
pid.Ti=; //微分系数常数
pid.Td=; //积分时间常数
pid.OUT0=; //一个维持的输出 pid.pwmcycle = ; //PWM的周期
} void pid_calc() //pid??
{
float dk1;float dk2;
float t1,t2,t3; if(pid.Tdata < (pid.T)) //最小计算周期未到
{
return ;
}
pid.Tdata = ; pid.En=pid.set-pid.curr; //本次误差
dk1=pid.En-pid.En_1; //本次偏差与上次偏差之差
dk2=pid.En-*pid.En_1+pid.En_2; t1=pid.Kp*dk1; //比例 t2=(pid.Kp*pid.T)/pid.Ti; //积分
t2=t2*pid.En; t3=(pid.Kp*pid.Td)/pid.T; //微分
t3=t3*dk2; switch(pid.choose_model)
{
case MODEL_P: pid.Dout= t1; printf("使用P运算\r\n") ;
break; case MODEL_PI: pid.Dout= t1+t2; printf("使用PI运算\r\n") ;
break; case MODEL_PID: pid.Dout= t1+t2+t3; printf("使用PID运算\r\n") ;
break;
} pid.currpwm+=pid.Dout; //本次应该输出的PWM
printf("PID算得的OUT:\t%d\r\n",(int)pid.currpwm) ; /*判断算出的数是否符合控制要求*/
if(pid.currpwm>pid.pwmcycle) //算出的值取值,肯定是在0-pid.pwmcycle之间,不然的话PWM怎么输出
{
pid.currpwm=pid.pwmcycle;
}
if(pid.currpwm<)
{
pid.currpwm=;
} printf("实际输出使用的OUT:\t%d\r\n",(int)pid.currpwm) ;
pid.En_2=pid.En_1;
pid.En_1=pid.En; Turn_Angle(pid.currpwm); //输出PWM }
(十五)上面我们贴出来位置式PID算法和增量式PID算法的核心部分了,但是上面的理论上可以直接移植,添加一些还没有定义的变量就好了,下面是具体的演示工程
024——PID算法整定
(一)首先在使用PID算法之前先进行基础的设置
1. PWM正脉冲控制输出开
2. 传感器曲线随着PWM占空比越大而越大
3. 传感器在环境下情况下最低数据 ,和最高数据。 设定值不能超过这两个范围
(三)总结试凑法
1. 比例系数有小到大,然后找出超调小的Kp
2. 积分时间常数Ti由大变小,适当调整Kp
3. 微分时间常数Td由小变大,适当调整Ti和Kp
(四)实验总结
1. KP设定,最初使用1,假如控制之后实际值比设定值小不够,那就增大。反之就减少。
2. TI设定,数据先很大。看效果
1). 如果TI加进去之后数据很久才变化到目标值就逐渐减小。如果TI减少到执行几次都是比设定值大的时候那就逐渐增大
2). 如果刚加进去变化很快,并且超调很高,就增大来调节
3. 积分就看情况调节
注意:视频中有一些地方口误,记得识别,如毫秒可能会读成微妙,额。。。。没办法
注意:关于位置式PID算法中程序积分公式那里多了个pid.Kp,记得删除,具体的位置看上面的位置式PID
程序中有注解,资料下载下来的程序没有删除,记得删除!!!!!!
视频教程:https://v.qq.com/x/page/o0826j2am1x.html
资料下载:https://download.csdn.net/download/xiaoguoge11/10911361
023_STM32之PID算法原理及应用的更多相关文章
- PID控制器开发笔记之一:PID算法原理及基本实现
在自动控制中,PID及其衍生出来的算法是应用最广的算法之一.各个做自动控制的厂家基本都有会实现这一经典算法.我们在做项目的过程中,也时常会遇到类似的需求,所以就想实现这一算法以适用于更多的应用场景. ...
- PID算法原理 一图看懂PID的三个参数
找了好久这一篇算是很容易看懂的了 推荐给大家 写的十分清楚 原文作者DF创客社区virtualwiz LZ以前有个小小的理想,就是让手边的MCU自己"思考"起来,写出真正 ...
- PID控制算法的C语言实现一 PID算法原理
本系列是转载............. 全部的程序有一个共同点:就是我没认真去调pid的参数 在工业应用中PID及其衍生算法是应用最广泛的算法之一,是当之无愧的万能算法,如果能够熟练掌握PID算法的设 ...
- 某科学的PID算法学习笔记
最近,在某社团的要求下,自学了PID算法.学完后,深切地感受到PID算法之强大.PID算法应用广泛,比如加热器.平衡车.无人机等等,是自动控制理论中比较容易理解但十分重要的算法. 下面是博主学习过程中 ...
- 第2章 rsync算法原理和工作流程分析
本文通过示例详细分析rsync算法原理和rsync的工作流程,是对rsync官方技术报告和官方推荐文章的解释. 以下是本文的姊妹篇: 1.rsync(一):基本命令和用法 2.rsync(二):ino ...
- [转]PID控制算法原理
PID控制算法是工业界使用极其广泛的一个负反馈算法,相信这个算法在做系统软件时也有用武之处,这里摘录了知乎上的一篇文章,后面学习更多后自己总结一篇 以下为原文: PID控制应该算是应用非常广泛的控制算 ...
- rsync算法原理和工作流程分析
本文通过示例详细分析rsync算法原理和rsync的工作流程,是对rsync官方技术报告和官方推荐文章的解释.本文不会介绍如何使用rsync命令(见rsync基本用法),而是详细解释它如何实现高效的增 ...
- PID控制算法的C语言实现二 PID算法的离散化
上一节中,我论述了PID算法的基本形式,并对其控制过程的实现有了一个简要的说明,通过上一节的总结,基本已经可以明白PID控制的过程.这一节中先继续上一节内容补充说明一下. 1.说明一下反馈控制的原理, ...
- rsync(三)算法原理和工作流程分析
在开始分析算法原理之前,简单说明下rsync的增量传输功能. 假设待传输文件为A,如果目标路径下没有文件A,则rsync会直接传输文件A,如果目标路径下已存在文件A,则发送端视情况决定是否要传输文件A ...
随机推荐
- LeetCode. 3的幂
题目要求: 给定一个整数,写一个函数来判断它是否是 3 的幂次方. 示例: 输入: 27 输出: true 代码: class Solution { public: bool isPowerOfThr ...
- 1192: 零起点学算法99——The sum problem(C)
一.题目 http://acm.wust.edu.cn/problem.php?id=1192&soj=0 二.分析 要求从序列1,2,3,,,N,中截取一部分使他们的和为M 输入多组数据 输 ...
- 在oracle表中增加、修改、删除字段,表的重命名,字段顺序调整
增加字段语法:alter table tablename add (column datatype [default value][null/not null],….); 说明:alter table ...
- MySQL的explain语句分析
+----+-------------+-------+------------+------+---------------+-----+---------+------+------+------ ...
- IDEA忽略不必要提交的文件
1.在idea中安装插件用来生成和管理 .gitignore 文件,安装成功后重启idea 2.新建.gitignore 文件 3.将不需要提交的文件添加到.gitignore 4.删除缓冲文件 . ...
- Myeclipse debug 调式java 报错,留做后面解决!
FATAL ERROR in native method: JDWP No transports initialized, jvmtiError=AGENT_ERROR_TRANSPORT_INIT( ...
- TCP/IP及http协议 SOAP REST
TCP/IP及http协议: TCP/IP协议主要解决数据如何在网络中传输, 而HTTP是应用层协议,主要解决如何包装数据 SOAP:简单对象访问协议(Simple Object Access Pro ...
- springboot启动流程(四)application配置文件加载过程
所有文章 https://www.cnblogs.com/lay2017/p/11478237.html 触发监听器加载配置文件 在上一篇文章中,我们看到了Environment对象的创建方法.同时也 ...
- springboot启动流程(五)创建ApplicationContext
所有文章 https://www.cnblogs.com/lay2017/p/11478237.html 正文 springboot在启动过程中将会根据当前应用的类型创建对应的ApplicationC ...
- 搭建nginx静态资源站
搭建静态资源站包括以下几部分: root指令与alias指令的区别 使用gzip压缩资源 如何访问指定目录下的全部资源文件 如何限制访问流量 如何自定义log日志 root指令与alias指令的区别 ...