平衡小车制作系列之二——模块原理解析
文章目录
- 一、 模块概述
- 二、 直流电机
- 2.1 直流电机介绍
- 2.2 直流电机外围设备介绍
- 2.2.1 减速器
- 2.2.2 控制PWM的单片机
- 2.2.3 编码器
- 三、 编码器
- 3.1 编码器介绍
- 3.1.1 编码器作用
- 3.1.2 具体原理
- 3.2 STM32的编码器接口模式
- 3.2.1 概述
- 3.2.2 编码器模式配置
- 3.3 使用方法
- 3.3.1 核心
- 3.3.2 代码部分
- 3.4 编码器实物参数
- 四、 结尾说明
一、 模块概述
带编码器的直流减速电机,stm32f103系列单片机,蓝牙模块,电源电池,面包板,后续补充…
二、 直流电机
2.1 直流电机介绍
下面是分析直流电机的物理模型图。其中,固定部分有磁铁,这里称作主磁极;固定部分还有电刷。转动部分有环形铁芯和绕在环形铁芯上的绕组。
把上图中的+和-分别接到电池的正极和负极,电机即可正转;如果是把上图中的+和-分别接到电池的负极和正极那么电机就会反方向转动。电机的转速可以理解为和外接的电压是正相关的。(实际由电枢电流决定!这一点很关键,会在后面的讲解中体现出来。)
总而言之,如果我们可以调节施加在电机上面的直流电压大小,即可实现直流电机调速,改变施加电机上面直流电压的极性,即可实现电机换向。
2.2 直流电机外围设备介绍
2.2.1 减速器
在本次平衡小车项目中,我们使用到的直流电机自带一个减速器,用来降低电机的转速,以提高电机的扭矩。因为直流电机的转速一般都是一分钟几千上万转转速特别的快,减小转速后可以使电机可控性增强,并且转速快电机能产的扭矩就小,通俗的说就是负载一大就很容易转不动(扭矩不够,拉不动)。
2.2.2 控制PWM的单片机
通过改变电机正负极两端的压降就可以改变电机的转速,因此,我们就可以通过改变引脚PWM波的占空比来改变引脚输出的有效电压,但32单片机为3.3V单片机,而要驱动的直流减速电机的电压一般都大于3.3V,并且单片机引脚能输出的电流只有几毫安,而电机的额定电流远远大于这个值,所以单片机是无法直接驱动电机的。因此我们就需要使用电机驱动来帮助单片机来驱动电机转动,例如LM298N。即由电机驱动来提供驱动电机的电压与电流,单片机通过输出PWM波来改变电机驱动输出的电压从而该变电机的转速。
2.2.3 编码器
后续详细介绍
三、 编码器
3.1 编码器介绍
编码器是将信号或数据进行编制、转换为可用以通信、传输和存储的信号形式的设备。在直流减速电机中,编码器就是将电机的转动信息(比如转速、转动角度等)转换为脉冲信号。按照原理可将其分为:光电编码器(光学式)和霍尔编码器(磁式)。
3.1.1 编码器作用
由上述可知,编码器能够将电机的机械几何位移转化为脉冲信号或数字量。也就是说,通过检测编码器输出的脉冲信号,就能获取电机的转速、转动角度等相关信息。这样,我们不仅能够定量地测量电机转向、转速,还能实现对电机的定性控制。
3.1.2 具体原理
简单来说,就是电机带动码盘转动,码盘的结构使得当电机在转动时会产生A、B两相的脉冲信号,且这两路脉冲信号的相位差为90°(即正交)。并且由上图可以间接知道,无论电机的转速如何,每一转的脉冲数目都是一致的!
由于A、B信号正交,因此可以根据两个信号谁先到,谁后到来判断方向,根据每个信号脉冲数量的多少以及每一圈电机产生的脉冲数,就可以算出当前行走的距离,如果再加上定时器的话,还可以算出速度。
- 通过定时器的输入捕获或者GPIO引脚的外部中断来检测边沿变化,以此来检测脉冲数。这方法好像没毛病,当电机正常运转时行得通。
但是如果电机输出的脉冲信号出现了毛刺呢? 会存在误差!
- 通过软件编写算法来滤去毛刺似乎有点困难,于是我们想到通过硬件来处理这个毛刺。(而STM32正好有硬件编码器,nice!)
3.2 STM32的编码器接口模式
3.2.1 概述
此模式就是特殊的输入捕获模式——在该模式下能计算电机输出脉冲信号的个数,且stm32根据其内部机制能够消除毛刺的干扰。
配置过程:由于编码器接口模式是一种特殊的输入捕获,所以要先配置一下输入捕获(毕竟你要通过捕获边沿来检测脉冲)。
在输入捕获过程中,我们把A6、A7复用为TIM3,作为输入捕获的引脚,对电机的A、B相脉冲进行输入捕获。
输入捕获配置完成之后再配置一下编码器模式就可以开始工作了。
3.2.2 编码器模式配置
配置函数void TIM_EncoderInterfaceConfig(TIMx, TIM_EncoderMode, TIM_IC1Polarity, TIM_IC2Polarity)
- TIMx就是输入捕获时设置的TIM3,
- polarity就分别是TI1和TI2的捕获极性(TI1是定时器输入通道1,TI2同理),即A、B两相信号的捕获极性(上升沿捕获或者下降沿捕获)
- ♥♥♥编码器的模式TIM_EncoderMode:
a) 当模式选为TIM_EncoderMode_TI1时,计数器仅在TI1的边沿处计数
b) 当模式选为TIM_EncoderMode_TI2时,计数器仅在TI2的边沿处计数
c) 当模式选为TIM_EncoderMode_TI12时,计数器在TI1和TI2边沿处均计数
如图,A、B两相正交信号,如果根据模式1或模式2对脉冲信号进行检测,假设我们上升沿捕获一次,那么图中的信号我们只检测到3个上升沿,也就是三个脉冲。但是如果采用模式3,对TI1和TI2检测上升沿,那么同一段时间我们检测到6个上升沿。如果下降沿也检测,那么一共就是12个边沿跳变。每个实际来的脉冲会被检测4次,同样是12/4=3个脉冲,但是这样的话精度大大提高了。至此,我们通过STM32的TIM3的编码器模式,能够测出任意时刻的脉冲值了。
3.3 使用方法
3.3.1 核心
KEY:利用获取的脉冲数来测量电机转动角度、转速。
a) 首先,根据带编码器的直流减速电机的原理,显然无论电机的转速如何,每转产生的脉冲数是固定的。这里假设电机每转产生260个脉冲(具体数据各位自行查看自己的电机参数啦),那么只要我们用‘电机已产生的脉冲数’除以‘260个/转’,就可以得到电机转了多少圈,一圈即为360度,由此便可将脉冲数和转动角度联系起来。
WARNING: 如果使用编码器模式3(TIM_EncoderMode_TI12),我们得到的脉冲数是电机实际产生的脉冲数的四倍。则电机实际产生的脉冲数应为‘得到的计数值’除以4。于是,电机转动圈数为脉冲数除以260再除以4。*
b) 其次,我们根据计数方向(递增计数或递减计数)来判断转动角度。
e.g. TIM_EncoderMode_TI1: Counter counts on TI1FP1 edge depending on TI2FP2 level,意思就是当选择模式1时,计数器根据TI2的电平高低来记录TI1的边沿信号。
示例:如下图,电机转动时产生A、B两相信号通过TI1、TI2输入到TIM3。
假设我们选择的是模式1,即计数器仅在TI1的边沿处计数。我们观察TI1的上升沿,若此时对应的TI2信号处于低电平(下图红框),于是根据表格我们可以得到计数方向为递增,假设计数器递增时电机正向转动,则可判断此时电机正转。
再譬如,假设我们选择模式2,即计数器仅在TI2的边沿处计数。我们观察TI2的下降沿,若此时对应的TI1信号为高电平(下图蓝框),于是根据表格我们可以得到计数方向为递减,假设计数器递减时电机反向转动,则可判断此时电机反转。
也就是说,当以TI1为计数信号时,需要根据TI2的电平(也就是第二纵列的“相对信号的电平”)来进行判断是向上计数还是向下计数。TI2也同理。
3.3.2 代码部分
a)定时器初始化(输入捕获模式)
这里的period即为计数器的重装载值,prescaler即为预分频系数。注意在编码器模式时,要把TIM理解为计数器,而不是定时器,这样的话,时钟信号就不是系统内部产生的,而是通过PA6、PA7输入到TIM3的TI1和TI2的。
计数器原理与普通定时器一致——Period就是计数器每一次能检测脉冲的最大值,每来一个脉冲计数值就加一,当计数值超过period就溢出中断;Prescaler就是对电机产生的脉冲信号进行分频的分频系数。比如当分频系数为2时,每当电机产生两个脉冲,stm32才认为接收到一个有效脉冲,计数值才加一。
/**************************************************************************
函数功能:把TIM2初始化为编码器接口模式
入口参数:无
返回 值:无
**************************************************************************/
void Encoder_Init_TIM2(void)
{TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_ICInitTypeDef TIM_ICInitStructure; GPIO_InitTypeDef GPIO_InitStructure;RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);//使能定时器2的时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//使能PA端口时钟GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1; //端口配置GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入GPIO_Init(GPIOA, &GPIO_InitStructure); //根据设定参数初始化GPIOATIM_TimeBaseStructInit(&TIM_TimeBaseStructure);TIM_TimeBaseStructure.TIM_Prescaler = 0x0; // 预分频器 TIM_TimeBaseStructure.TIM_Period = ENCODER_TIM_PERIOD; //设定计数器自动重装值TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;//选择时钟分频:不分频TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;TIM向上计数 TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);TIM_EncoderInterfaceConfig(TIM2, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);//使用编码器模式3TIM_ICStructInit(&TIM_ICInitStructure);TIM_ICInitStructure.TIM_ICFilter = 10;TIM_ICInit(TIM2, &TIM_ICInitStructure);TIM_ClearFlag(TIM2, TIM_FLAG_Update);//清除TIM的更新标志位TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);//Reset counterTIM_SetCounter(TIM2,0);TIM_Cmd(TIM2, ENABLE);
}
/**************************************************************************
函数功能:把TIM4初始化为编码器接口模式
入口参数:无
返回 值:无
**************************************************************************/
void Encoder_Init_TIM4(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 = ENCODER_TIM_PERIOD; //设定计数器自动重装值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 Read_Encoder(u8 TIMX)
{int Encoder_TIM; switch(TIMX){case 2: Encoder_TIM= (short)TIM2 -> CNT; TIM2 -> CNT=0;break;case 3: Encoder_TIM= (short)TIM3 -> CNT; TIM3 -> CNT=0;break; case 4: Encoder_TIM= (short)TIM4 -> CNT; TIM4 -> CNT=0;break; default: Encoder_TIM=0;}return Encoder_TIM;
}
/**************************************************************************
函数功能:TIM4中断服务函数
入口参数:无
返回 值:无
**************************************************************************/
void TIM4_IRQHandler(void)
{ if(TIM4->SR&0X0001)//溢出中断{ } TIM4->SR&=~(1<<0);//清除中断标志位
}
/**************************************************************************
函数功能:TIM2中断服务函数
入口参数:无
返回 值:无
**************************************************************************/
void TIM2_IRQHandler(void)
{ if(TIM2->SR&0X0001)//溢出中断{ } TIM2->SR&=~(1<<0);//清除中断标志位
}
3.4 编码器实物参数
以某宝店铺的驰海电机进行参数学习——CHR-GM37-520ABHL碳刷霍尔编码器减速电机。
四、 结尾说明
本文重点参考以下几篇博客文章:
《带编码器的直流减速电机——基于STM32F407》
《STM32直流减速电机控制篇》
平衡小车制作系列之二——模块原理解析相关推荐
- 平衡小车制作系列之八——总结
文章目录 一. 前言 二. 说在最前面 2.1 模块总结 2.2 时间分配(2 Weeks In All) 2.3 一些问题 三. 收获与总结 四. 碎碎念 一. 前言 本博客原题目叫做"我 ...
- 平衡小车制作系列之三——stm32软件调试
文章目录 前言 一. STM32F103RCT6最小系统板 1.1 STlink程序烧录 1.1.1 模式选择 1.2 烧录功能测试 1.2 点亮一个LED灯 1.3 测试OLED 1.4 测试PWM ...
- 【平衡小车制作】(一)硬件原理图讲解(超详解)
大家好,我是小政.之后的一系列文章我将介绍我玩平衡小车的过程以及遇到的一些问题,将这些内容记录下来分享给大家,也让大家少走一些弯路.接下来我将从硬件框架选择.软件编程.PID算法.PID调参.蓝牙 ...
- 【平衡小车制作】(七)串级PID调参及平衡成果展示(超详解)
大家好,我是小政.本篇文章我将针对PID调参进行详细的讲解,让每位小伙伴能够对比例.积分.微分三个参数如何调节有更加清晰的理解. 一.调参步骤 确立机械中值 直立环(内环)--Kp极性.Kp大小. ...
- TT马达平衡小车制作
TT马达平衡小车制作 假期无聊本来买个淘宝的寻迹小车套件,做了个寻迹小车和遥控功能.后来看到了平衡小车就想搞一个. 去搜了方案基本都是平衡小车之家的编码器电机和车模,一搜好几百,学生党不太买得起. 还 ...
- 单机游戏制作系列之二——基本框架
单机游戏制作系列之二--基本框架 笔者个人的想法,是打算将这个系列的文章写成通用性的,不局限于某一种语言,也不局限于某一种引擎,但是水平有限,预计是达不到这个效果.以下仅以C++来举例,如果其他的语言 ...
- android黑科技系列——微信抢红包插件原理解析和开发实现
一.前言 自从几年前微信添加抢红包的功能,微信的电商之旅算是正式开始正式火爆起来.但是作为Android开发者来说,我们在抢红包的同时意识到了很多问题,就是手动去抢红包的速度慢了,当然这些有很多原因导 ...
- 简单平衡小车制作过程中遇到的问题
本人最近做了一个平衡小车,过程中遇到不少问题,在这里总结一下,可能也会帮助到大家 文章目录 前言 一.嫖资料,找教程 二.小车结构 三.电子元件的组装 四.写程序时(改嫖到的程序)遇到的问题 总结 前 ...
- (六)【平衡小车制作】位置式PID、直立环与速度环编程
本篇文章我将针对位置式PID算法.直立环.速度环等的编程进行详细的讲解,让每位小伙伴能够对这三个概念的编程逻辑有更加清晰的理解. 一.直立环(PD控制器) 1.中文公式 直立环输出=Kp1×角度偏差 ...
最新文章
- 数位DP 不断学习中。。。。
- STM32-超级终端显示日历
- ubuntu 安装nginx,php,mysql。常见错误解决
- 解读 Q_D, Q_Q 指针
- GPS服务端解析程序编写日记
- JQuery获取元素本身HTML
- Qt Creator基本使用方法
- 合作开发和委托开发完成成果的归属
- ipython怎么安装_ipython的两种安装方式
- 电脑故障扫描修复软件_非常时期不出门,自己在家修电脑,三例常见电脑故障排除方法。...
- Anaconda中使用图形化界面创建虚拟环境
- 开源大数据:openLookeng 虚拟化引擎
- 服务器操作系统使用相关要求,服务器操作系统使用相关要求
- Linux-nali解析IP归属信息
- word转换成pdf后图片压缩失真的解决方法
- python图层合并_Photoshop_【批量将同一背景与不同的上层合并图层的技巧】导出+Python3.X实现...
- docker使用和搭建
- opencv VideoWriter保存摄像头视频、本地视频等
- 模型选择准则之AIC和BIC
- 编写程序模拟掷骰子游戏。已知掷骰子游戏的游戏规则为:每个骰子有6面,这些面包含1、2、3、4、5、6个点,掷两枚骰子之后,计算点数之和。