3.15. 直流电机控制¶
有刷直流电机本质上是处于磁场中的轴上缠绕的一圈线圈。让电流流过线圈,磁场便会对其施加一个力;这个力转化为轴上的转矩。电机内部的电刷会随着轴的转动切换线圈中的电流方向,使转矩始终朝同一方向推动轴转动。在电机的两根引线两端施加直流电压,轴就会旋转;将极性反过来,它就会朝另一方向旋转。
电机通常需要数百毫安到数安的电流,且供电电压高于摄像头 3.3 V 的逻辑电平轨。一个 GPIO 引脚只能提供大约 25 mA 的电流,并且无法反转极性——它只能驱动它自己的两条电平轨。摄像头与电机之间的驱动级必须能够承载电机的电流、引入一路独立的较高电压电机电源,并能在指令下让摄像头反转极性。四晶体管的 H 桥(H-bridge)就是标准的解决方案。
3.15.1. H 桥¶
H 桥是围绕电机排布成 H 形的四个开关:
H 桥:四个开关(S1 -- S4)将电机 M 连接在 Vmotor 与地之间。¶
闭合不同的开关组合,决定了电机在其引线上所看到的电压:
S1 + S4 闭合,S2 + S3 断开。 电流从 Vmotor 经过
S1流入A,穿过电机到达B,再经过S4流向地。电机朝一个方向转动。S2 + S3 闭合,S1 + S4 断开。 电流以相反方向流过电机。电机朝另一个方向转动。
四个开关全部断开。 电机两根引线都悬空;电机自由滑行。
S3 + S4 闭合(或 S1 + S2 闭合)。 电机两根引线被连到同一条电平轨上;电机自身的动能驱动的电流被这对闭合的开关短路,以热量形式耗散掉。电机制动。
非法的组合是闭合同一列中的两个开关——S1 + S3 或 S2 + S4——这会形成一条从 Vmotor 直接到地的短路。这就是直通(shoot-through),摄像头的代码必须杜绝它。
实际中,这四个开关是位于集成驱动 IC 内部的 MOSFET(已在 电平转换 页面中介绍)。该芯片对外提供两到三个逻辑电平输入引脚,它们在内部映射到这四个开关,并包含防止直通的互锁逻辑,因此摄像头的代码无需直接管理它。
3.15.2. PWM 与电机的电感¶
设定电机的转速所需的不仅仅是全开和全关。这里用到的技巧与 使用 PWM 进行 LED 调光 中用于 LED 的技巧相同:以高频率脉冲驱动负载,让负载对结果取平均。对于 LED,取平均的是人眼;对于电机,取平均的则是线圈本身。
电机线圈具有相当大的电感。流过电感的电流不能瞬间改变;它的变化速率与其两端的电压成正比。以 20 kHz 频率开关 H 桥,会在每个导通阶段使线圈电流上升,而在关断阶段,电流必须继续流动——线圈会反转自身两端的电压以维持电流。
如果电流无处可去,它会使刚刚断开的开关两端电压向上飙升,可能损坏晶体管。跨接在每个开关上的续流二极管(freewheeling diode)——往往就是驱动芯片内部 MOSFET 自身的体二极管——为电流提供了所需的通路。电流流经一个二极管,再绕回流过某个仍处于闭合状态的开关,完成一个续流回路,电流在该回路中通过 H 桥和电机本身的微小电阻逐渐衰减。该二极管还将断开开关两端的电压钳位在回路返回的那条电平轨的一个二极管压降范围之内,远在 MOSFET 的安全工作区之内。
在每个 PWM 周期内,电流的平均值才是产生转矩的因素,而这个平均值与占空比呈线性关系——占空比加倍,转矩大致加倍,在恒定负载下转速也大致加倍。与 LED 调光不同(人眼的非线性响应需要一条曲线),duty_u16 的线性扫描本身就对应于电机出力的线性扫描。
PWM 频率只需越过两个阈值即可:
在约 20 kHz 以上,载波处于人耳可听频带之外。低于该频率时,线圈上的磁力会随每个 PWM 脉冲上下变化,绕组和叠片会以载波频率发生物理振动——电机实际上变成了一个小喇叭,发出与 PWM 频率相应音高的声音。
在远高于约 50 kHz 时,MOSFET 及其栅极驱动器开始因开关损耗而损失效率。在每次开关转换过程中,MOSFET 会短暂地同时承受较大的电压和较大的电流,以热量形式耗散一小股功率;MOSFET 的栅极电容也必须在每个周期被充电和放电,这由驱动芯片承担。这两种代价都随 PWM 频率上升,因此在高频率下,开关产生的热量可能与导通电机电流所产生的热量相当。
对于业余爱好级别大小的电机,20 kHz 是理想的默认值。
3.15.3. 驱动 H 桥¶
双输入 H 桥驱动芯片大致按如下方式将 IN1 和 IN2 映射到四个开关:
IN1 = 0, IN2 = 0—— 自由滑行(四个开关全部断开)。IN1 = 1, IN2 = 0—— 朝一个方向驱动。IN1 = 0, IN2 = 1—— 朝另一个方向驱动。IN1 = 1, IN2 = 1—— 制动。
将这两个输入作为 PWM 输出来驱动,摄像头便可通过选择两个引脚中哪一个承载占空比来设定方向,并通过占空比的数值本身来设定转速:
import time
from machine import PWM, Pin
in1 = PWM(Pin("P7"), freq=20_000, duty_u16=0)
in2 = PWM(Pin("P8"), freq=20_000, duty_u16=0)
def drive_a(speed): # speed: 0..65535
in1.duty_u16(speed)
in2.duty_u16(0)
def drive_b(speed):
in1.duty_u16(0)
in2.duty_u16(speed)
def coast():
in1.duty_u16(0)
in2.duty_u16(0)
def brake():
in1.duty_u16(65535)
in2.duty_u16(65535)
drive_a(32768) # half speed in direction A
time.sleep(2)
drive_b(16384) # quarter speed in direction B
time.sleep(2)
coast()
从关闭斜升到全速再斜降回来,可实现平滑的启动和停止:
for d in range(0, 65535, 256):
in1.duty_u16(d)
time.sleep_ms(10)
for d in range(65535, 0, -256):
in1.duty_u16(d)
time.sleep_ms(10)
3.15.4. 方向与速度型驱动器¶
另一类 H 桥芯片提供了更便利的接口:一个数字方向输入(常标记为 DIR 或表示"相位"的 PH)外加一个速度输入(常为 PWM 或表示"使能"的 EN)。方向引脚决定 H 桥的驱动方向;速度引脚上的占空比设定平均电流。
相比双 PWM 输入方案,这种方式在软件中更易于驱动。这两个信号与问题通常的表述方式相吻合——"朝这个方向转,以这个速度转"——因此代码可以写成 set_direction(forward); set_speed(50),而无需在 in1 和 in2 之间分支处理。只需要一个 PWM 通道,从而释放出同一定时器上的另一个通道去处理无关的任务。而且方向引脚在两次更改之间可以保持不动而不会重新触发 H 桥,因此在固定方向下改变速度只需操作一个寄存器。
import time
from machine import PWM, Pin
dir_pin = Pin("P8", Pin.OUT)
speed = PWM(Pin("P7"), freq=20_000, duty_u16=0)
def drive(direction, speed_u16):
dir_pin.value(direction) # 0 or 1
speed.duty_u16(speed_u16) # 0..65535
drive(0, 32768) # direction A at half speed
time.sleep(2)
drive(1, 16384) # direction B at quarter speed
time.sleep(2)
speed.duty_u16(0) # stop
在这类驱动器上,"停止"实际执行的是什么——自由滑行还是制动——取决于芯片。对于双输入驱动器,由摄像头的代码决定(两个输入都置低为滑行,都置高为制动);而对于方向与速度型驱动器,则由芯片决定,因此在依赖任一行为之前,最好查阅一下数据手册。