在接下来的时间里,我将记录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
#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);
attachInterrupt(ENCODER_L, READ_ENCODER_L, CHANGE);
attachInterrupt(ENCODER_R, READ_ENCODER_R, CHANGE);
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)
{
Velocity_Left = Velocity_L*2/interrupt_time; Velocity_L = 0;
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。
|