步进电机
这一节我们学习如何使用我们的 ESP32 开发板来控制步进电机。
实验原理
步进电机是一种通过步进(即以固定的角度移动)方式使轴旋转的电机。其内部构造使它无需传感器,通过简单的步数计算即可获知轴的确切角位置。这种特性使它适用于多种应用。
步进电机广泛应用于各种需要控制位置和速度的场景,例如:
- CNC 机床:用于控制刀具的位置和速度。
- 3D 打印机:用于控制打印头的位置和速度。
- 自动化设备:用于控制各种运动部件的位置和速度。
- 机器人:用于控制机器人的运动。
与所有电机一样,步进电机也包括固定部分(定子)和活动部分(转子)。定子上有缠绕了线圈的齿轮状突起,而转子为永磁体或可变磁阻铁芯。稍后我们将更深入地介绍不同的转子结构。
步进电机的基本工作原理为:
- 给一个或多个定子相位通电,线圈中通过的电流会产生磁场,而转子会与该磁场对齐;
- 依次给不同的相位施加电压,转子将旋转特定的角度并最终到达需要的位置。
下图显示了其工作原理。首先,线圈 A 通电并产生磁场,转子与该磁场对齐;线圈 B 通电后,转子顺时针旋转 60° 以与新的磁场对齐;线圈 C 通电后也会出现同样的情况。下图中定子小齿的颜色指示出定子绕组产生的磁场方向。
我们今天实验用到的是 28BYJ-48 步进电机,28BYJ-48 含义:28
指的是电机最大外径,B
指的是步进式电机,Y
指的是永磁式电机,J
指的是减速型电机,48
表示可以四相八拍。换句话说,28BYJ-48 的含义为外径 28 毫米四相八拍式永磁减速型步进电机。
首先我们需要了解什么是 4相永磁式
,28BYJ-48 的内部结构示意图如下所示。先看里圈,它上面有 6 个齿,分别标注为 0~5,这个叫做转子,顾名思义,它是要转动的,转子的每个齿上都带有永久的磁性,是一块永磁体,这就是 永磁式
的概念。再看外圈,这个就是定子,它是保持不动的,实际上它是跟电机的外壳固定在一起的,它上面有 8 个齿,而每个齿上都缠上了一个线圈绕组,正对着的 2 个齿上的绕组又是串联在一起的,也就是说正对着的 2 个绕组总是会同时导通或关断的,如此就形成了 4 相,在图中分别标注为 A-B-C-D,这就是 4相
的概念。
步进电机驱动方式三种工作模式:
单四拍
:这是最简单的步进电机驱动方式。这种方式,电机在每个瞬间只有一个线圈导通,消耗电力小。但在切换瞬间时没有任何的电磁作用在转子上,容易造成振动,也容易因为惯性而失步;双四拍
:这种方式输出的转矩较大且振动较少,切换过程中至少有一个线圈通电作用于转子,使得输出的转矩较大,振动较小,也比单四拍平稳,不易失步;八拍
:综合上述两种驱动信号,使用单四拍和双四拍交替进行的方式,每传送一个励磁信号,步进电机前进半个步距角。其特点是分辨率高,运转更加平滑,也是最常用的一种方式;
下面是这三种驱动方式的时序波形图:
接着,我们需要了解一下他的工作原理,假定电机的起始状态就如上图所示,逆时针方向转动,起始时是 B 相绕组的开关闭合,B 相绕组导通,那么导通电流就会在正上和正下两个定子齿上产生磁性,这两个定子齿上的磁性就会对转子上的 0 和 3 号齿产生最强的吸引力,就会如图所示的那样,转子的 0 号齿在正上、3 号齿在正下而处于平衡状态;此时我们会发现,转子的 1 号齿与右上的定子齿也就是 C 相的一个绕组呈现一个很小的夹角,2 号齿与右边的定子齿也就是 D 相绕组呈现一个稍微大一点的夹角。
接下来,我们把 B 相绕组断开,而使 C 相绕组导通,右上的定子齿将对转子 1 号齿产生最大的吸引力,而左下的定子齿将对转子 4 号齿,产生最大的吸引力,在这个吸引力的作用下,转子 1、4 号齿将对齐到右上和左下的定子齿上而保持平衡。
再接下来,断开 C 相绕组,导通 D 相绕组,过程与上述的情况完全相同,最终将使转子 2、5 号齿与定子 D 相绕组对齐,转子又转过了上述同样的角度。
当 A 相绕组再次导通,即完成一个 B-C-D-A 的四节拍操作后,转子的 0、3 号齿将由原来的对齐到上下 2 个定子齿,而变为了对齐到左上和右下的两个定子齿上,即转子转过了一个定子齿的角度。依此类推,再来一个四节拍,转子就将再转过一个齿的角度,8个四节拍以后转子将转过完整的一圈,而其中单个节拍使转子转过的角度就很容易计算出来了,即 360°/(8 * 4) = 11.25°
,这个值就叫做 步进角度
。而上述这种工作模式就是步进电机的 单四拍模式
。
八拍
就是在单四拍的每两个节拍之间再插入一个双绕组导通的中间节拍,组成八拍模式。比如,在从 B 相导通到 C 项导通的过程中,假如一个 B 相和 C 相同时导通的节拍,这个时候,由于 B、C 两个绕组的定子齿对它们附近的转子齿同时产生相同的吸引力,这将导致这两个转子齿的中心线对比到 B、C 两个绕组的中心线上。这样一来,就使转动精度增加了一倍,而转子转动一圈则需要 8*8=64 拍。
双四拍
的工作模式其实就是把八拍模式中的两个绕组同时通电的那四拍单独拿出来,而舍弃掉单绕组通电的那四拍而已。其步进角度同单四拍是一样的,但由于它是两个绕组同时导通,所以扭矩会比单四拍模式大。
八拍模式
是这类4相步进电机的最佳工作模式,能最大限度的发挥电机的各项性能,也是绝大多数实际工程中所选择的模式。
转子转 64 圈,最终输出轴才会转一圈,也就是需要 64×64=4096 个节拍输出轴才转过一圈。4096 个节拍转动一圈,那么一个节拍转动的角度(步进角度)就是 360/4096 度。
单片机的管脚输出电流较小,只有零点几个毫安,吸纳电没也只有十几个毫安(大多数单片机只有几个毫安),输出最高电压也不会越过 5V,由于这个原因很少用单片机直接驱动外设。ULN2003 的作用就是把单片机的信号进行放大,吸纳电流可以达到 500mA,耐压也提高很多,基本能满足微型步进电机的驱动电流和电压。
硬件电路设计
物料清单(BOM 表):
材料名称 | 数量 |
---|---|
28BYJ-48 步进电机 | 1 |
ULN2003 驱动板 | 1 |
杜邦线(跳线) | 若干 |
面包板 | 1 |
步进电机有防呆插头,直接插在电路板上即可。
软件程序设计
我们先通过代码来了解,如何通过 ULN2003 驱动步进电机转动指定步数,我们已经知道八拍模式下,4096 个节拍转动一圈,那我们如果想要转动半周,也就是 180°,就需要 2048 拍,我们的代码,每次循环走每 8 拍(四拍模式下虽然走的是四拍,但是与八拍转动相同的角度)。因此,我们需要循环 2048/8=256 次,才能转动 180°。
那如果我们想要转动其他角度就可以通过这么一个公式 4096/8 * 角度/360
来计算。
import time
from machine import Pin
a = Pin(13, Pin.OUT)
b = Pin(12, Pin.OUT)
c = Pin(14, Pin.OUT)
d = Pin(27, Pin.OUT)
delay_time = 2 # 这个时间不能设置太小,否则电机来不及响应
print("单四拍模式")
for i in range (256): # 顺时针转动180度
a.value(1)
b.value(0)
c.value(0)
d.value(0)
time.sleep_ms(delay_time)
a.value(0)
b.value(1)
c.value(0)
d.value(0)
time.sleep_ms(delay_time)
a.value(0)
b.value(0)
c.value(1)
d.value(0)
time.sleep_ms(delay_time)
a.value(0)
b.value(0)
c.value(0)
d.value(1)
time.sleep_ms(delay_time)
# 改变脉冲的顺序, 可以方便的改变转动的方向
for i in range (256): # 逆时针转动转动180度
a.value(0)
b.value(0)
c.value(0)
d.value(1)
time.sleep_ms(delay_time)
a.value(0)
b.value(0)
c.value(1)
d.value(0)
time.sleep_ms(delay_time)
a.value(0)
b.value(1)
c.value(0)
d.value(0)
time.sleep_ms(delay_time)
a.value(1)
b.value(0)
c.value(0)
d.value(0)
time.sleep_ms(delay_time)
# 双四拍模式
print("双四拍模式")
for i in range (256): # 顺时针转动 180 度
a.value(1)
b.value(1)
c.value(0)
d.value(0)
time.sleep_ms(delay_time)
a.value(0)
b.value(1)
c.value(1)
d.value(0)
time.sleep_ms(delay_time)
a.value(0)
b.value(0)
c.value(1)
d.value(1)
time.sleep_ms(delay_time)
a.value(1)
b.value(0)
c.value(0)
d.value(1)
time.sleep_ms(delay_time)
print('八拍模式')
for i in range(256):
a.value(1)
b.value(0)
c.value(0)
d.value(0)
time.sleep_ms(delay_time)
a.value(1)
b.value(1)
c.value(0)
d.value(0)
time.sleep_ms(delay_time)
a.value(0)
b.value(1)
c.value(0)
d.value(0)
time.sleep_ms(delay_time)
a.value(0)
b.value(1)
c.value(1)
d.value(0)
time.sleep_ms(delay_time)
a.value(0)
b.value(0)
c.value(1)
d.value(0)
time.sleep_ms(delay_time)
a.value(0)
b.value(0)
c.value(1)
d.value(1)
time.sleep_ms(delay_time)
a.value(0)
b.value(0)
c.value(0)
d.value(1)
time.sleep_ms(delay_time)
a.value(1)
b.value(0)
c.value(0)
d.value(1)
time.sleep_ms(delay_time)
# 步进电机停止后需要使四个相位引脚都为低电平,否则步进电机会发热
a.value(0)
b.value(0)
c.value(0)
d.value(0)
使用第三方模块驱动步进电机
我们也可以使用 ULN2003
的第三方模块驱动步进电机,把一下代码上传到 libs
目录下的 uln2003.py
文件中。
# libs/uln2003.py
import time
# only test for uln2003
class Uln2003:
FULL_ROTATION = int(4075.7728395061727 / 8)
HALF_STEP = [
[1, 0, 0, 0],
[1, 1, 0, 0],
[0, 1, 0, 0],
[0, 1, 1, 0],
[0, 0, 1, 0],
[0, 0, 1, 1],
[0, 0, 0, 1],
[1, 0, 0, 1],
]
FULL_STEP = [
[1, 1, 0, 0],
[0, 1, 1, 0],
[0, 0, 1, 1],
[1, 0, 0, 1]
]
def __init__(self, pin1, pin2, pin3, pin4, delay, mode='FULL_STEP'):
if mode == 'FULL_STEP':
self.mode = self.FULL_STEP
else:
self.mode = self.HALF_STEP
self.pin1 = pin1
self.pin2 = pin2
self.pin3 = pin3
self.pin4 = pin4
self.delay = delay # Recommend 10+ for FULL_STEP, 1 is OK for HALF_STEP
# Initialize all to 0
self.reset()
def step(self, count, direction=1):
"""Rotate count steps. direction = -1 means backwards"""
if count < 0:
direction = -1
count = -count
for x in range(count):
for bit in self.mode[::direction]:
self.pin1(bit[0])
self.pin2(bit[1])
self.pin3(bit[2])
self.pin4(bit[3])
time.sleep_ms(self.delay)
self.reset()
def angle(self, r, direction=1):
self.step(int(self.FULL_ROTATION * r / 360), direction)
def reset(self):
# Reset to 0, no holding, these are geared, you can't move them
self.pin1(0)
self.pin2(0)
self.pin3(0)
self.pin4(0)
接着在其他程序中调用 Uln2003
这个类即可,代码如下:
from machine import Pin
from libs.uln2003 import Uln2003
motor = Uln2003(pin1=Pin(13), pin2=Pin(12), pin3=Pin(14), pin4=Pin(27), delay=2, mode='HALF_STEP')
motor.angle(180, -1)