【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;    //速度环的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控制

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

LeetCode450删除二叉搜索树中的节点

题目描述 给定一个二叉搜索树的根节点 root 和一个值 key&#xff0c;删除二叉搜索树中的 key 对应的节点&#xff0c;并保证二叉搜索树的性质不变。返回二叉搜索树&#xff08;有可能被更新&#xff09;的根节点的引用。一般来说&#xff0c;删除节点可分为两个步骤&#xff1…

合约的值类型

基本数据类型&#xff1a;整数、枚举、布尔&#xff08;类似java的数据类型&#xff09;Address、Contract&#xff08;这两种是solidity特有的数据类型&#xff09;Fixed byte array&#xff08;定长字节数组&#xff09; Integer(int/uint) int/uint 以8位字节递增&#xf…

代码随想录算法训练营Day2|977.有序数组的平方、59.螺旋矩阵||、 209.长度最小的子数组

977.有序数组的平方 这道题给出的原数组有两个特点&#xff1a; 1、由小到大 2、有负数有正数 因此&#xff0c;这个数组平方后的数应该是从两头向中间的0减小的&#xff0c;但是两头的大小需要我们用两个指针便历之后去判断大小。在遍历的同时left指针向右走&#xff0c;righ…

Spring使用的设计模式

Spring 框架是一个广泛使用的 Java 框架&#xff0c;它内部使用了多种设计模式来简化开发过程、提高代码的可维护性和扩展性。 以下是一些在 Spring 框架中常见的设计模式&#xff0c;以及用代码示例来解释它们&#xff1a; 一、工厂模式&#xff08;Factory Pattern&#xff…

DIYGW UniApp可视化开发工具:前端开发人员的新宠

在前端开发的领域中&#xff0c;API接口的测试与调试一直是开发人员面临的挑战之一。传统的测试工具虽然能够完成基本的测试任务&#xff0c;但在效率、易用性和直观性方面仍有提升的空间。随着技术的发展&#xff0c;DIYGW UniApp可视化工具应运而生&#xff0c;为开发人员提供…

智慧园区:打造未来城市的新模式

随着城市化进程的加速和科技创新的推动&#xff0c;城市面临着诸多挑战和机遇。如何提升城市的竞争力和可持续性&#xff0c;是一个亟待解决的问题。在这个背景下&#xff0c;智慧园区作为一种新型的城市发展模式&#xff0c;引起了越来越多的关注和探索。 什么是智慧园区&…

gitlab将本地文件项目上传至gitlab服务

打开gitlab网页界面&#xff0c;登陆管理员账号 &#xff08;测试服务器安装的gitlab&#xff0c;浏览器输入ip或配置的gitlab地址&#xff09; 创建新项目 使用gitlab创建项目 创建一个新项目&#xff08;忽略分组&#xff09; &#xff08;忽略分组&#xff09; 在创建工…

CSS文本粒子动画特效之爱心粒子文字特效-Canvas

1. 效果图 2.完整代码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><style>body,html {margin: 0;paddin…

一篇文章带你快速搞定Kafka术语no.2

在Kafka的世界中有很多概念和术语是需要你提前理解并熟练掌握的&#xff0c;这对于后面你深入学习Kafka各种功能和特性将大有裨益。下面我来盘点一下Kafka的各种术语。 在专栏的第一期我说过Kafka属于分布式的消息引擎系统&#xff0c;它的主要功能是提供一套完备的消息发布与…

全球排名第一的免费开源ERP:Odoo与微信集成的应用场景解析

概述 本文介绍了世界排名第一的开源免费企业应用软件Odoo ERP和企业微信、个人微信的各种对接功能。包括微信登录的对接、微信公众号的对接、微信消息的对接、微信支付的对接、微信打卡的对接、微信小程序的对接。 微信登录的对接 Odoo的登录&#xff0c;除了标准的用户名/密码…

律所电子签章有效吗,怎么操作?

电子签章在很多国家和地区是合法有效的&#xff0c;但其有效性、使用条件和操作流程可能依据具体的法律法规而有所不同。在中国&#xff0c;随着《中华人民共和国电子签名法》的实施&#xff0c;电子签章在满足一定条件下是具有法律效力的。电子签章可以提高合同签订的效率&…

QT 自定义协议TCP传输文件

后面附带实例的下载地址 一、将文件看做是由:文件头+文件内容组成,其中文件头包含文件的一些信息:文件名称、文件大小等。 二、文件头单独发送,文件内容切块发送。 三、每次发送信息格式:发送内容大小、发送内容类型(文件头或是文件块内容)、文件块内容。 四、效果展…

【香橙派 AIpro】OrangePi AIpro :教育、机器人、无人机领域的超级AI大脑,华为昇腾处理器驱动的AI开发板新标杆

【OrangePi AIpro&#xff1a;教育、机器人、无人机领域的超级AI大脑&#xff0c;华为昇腾处理器驱动的AI开发板新标杆】 文章目录 一、开箱与初印象1. 初印象2. 上手开机3. 安装和运行 TightVNC 远程桌面3.1. 安装 TightVNC 服务器3.2. 启动 VNC 服务器3.3. 在 Windows 上使用…

clickhouse 特性——clickhouse 基础篇(一)

文章目录 列式存储向量化查询执行引擎数据压缩使用磁盘支持SQL实时数据更新 列式存储 列式存储的目的有两个&#xff0c;一是缩小数据扫描范围&#xff0c;二是减少数据传输大小&#xff0c; 因此列存储和数据压缩通常是伴生的&#xff0c;列存储是数据压缩的前提。列存储的好…

MySQL测试数据

012熟悉测试数据 查看表结构&#xff1a;desc或describe&#xff0c;语法格式&#xff1a;desc或describe 表名 desc dept;查询部门的所有信息 &#xff1a; select * from dept;013查一个字段 语法格式&#xff1a;select 字段名 from 表名;&#xff08;大小写都可以&…

SpringBoot——基于Spring Task实现定时任务

目录 定时任务 项目总结 新建一个SpringBoot项目 pom.xml无需引入依赖 SpringTaskDemo SpringbootSpringtaskApplication启动类 定时任务 在日常的项目开发中&#xff0c;往往会涉及一些需要做到定时执行的代码&#xff0c;例如自动将超过24小时的未付款的订单改为取消状…

finetuning大模型准备(基于Mac环境)

为finetuning进行的热身准备&#xff0c;涉及周边的软件工具&#xff0c;方法。 问题1&#xff1a;finetuning过程较长&#xff0c;采用系统自带命令行没有后台&#xff0c;前台被杀后&#xff0c;容易造成训练失败。 解决方法&#xff1a; tmux可以开启后台训练 问题2&…

地下停车场FM信号覆盖系统技术原理用与应用

随着我国城市化水平的快速推进与房地产的快速发展&#xff0c;城市停车场称为每栋建筑物的硬性配套建筑&#xff0c;尤其是商业综合体、医院、政府机关、机场、高铁站等场所出现了超大规模停车场&#xff0c;停放车辆可达数千辆&#xff0c;停车场的智能化与信息化水平也越来越…

echarts-事件

echarts部分事件 添加点击事件 添加点击事件&#xff1a; let options {tooltip: {},xAxis: {type: "category",data: ["d1", "d2", "d3", "d4"],},yAxis: {},series: [{type: "line",data: d1,},{type: &qu…

推送镜像到私有harbor仓库

本地已制作镜像&#xff1a;tomcat-8.5.100-centos7.9:1.0。 本地已经搭建私有仓库&#xff1a;harbor.igmwx.com。 现在需要把镜像 tomcat-8.5.100-centos7.9:1.0 推送到harbor。 &#xff08;1&#xff09;查看本地镜像&#xff1a;sudo docker images zhangzkzhangzk:~/d…