STM32——直流电机PI调速

所需元件

  STM32F103开发板、L298N一个、带编码器的直流电机一个(如下图所示,淘宝上有很多)
在这里插入图片描述

系统框图

在这里插入图片描述
  通过系统框图,我们需要做两件事,一是要测速,二是要调节。测速目前流行的就是通过编码器测速,调节器我采用的时PI调节,PI调节器调节的参数少,而且能够消除静差,当然用PID调节器也行。

编码器

  编码器的结构简化如下图:
在这里插入图片描述
  在电机转轴上安装了一个磁环,在磁环的下方有一个霍尔传感器,在磁环转动过程中就在霍尔传感器的附近产生了变化的磁场,于是霍尔传感器就输出了脉冲信号。我所用的这个直流电机是1:48的减速电机,电机转轴每转动1圈,编码器输出13个脉冲信号,也就是说输出转轴转动1圈,编码器输出13x48=624个脉冲,再通过STM32编码器接口 4 倍频就是 624x4=2496 个脉冲信号,通过STM32定时器的计数值除以2496就是输出转轴转动的圈数。
  所谓4倍频,如下图:
在这里插入图片描述
  编码器中有两个线路,即A相和B相。我们以A相或B相为例,1个上升沿或者下降沿代表1个脉冲信号,由图中可知有2个上升沿或2个下降沿,即2个脉冲信号。而所谓的4倍频,就是把A、B相的上升沿和下降沿都加起来,一共8个,与之前的2个脉冲信号就是4倍,而所以要加起来做成4倍频,可以提高测量转速的精度。另外A、B相之间相差90度,从而可以判断电机的转向。如果电机正转,A相比B相先90度,也就是说A相已经上升沿了B还是低电平。

理论分析

建模

  直流有刷电机可以等效为下图结构。
在这里插入图片描述
在这里插入图片描述
经拉式变换得传递函数
在这里插入图片描述
  由于电枢电感和转子转动惯量都较小,故而传递函数中二次项系数非常小,可忽略二次项做降阶处理,得
在这里插入图片描述

PI调节器

  关于PID算法,可参考STM32——PID恒温控制
PIPIPI调节器表达式如下
在这里插入图片描述
PIPIPI算法省去了微分控制,以损失响应快速性为代价以保证系统的可靠性。

理论计算

  直流电机的相关参数可以测量出来,但由于没有工具只得通过系统辨识的方法获取电机的传递函数
在这里插入图片描述
已知电源电压为12v12v12v,单片机PWM配置中计数值为100时代表100%占空比,周期为10ms,可近似pwm的传递函数为
在这里插入图片描述
输入为占空比DDD,输出为电压,且0<D<1000<D<1000<D<100(因为计数值为100时代表100%100 \%100%占空比,所以可认为占空比就在0<D<1000<D<1000<D<100之间,但实际上真正的占空比数值在0−10-101之间)。令G(s)=GG(s)=GG(s)=Gm(s)∗G(s)*G(s)Gpwm(s)(s)(s),得
在这里插入图片描述
可近似为一阶系统
在这里插入图片描述
此时系统框图如下
在这里插入图片描述

得系统闭环传递函数
在这里插入图片描述
我希望电机响应的超调量很低,调节时间可以长一点,相关参数如下
在这里插入图片描述

在这里插入图片描述
计算出来的参数还不能直接使用,由于单片机控制电机是离散控制,所以实际使用的积分系数KKKi等于计算出的KKKi乘以采样周期TTT。由于传递函数误差或者其他一些原因会造成理论计算的参数并不一定与实际效果高度一致,还需手动微调一下,找到一个更为合适的参数。
仿真结果如下
在这里插入图片描述
通过仿真来看,超调量仍然较大,调节时间在0.7s0.7s0.7s左右,超调量大是由于引入了一个闭环零点,调节时间与理论值有误差是由于理论计算是取近似值等原因造成的。如果要追求更低的超调量,可以在输入端加入一个前置滤波器,该前置滤波器的作用就是用滤波器的极点对消闭环系统的零点,系统框图如下
在这里插入图片描述
仿真结果如下
在这里插入图片描述
从图像上看,调节时间变化不大,但是超调量明显的小了许多。
  这里贴两张速度曲线图:
  1、
在这里插入图片描述
  2、
在这里插入图片描述
  这两组响应的曲线的参数是试凑得来的,与理论计算的参数相差不是很大,理论计算的参数使用效果上略好一些。图1中设定目标值为400,从图上可以看出超调量还是比较小的,调节时间也比较短,调节的效果还是可以的。图2中,目标值每隔一段时间增加100,加到400后又设为100,整体的调节效果还是蛮不错的。

主要程序

TIM_Encoder.c

#include "TIM_Encoder.h"float RPM_1=0;            //存储上一次测速结果void TIM_Encoder_Init(void)
{TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;  TIM_ICInitTypeDef TIM_ICInitStructure;  GPIO_InitTypeDef GPIO_InitStructure;RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);        //使能定时器4的时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);       //使能PB端口时钟GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7;	    //端口配置GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;       //浮空输入GPIO_Init(GPIOB, &GPIO_InitStructure);					    //根据设定参数初始化GPIOBTIM_TimeBaseStructInit(&TIM_TimeBaseStructure);TIM_TimeBaseStructure.TIM_Prescaler = 0x0;                  // 预分频器 TIM_TimeBaseStructure.TIM_Period = 65535;                   //设定计数器自动重装值TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;     //选择时钟分频:不分频TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数  TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);TIM_EncoderInterfaceConfig(TIM4, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);//使用编码器模式3TIM_ICStructInit(&TIM_ICInitStructure);TIM_ICInitStructure.TIM_ICFilter = 10;TIM_ICInit(TIM4, &TIM_ICInitStructure);TIM_ClearFlag(TIM4, TIM_FLAG_Update);                       //清除TIM的更新标志位TIM_ITConfig(TIM4, TIM_IT_Update, ENABLE);//Reset counterTIM_SetCounter(TIM4,0);TIM_Cmd(TIM4, ENABLE);  
}int GetTIMCounter(void)          //获取计数值
{int count=TIM_GetCounter(TIM4);return count;
}float GetRPM(int count)           //计算转速
{
//   int RPM=count/2496*2000+0.5;//30ms计算一次(pid.T=30),60000ms为1min,也就是1min计算了2000次,2496=13*4*48表示转动一圈的脉冲数,48表示1:48的减速比float RPM=count*0.8f;   //等同于上式,2000/2496约等于0.8if(RPM>1000)                 //过滤掉不合理的结果,仍然使用上次的速度,在按键设定速度的时候或者在减速为0时会有非常的大的错误测速结果,具体原因还未查清    {{return RPM_1;}RPM_1=RPM;                   //更新return RPM;
}

PID.c

#include "PID.h"PID pid;
//int time=0;void PID_Init()
{           pid.Sv=400;         //用户设定转速400pid.Kp=0.3;         //比例pid.Ki=0.015;       //积分pid.Kd=0;           //微分pid.pwmcycle=100;   pid.T=30;           //PID计算周期30mspid.OUT0=0;pid.C1ms=0;pid.SEk=0;pid.Ek=0;pid.Ek_1=0;pid.DelEk=0;pid.Dout=0;pid.Iout=0;pid.Pout=0;
}void PID_Calc(float data)        //pid计算
{float out;pid.Pv=data;pid.Ek=pid.Sv-pid.Pv;       //得到当前的偏差值pid.Pout=pid.Kp*pid.Ek;     //比例输出pid.SEk+=pid.Ek;            //历史偏差总和if(pid.SEk<(-50)){pid.SEk=(-50);}pid.DelEk=pid.Ek-pid.Ek_1;  //最近两次偏差之差pid.Iout=pid.Ki*pid.SEk;    //积分输出if(pid.Iout<(-10)){pid.Iout=(-10);}pid.Dout=pid.Kd*pid.DelEk;  //微分输出out= pid.Pout+ pid.Iout+ pid.Dout;if(out>pid.pwmcycle){pid.OUT=pid.pwmcycle;}else if(out<=0){pid.OUT=pid.OUT0; }else {pid.OUT=out+0.5f;       //四舍五入}pid.Ek_1=pid.Ek;            //更新偏差pid.C1ms=0;
}

工程链接
链接:https://pan.baidu.com/s/1dSXgPf0gzSvTdjlMHyOZ7w
提取码:f8h1

  PID调参比较麻烦,这里推荐一个ST官方的软件StmStdio,这个软件网上有很多教程,使用也比较简单。
链接:https://pan.baidu.com/s/1etsrBL80rCe_LouNEE1XEg
提取码:ckve

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

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

相关文章

JAVA设计模式--简单介绍

2019独角兽企业重金招聘Python工程师标准>>> &#xfeff;一、简介 Design pattern 是众多软件开发人员经过漫长的试验和错误总结出来的在软件开发过程中面临一般问题的解决方案&#xff0c;代表着最佳实践。使用设计模式是为了重用代码、让代码更容易被他人理解、保…

为什么是PID控制

在进入正式话题之前需要引入四个概念&#xff1a;稳态误差、终值定理、幅角条件和系统稳定的充要条件。 稳态误差&#xff1a;系统达到稳定状态后&#xff0c;系统的实际输出量与系统希望的输出量之间的偏差。 终值定理&#xff1a;设有连续函数f(t)f(t)f(t)&#xff0c;当t趋于…

卡尔曼滤波器推导

注&#xff1a;受控制领域大牛CAN博士启发&#xff0c;受益匪浅&#xff0c;作此文以为笔记。 简介 设 卡尔曼滤波器是从测量值ZZZk的平均数开始的。开始推导&#xff1a; 由上式可知   也就是说随着kkk的增大&#xff0c;测量结果Zk不在重要&#xff0c;因为已经获得了足…

cocos2dx3.2文件结构和代码结构

既然选定了cocos2dxlua的原生方式来开发&#xff0c;首先要确定的是使用哪个版本的cocos2dx&#xff0c;先看看github上的changelog和releasenote&#xff0c;然后在google里搜索一下&#xff0c;参考了jacky的博客http://zengrong.net/post/2100.htm&#xff0c;最终选择了coc…

改进的PID算法

位置式PID算法 位置式PIDPIDPID算法是一种比较直观的的PIDPIDPID算法&#xff0c;如系统框图中所示&#xff0c;ininin表示设定值&#xff0c;errorerrorerror表示差值&#xff0c;uuu表示控制器输出值&#xff0c;outoutout表示被控量。算法表达式如下&#xff1a; 增量式PI…

几种简单电路知识汇总

这篇文章用于记录平时设计电路或者在书中遇到的一些电路方面的知识&#xff0c;会不定期更新。就先从运算放大器开始&#xff0c;对此做个简单的介绍。 运算放大器 说到运算放大器就不得不说两个概念&#xff0c;虚短与虚断。 虚短&#xff1a; 在理想情况下&#xff0c;运算…

51单片机——交通灯

原理图 功能描述 1、基本功能就是如同红绿灯一般&#xff0c;不做赘述。   2、红灯时长和绿灯时长可通过按键设置&#xff0c;即按键列中的上面4个&#xff0c;当这4个按键有一个按下后便进入时长设置功能&#xff0c;设置完成后按最下面两个按键&#xff08;紧急控制按钮&am…

设置TextField内文字距左边框的距离

2019独角兽企业重金招聘Python工程师标准>>> //设置文本框左边的viewUITextField *textField [[UITextField alloc]init];textField.frame CGRectMake(10, 30, 300, 30);[self.view addSubview:textField];textField.leftView [[UIView alloc]initWithFrame:CGRe…

类的三大特性

类有三大特性&#xff1a;继承&#xff0c;封装&#xff0c;多态&#xff0c;这个也是介绍类的时候&#xff0c;必须提到的话题&#xff0c;那么今天就来看一下OC中类的三大特性&#xff1a; 一、封装 学习过Java中类的同学可能都知道了&#xff0c;封装就是对类中的一些字段&a…

操作系统抢占式优先级调度_操作系统中的优先级调度(非抢先)

操作系统抢占式优先级调度Priority scheduling is a type of scheduling algorithm used by the operating system to schedule the processes for execution. The priority scheduling has both the preemptive mode of scheduling and the non-preemptive mode of scheduling…

数据结构pta选择判断复习

第一章绪论 1-3数据的逻辑结构是指数据的各数据项之间的逻辑关系。 错 是数据元素之间的逻辑关系 2-4以下属于逻辑结构的是&#xff08; &#xff09;。 (2分) 顺序表 散列表 有序表 单链表 有序表 2-12以下关于数据结构的说法中正确的是____。 (2分) A数据结构的逻辑结构独立于…

粗略的看JFinal的基于AOP的拦截器的实现

2019独角兽企业重金招聘Python工程师标准>>> 简单的说一下AOP的实现&#xff0c;所谓AOP&#xff0c;即&#xff08;Aspect Oriented Programming&#xff09;的缩写&#xff0c;体现在程序中就是你可以通过配置在任意的代码块前后插入你想插入的执行代码。例如日志…

大二上数据结构复习

目录 第一章绪论练习 第二章线性表 第三章栈和队列 第四章串 第五章数组和广义表 第六章树和二叉树 第七章图 第九章查找 第十章排序 第一章绪论练习 1-8 数据结构的抽象操作的定义与具体实现有关。 (1分) T F 1-14 数据结构包括数据对象集以及它们的逻辑结构和物理结构&#…

大二上数据结构复习2

第二章线性表 综合 一、在什么情况下用顺序表比用链表好 表长度确定&#xff0c;很少进行插入删除操作且经常访问元素 二、2-4 顺序表的插入和删除要求仍然保持各个元素原来的次序。设在等概率情形下, 对有 127 个元素的顺序表进行插入, 平均需要移动多少个元素? 删除一个元素…

操作系统(王道笔记第二章)

目录第二章 2.1_1进程的定义、组成、组成形式、特征 2.1_2进程的状态与转换 2.1_3进程的控制 2.1_4进程通信 2.1_5线程概念和多线程模型 2.2_1处理机调度的概念层次 2.2_2处理机调度的时机、切换与过程、方式 2.2_3调度算法的评价指标 2.2_4FCFS、SJF、HRRN调度算法 2.2_5时间片…

C语言画图形(图形库graphics的使用)

目录 工具 c语言基本绘图 文字输出 c语言基本贴图 获取鼠标、键盘信息 工具 &#xff08;1&#xff09;环境&#xff1a;VC &#xff08;2&#xff09;库函数&#xff1a;graphics.h&#xff08;因为不是标准库函数&#xff0c;所以需下载EASYX&#xff09; &#xff08;3&am…

关于DDD中Domain的思考

2019独角兽企业重金招聘Python工程师标准>>> 本文既不推销UML&#xff0c;也不推广DDD&#xff0c;更不涉及各种论战。-- 作者 某天又一次打开关于DDD(领域驱动设计)的PDF文档时&#xff0c;自己有了个疑问&#xff1a;什么是领域(Domain)&#xff1f;译文中是这样描…

算法设计TSP问题动态规划

#include <iostream> #include <cmath> using namespace std; //集合虚拟化用000 、001 、010 、011 、100 、101 、110 、111分别表示{} 、{1}&#xff08;V[2^(1-1)]&#xff09; 、{2}&#xff08;V[2^(2-1)]&#xff09; 、{1,2}&#xff08;V[2^(1-1)2^(2-1)]…

字符串使用与内部实现原理

Redis 发展到现在已经有 9 种数据类型了&#xff0c;其中最基础、最常用的数据类型有 5 种&#xff0c;它们分别是&#xff1a;字符串类型、列表类型、哈希表类型、集合类型、有序集合类型&#xff0c;而在这 5 种数据类型中最常用的是字符串类型&#xff0c;所以本文我们先从字…

Lisp-Stat翻译 —— 第九章 统计绘图窗体

2019独角兽企业重金招聘Python工程师标准>>> 第九章 统计绘图窗体 除了前几章略述的绘图窗体原型提供的基本绘图工具之外&#xff0c;Lisp-Stat里的统计绘图还需要用来管理数据和将那些数据转换成屏幕上的图形的工具集。这些工具由绘图原型graph-proto提供。更多的…