霍尔传感器是根据据霍尔效应制作的一du种磁场传感器。霍尔效应zhi是磁电效应的一种,这一现dao象是霍尔(A.H.Hall,1855—1938)于1879年在研究金属的导电机构时发现的。后来发现半导体、导电流体等也有这种效应,而半导体的霍尔效应比金属强得多,利用这现象制成的各种霍尔元件,广泛地应用于工业自动化技术、检测技术及信息处理等方面。霍尔效应是研究半导体材料性能的基本方法。通过霍尔效应实验测定的霍尔系数,能够判断半导体材料的导电类型、载流子浓度及载流子迁移率等重要参数。
磁场中有一个霍尔半导体片,恒定电流I从A到B通过该片。在洛仑兹力的作用下,I的电子流在通过霍尔半导体时向一侧偏移,使该片在CD方向上产生电位差,这就是所谓的霍尔电压。
霍尔电压随磁场强度的变化而变化,磁场越强,电压越高,磁场越弱,电压越低,霍尔电压值很小,通常只有几个毫伏,但经集成电路中的放大器放大,就能使该电压放大到足以输出较强的信号。若使霍尔集成电路起传感作用,需要用机械的方法来改变磁感应强度。下图所示的方法是用一个转动的叶轮作为控制磁通量的开关,当叶轮叶片处于磁铁和霍尔集成电路之间的气隙中时,磁场偏离集成片,霍尔电压消失。这样,霍尔集成电路的输出电压的变化,就能表示出叶轮驱动轴的某一位置,利用这一工作原理,可将霍尔集成电路片用作用点火正时传感器。霍尔效应传感器属于被动型传感器,它要有外加电源才能工作,这一特点使它能检测转速低的运转情况。
每台编码器的规格指标中,都有标明线数是多少。
单位是:线/圈
假设是1024线/圈,那么就意味着编码器每转一圈,就将送出1024个A相和1024个B相的脉冲。
如果是一倍频(就是完整的接收到一个A相脉冲上升沿和一个B相脉冲上升沿后,计一个脉冲),那么就是接收到1024个脉冲;如果是4倍频(每一个A相和B相脉冲的上升沿和下降沿都计一个脉冲,那么一对AB相脉冲,接收器就计4个),那么就是接收到4096个脉冲。
因为在Micropython的Timer库中有专门的编码器读取模式,该模式是在CH1和CH2改变时改变,所以技术方式为4倍频。
Timer.ENC_AB
— 配置编码器模式下的定时器。定时器只在CH1和CH2改变时改变。本电机对应的脉冲计速方法
线数为390,即在一倍频、单相的情况下,每圈会有390个脉冲;在四倍频、AB相的情况下,每圈会有1560个脉冲。
MG540 | PYB |
---|---|
编码器A相 | X1(TIM2,CH1) |
编码器B相 | X2(TIM2,CH2) |
编码器5V | V+(Vin) |
编码器GND | GND |
电机12V | 12V电源 |
电机GND | 电源GND |
使用putty远程连接输入代码,进行测试:
from pyb import Timer, Pin
#定义引脚
p1 = Pin("X1")
p2 = Pin("X2")
tim=pyb.Timer(2)
tim.init(prescaler=0,period=10000)
ch1=tim.channel(1,pyb.Timer.ENC_AB,pin=p1)
ch2=tim.channel(2,pyb.Timer.ENC_AB, pin=p2)
tim.counter()
将以下代码写入main.py中,进行执行即可。
from pyb import Timer, Pin
def cb(t):
pyb.LED(3).toggle()
print(tim.counter())
#配置编码器AB相读取模式,利用定时器中断进行读取
p1 = Pin("X1")
p2 = Pin("X2")
tim=pyb.Timer(2)
tim.init(prescaler=0,period=10000, callback=cb)
ch1=tim.channel(1,pyb.Timer.ENC_AB,pin=p1)
ch2=tim.channel(2,pyb.Timer.ENC_AB, pin=p2)
将以下代码写入main.py中,进行执行即可。
from pyb import Timer, Pin
#配置编码器AB相读取模式,利用定时器中断进行读取
p1 = Pin("X1")
p2 = Pin("X2")
tim=pyb.Timer(2)
tim.init(prescaler=0,period=10000)
ch1=tim.channel(1,pyb.Timer.ENC_AB,pin=p1)
ch2=tim.channel(2,pyb.Timer.ENC_AB, pin=p2)
def cb2(t):
print(tim.counter()) #读取编码器值
tim.counter(0) #将编码器值设未0,清0
tim2=pyb.Timer(10,freq=10,callback=cb2)
以10的频率定时返回编码器的当前值。
即在0.1s内,编码器发出了XXX个脉冲。通过脉冲可以算出当前的速度。
为了方便使用,在这里我将编码器读取任务封装为一个py模块。
encoder.py
import pyb
from pyb import Timer, Pin
import cmath
"""
入口参数:编码器读取频率
# 编码器电机参数参考
1.光电编码器电机(MG513P30_12V)的参数:
减速比:1:30
分辨率(电机驱动线数):500ppr(编码器精度,转一圈输出的脉冲数)
2.霍尔编码器电机()的参数:
减速比:1:30
分辨率:13ppr
# 底盘机械参数参考
标准轮式机器人硬件尺寸参数:
轮子直径:6.5cm
两轮间距:16cm
履带式机器人硬件尺寸参数:
轮子直径:4cm
两轮间距:23cm
"""
class Encoder:
'''
机器人自身及编码器电机配置
'''
def __init__(self, encoder_freq):
'''————————————————————————————可调参数——————————————————————————————————'''
# -------底盘机械参数--------
self.wheel_distance = 0.160 # 轮间距,单位:cm
self.Wheel_diameter = 0.065 # 轮直径:单位:cm
# -------编码器电机参数--------
reduction_ratio = 1/30 # 减速比,
resolution_ratio = 500 # 分辨率,单位:ppr
'''————————————————————————————系统参数——————————————————————————————————'''
#配置编码器AB相读取模式,利用定时器中断进行读取
p1_A = Pin("Y1"); p2_A = Pin("Y2");
tim_A = Timer(8)
tim_A.init(prescaler=0,period=10000)
ch1_A = tim_A.channel(1,Timer.ENC_AB,pin=p1_A); ch2_A = tim_A.channel(2,Timer.ENC_AB, pin=p2_A);
p1_B = Pin("X1"); p2_B = Pin("X2");
tim_B = Timer(5)
tim_B.init(prescaler=0,period=10000)
ch1_B = tim_B.channel(1,Timer.ENC_AB,pin=p1_B); ch2_B = tim_B.channel(2,Timer.ENC_AB, pin=p2_B)
# 初始化系统参数
freq_multiplier = 4 # 倍频数
self.pi = cmath.pi # pi的值
self.encoder_freq = encoder_freq
self.encoder_precision = freq_multiplier * resolution_ratio / reduction_ratio # 编码器精度 = 倍频数*编码器精度(电机驱动线数)*电机减速比
self.tim_A = tim_A
self.tim_B = tim_B
self.encoder_A = 0
self.encoder_B = 0
# 定时器中断:固定时间读取编码器数值
timer_read = Timer(10,freq=self.encoder_freq,callback=self.encoder_cb)
def encoder_cb(self, encoder):
'''
函数功能:通过定时器中断读取编码器A、B计数值,并重置编码器
'''
if self.tim_B.counter() > 5000:
self.encoder_B = 10000 - self.tim_B.counter()
else:
self.encoder_B = -self.tim_B.counter()
self.tim_B.counter(0)
if self.tim_A.counter() > 5000:
self.encoder_A = -(10000 - self.tim_A.counter())
else:
self.encoder_A = self.tim_A.counter()
self.tim_A.counter(0)
def target_enc_process(self, speed):
'''
函数功能:将目标速度值转化为目标编码器值
入口参数:目标速度值
返回值 :目标编码器值
# 目标编码器值=(目标速度*编码器精度)/(轮子周长*控制频率)
'''
enc = (speed*self.encoder_precision) / ( (self.pi*self.Wheel_diameter) * self.encoder_freq)
return enc
def enc_to_speed(self, enc):
'''
函数功能:将编码器值转化为速度值
入口参数:编码器值
返回值:速度值
速度值=(采集到的脉冲数/编码器精度)*轮子周长*控制频率
'''
speed = (enc / self.encoder_precision) * (self.pi*self.Wheel_diameter) * self.encoder_freq
return speed
'''
# 已知量,单位m
v = 0 # 机器人的线速度
w = 0 # 机器人的角速度
v_l = 0 # 左轮速度
v_r = 0 # 右轮速度
D = 0.2 # 轮间距
d = D/2
# 速度、角速度、左右轮速的关系式
v_l = v + wd
v_r = v - wd
v = (v_l + v_r)/2
w = (v_l - v_r)/D
'''
def speed_to_anglin(self, speed_A, speed_B):
'''
函数功能:将两轮速度值转化为角速度和线速度值
入口参数:两轮速度值
返回值:角速度,线速度
'''
linear_vel = (speed_A + speed_B)/2
angular_vel = (speed_B - speed_A)/self.wheel_distance
return angular_vel, linear_vel
def anglin_to_speed(self, angular_vel, linear_vel):
'''
函数功能:将角速度和线速度值转化为两轮速度值
入口参数:角速度,线速度
返回值:两轮速度值
'''
speed_A = linear_vel - angular_vel * self.wheel_distance/2
speed_B = linear_vel + angular_vel * self.wheel_distance/2
return speed_A, speed_B
main.py
import encoder
if __name__ == '__main__':
# 编码器初始化
print("编码器初始化----")
encoder_freq = 100 # 编码器读取频率,一般都为100Hz
enc = encoder.Encoder(encoder_freq)
# 获取当前编码器值
enc_A = enc.encoder_A
enc_B = enc.encoder_B
speed_A = enc.enc_to_speed(enc_A)
speed_B = enc.enc_to_speed(enc_B)
angular_vel, linear_vel = enc.speed_to_anglin(speed_A, speed_B)
可以直接看我的另一篇基于PYB和编码器的PID调节博客:
Micropython——基于PYB的霍尔编码器电机的PID控制