【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。
在这里插入图片描述

  • 16
    点赞
  • 111
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
霍尔编码器与电机的搭配可以用于测量电机的速度信息。在给定的引用中,使用了一个13线的霍尔编码器电机,其减速比为30:1。这意味着电机转动一圈会输出390个脉冲。同时,引用中还提到了轮胎的直径为75mm,轮胎的周长为225mm。定时器采用四倍频计数,因此一圈输出1560个脉冲。通过读取定时器的计数值,可以获取编码器脉冲值。根据编码器脉冲值,可以计算出实际速度。在给定的代码中,使用了GetEncoderPulse函数来读取编码器脉冲值,并使用CalActualSpeed函数来计算速度值。这样,通过霍尔编码器和电机的搭配,可以准确获取小车的速度信息。\[1\]\[2\]\[3\] #### 引用[.reference_title] - *1* [stm32霍尔编码器电机测速原理](https://blog.csdn.net/m0_67318127/article/details/124470127)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down1,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [STM32机器人控制开发教程No.2 霍尔编码器电机测速以及增量PID控制(基于HAL库)](https://blog.csdn.net/COONEO/article/details/125909782)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值