【PID算法详解】

news2024/9/23 3:19:51

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;    //速度环的Kp
	float VKi;    //速度环的Ki
	float 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_H

int 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.coloradmin.cn/o/1706808.html

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

相关文章

LeetCode199二叉树的右视图

题目描述 给定一个二叉树的 根节点 root&#xff0c;想象自己站在它的右侧&#xff0c;按照从顶部到底部的顺序&#xff0c;返回从右侧所能看到的节点值。 解析 这一题的关键其实就是找到怎么去得到当前是哪一层级&#xff0c;可以利用队列对二叉树进行层次遍历&#xff0c;但…

4款让人骄傲的国产软件,功能过于强大,却被误认为是外国佬研发

说到国产软件&#xff0c;许多人可能会有“流氓软件、弹屏广告多、隐藏消费套路”等负面印象。 这种偏见导致一些功能强大、用户友好的国产软件被误认为是外国人开发的。 1、格式工厂 格式工厂是一个很实用的国产格式转换工具&#xff0c;它完全免费且没有广告&#xff0c;不…

Dropzone 4 for Mac:一拖即达,文件处理更高效!

在繁忙的工作中&#xff0c;你是否曾因频繁切换应用程序和文件夹而烦恼&#xff1f;Dropzone 4 for Mac&#xff0c;这款强大的文件拖拽操作工具&#xff0c;将彻底改变你的工作方式&#xff01; 只需简单地将文件、文本或图片拖放到Dropzone图标上&#xff0c;即可快速执行各种…

一文搞定jdk8升级到jdk11

一、背景 为什么要升级JDK11 性能 JDK11的G1的GC性能高很多&#xff0c;对比JDK8无论是性能还是内存占比都有很大的提升&#xff0c;业内各项数据指标也都表明JDK11的G1在应对突发流量的下的效果惊人&#xff1b; 版本兼容 Spring Boot 2.7.x及以后的版本将不再支持Java 8作为…

Python开发 —— 对象type、object、class

1. "Python中一切皆为对象"的理解 在Python中&#xff0c;一切皆为对象的意思是指&#xff1a;无论是数字、字符串、函数、类、模块等任何数据类型&#xff0c;都可以被看做是一个对象。每个对象都具有自己的属性和方法&#xff0c;可以被操作和调用。 例如&#xff…

IP地址SSL证书应用场景以及如何申请?

一&#xff1a;IP地址SSL证书主要应用于以下几种场景&#xff1a; 1.API接口保护&#xff1a;许多云服务和企业内部系统使用IP地址直接作为服务的访问点&#xff0c;特别是在API接口的调用中。IP地址SSL证书可以为这些API接口提供必要的安全加密&#xff0c;确保数据在传输过程…

DreamPose: Fashion Image-to-Video Synthesis via Stable Diffusion

UW&UCB&Google&NVIDIA ICCV23https://github.com/johannakarras/DreamPose?tabreadme-ov-file 问题引入 输入参考图片 x 0 x_0 x0​和pose序列 { p 1 , ⋯ , p N } \{p_1,\cdots,p_N\} {p1​,⋯,pN​}&#xff0c;输出对应视频 { x 1 ′ , ⋯ , x N ′ } \{x_1,…

停车场变综合楼,结构分析助力低碳设计

PLAXIS 和 RAM 助力确定更有效的结构设计并大幅降低施工成本 总部和周边区域 桑坦德银行位于英国的新总部将现有的四个英国办事处合并到米尔顿凯恩斯的一个中心枢纽&#xff0c;位于伦敦以北 50 英里。 Unity Place 将作为桑坦德银行约 5,000 名员工的办公场所。该项目总投资 …

AIGC笔记--基于PEFT库使用LoRA

1--相关讲解 LORA: LOW-RANK ADAPTATION OF LARGE LANGUAGE MODELS LoRA 在 Stable Diffusion 中的三种应用&#xff1a;原理讲解与代码示例 PEFT-LoRA 2--基本原理 固定原始层&#xff0c;通过添加和训练两个低秩矩阵&#xff0c;达到微调模型的效果&#xff1b; 3--简单代…

web自动化-下拉框操作/键鼠操作/文件上传

在我们做UI自动化测试的时候&#xff0c;会有一些元素需要特殊操作&#xff0c;比如下拉框操作/键鼠操作/文件上传。 下拉框操作 在我们很多页面里有下拉框的选择&#xff0c;这种元素怎么定位呢&#xff1f;下拉框分为两种类型&#xff1a;我们分别针对这两种元素进行定位和…

答应我!养猫就一定要入手的七款好物!养猫真的会开心

养猫是一件让人愉悦的事情&#xff0c;猫咪的陪伴能让我们感到温暖和满足。然而&#xff0c;想要让猫咪健康快乐地成长&#xff0c;除了关心它们的饮食和健康&#xff0c;还需要为它们准备一些必要的生活用品。今天&#xff0c;我将为大家推荐几个养猫必备的好物&#xff0c;让…

黑马头条day6总结

1、wemedian错误 一开始没加EnableFeignClients(basePackages "com.heima.apis")导致获取ischeduleClient错误&#xff0c;找不到bean。 我看教程的代码中没有&#xff0c;【ComponentScan({"com.heima.apis","com.heima.wemedia"})】&#x…

11款必备IP地址管理软件,你都用过吗?

1、LightMesh IPAM 产品描述&#xff1a;LightMesh IPAM 是一款功能强大的工具&#xff0c;可简化和自动化互联网协议网络的管理。它提供可扩展性、子网规划器、即时云发现、IP 和网络管理以及 IP 规划和可视化&#xff0c;以帮助您优化效率、可见性和安全性。 特征&#xff1…

强化学习——学习笔记

一、什么是强化学习&#xff1f; 强化学习 (Reinforcement Learning, RL) 是一种通过与环境交互来学习决策策略的机器学习方法。它的核心思想是让智能体 (Agent) 在执行动作 (Action)、观察环境 (Environment) 反馈的状态 (State) 和奖励 (Reward) 的过程中&#xff0c;学习到…

C++音视频开发面试题集锦

老规矩&#xff0c;先上面试题目&#xff1a; 1、iOS 中系统 API 提供了哪些视频编码的方式&#xff1f;2、VideoToolbox 视频帧解码失败以后应该如何重试&#xff1f;3、如何使用 PSNR 对视频转码质量进行评估&#xff1f;4、什么是 VAO&#xff0c;什么是 VBO&#xff0c;它…

【图书推荐】《机器学习实战(视频教学版)》

本书用处 快速入门Python机器学习基础算法。 最后3个综合实战项目&#xff08;包括新闻内容分类实战、泰坦尼克号获救预测实战、中药数据分析项目实战&#xff09;可以作为研究可以的素材。 内容简介 本书基于Python语言详细讲解机器学习算法及其应用&#xff0c;用于读者快…

Java 五种内部类演示及底层原理详解

内部类 什么是内部类 在A类的内部定义B类&#xff0c;B类就被称为内部类 发动机类单独存在没有意义 发动机为独立个体 可以在外部其他类里创建内部类的对象去调用方法 类的五大成员 属性 方法 构造方法 代码块 内部类 内部类的访问特点 内部类可以直接访问外部类的成员&a…

Java处理CSV文件示例

Java处理CSV文件示例 1. 导入依赖 <dependency><groupId>org.apache.commons</groupId><artifactId>commons-csv</artifactId><version>1.10.0</version></dependency>文件示例 下面是示例文件文件数据 vscode和idea都有解析…

第二证券股市资讯:连续3天20%涨停!A股这一赛道,牛股批量出现!

今日&#xff0c;A股小幅轰动调整&#xff0c;上证指数下试3100点支撑。 两市成交7453亿元&#xff0c;创近4个月来新低&#xff0c;超4000只个股下跌。盘面上&#xff0c;电力、芯片、煤炭、石油等板块涨幅居前&#xff0c;铜缆高速衔接、房地产、工程机械、网络游戏等板块跌幅…

word-主控文档、文档拆分及标书编写技巧建议

一、主控文档 视图-大纲视图-显示文档-插入子文档 子文档一旦更新&#xff0c;主文档也会更新。更新主文档&#xff0c;子文档也会更新 需要注意&#xff0c;不可修改子文档名字 二、上交文件 显示文档-折叠子文档-只显示一级-取消链接-关闭大纲视图-保存 三、文档拆分 根…