PID算法讲解+PID电机闭环控制介绍

1.PID简介

PID是控制领域相当经典且重要的控制算法。

PID就是“比例(proportional)、积分(integral)、微分(derivative)”,是一种很常见的控制算法。它应用的范围相当之广。小到我们玩的无人机,平衡车,大到工业领域的温度、液位、流量控制,都出现了PID的身影。

PID控制框图
数学模型

1.1个人对PID的理解

个人理解的PID就是一个“跟随”算法。

让被控对象,比如温度,水位,速度,高度,压力等到达我们期望的值,并且保持住。

PID在实际使用中更像一个数学的二元函数,你只要输入你想要的值,当前值,在调节好参数的情况下,无需关心内部过程,直接使用PID算出的结果值送入到执行机构即可。

PID有3个值,设定值(期望值,给定值),实际值(测量值),输出值(结果值)。

这是不是很像我们数学中经常使用的函数,y=f(x,y),输入期望值,当前值,得到结果。

1.2 PID变形以及参考代码

PID存在非常多的变形,最基本的PID变形是增量式PID和位置式PID。还有其他的变形,如去掉PID某一部分的PD算法,PI算法,再有更高端一些的抗饱和PID,微分先行PID,自适应PID,还有模糊PID。这些PID算法万变不离其宗,只要掌握了基本PID使用规律,用什么样的PID都是一样的。

位置式和增量式PID略有区别,主要区别如下:

位置式PID控制器的输出是一个绝对值,即控制器对系统的控制作用量的绝对大小。它根据比例项、积分项和微分项直接计算出最终的输出值。

而增量式PID控制器的输出是一个增量值,即控制器对系统的控制作用量的变化量。它根据比例增量、积分增量和微分增量来计算最终的输出增量,然后将该增量值与前一时刻的输出值相加得到当前的输出值。

位置式PID的c语言参考代码如下:

// PID控制器结构体  
typedef struct 
{  
    float Kp;       // 比例系数  
    float Ki;       // 积分系数  
    float Kd;       // 微分系数  
    float setpoint; // 设定值  
    float integral; // 积分项  
    float prev_error; // 上一次误差  
} PID_Controller;  

// PID控制器初始化函数  
void PID_Init(PID_Controller *pid, float Kp, float Ki, float Kd, float setpoint) 
{  
    pid->Kp = Kp;  
    pid->Ki = Ki;  
    pid->Kd = Kd;  
    pid->setpoint = setpoint;  
    pid->integral = 0.0f;  
    pid->prev_error = 0.0f;  
}  

// PID控制器计算函数  
float PID_Compute(PID_Controller *pid, float measured_value) 
{  
    float error = pid->setpoint - measured_value; // 计算误差  
    pid->integral += error; // 更新积分项  
    float derivative = error - pid->prev_error; // 计算微分项  
    pid->prev_error = error; // 更新上一次误差  
    float output = pid->Kp * error + 
                   pid->Ki * pid->integral +
                   pid->Kd * derivative; // 计算PID输出  
    return output;  
}  

增量式PID的c语言参考代码如下:

// 增量式PID控制器结构体  

typedef struct
 {  
    float Kp;       // 比例系数  
    float Ki;       // 积分系数  
    float Kd;       // 微分系数  
    float prev_error; // 上一次误差  
    float prev_prev_error; // 上上一次误差  
} IncrementalPID_Controller;  

// 增量式PID控制器初始化函数  
void IncrementalPID_Init(IncrementalPID_Controller *pid, float Kp, float Ki, float Kd) {  
    pid->Kp = Kp;  
    pid->Ki = Ki;  
    pid->Kd = Kd;  
    pid->prev_error = 0.0f;  
    pid->prev_prev_error = 0.0f;  
}  

// 增量式PID控制器计算函数  
float IncrementalPID_Compute(IncrementalPID_Controller *pid, float setpoint, float measured_value) 
{  
    float error = setpoint - measured_value; // 计算当前误差  
    float delta_error = error - pid->prev_error; // 计算误差变化量  
    float increment = pid->Kp * (error - pid->prev_error) +   
                      pid->Ki * error +   
                      pid->Kd * (delta_error - pid->prev_prev_error); // 计算增量  

    pid->prev_prev_error = pid->prev_error;    // 更新之前的误差值  
    pid->prev_error = error;  
      
    return increment; // 返回增量值  
} 

2.PID+编码器电机闭环控制介绍

做智能车的同学电机闭环控制直接采用增量式PI算法,方向控制直接采取位置式PD即可。这是无数前辈车友总结出的结果。

2.1编码器使用简介

编码器有很多种,有角速度编码器,正交编码器,方向编码器,绝对值编码器等。

智能车用的比较多的是正交,方向,绝对值这三种编码器,他们都属于脉冲编码器。

正交和方向编码器输出结果有方向,车轮正转输出正数,车轮反转输出负数。绝对值编码器不分正反转,只有正处输出。

脉冲编编码器根据输出范围分为1024线,512线,256线编码器等。他们的含义是编码器轴每转一圈,输出脉冲个数,我们配置单片机读取脉冲个数就可以。

以1024线编码器为例。当我间隔10毫秒读出编码器数值为100时,说明编码器在0.01秒钟,轴转动了100/1024≈0.1圈。

注意,是编码器轴转动了这么多圈,车轮转动还要考虑齿轮之间的齿轮比。

智能车中使用编码器通过齿轮啮合获取车轮转速

2.2转速获取

智能车里面通过编码器获得车轮转速,具体原理如下。

首先,我们知道

v=\frac{dx}{dt}

其中dt越大,v就是平均速度,dt越小,v就趋近顺时速度。

我们将编码器放在单片机定时器中断中读取,比如我们每间隔10毫秒去读取一次编码器的值,读完了将它清空,那么我们就得到了在每10毫秒中编码器的旋转圈数。

(读取完要将寄存器清空,因为寄存器的值是累加的)

得到编码器旋转的圈数,再根据齿轮比算出轮胎转动圈数,再测量轮胎半径,理论上可以得到非常准确的车轮转速,但一般我们不这么做

因为没有意义,理论上经过上述处理换算的转速是有单位的,但是我们做智能车控制非常多的控制量都是模糊量,他根本没有单位,比如摄像头误差。

我们常规处理直接在定时器中读取编码器值就好,不必做特殊处理。

因为当你的dt固定了,也就是你定时器中断的时间固定了,你的速度:

v=kdx

k是个比例系数。1/dt是定时器时间的倒数,b是齿轮比,以及车轮半径相关的系数,都是固定值

k=\frac{1}{dt}*b

也就是说你又是测编码器之间的齿轮比,又是测车轮的半径,求得的速度也不过是在编码器反馈的数据前乘上一个固定系数而已。完全没有什么实际意义。何况车轮还有可能打滑,磨损造成测量不准。

大家如果想知道车速,直接用尺子测赛道长度,然后用手机掐秒表算一下平均速度即可。

2.3电机闭环控制

上面我们知道了如何获取电机转速,下面我们讲一讲如何控制电机转速。

智能车电机

上面这张图是智能车最常用的电机。

他有两个接头,用来驱动电机。显然在电机两端施加电压越大,电机转速越快。

那么很简单,我只需要控制电机两端电压就可以控制电机转速。

比如相同的电机,我施加3V电压,他的转速肯定不如6v的电压转速快。

至于如何测量他的转速,我们使用上文提到的编码器外接齿轮啮合住电机输出端即可。

按照道理在一定区间内,电压与转速应该是呈现线性关系,实际情况有可能因为电机转动中发热,老化,电机磁铁退磁,齿轮啮合过紧等原因会有偏差。但是我给的电压越高,他转的越快,这一点是肯定没有问题的。

380电机参数图

该电机推荐电压7.2V,空载电流约630mA。(其实你电压给大一点也可以,只是电机更容易烧)

单片机所使用的电源一般都是3.3V或5V,驱动电流更是毫安级别,不可能驱动这个大家伙。

2.3.1 电机驱动

想要驱动电机,起码需要一个比较高的电压。

这里就想到了我们车上有一块电池,用来给所有外设供电。

这样就有了7.4v的电压,把电机线接上电池,电机可以转,电池电压降低,电机转速变慢。

但是显然这样不符合我们的控制需求,不能自由控制电机转速。

这时候我们就需要一个电机驱动。

一款电机驱动

上面的电机驱动有四组对外接口。

一个输入电源,用来连接电池,两个输出接口,用来连接电机(一辆C车有两个电机),还有一组排针接口,作为输入控制信号。

通过输入信号,控制输出给电机的输出电压,这就是驱动。

用3.3v的电压,控制7.4v(此处电压取决于电池电压)的电机。

2.3.2 PWM

对于一个电机来说,驱动信号是两路信号。这两路信号可以控制电机的转速和方向。

根据驱动器芯片的不同这两路信号略微有点区别。

电机的两种驱动方式

无论是哪一种控制信号,想要控制速度,都需要控制PWM占空比。

这里简单介绍一下PWM,等后续有空再出一篇文章专门讲一讲PWM。

PWM(Pulse width modulation)也叫脉宽调制,可以用示波器测一下,他的样子就是一连串的矩形波。

他有两个参数,一个是频率,一个是占空比。

大家看驱动参数那张图可以在下面看到小字,不同型号的电机他的工作频率不一样,这个是电机的固有特性,大家按照要求设置即可。

我们主要看看占空比。

前面我们说,我们通过PWM可以控制电机转速。我们又知道,电机的电压变化会导致电机转速变化。我们能否得到结论,PWM就是控制的电机两端电压来控制的转速呢?

答案是可以的。

占空比是指在一个周期内,高电平(或低电平)所占的时间长度,他的范围是0%-100%

PWM功能

上图中,纵坐标是电压,横坐标其实是时间。

第一行,高电平时间占周期的50%,那么他等效电压就是5V*50%=2.5V

等效2.5V的电压施加到电机上。

第二行同理,75%的占空比,那么5V*75%=3.75V,3.75V的电压将被施加到电击上。

第三行同理,20%的占空比,那么5V*20%=1V,1V的电压将被施加到电击上。

我们将纵坐标换成我们的电池电压,我们改变占空比就可以产生7.4v*x%就的电压,可以控制电机转速。

所谓驱动,就是使用3.3V的PWM波,让输出端输出频率,占空比相同的以电池电压为单位的PWM波。

2.3.3 开环

开环控制一般来说就是没有反馈的控制。

现在我们已经可以通过调整PWM占空比(或脉宽)控制车轮转速。在直道处,占空比给高一点,弯道处占空比给小一点,这样就实现了转速控制。

但是这样有个问题,车子是有惯性的。电机的加速减速也是需要时间反应的,很有可能在直道想要提速,加大了占空比,结果车子加速不及时,已经到了弯道速度才加起来。又到了弯道,需要减速,然后一个减速不及时冲了出去。

开环控制是属于能用,但不好用的情况。

主要是因为惯性的存在,导致加速不及时,减速刹不住。

2.3.3 闭环

好了,我们讲了这么久,终于到了PID+PWM闭环控制车轮转速。

开环更多的是定性控制,闭环可以做到定量控制转速。

还记得我们上面讲过的测速吗,如果是开环控制的话你可以看到在占空比不变的情况下速度值其实是很不稳定的。而且根据电池的电量不同,相同的占空比得到的转速也不同。在开环状态下其实测转速意义不大,毕竟你只能看,也不能用。

所谓闭环,就是反馈控制。每算出一次占空比输出后,测一下转速。查看当前转速和我期望转速差距大不大,如果当前转速还是与我期望转速差距过大,那么我就增大占空比输出,如果过小,我可以减小占空比,甚至可以让电机反转,给车子一个反向的力,让他迅速刹车。

那么我的期望值就是我期望车轮转速,无论是空载还是负载,都可以保证速度的稳定。

这个输出占空比的计算,是由PID完成。

使用时,输入两个参数,当前转速,期望转速,输出一个参数,占空比。

随后在电机驱动函数中,将刚算出的占空比应用到电机中去,就可以做到对于转速的准确控制。

注意这两者的时间关系,我个人习惯是电机转速读取频率要大于等于控制频率。当转速读取的频率过低,反馈的意义就不大了。

最后补充一下,PID的占空比输出和电机转速的关系。

比如我10毫秒读取一次电机转速,PID20毫秒控制一次占空比,和我20毫秒读取一次电机转读,PID20毫秒控制一次占空比。

这两者肯定会有很大的不同,哪怕是客观上一样的转速,10毫秒读取一次编码器,和20毫秒读取一次编码器读取到的编码器的值理论上是有两倍的差距的。

那么我们如何来克服这些差距的影响?

答案是调参。

电机控制一般采用增量式PI,那么就需要调整P和I系数,来消除读取频率,电机种类这些差距,做到编码器数值与占空比相对应。

至于调参,那就是一门玄学.

2.3.4 调参

一般来说,P代表比例,他决定反应速度,I代表积分,是对误差的累计,代表稳定后的波动范围,D代表微分,代表对误差变化的趋势,可以理解为预判。

当然,一切都要看实际情况而定。

具体参数也没什么范围而言,控制周期5毫秒和10毫秒,他的参数也不见得是两倍关系。

我的车参数在30左右,我队友的车子参数在几万,所以不同平台,不同周期,不同设备之间参数并不通用。

3.其他领域的PID控制

类似的,如果我想要控制某个水缸的水温,那我需要读取当前的水温,设置我期望的温度,输出量可以是加热棒的功率。

比如焊接电路板的烙铁就是这个原理,在到达设定值附近,会有一颗加热灯在一闪一闪,就是在间歇性加热,保证烙铁头温度在设定的范围附近。

比如液位控制,那就读取当前水位,设置期望水位,输出量就可以是阀门的开度(视阀门类型而定)。

其他领域基本都是同理,由于我也没有调过,就不多说了。

希望能够帮助到一些人。

本人菜鸡一只,各位大佬发现问题欢迎留言指出。

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

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

相关文章

双摆及其他:从多臂摆研究混沌

目录 一、说明 二、钟摆物理方程 三、无法确定解的混沌方程 四、计算机模拟 一、说明 关于混沌如何实现?能否用计算机模拟?本文从简单的物理道具:双臂摆的物理方程,引进混沌理念。进而进行复杂的自然状态中。本文只是研究题目的引…

【python】python鲜花管理系统(界面GUI版本)(源码+数据库)【独一无二】

👉博__主👈:米码收割机 👉技__能👈:C/Python语言 👉公众号👈:测试开发自动化【获取源码商业合作】 👉荣__誉👈:阿里云博客专家博主、5…

WebGIS 地铁交通线网数据可视化监控平台

数字孪生技术在地铁线网的管理和运维中的应用是一个前沿且迅速发展的领域。随着物联网、大数据、云计算以及人工智能技术的发展,地铁线网数字孪生在智能交通和智慧城市建设中的作用日益凸显。 图扑软件基于 HTML5 的 2D、3D 图形渲染引擎,结合 GIS 地图&…

【项目新功能开发篇】需求分析和开发设计

作者介绍:本人笔名姑苏老陈,从事JAVA开发工作十多年了,带过大学刚毕业的实习生,也带过技术团队。最近有个朋友的表弟,马上要大学毕业了,想从事JAVA开发工作,但不知道从何处入手。于是&#xff0…

leetcode(HOT100)——链表篇

1、相交链表 本题思路就是定义两指针,指向两链表的同一起跑线,然后共同往前走,边走边判断两链表的节点是否相等, 代码如下: /*** Definition for singly-linked list.* public class ListNode {* int val;* L…

最新在线工具箱网站系统源码

内容目录 一、详细介绍二、效果展示1.部分代码2.效果图展示 三、学习资料下载 一、详细介绍 系统内置高达72种站长工具、开发工具、娱乐工具等功能。此系统支持本地调用API,同时还自带免费API接口, 是一个多功能性工具程序,支持后台管理、上…

算法设计与分析实验报告c++java实现(ACM面试题、字符串匹配算法、循环赛日程安排问题、分治法求解最大连续子序列和、动态规划法求解最大连续子序列和)

一、 实验目的 1.加深学生对算法设计方法的基本思想、基本步骤、基本方法的理解与掌握; 2.提高学生利用课堂所学知识解决实际问题的能力; 3.提高学生综合应用所学知识解决实际问题的能力。 二、实验任务 1、【ACM、…

jmeter下载与使用

下载 官网下载地址:Apache JMeter - Apache JMeter™ 由于jmeter是由java语言编写的,所以要先安装jdk1.8或者以上的版本 配置环境变量 配置classpath环境变量 %JMETER_HOME%\lib\ext\ApacheJMeter_core.jar;%JMETER_HOME%\lib\jorphan.jar;%JMETER_HO…

深入理解 SQL 中的数据集合和数据关联

引言 在数据库管理系统中,数据集合和数据关联是 SQL 查询中常见的概念。它们是构建复杂查询和分析数据的基石。本文将深入探讨 SQL 中的数据集合和数据关联,包括它们的概念、常见用途以及实际示例。 首先引入一下数学中的集合 集合的基本概念&#x…

【Kafka】聊聊如何做Kafka集群部署方案

实际业务问题 在实际的业务中,因业务方要求,每天从三方拉取一定100W用户的三方数据,具体就是 提供uid,然后每天进行离线跑批。前期是部署多个jar实例,然后将名单拆分成多分,然后python脚本读取uid&#xf…

基于spark分析以springboot为后段vue为前端的大学生就业管理系统

基于spark分析以springboot为后段vue为前端的大学生就业管理系统 大学生就业管理系统是一个针对高校毕业生就业信息管理的有效工具,它能够帮助学校和学生更好地管理就业数据,提供数据驱动的决策支持。本文将介绍如何通过爬虫采集数据,利用Spark进行数据分析处理,再结合Spr…

【cpp】快速排序优化

标题:【cpp】快速排序 水墨不写bug 正文开始: 快速排序的局限性: 虽然快速排序是一种高效的排序算法,但也存在一些局限性: 最坏情况下的时间复杂度:如果选择的基准元素不合适,或者数组中存在大…

【C++】c++11新特性(一)

目录 { }列表初始化 内置类型---对单值变量及数组的初始化 列表初始化时进行的类型转换 自定义类型---对类对象或结构的初始化 initializer_list 1. 定义接受 initializer_list 参数的构造函数 2. 在函数中使用 initializer_list 参数 3. 使用 initializer_list 与 vect…

教你网络安全

如今,组织的信息系统和数据面临着许多威胁。而人们了解网络安全的所有基本要素是应对这些威胁的第一步。 网络安全是确保信息完整性、机密性和可用性(ICA)的做法。它代表了应对硬盘故障、断电事故,以及来自黑客或竞争对手攻击等防御和恢复能力。而后者包…

Android14应用启动流程(源码+Trace)

1.简介 应用启动过程快的都不需要一秒钟,但这整个过程的执行是比较复杂的,无论是对手机厂商、应用开发来说启动速度也是核心用户体验指标之一,本文采用Android14源码与perfetto工具进行解析。 源码参考地址:Search trace分析工…

基于单片机多功能MP3播放器系统设计

**单片机设计介绍,基于单片机多功能MP3播放器系统设计 文章目录 一 概要二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于单片机多功能MP3播放器系统设计是一个结合了硬件和软件设计的复杂项目。以下是对该系统设计的概要描述&#…

初识二叉树和二叉树的基本操作

目录 一、树 1.什么是树 2. 与树相关的概念 二、二叉树 1.什么是二叉树 2.二叉树特点 3.满二叉树与完全二叉树 4.二叉树性质 相关题目: 5.二叉树的存储 6.二叉树的遍历和基本操作 二叉树的遍历 二叉树的基本操作 一、树 1.什么是树 子树是不相交的;…

Github 2024-04-06Rust开源项目日报Top10

根据Github Trendings的统计,今日(2024-04-06统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量Rust项目10HTML项目1Dart项目1RustDesk: 用Rust编写的开源远程桌面软件 创建周期:1218 天开发语言:Rust, Dart协议类型:GNU Affero General …

docker + miniconda + python 环境安装与迁移(详细版)

本文主要列出从安装dockerpython环境到迁移环境的整体步骤。windows与linux之间进行测试。 简化版可以参考:docker miniconda python 环境安装与迁移(简化版)-CSDN博客 目录 一、docker 安装和测试 二、docker中拉取miniconda&#xff…

C语言--指针终章

目录 1. sizeof和strlen的对⽐ 1.1 sizeof 1.2 strlen 1.3 sizeof 和 strlen的对⽐ 2. 数组和指针的理解——题目理解 2.1.sizeof 代码1: 代码2: 代码3: 代码4: 代码5(二维数组): 2.2…