jjzjj

STM32应用(十)经典控制算法PID(单级和串级)原理与代码实现

三木今天学习了嘛 2023-04-21 原文

文章目录

1.PID原理

PID是什么,P,I,D的分别功能

你和PID调参大神之间,就差这篇文章!

1.1 P I D三个参数简单理解

P(比例): 简单来说,P就是凉了加热水,热了加凉水。比目标值小,我就增加一点,比目标值大,我就减小一点。(现在)
P可能出现的问题: 1.P太小,达到目标值需要花费很长的时间,而且会有稳态误差。2.P太大,达到目标值时可能会一直震荡。

I(积分): 将一段时间内的误差累积起来加到输出上,可以消除历史误差对当前实际曲线的影响,提高系统的稳定性。 (过去)
I可能出现的问题: 1.I太小,可以消除稳态误差,但太慢了,对于某些需要很快响应的系统,显然不能满足要求。2.I太大,累计误差占比过大,就会出现抖动现象,难以收敛。

D(微分): 减小最大超调量。(下图中③就是最大超调量。) 可以有效减小震动的幅度。让曲线收敛更快 (未来)
D可能出现的问题: 1.D太小,作用小,时间长。2.D太大,为了减小超调量,补偿的过多,导致震荡很久。

1.2 P I D

先调P,逐渐增加P直到系统出现震荡,将当前值乘0.7就是较为合适的值。
再调I,将稳态误差逐渐降低。
后调D,将最大超调量降到最低。

1.3 PI PD PID适用系统

PI:响应速度要求不那么高的系统。
PD:大惯性系统。超调量太大。
PID:都可以。

网上将PID原理太多太多了,我的理解也都是参见上面的内容。认真看肯定有收获。

2.串级PID原理

【串级PID】浅谈串级PID作用及意义——快速理解串级PID结构优势

这里个人理解就是,单机PID就是稳定速度。而需要带位置和角度的就要用串级PID了。常用于平衡车,板球系统等。
而转速闭环称为串级PID的内环,位置 (角度) 闭环称为串级PID的外环。其实也很好理解,位移是速度的积分,只有速度慢慢稳定,位置才能确定。

3.PID代码

3.1 单级PID

3.1.1 初始化PID结构体

typedef struct _PID
{
	float kp,ki,kd;
	float error,lastError;//误差、上次误差
	float integral,maxIntegral;//积分、积分限幅
	float output,maxOutput;//输出、输出限幅
}PID;

3.1.2 单级PID计算

#define LIMIT(x,min,max) (x)=(((x)<=(min))?(min):(((x)>=(max))?(max):(x)))

//单级pid计算
void PID_SingleCalc(PID *pid,float reference,float feedback)
{
	//更新数据
	pid->lastError=pid->error;
	pid->error=reference-feedback;
	//计算微分
	pid->output=(pid->error-pid->lastError)*pid->kd;
	//计算比例
	pid->output+=pid->error*pid->kp;
	//计算积分
	pid->integral+=pid->error*pid->ki;
	LIMIT(pid->integral,-pid->maxIntegral,pid->maxIntegral);//积分限幅
	pid->output+=pid->integral;
	//输出限幅
	LIMIT(pid->output,-pid->maxOutput,pid->maxOutput);
}

3.1.3PID初始化

void PID_Init(PID *pid,float p,float i,float d,float maxI,float maxOut)
{
	pid->kp=p;
	pid->ki=i;
	pid->kd=d;
	pid->maxIntegral=maxI;
	pid->maxOutput=maxOut;
}

3.1.4 清空PID

//清空一个pid的历史数据
void PID_Clear(PID *pid)
{
	pid->error=0;
	pid->lastError=0;
	pid->integral=0;
	pid->output=0;
}

3.2 串级PID

3.2.1 初始化串级PID结构体

typedef struct _CascadePID
{
	PID inner;//内环
	PID outer;//外环
	float output;//串级输出,等于inner.output
}CascadePID;

3.2.2 串级PID计算

//串级pid计算
void PID_CascadeCalc(CascadePID *pid,float angleRef,float angleFdb,float speedFdb)
{
	PID_SingleCalc(&pid->outer,angleRef,angleFdb);//计算外环(角度环)
	PID_SingleCalc(&pid->inner,pid->outer.output,speedFdb);//计算内环(速度环)
	pid->output=pid->inner.output;
}

4.PID的使用

STM32应用(九)编码器及其测速原理、L298N电机驱动控制编码器电机

在这篇博客的配置下,只需要修改部分代码。以单级PID为例子。

4.1 定义PID结构体并初始化

PID pid;

void Motor_Init(void)
{
	PID_Init(&pid,10,0,0,1000,1000);
	HAL_TIM_Encoder_Start(&htim1, TIM_CHANNEL_ALL);      //开启编码器定时器
  __HAL_TIM_ENABLE_IT(&htim1,TIM_IT_UPDATE);         	 //开启编码器定时器更新中断,防溢出处理
	HAL_TIM_Base_Start_IT(&htim6);                       //开启10ms定时器中断
	HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);            //开启PWM
	__HAL_TIM_SET_COUNTER(&htim1, 10000);                //编码器定时器初始值设定为10000
	motor.loopNum = 0;                                   //防溢出
}

4.2 定义电机速度函数

void Motor_Send()
{
	float output = 0;
	PID_SingleCalc(&pid, motor.targetSpeed, motor.speed);
	output = pid.output; 
	if(output > 0)	//正转
	{
		__HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_1, (uint32_t)output);
		IN1(1);
		IN2(0);
	}
	else										//反转
	{
		__HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_1, (uint32_t)(-output));
		IN1(0);
		IN2(1);
	}
}

4.3 在检测霍尔码盘时发送速度给电机

	if(htim->Instance==htim6.Instance)		         //10ms中断
	{
		int16_t pluse = COUNTERNUM - RELOADVALUE/2;											
		motor.totalAngle = pluse + motor.loopNum * RELOADVALUE/2;  
		motor.speed = (float)(motor.totalAngle - motor.lastAngle)/(4*13*RR)*6000;			//进行速度计算,根据前文所说的,4倍频,编码器13位,减速比30,再乘以6000即为每分钟输出轴多少转
		motor.lastAngle = motor.totalAngle;         //更新转过的圈数
		Motor_Send();//发送速度
	}

4.4 实验效果

有关STM32应用(十)经典控制算法PID(单级和串级)原理与代码实现的更多相关文章

  1. ruby - 将差异补丁应用于字符串/文件 - 2

    对于具有离线功能的智能手机应用程序,我正在为Xml文件创建单向文本同步。我希望我的服务器将增量/差异(例如GNU差异补丁)发送到目标设备。这是计划:Time=0Server:hasversion_1ofXmlfile(~800kiB)Client:hasversion_1ofXmlfile(~800kiB)Time=1Server:hasversion_1andversion_2ofXmlfile(each~800kiB)computesdeltaoftheseversions(=patch)(~10kiB)sendspatchtoClient(~10kiBtransferred)Cl

  2. ruby - 如何在 buildr 项目中使用 Ruby 代码? - 2

    如何在buildr项目中使用Ruby?我在很多不同的项目中使用过Ruby、JRuby、Java和Clojure。我目前正在使用我的标准Ruby开发一个模拟应用程序,我想尝试使用Clojure后端(我确实喜欢功能代码)以及JRubygui和测试套件。我还可以看到在未来的不同项目中使用Scala作为后端。我想我要为我的项目尝试一下buildr(http://buildr.apache.org/),但我注意到buildr似乎没有设置为在项目中使用JRuby代码本身!这看起来有点傻,因为该工具旨在统一通用的JVM语言并且是在ruby中构建的。除了将输出的jar包含在一个独特的、仅限ruby​​

  3. ruby-on-rails - Rails 源代码 : initialize hash in a weird way? - 2

    在rails源中:https://github.com/rails/rails/blob/master/activesupport/lib/active_support/lazy_load_hooks.rb可以看到以下内容@load_hooks=Hash.new{|h,k|h[k]=[]}在IRB中,它只是初始化一个空哈希。和做有什么区别@load_hooks=Hash.new 最佳答案 查看rubydocumentationforHashnew→new_hashclicktotogglesourcenew(obj)→new_has

  4. ruby-on-rails - Rails 应用程序之间的通信 - 2

    我构建了两个需要相互通信和发送文件的Rails应用程序。例如,一个Rails应用程序会发送请求以查看其他应用程序数据库中的表。然后另一个应用程序将呈现该表的json并将其发回。我还希望一个应用程序将存储在其公共(public)目录中的文本文件发送到另一个应用程序的公共(public)目录。我从来没有做过这样的事情,所以我什至不知道从哪里开始。任何帮助,将不胜感激。谢谢! 最佳答案 无论Rails是什么,几乎所有Web应用程序都有您的要求,大多数现代Web应用程序都需要相互通信。但是有一个小小的理解需要你坚持下去,网站不应直接访问彼此

  5. ruby - 无法运行 Rails 2.x 应用程序 - 2

    我尝试运行2.x应用程序。我使用rvm并为此应用程序设置其他版本的ruby​​:$rvmuseree-1.8.7-head我尝试运行服务器,然后出现很多错误:$script/serverNOTE:Gem.source_indexisdeprecated,useSpecification.Itwillberemovedonorafter2011-11-01.Gem.source_indexcalledfrom/Users/serg/rails_projects_terminal/work_proj/spohelp/config/../vendor/rails/railties/lib/r

  6. ruby-on-rails - Rails 应用程序中的 Rails : How are you using application_controller. rb 是新手吗? - 2

    刚入门rails,开始慢慢理解。有人可以解释或给我一些关于在application_controller中编码的好处或时间和原因的想法吗?有哪些用例。您如何为Rails应用程序使用应用程序Controller?我不想在那里放太多代码,因为据我了解,每个请求都会调用此Controller。这是真的? 最佳答案 ApplicationController实际上是您应用程序中的每个其他Controller都将从中继承的类(尽管这不是强制性的)。我同意不要用太多代码弄乱它并保持干净整洁的态度,尽管在某些情况下ApplicationContr

  7. ruby-on-rails - 如何在我的 Rails 应用程序 View 中打印 ruby​​ 变量的内容? - 2

    我是一个Rails初学者,但我想从我的RailsView(html.haml文件)中查看Ruby变量的内容。我试图在ruby​​中打印出变量(认为它会在终端中出现),但没有得到任何结果。有什么建议吗?我知道Rails调试器,但更喜欢使用inspect来打印我的变量。 最佳答案 您可以在View中使用puts方法将信息输出到服务器控制台。您应该能够在View中的任何位置使用Haml执行以下操作:-puts@my_variable.inspect 关于ruby-on-rails-如何在我的R

  8. ruby-on-rails - 浏览 Ruby 源代码 - 2

    我的主要目标是能够完全理解我正在使用的库/gem。我尝试在Github上从头到尾阅读源代码,但这真的很难。我认为更有趣、更温和的踏脚石就是在使用时阅读每个库/gem方法的源代码。例如,我想知道RubyonRails中的redirect_to方法是如何工作的:如何查找redirect_to方法的源代码?我知道在pry中我可以执行类似show-methodmethod的操作,但我如何才能对Rails框架中的方法执行此操作?您对我如何更好地理解Gem及其API有什么建议吗?仅仅阅读源代码似乎真的很难,尤其是对于框架。谢谢! 最佳答案 Ru

  9. ruby - 模块嵌套代码风格偏好 - 2

    我的假设是moduleAmoduleBendend和moduleA::Bend是一样的。我能够从thisblog找到解决方案,thisSOthread和andthisSOthread.为什么以及什么时候应该更喜欢紧凑语法A::B而不是另一个,因为它显然有一个缺点?我有一种直觉,它可能与性能有关,因为在更多命名空间中查找常量需要更多计算。但是我无法通过对普通类进行基准测试来验证这一点。 最佳答案 这两种写作方法经常被混淆。首先要说的是,据我所知,没有可衡量的性能差异。(在下面的书面示例中不断查找)最明显的区别,可能也是最著名的,是你的

  10. ruby - 寻找通过阅读代码确定编程语言的ruby gem? - 2

    几个月前,我读了一篇关于ruby​​gem的博客文章,它可以通过阅读代码本身来确定编程语言。对于我的生活,我不记得博客或gem的名称。谷歌搜索“ruby编程语言猜测”及其变体也无济于事。有人碰巧知道相关gem的名称吗? 最佳答案 是这个吗:http://github.com/chrislo/sourceclassifier/tree/master 关于ruby-寻找通过阅读代码确定编程语言的rubygem?,我们在StackOverflow上找到一个类似的问题:

随机推荐