PID控制算法介绍及使用举例
PID 控制算法是一种常用的反馈控制算法,用于控制系统的稳定性和精度。PID 分别代表比例(Proportional)、积分(Integral)和微分(Derivative),通过组合这三个部分来调节控制输出,以使系统的实际输出值尽可能接近预期的参考值。
算法介绍
PID(比例-积分-微分)控制算法是一种广泛使用的控制算法,用于调节系统的输出以匹配所需的参考输入。PID 控制器基于三个基本组件来计算其控制输出:比例(Proportional)、积分(Integral)和微分(Derivative)。
- 比例(P)控制:
- 比例控制是最简单的控制形式。控制器的输出是输入误差的一个比例。误差是参考输入与实际系统输出之间的差异。
- 比例控制可以快速响应误差,但它不能消除稳态误差(即系统稳定后仍然存在的误差)。
- 如果比例系数设置得太大,系统可能会变得不稳定,出现振荡。
- 积分(I)控制:
- 积分控制考虑了过去的误差。它通过对误差进行积分来消除稳态误差。
- 积分控制有助于减小系统稳定后的误差,但也可能导致系统响应变慢,并可能增加超调(即系统输出超过参考输入的情况)。
- 如果积分系数设置得太大,系统可能变得对扰动非常敏感,甚至可能产生积分饱和现象(即积分项累积到过大,导致系统响应异常)。
- 微分(D)控制:
- 微分控制基于误差的变化率来预测未来的误差,并据此调整控制输出。
- 微分控制有助于加快系统的响应速度,减少超调,并增加系统的稳定性。
- 然而,微分控制对噪声非常敏感,因为噪声通常会导致误差的突然变化,这可能被误认为是误差的变化率。
PID 的基本公式:
Output = K_p * Error + K_i * Integral(Error) + K_d * Derivative(Error)
其中,Error 表示期望值与实际值之间的偏差,(K_p)、(K_i) 和 (K_d) 分别表示比例、积分和微分部分的系数。如何使用 PID 控制算法:
-
确定系统模型和参数 在应用 PID 控制算法前,需要确定控制对象的数学模型和相关参数,例如比例系数 (K_p)、积分时间 (T_i)、微分时间 (T_d) 等。
-
实现 PID 控制器 在代码中实现 PID 控制器,通常需要记录上一次的误差值以及积分值,以便计算出下一次的控制输出。
PID 控制器的调整
调整 PID 控制器的参数(即 K_p
、K_i
和 K_d
)是 PID 控制中的关键任务。这通常涉及到一些试验和误差调整,或者使用更先进的调优方法。
对不同工况和“场景”下往往需要设置不同的PID形式,不同的PID参数达到预期控制效果,其实就是需要人工经验设定规则来适应不同工况,所以不能算是自动的控制;相信用过PID的都知道一套口诀,在实际调参依赖口诀调参,然后调出一个理想的控制曲线,调参过程依赖人工。
也可以借助野火的 PID调试助手工具来调试pid的参数。
代码示例
class PIDController {
public:double compute(double setpoint, double measurement) {double error = setpoint - measurement;integral += error * dt;derivative = (error - prevError) / dt;output = Kp * error + Ki * integral + Kd * derivative;prevError = error;return output;}private:double Kp = 1.0;double Ki = 0.1;double Kd = 0.01;double integral = 0.0;double derivative = 0.0;double prevError = 0.0;double output = 0.0;double dt = 0.1; // 采样时间
};
-
调试和调整参数 调试 PID 控制器需要不断调整参数,观察实际输出值与期望值之间的偏差,逐步优化参数,以实现系统的稳定控制。
-
实时应用 在实际控制系统中,将计算得到的 PID 控制器的输出值应用到相应的执行机构或系统中,以实现期望的控制效果。
以下是一个简单的 C++ 示例,演示如何实现一个基本的 PID 控制器,并在一个简单的模拟系统中应用该控制器。这个例子中,模拟一个以恒定速度运动的小车,通过 PID 控制器调节小车的速度,使其尽快达到期望速度。注意,这只是一个简单的演示,实际系统中可能需要更复杂的控制逻辑和参数调整。
#include <iostream>class PIDController {
public:PIDController(double kp, double ki, double kd, double dt) : Kp(kp), Ki(ki), Kd(kd), dt(dt) {}double compute(double setpoint, double measurement) {double error = setpoint - measurement;integral += error * dt;derivative = (error - prevError) / dt;output = Kp * error + Ki * integral + Kd * derivative;prevError = error;return output;}private:double Kp;double Ki;double Kd;double dt;double integral = 0.0;double derivative = 0.0;double prevError = 0.0;double output = 0.0;
};class Car {
public:void setSpeed(double speed) {currentSpeed = speed;}void update() {// 模拟小车运动,这里假设小车以固定加速度加速到目标速度currentSpeed += acceleration;std::cout << "Current speed: " << currentSpeed << std::endl;}double getSpeed() const {return currentSpeed;}private:double currentSpeed = 0.0;double acceleration = 0.1;
};int main() {PIDController pid(0.5, 0.01, 0.1, 0.1); // 设置 PID 控制器的参数Car car;double targetSpeed = 10.0; // 设置目标速度for (int i = 0; i < 100; ++i) {double speedError = targetSpeed - car.getSpeed();double controlOutput = pid.compute(targetSpeed, car.getSpeed());std::cout << "speedError: " << speedError << std::endl;std::cout << "controlOutput: " << controlOutput << std::endl;car.setSpeed(9+i/50.0); // 应用控制输出调节小车速度car.update();}return 0;
}
在这个简单的示例中,创建了一个 PIDController 类来模拟 PID 控制器的行为,然后创建了一个 Car 类来模拟一个运动的小车。在主函数中,设置 PID 控制器的参数,并循环调用 PID 控制器来调节小车的速度,直到达到目标速度为止。
注意,实际的 PID 控制器需要根据具体的控制对象和系统需求进行调整和优化。
c语言实现
#include "pid.h"
/***************************************************************批量复位PID函数* @param[in] * @param[out] * @return ***************************************************************/
void pidRest(PidObject **pid,const uint8_t len)
{uint8_t i;for(i=0;i<len;i++){pid[i]->integ = 0;pid[i]->prevError = 0;pid[i]->out = 0;pid[i]->offset = 0;}
}/*************************************************************** Update the PID parameters.** @param[in] pid A pointer to the pid object.* @param[in] measured The measured value* @param[in] updateError Set to TRUE if error should be calculated.* Set to False if pidSetError() has been used.* @return PID algorithm output***************************************************************/
void pidUpdate(PidObject* pid,const float dt)
{float error;float deriv;error = pid->desired - pid->measured + pid->offset; //当前角度与实际角度的误差pid->integ += error * dt; //误差积分累加值// pid->integ = LIMIT(pid->integ,pid->IntegLimitLow,pid->IntegLimitHigh); //进行积分限幅deriv = (error - pid->prevError)/dt; //前后两次误差做微分pid->out = pid->kp * error + pid->ki * pid->integ + pid->kd * deriv;//PID输出//pid->out = LIMIT(pid->out,pid->OutLimitLow,pid->OutLimitHigh); //输出限幅pid->prevError = error; //更新上次的误差}/*************************************************************** CascadePID* @param[in] * @param[out] * @return ***************************************************************/
void CascadePID(PidObject* pidRate,PidObject* pidAngE,const float dt) //串级PID
{ pidUpdate(pidAngE,dt); //先计算外环pidRate->desired = pidAngE->out;pidUpdate(pidRate,dt); //再计算内环
}
应用示例
#include "pid.h"
#include <stdio.h>int main()
{printf("hello pid test \n");float target_water_level = 100.0; // 目标水位10Lfloat feedback_water_level = 0.0; // 初始水位0LPidObject pidRate;PidObject *pPidObject[]={&pidRate};pidRest(pPidObject,1);pidRate.kp = 0.1f; // 比例系数pidRate.ki = 0.01f; // 积分系数pidRate.kd = 0.05f; // 微分系数float dt = 0.003;// 3ms 采样时间pidRate.measured = 0;pidRate.desired = 100.00; //控制期望值 10L// 模拟控制循环for (int i = 0; i < 100; i++) { // 模拟水位反馈pidUpdate(&pidRate,dt); //pid处理feedback_water_level = 91+i/50.00; // 模拟每次循环水位波动 (传感器水位采集反馈值)pidRate.measured = feedback_water_level;//pidRate.desired = pidRate.out;// 输出当前水位和阀门开度补偿值printf("Feedback Water Level: %.2fL, Valve Openness: %.2f\n", feedback_water_level, pidRate.out);}return 0;
}
为什么pwm可以调速
pwm占空比就是一个脉冲周期内有效电平在整个周期所占的比例。
通过调节PWM的占空比就能调节IO口上电压的持续性变化,因此也能够控制外设的功率进行持续性变化,也就能控制直流电机的转速快慢。
一种情况,对于电阻,直流电机来说,有占空比虽然从微观来说是波,但从宏观来说,就相当于将输入电压打个折扣再输出,输入5伏,占空比是50%,那么输出就是2.5伏,一般来说,直流电机的转速是和其输入电压成正比的。
还有种情况,就是通过连续改变PWM的占空比,将直流电切成大小不一,有规律的波形,宏观上形成不同频率的正弦波,这就叫斩波。通过斩波可以产生任意频率的交流电。
其他资源
PID算法详解及实例分析_pid控制原理详解及实例说明-CSDN博客
一文搞懂PID控制算法_pid算法-CSDN博客
什么是PID控制?
PWM原理 PWM频率与占空比详解-CSDN博客
电机控制进阶——PID速度控制 - 知乎
通俗易懂!讲解PID! - 知乎
编码器计数原理与电机测速原理——多图解析 - 知乎
电机PID控制补充篇-野火上位机串口协议介绍 - 知乎
电机控制进阶——PID速度控制
野火串口调试助手PID功能(文末有工程链接)_野火多功能调试助手-CSDN博客
相关文章:
PID控制算法介绍及使用举例
PID 控制算法是一种常用的反馈控制算法,用于控制系统的稳定性和精度。PID 分别代表比例(Proportional)、积分(Integral)和微分(Derivative),通过组合这三个部分来调节控制输出&#…...
因子区间[牛客周赛44]
思路分析: 我们可以发现125是因子个数的极限了,所以我们可以用二维数组来维护第几个数有几个因子,然后用前缀和算出来每个区间合法个数,通过一个排列和从num里面选2个 ,c num 2 来计算即可 #include<iostream> #include<cstring> #include<string> #include…...
代码随想录算法训练营第四十四天 | 01背包问题理论基础、01背包问题滚动数组、416. 分割等和子集
背包问题其实有很多种,01背包是最基础也是最经典的,软工计科学生一定要掌握的。 01背包问题 代码随想录 视频讲解:带你学透0-1背包问题!| 关于背包问题,你不清楚的地方,这里都讲了!| 动态规划经…...
【PingPong_注册安全分析报告】
前言 由于网站注册入口容易被黑客攻击,存在如下安全问题: 暴力破解密码,造成用户信息泄露短信盗刷的安全问题,影响业务及导致用户投诉带来经济损失,尤其是后付费客户,风险巨大,造成亏损无底洞 …...
车辆路径规划之Dubins曲线与RS曲线简述
描述 Dubins和RS曲线都是路径规划的经典算法,其中车辆运动学利用RS曲线居多,因此简单介绍Dubins并引出RS曲线。 花了点时间看了二者的论文,并阅读了一个开源的代码。 Dubins曲线 Dubins曲线是在满足曲率约束和规定的始端和末端的切线&#…...
PostgreSQL 和Oracle锁机制对比
PostgreSQL 和Oracle锁机制对比 PostgreSQL 和 Oracle 都是业界广泛使用的关系型数据库管理系统,它们在锁机制方面都有独到的设计来控制并发访问,确保数据的一致性和完整性。下面我们详细比较一下这两个数据库系统的锁机制。 1. 锁类型 PostgreSQL P…...
6月05日,每日信息差
第一、特斯拉在碳博会上展示了其全品类的可持续能源解决方案,包括首次在国内展出的超大型电化学商用储能系统 Megapack 和家庭储能系统 Powerwall。此外,特斯拉还展示了电动汽车三电系统的解构和电池回收技术产品 第二、2024 年第一季度,全球…...
MongoDB~俩大特点管道聚合和数据压缩(snappy)
场景 在MySQL中,通常会涉及多个表的一些操作,MongoDB也类似,有时需要将多个文档甚至是多个集合汇总到一起计算分析(比如求和、取最大值)并返回计算后的结果,这个过程被称为 聚合操作 。 根据官方文档介绍&…...
HTML+CSS+JS 动态登录表单
效果演示 实现了一个登录表单的背景动画效果,包括一个渐变背景、一个输入框和一个登录按钮。背景动画由多个不同大小和颜色的正方形组成,它们在页面上以不同的速度和方向移动。当用户成功登录后,标题会向上移动,表单会消失。 Code <!DOCTYPE html> <html lang=&q…...
统一返回响应
前言 我们为什么要设置统一返回响应 提高代码的可维护性:通过统一返回请求的格式,可以使代码更加清晰和易于维护,减少重复的代码,提高代码质量。 便于调试和测试:统一的返回格式使得在调试和测试时更为简单ÿ…...
大数据学习问题记录
问题记录 node1突然无法连接finalshell node1突然无法连接finalshell 今天我打开虚拟机和finalshell的时候,发现我的node1连接不上finalshell,但是node2、node3依旧可以链接,我在网上找了很多方法,但是是关于全部虚拟机连接不上finalshell&a…...
第N4周:中文文本分类
🍨 本文为🔗365天深度学习训练营 中的学习记录博客🍖 原作者:K同学啊 一、预备知识 中文文本分类和英文文本分类都是文本分类,为什么要单独拎出来个中文文本分类呢? 在自然语言处理(NLP&#x…...
【kubernetes】探索k8s集群的pod控制器详解(Deployment、StatefulSet、DaemonSet、Job、CronJob)
目录 一、Pod控制器及其功用 二、pod控制器有多种类型 2.1ReplicaSet 2.1.1ReplicaSet主要三个组件组成 2.2Deployment 2.3DaemonSet 2.4StatefulSet 2.5Job 2.6Cronjob 三、Pod与控制器之间的关系 3.1Deployment 3.2SatefulSet 3.2.1StatefulSet三个组件 3.2.2为…...
直接插入排序
#include <stdio.h>void insert_sort(int arr[], int n) {int i;int j;int tmp;for (i 1; i < n; i){tmp arr[i];j i - 1;// 将要插入的元素与数组中的元素比较(从后向前比) while (j > 0 && arr[j] > tmp){arr[j 1] arr[…...
esp32s3 nvs 存储过程中使用malloc和free函数的一点困惑
我的项目中,大量使用了malloc()和free()函数,在使用nvs存储之前没有出现问题。 esp32厂家nvs的blob存储的例程中,有使用malloc()和free(),我参照例程写了自己的blob存储函数f,一开始是可以正常使用的,后来…...
除visio以外的几款好用流程图绘制工具
流程图绘制软件在嵌入式软件开发中扮演着重要的角色,它们能够帮助用户清晰、直观地展示工作流程。以下是几款流行的流程图绘制软件及其特点的详细报告: 思维导图MindMaster MindMaster作为一款专业的思维导图软件,不仅具备强大的思维导图制作…...
CentOS 7 64位 常用命令
一、系统管理命令 systemctl start firewalld.service:启动防火墙服务 systemctl stop firewalld.service:停止防火墙服务 systemctl enable firewalld.service:设置防火墙服务开机自启 systemctl disable firewalld.service:禁止…...
ChatGPT-4o抢先体验
速度很快,结果很智能,支持多模态输入输出,感兴趣联系作者。 windows/linux/mac 客户端下载参考:https://github.com/lencx/Noi...
STM32实验之USART串口发送+接受数据(二进制/HEX/文本)
涉及三个实验: 1.USART串口发送和接收数据 我们使用的是将串口封装成为一个Serial.c模块.其中包含了 void Serial_Init(void);//串口初始化 void Serial_SendByte(uint8_t Byte);//串口发送一个字节 void Serial_SendArray(uint8_t *Array,uint16_t Length);//…...
网关(Gateway)- 内置过滤器工厂
官方文档:Spring Cloud Gateway 内置过滤器工厂 AddRequestHeaderGatewayFilterFactory 为请求添加Header Header的名称及值 配置说明 server:port: 8088 spring:application:name: api-gatewaycloud:nacos:discovery:server-addr: 127.0.0.1:8847username: nacos…...
电风扇如何实现跌倒断电保护功能
电风扇作为日常生活中常用的家电产品,为了提升安全性能,在设计上通常会考虑加入跌倒断电保护功能。其中,光电倾倒开关是实现跌倒断电保护功能的关键组件之一。 光电倾倒开关内置红外发光二极管和光敏接收器,其工作原理非常巧妙。…...
编译原理总结
编译器构成 1. 前端分析部分 1.1 词法分析 确定词性,输出为token序列 1.2 语法分析 识别短语 1.3 语义分析 分析短语在句子中的成分 IR中间代码生成 2. 机器无关代码优化 3. 后端综合部分 目标代码生成 机器相关代码优化 4. 其他 全局信息表 异常输出...
JavaScript:从基础到进阶的全面介绍
JavaScript:从基础到进阶的全面介绍 JavaScript(简称JS)是一种广泛用于Web开发的编程语言。它是一种轻量级的、解释型或即时编译的语言,具有函数优先的特点。JS最初是为了实现网页的动态效果而设计的,如今已发展成为前…...
linux指令-sed
sed 是一个流编辑器,用于对输入流(或文件)进行基本的文本转换。以下是 sed 命令的详细输出说明文档: 1. 基本语法 sed [OPTIONS]... [SCRIPT] [INPUTFILE...] OPTIONS:可选的命令行选项,如 -i 用于直接修…...
Docker部署青龙面板
青龙面板 文章目录 青龙面板介绍资源列表基础环境一、安装Docker二、安装Docker-Compose三、安装青龙面板3.1、拉取青龙(whyour/qinglong)镜像3.2、编写docker-compose文件3.3、检查语法启动容器 四、访问青龙面板五、映射本地部署的青龙面板至公网5.1、…...
【LeetCode】每日一题 2024_6_4 将元素分配到两个数组中 II(二分、离散化、树状数组)
文章目录 LeetCode?启动!!!题目:将元素分配到两个数组中 II题目描述代码与解题思路 每天进步一点点 LeetCode?启动!!! 又有段时间没写每日一题的分享了,原本今…...
JAVA小案例-break练习,随机数,到88停止
JAVA小案例-break练习,随机数,到88停止 代码如下: public class Break {/*** break练习,随机数,到88停止* param args*/public static void main(String[] args) {int count0;//计数器System.out.println("Begi…...
C++第三方库【httplib】断点续传
什么是断点续传 上图是我们平时在浏览器下载文件的场景,下载的本质是数据的传输。当出现网络异常,浏览器异常,或者文件源的服务器异常,下载都可能会终止。而当异常解除后,重新下载文件,我们希望从上一次下载…...
[SaaS] AI+数据,tiktok选品,找达人,看广告数据
TK观察专访丨前阿里“鲁班”创始人用AIGC赋能TikTok获千万融资用AI数据做TikTokhttps://mp.weixin.qq.com/s/xp5UM3ROo48DK4jS9UBMuQ主要还是爬虫做数据的。 商家做内容:1.找达人拍内容,2.商家自己做原生自制内容,3.广告内容。 短视频&…...
A股冲高回落,金属、地产板块领跌,新股N汇成真首日暴涨753%
行情概述 AH股有色金属、教育及地产板块领跌,军工航天及半导体板块逆势走强;锂电池、创新药概念股也走强。创业板新股N汇成真首日暴涨753%,触发二次临停。 周三A股冲高回落,上证指数收跌0.83%,深成指跌0.8%ÿ…...
什么叫网站建设/企业培训课程视频
我正在尝试使用Sipjs的帮助为用户设置Asterisk语音聊天,遵循SIPJS docs http://sipjs.com/guides/server-configuration/asterisk上给出的说明 . 用户已创建并已连接 . 他们可以通过Zoiper互相打电话 . 但无法通过Sipjs或SipML5调用 . 当任何人用户从Sipjs或SipMl5进…...
wordpress二次开发教程种子/网站做优化好还是推广好
关于ARM中的重定位引入:要想弄明白重定义的问题,首先我们需要引入4个概念:链接地址 / 运行地址 / 位置无关码 / 位置有关码这里我们先简单回顾一下三星S5PV210芯片的启动过程(如果想详细了解,请翻我之前的文章):由于三星芯片设计时IROM为64Kb(存放BL0的位…...
部落冲突做弊器网站/重庆疫情最新数据
SQL Server连接SQL Server、SQL Server连接ORACLE 链接服务器 >> > > >> &...
嘉兴市建设街道网站/网站关键词优化排名软件系统
拼音字母表学习攻略包括26个汉语拼音字母表读法、拼音字母表图片大全、汉语拼音字母表大小写等拼音字母表学习攻略,请看拼音字母表学习攻略:26个汉语拼音字母表读法。汉语拼音字母表—声母表汉语中每个音节起始处的辅音可以构成声母。汉语拼音方案《声母…...
找我家是做的视频网站好/导航网站怎么推广
var obj{name:"wz",age:"12",sex:"女"}console.log(Object.values(obj))var arrObject.values(obj)console.log(Object.entries(obj))这是第一个打印的结果 怎么将键和值都打印出来呢? 可以使用Object.entries(obj&…...
做网站挂广告赚钱犯法吗/无锡网站关键词推广
Next[i]数组是得到模式串 i之前最大重复长度,在形成next数组的时候,每当失配时 把jnext[j] 去寻找比当前小一点的长度继续开始 如 : abcabcabcd 在 i9 和j6 是失配,所以到此时 以最长重复字符串abcabc的next数组中的值位参考数据…...