IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> 【ESP32 Arduino平衡小车制作】(一)霍尔编码器解码 -> 正文阅读

[嵌入式]【ESP32 Arduino平衡小车制作】(一)霍尔编码器解码

在接下来的时间里,我将记录ESP32 Arduino平衡小车制作的全部过程。

一、编码器介绍

1-1增量式编码器

增量式旋转编码器是将设备运动时的位移信息变成连续的脉冲信号,脉冲个数表示位移量的大小。只有当设备运动的时候增量式编码器才会输出信号。编码器一般会把这些信号分为通道A和通道B 两组输出,并且这两组信号间有90° 的相位差。同时采集这两组信号就可以知道设备的运动和方向。

增量式编码器只输出设备的位置变化和运动方向,不会输出设备的绝对位置。

1-2 绝对式编码器

绝对式旋转编码器是将设备运动时的位移信息通过二进制编码的方式变成数字量直接输出。
这种编码器与增量式编码器的区别主要在内部的码盘。

二、常用测速方法

2-1 M 法(高速):

在一个固定的定时时间内(以秒为单位),统计这段时间的编码器脉冲数,计算速度值。

设编码器单圈总脉冲数为C,在时间T0 内,统计到的编码器脉冲数为M0,则转速n 的计算公式为:公式中的编码器单圈总脉冲数C 是常数,所以转速n 跟M0 成正比。

2-2 T 法(低速):

建立一个已知频率的高频脉冲并对其计数,计数时间由捕获到的编码器相邻两个脉冲的间隔时间TE 决定,计数值为M1。

设编码器单圈总脉冲数为C,高频脉冲的频率为F0,则转速n 的计算公式为:公式中的编码器单圈总脉冲数C 和高频脉冲频率F0 是常数,所以转速n 跟M1 成反比

2-3 M-T 法:

既测量编码器脉冲数又测量一定时间内的高频脉冲数。在一个相对固定的时间内,计数编码器脉冲数M0,并计数一个已知频率为F0 的高频脉冲,计数值为M1,计算速度值

设编码器单圈总脉冲数为C,则转速n 的计算公式为:

由于M/T 法公式中的F0 和C 是常数,所以转速n 就只受M0 和M1 的影响。电机高速时,M0增大,M1 减小,相当于M 法,低速时,M1 增大,M0 减小,相当于T 法。

三、ESP32编码器程序

3-1正交信号

编码器返回的数据是一组正交信号,由于Arduino和ESP32都没有正交解码功能,所以要想实现正交解码功能的话就需要用两个io口来同时判断当前是属于状态。
在这里插入图片描述一个脉冲信号周期完成4次跳变。精度提高

1时刻:TI2为低电平,TI1上升沿跳变,计数器向上计数;

2时刻:TI1为高电平,TI2上升沿跳变,计数器仍然向上计数;

3时刻:TI2为高电平,TI1下降沿跳变,计数器仍然向上计数;

4时刻:TI1为低电平,TI2下降沿跳变,计数器仍然向上计数。

3-2 代码编写

首先需要宏定义当前的使用的io口和中断时间。

#define ENCODER_L 	5  //编码器采集引脚 每路2个 共4个
#define DIRECTION_L 18
#define ENCODER_R   4
#define DIRECTION_R 19
#define interrupt_time 20 // 中断时间

配置对应的io口,一个编码器需要两个io口,一个用来检测外部跳边沿中断,另一个来判断方向。

但是这个对于毛刺确实无法识别的,当有毛刺出现的时候也会计做是正常的脉冲,这也就是为什么esp32做软件正交解码的缺点,计数值也会改变

#include <Arduino.h>
#include<Ticker.h>

Ticker timer_read_encoder;  // 中断函数定时器定义

void setup()
{
    Serial.begin(115200);

	pinMode(ENCODER_L, INPUT);       //编码器引脚 输入模式
	pinMode(ENCODER_R, INPUT);       //编码器引脚 输入模式
	pinMode(DIRECTION_L, INPUT);     //编码器引脚 输入模式
	pinMode(DIRECTION_R, INPUT);     //编码器引脚 输入模式
	
	//编码器接口1 开启外部跳边沿中断 
	attachInterrupt(ENCODER_L, READ_ENCODER_L, CHANGE);  //中断函数READ_ENCODER_L
	//编码器接口2 开启外部跳边沿中断 
	attachInterrupt(ENCODER_R, READ_ENCODER_R, CHANGE);  //中断函数READ_ENCODER_R
	
	interrupts();                      //打开外部中断  
    timer_read_encoder.attach_ms(interrupt_time, read);  
}

void loop()
{
	Serial.print("Velocity_L:");Serial.print(Velocity_L);
	Serial.print(" | Velocity_Left:");Serial.println(Velocity_Left);
	Serial.print("Velocity_R:");Serial.print(Velocity_R);
	Serial.print(" | Velocity_Right:");Serial.println(Velocity_Right);
}

下面的部分放到主函数之前就可以,主要是跳变沿中断函数READ_ENCODER_L ()和READ_ENCODER_R()和定时器中断函数READ()。


int32_t Velocity_L, Velocity_R;   //左右轮编码器数据
int16_t Velocity_Left, Velocity_Right;     //左右轮速度


void READ_ENCODER_L(void);
void READ_ENCODER_R(void);
void read(void);


/**************************************************************************
函数功能:外部中断读取编码器数据,具有二倍频功能 注意外部中断是跳变沿触发
入口参数:无
返回  值:无
**************************************************************************/
void READ_ENCODER_L(void) {
  if (digitalRead(ENCODER_L) == LOW) {     //如果是下降沿触发的中断
    if (digitalRead(DIRECTION_L) == LOW)      Velocity_L--;  //根据另外一相电平判定方向
    else      Velocity_L++;
  }
  else {     //如果是上升沿触发的中断
    if (digitalRead(DIRECTION_L) == LOW)      Velocity_L++; //根据另外一相电平判定方向
    else     Velocity_L--; 
  }
}
/**************************************************************************
函数功能:外部中断读取编码器数据,具有二倍频功能 注意外部中断是跳变沿触发
入口参数:无
返回  值:无
**************************************************************************/
void READ_ENCODER_R(void) {
  if (digitalRead(ENCODER_R) == LOW) { //如果是下降沿触发的中断
    if (digitalRead(DIRECTION_R) == LOW)      Velocity_R--;//根据另外一相电平判定方向
    else      Velocity_R++;
  }
  else {   //如果是上升沿触发的中断
    if (digitalRead(DIRECTION_R) == LOW)      Velocity_R++; //根据另外一相电平判定方向
    else     Velocity_R--;
  }
}
void read(void)
{
/**************************************************************************
计算为转速n/s  500线光电编码器数据 定时时间为20MS
 转速 = num/500/20ms
 转速 = num*2/time
**************************************************************************/
    Velocity_Left = Velocity_L*2/interrupt_time;    Velocity_L = 0;  //读取左轮编码器数据,并清零,这就是通过M法测速(单位时间内的脉冲数)得到速度。
    Velocity_Right = Velocity_R*2/interrupt_time;    Velocity_R = 0; //读取右轮编码器数据,并清零
   
}

四、速度计算

首先我们的esp32实际使用的m法测速,即:计算固定时间内的脉冲数。
编码器如果想把速断计算为转速n/s具体步骤如下:

①明确参数:编码器规格:500线(转一圈是500个脉冲), 定时时间为interrupt_time(单位MS)

②固定时间内的圈数M:脉冲数num/500

③转换为秒:固定时间内的圈数/interrupt_time(单位ms)

总的来说公式就是num*2/interrupt_time,

这里我的时间是20ms,所以转速为num/500/20ms=num*40。
在这里插入图片描述

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2022-05-09 12:53:52  更:2022-05-09 12:55:19 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 2:44:18-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码