【PID算法详解】

PID算法

  • PID算法介绍
  • 用途
  • pid数学表达式及其含义
    • P算法
    • D算法
    • I算法
  • PID总结
  • 数学公式转换代码设计
  • 实际运用
  • PID代码实现

PID算法介绍

PID控制器是一种广泛应用于工业控制系统的反馈控制器,它通过比例(Proportional)、积分(Integral)、微分(Derivative)三个部分的组合来调节控制量,以实现对系统输出的精确控制。
大白话将:是一种闭环算法,有效果反馈,输入受输出的影响。
在这里插入图片描述
拿电烙铁举例,有的可以通过温度自动调节,有的是恒温,不能调节。
开环控制再举例:
在这里插入图片描述

闭环控制再举例:
在这里插入图片描述

用途

在这里插入图片描述
为什么空调不是PID控制?因为空调假如是制冷,根据阈值控制,到达一定值可能就会送自然风,可问题就出现在这个送自然风上,它是采用了两种模式,而PID只针对一种,也即是,假如速度超过了阈值,就降低速度到预期值,假如速度还未超过预期值,就提高速度,都针对速度一种而言。而空调就相当不同,这点应该理解。

工业项目中的用途:在这里插入图片描述

pid数学表达式及其含义

PID算法:就是“比例(proportional)、积分(integral)、微分(derivative)”
在这里插入图片描述
在使用过程中,不会完整的使用该表达式,会进行拆分,使用需要的。例如,可能只用Kp*ek+Kd(ek-ek-1)也可能只用别的。

Kp:比例增益,是调适参数;
Ki:积分增益,也是调适参数;
Kd:微分增益,也是调适参数;
在这里插入图片描述

P算法

在这里插入图片描述
Kp比例控制考虑当前误差,误差值和一个正值的常数Kp(表示比例)相乘。需要控制的量,比如的温度,有它现在的当前值假如是90,也有我们期望的目标值假如是100。

当两者差距不大时,就让加热器“轻轻地”加热一下。
要是因为某些原因,温度降低了很多,就让加热器“稍稍用力”加热一下。
要是当前温度比目标温度低得多,就让加热器“开足马力”加热,尽快让水温到达目标附近。
这就是P的作用,跟开关控制方法相比,是不是“温文尔雅”了很多。

实际写程序时,就让偏差(目标减去当前)与调节装置的“调节力度”,建立一个一次函数的关系,就可以实现最基本的“比例”控制了~

Kp越大,调节作用越激进,Kp调小会让调节作用更保守。

D算法

在这里插入图片描述
设想有一个弹簧:现在在平衡位置上,拉它一下,然后松手,这时它会震荡起来,因为阻力很小,它可能会震荡很长时间,才会重新停在平衡位置。

请想象一下:要是把上图所示的系统浸没在水里,同样拉它一下 :这种情况下,重新停在平衡位置的时间就短得多。

此时需要一个控制作用,让被控制的物理量的“变化速度”趋于0,即类似于“阻尼”的作用。

因为,当比较接近目标时,P的控制作用就比较小了,越接近目标,P的作用越温柔,有很多内在的或者外部的因素,使控制量发生小范围的摆动。

D的作用就是让物理量的速度趋于0,只要什么时候,这个量具有了速度,D就向相反的方向用力,尽力刹住这个变化。

在这里插入图片描述
两次误差只差有正有负的,但不管正负,都是减弱P的算法的,让其尽恢复平衡。

I算法

在这里插入图片描述
案例:可以玩一玩该网址链接的小项目:无人机PID模拟:
无人机PID模拟调参
在这里插入图片描述

PID总结

在这里插入图片描述

数学公式转换代码设计

在这里插入图片描述

实际运用

在这里插入图片描述

在这里插入图片描述

速度环一般需要加滤波进行过滤,一般采用一阶滤波,为什么加上滤波?因为防止有突发的情况数值突然增大,和之前的一个值对比误差特别大,这时候应该舍弃这个值吗?不应该,因为它也是数
值的一部分,假如第一次数据是1,第二次的数据是10,突变为10,变换就很明显,这时候可以用一阶滤波来进行处理:

float a=0.3;//权重filt_value=a*value + (1-a) * last_value;

a:权重比例
value:现在最新的值
last_value:上次的值
filt_value:滤波后的真实值。
带入上面的数据,新的值10, 10 x 0.3 =3 , 1*0.7 =0.7 3+0.7=3.7 所以滤波后的值也就是3.7而已,比之前的数据滤掉了很多。

如果第一次是2,第二次还是2 ,带入公式,仍然是2。

PID代码实现

Pid.c

#include "Pid.h"/*** @brief  PID参数初始化*	@note 	无* @retval 无* @author:i want to舞动乾坤*/
void PID_init()
{PosionPID.target_val=3600;				PosionPID.output_val=0.0;PosionPID.Error=0.0;PosionPID.LastError=0.0;PosionPID.integral=0.0;PosionPID.Kp = 10;PosionPID.Ki = 0.5;PosionPID.Kd = 0.8;//速度环初始化PosionPID.VKp=+190;PosionPID.VKi=0.95;PosionPID.VspeedSum=0;PosionPID.LastFilt_Vspeed=0;
}/*** @brief  位置PID算法实现* @param  pid:指向PID结构体的指针变量,measure:实际测量值*	@note 	无* @retval 通过PID计算后的输出* @author:i want to舞动乾坤*/
float PID_realize(PID *pid, float measure)
{/*计算目标值与实际值的误差*/pid->Error = pid->target_val - measure;/*积分项*/pid->integral += pid->Error;/*PID算法实现*/pid->output_val = pid->Kp * pid->Error +pid->Ki * pid->integral +pid->Kd *(pid->Error -pid->LastError);/*误差传递*/pid-> LastError = pid->Error;/*返回当前实际值*/return pid->output_val;
}/*** @brief  速度环PID算法实现* @param  pid:指向PID结构体的指针变量,Speed:实际测量的速度*	@note 	无* @retval 通过PID计算后的输出* @author:i want to舞动乾坤*///速度环:
int velocity_PID_value(PID *pid,int Speed)
{float a=0.3;                                           //滤波系数(反映滤波程度)pid->FiltVspeed = a * Speed + (1-a)* (pid->LastFilt_Vspeed); //一阶速度滤波pid->VspeedSum +=  pid->FiltVspeed;                        //速度的累加I_xianfu(pid,3000);                                        //累加限幅pid->LastFilt_Vspeed = pid->FiltVspeed;                    //此次速度记录为“上次速度”pid->VspeedOutPut_Val = pid->VKp * pid->FiltVspeed       //计算输出值+ pid->VKi * pid->VspeedSum ;        return pid->VspeedOutPut_Val;                          //返回输出值
}/*** @brief  对PID的I算法限幅实现* @param  pid:指向PID结构体的指针变量,max:最大限幅值*	@note 	无* @retval 无*/
void I_xianfu(PID *pid ,int max)
{if(pid->VspeedSum >   max)  pid->VspeedSum = max;if(pid->VspeedSum < - max)  pid->VspeedSum =-max;
}

Pid.h

#ifndef __PID_H__
#define __PID_H__
typedef struct PID
{float target_val;   //目标值float Error;          /*第 k 次偏差 */float LastError;     /* Error[-1],第 k-1 次偏差 */float PrevError;    /* Error[-2],第 k-2 次偏差 */float Kp,Ki,Kd;     //比例、积分、微分系数float integral;     //积分值float output_val;   //输出值float FiltVspeed;    //第k次的速度值float LastFilt_Vspeed;//第k-1次的滤波后的速度float VKp;    //速度环的Kpfloat VKi;    //速度环的Kifloat VspeedSum; //速度值的累加float VspeedOutPut_Val;//输出值}PID;struct PID PosionPID;//定义结构体void PID_init();
float PID_realize(PID *pid, float measure);
int velocity_PID_value(PID *pid,int Speed);
void I_xianfu(PID *pid ,int max);#endif

如果看不懂指针成员操作,可以看下面的简易版的
Pid.c

/******************************************************  本程序只供学习使用,未经作者许可,不得用于其它任何用途
******************************************************/
#include "pid.h"extern float Kp,Ki,Kd;   //直立环参数
float err;               //此次误差
float last_err;          //上次误差
float err_sum=0;         //误差累加
float err_difference;    //误差的差值extern float VKp,VKi;    //速度环参数
float filt_velocity;     //滤波后的速度
float last_filt_velocity;//上一次的滤波后的速度
float velocity_sum=0;    //速度的累加//直立环:
int vertical_PID_value(float measure,float calcu)
{err = measure - calcu;             //误差err_sum+=err;                      //误差的累加err_difference = err - last_err;   //误差的差值last_err = err;                    //此次误差记录为“上次误差”return Kp*err + Ki*err_sum + Kd*err_difference;
}//速度环:
int velocity_PID_value(int velocity)
{float a=0.3;                                           //滤波系数(反映滤波程度)filt_velocity = a*velocity + (1-a)*last_filt_velocity; //一阶速度滤波velocity_sum +=  filt_velocity;                        //速度的累加I_xianfu(3000);                                        //累加限幅last_filt_velocity = filt_velocity;                    //此次速度记录为“上次速度”return VKp*filt_velocity + VKi*velocity_sum;
}//I限幅:
void I_xianfu(int max)
{if(velocity_sum>max)  velocity_sum=max;if(velocity_sum<-max) velocity_sum=-max;
}

Pid.h

#ifndef __PID_H
#define __PID_Hint vertical_PID_value(float measure,float calcu); //直立环
int velocity_PID_value(int velocity);              //速度环
void I_xianfu(int max);                            //pwm限幅
#endif

参考大佬文章:
一文搞懂PID控制算法

使用stm32实现电机的PID控制

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/17780.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

快写猪好用吗 #知识分享#笔记#学习方法

快写猪是一个非常好用的论文写作工具&#xff0c;它提供了强大的查重降重功能&#xff0c;帮助用户轻松完成论文写作任务。无论是在学术研究还是日常写作中&#xff0c;快写猪都能提供高效、准确的检测&#xff0c;确保文本的原创性和质量。 首先&#xff0c;快写猪的查重降重功…

c 系统宏有多少

在C语言中&#xff0c;系统宏&#xff08;也称为预定义宏或内置宏&#xff09;的数量并不是固定的&#xff0c;因为它们取决于C标准、编译器以及可能的其他因素。然而&#xff0c;有一些常见的预定义宏是几乎所有C编译器都支持的。 以下是一些常见的C预定义宏&#xff1a; __…

利用预测大模型完成办公室饮水机剩余热水量

背景 在每天上班的时候&#xff0c;很多同事都有喝热水的习惯&#xff0c;但是饮水机内的热水量总是比较少的&#xff0c;如何避免等待&#xff0c;高效的接到热水是我接下来要做的事情的动机。 理论基础 在大量真实数据的情况下&#xff0c;可以分析出用水紧张的时间段和用水…

【css3】01-css3新特性样式篇

目录 1 背景 1.1 设置背景图片的定位 1.2 背景裁切-规定背景的绘制区域 1.3 设置背景图片尺寸 2 边框 2.1 盒子阴影box-shadow 2.2 边框图片border-image 3 文本 -文字阴影text-shadow 1 背景 1.1 设置背景图片的定位 background-origin&#xff1a;规定背景图片的定位…

科技守护,河流水文监测保障水资源安全!

中小河流是城乡水资源的补给&#xff0c;又是不可或缺的排放渠道&#xff0c;维系着城乡水资源的平衡与生态的健康。然而&#xff0c;随着工业化、城市化的快速推进&#xff0c;河流生态环境面临着越来越大的压力。为了有效保护和合理利用河流资源&#xff0c;河流水文监测成为…

2024年新算法-红嘴蓝鹊优化器(RBMO)优化BP神经网络回归预测

2024年新算法-红嘴蓝鹊优化器(RBMO)优化BP神经网络回归预测 亮点&#xff1a; 输出多个评价指标&#xff1a;R2&#xff0c;RMSE&#xff0c;MSE&#xff0c;MAPE和MAE 满足需求&#xff0c;分开运行和对比的都有对应的主函数&#xff1a;main_BP, main_RBMO, main_BPvsBP_R…

亡羊补牢,一文讲清各种场景下GIT如何回退

系列文章目录 手把手教你安装Git&#xff0c;萌新迈向专业的必备一步 GIT命令只会抄却不理解&#xff1f;看完原理才能事半功倍&#xff01; 常用GIT命令详解&#xff0c;手把手让你登堂入室 GIT实战篇&#xff0c;教你如何使用GIT可视化工具 GIT使用需知&#xff0c;哪些操作…

区块链的运行原理与演示

目录 前言 具体演示 1、在浏览器中输入区块链演示网址&#xff1a; 2、创建新区块 3、篡改区块信息使其无效 4、新增P2P 网络节点。 5、节点连接。 6、区块信息同步 总结 前言 区块链系统是由一系列分布在全球各地的分布式节点组成的。这些节点互不隶属&#xff0c;通过…

Mesa GL Dispatch分发分析与理解

Mesa GL Dispatch分发分析与理解 引言 这篇博客的核心是从OpenGL应用程序的典型api入手&#xff0c;分析gl api 调用到用户态驱动后端的过程&#xff0c;进而总结出一个典型的调用栈。理解了这个典型调用栈&#xff0c;对后续任何一个API的调用过程分析&#xff0c;都是a piec…

文本匹配.grep与Select-String用法对比

Linux Shell与PowerShell上匹配字符串 grep与Select-String用法对比 - 文章信息 - Author: 李俊才 (jcLee95) Visit me at CSDN: https://jclee95.blog.csdn.netMy WebSite&#xff1a;http://thispage.tech/Email: 291148484163.com. Shenzhen ChinaAddress of this article…

家居厨房安全无小事:可燃气体报警器探头校准检测重要性解析

家居厨房作为日常生活中烹饪美食的重要场所&#xff0c;其安全问题不容忽视。 近年来&#xff0c;随着家庭用气设备的普及&#xff0c;煤气泄露事件时有发生&#xff0c;给人们的生命财产安全带来了严重威胁。 因此&#xff0c;安装可燃气体报警器探头&#xff0c;及时检测并…

Python Orange3库:数据挖掘与机器学习的终极利器

更多Python学习内容&#xff1a;ipengtao.com Orange3是一个开源的数据挖掘和机器学习库&#xff0c;提供了丰富的工具和算法来处理和分析数据。Orange3的图形用户界面使得非编程用户也能轻松进行数据分析&#xff0c;而其Python API则为编程用户提供了强大的灵活性。本文将详细…

如何在线转换图片的格式?一键修改图片格式的方法

图片是日常生活和工作中的一种常用的内容展示类型&#xff0c;在使用图片的时候不同用途需要使用的图片格式也是不同的&#xff0c;比如我们手中有一张jpg格式图片&#xff0c;但是平台上传要求格式是png&#xff0c;那么怎样才能将jpg转png格式呢&#xff1f;下面将教大家图片…

模拟量4~20mA电流传感器接线方式

一、模拟量4~20mA电流传感器接线方式 无源双线制是常见的电流型传感器接线方式&#xff0c;它具有简单、经济的特点。其接线方式如下&#xff1a; 传感器的“”接到数据采集器的电源“”上&#xff0c; 传感器的“-”端子连接到数据采集器的“AI”端子上&#xff0c; 数据采集器…

无人机+EasyDSS互联网视频平台:构建秸秆焚烧监控的“天眼”系统

一、方案背景 在每年的夏收时节&#xff0c;秸秆禁烧成为各地政府面临的一项重要任务。随着夏收季节的结束&#xff0c;大量农作物秸秆的处理问题逐渐凸显。一方面农作物种植面积辽阔&#xff0c;禁烧区域面积较大&#xff0c;监管巡逻人员的数量有限&#xff0c;无法全面顾及…

使用 ASM 修改字段类型,解决闪退问题

问题 我的问题是什么&#xff1f; 在桥接类 UnityBridgeActivity 中处理不同 unity 版本调用 mUnityPlayer.destroy(); 闪退问题。 闪退日志如&#xff1a; 闪退日志说在 UnityBridgeActivity中找不到类型为 UnityPlayer 的属性 mUnityPlayer。 我们知道&#xff0c;Android…

【鸟叔的Linux私房菜】2-主机规划与磁盘分区

文章目录 2.1 Linux与硬件的搭配各硬件设备在Linux的文件名使用虚拟机学习 2.2 磁盘分区磁盘连接方式和设备文件名的关系MBR(MS-DOS)与GPT磁盘分区表MBR(MS-DOS)GPT磁盘分区表 启动流程的BIOS与UEFI启动检测程序BIOS搭配MBR/GPT的启动流程UEFI BIOS搭配 GPT启动的流程 Linux安装…

RGB 平均值统计

任务&#xff1a;有一一对应的图片多组如下&#xff0c;希望统计灰色部分原有grb平均值&#xff0c;彩色部分rgb平均值。 方法&#xff1a;由下图对各个像素分析&#xff0c;分为3类&#xff0c;并记录坐标&#xff0c;根据坐标统计上图的rgb平均值&#xff0c;结果放在一张Exc…

linux开发之设备树基本语法二

设备树特殊节点,对节点定义别名,chosen节点用来uboot给内核传参 上面的mmc0就是sdmmc0节点的别名 device_type属性 只对cpu节点和memory节点进行描述 自定义属性 这部分自定义,比如定义管脚标号,初始数值等 为什么我们可以在设备树上自己定义属性呢?设备树文件描述的是硬…

JD3-40/23漏电继电器 AC220V 50-500mA 0.1s 导轨安装

系列型号&#xff1a; JD3-40/13漏电继电器JD3-40/23漏电继电器JD3-40/33漏电继电器JD3-40/43漏电继电器 JD3-70/13漏电继电器JD3-70/23漏电继电器JD3-70/33漏电继电器JD3-70/43漏电继电器 JD3-100/23漏电继电器JD3-100/43漏电继电器JD3-100/33漏电继电器JD3-100/13漏电继电…