🍓 第十五章 硬件接口实验范例(一):树莓派 WiFi 遥控视频车
📄 一句话概括

直流电机不能直连 GPIO,要靠 H 桥驱动板隔一层:方向由两根信号线定,速度由 PWM 占空比定,而电机的电必须来自自己的电池——只共地,不共电。

📝 本节和前面几节的关系

7-3/7-4 学的是【GPIO 输出电平】和【PWM 调亮度】,当时驱动的是 LED 这种毫瓦级负载;本节把同样的两件工具用在安培级负载上,于是必须插入一块驱动板来放大和隔离。所有【Pi 5 上 RPi.GPIO 失效】的结论(7-2)在这里继续有效:电机控制同样用 gpiozero + lgpio。

一、为什么必须经驱动板

电机和 LED 的根本区别有三条,每条都足以烧掉树莓派:

  1. 电流量级不同:GPIO 单针安全电流约 10~16mA,TT 电机空转就近百毫安、堵转可达 0.6~0.8A——差两个数量级;
  2. 电机会【倒灌】:电机是电感,断电瞬间线圈要维持电流,会从转动的方向往回送一个远高于供电的反电动势尖峰。LED 没有这个问题,电机每次开关都有;
  3. 电机要正反转:GPIO 只会给高或低,没法把电压极性倒过来。

H 桥电路一次解决这三件事:用四个开关(现代用 MOSFET)搭成一个【桥】,电机挂在桥中间,改变对角开关的通断组合,就能改变电机两端电压的极性——这就是正转与反转的物理本质。

二、方向真值表:两根线定方向

以 L298N 的 Motor A 为例(IN1/IN2 两根方向线):

IN1 IN2 结果
低 低 停止(滑行)
高 低 正转
低 高 反转
高 高 刹车(两端短接,急停)

Motor B 用 IN3/IN4,规则完全相同。记住【一高一低=转,同高同低=不转】,接线时就不会晕。

三、两块驱动板怎么选

L298N TB6612FNG
内部结构 双极型晶体管(老工艺) MOSFET(新工艺)
电压降 约 1.5~2V(发热形式浪费掉) 约 0.5V
发热 明显,要散热片 很小,通常不用散热片
单通道电流 2A 1.2A 连续/3.2A 峰值
逻辑电平 5V 兼容,3.3V 也认 3.3V 原生友好
额外引脚 — STBY 必须拉高才工作
适合 初学、12V 电机 电池车、追求效率

关键认识:L298N 那 1.5~2V 的压降不是小数目——6V 电机上等于白白损失三分之一的电压,车会明显没劲。做电池驱动的车,TB6612FNG 是更优解;手上的 L298N 也完全能跑,知道它的短板在哪就行。

四、gpiozero 的 Motor 类:把真值表封装掉

不需要自己写四路电平,Motor 类把方向+速度合成一个对象:

from gpiozero import Motor

# 左电机:IN1=GPIO17、IN2=GPIO27、ENA=GPIO12(PWM)
left  = Motor(forward=17, backward=27, enable=12, pwm=True)
# 右电机:IN3=GPIO22、IN4=GPIO23、ENB=GPIO13(PWM)
right = Motor(forward=22, backward=23, enable=13, pwm=True)

left.forward(0.6)    # 正转,速度 60%
right.forward(0.6)

三个要点:

PWM 引脚选择:GPIO12/13/18/19 是硬件 PWM 引脚,用它俩(12、13)抖动量最小;用其他引脚会走软件 PWM,有一定抖动——但电机惯性大、能吸收抖动,所以电机控速对 PWM 抖动不敏感(这点和舵机完全不同,舵机必须硬件 PWM)。

五、电源铁律:只共地,不共电

这是整章最容易翻车的地方,五条背下来:

  1. 电机电源独立:电池正负极接驱动板的电机电源输入(L298N 的 +12V/VIN,TB6612 的 VM);
  2. 只共地:树莓派的 GND 与驱动板的 GND 必须相连——PWM 信号需要一个共同的电压参考,不共地信号就是噪声;
  3. 绝不从驱动板反哺树莓派:L298N 板上的 5V 输出不要接到树莓派,电机启停的电压波动会顺着这条线灌进树莓派;
  4. 不接电机线到 GPIO:任何情况下电机两端都不碰 GPIO;
  5. 加一颗大电容(可选但推荐):在电机电源输入端并一个几百微法的电解电容,吸收尖峰。

诊断口诀:如果电机一转树莓派就重启(或屏幕出现闪电图标),九成是第 1、3 条没做好——先查电源,再怀疑代码。

六、动手 Demo:两层验证法

照坑 49 的老规矩,先验软件链路、再接硬件。

第一层:不接电机,只验代码与 pin 配置

from gpiozero import Motor
from gpiozero import Device

print("pin factory =", Device.pin_factory)   # 应看到 LGPIOFactory 之类,不是 MockFactory
m = Motor(forward=17, backward=27, enable=12, pwm=True)
m.forward(0.5)
print("value =", m.value)                     # 期望 0.5,证明对象活着
m.stop()

看到什么算成功:打印出真实 pin factory(不是 MockFactory),且 value 能读回 0.5。这一步不接电机也能跑——它证明库、引脚号、PWM 对象都正常。

第二层:接上电机,跑四向测试

from gpiozero import Motor
from time import sleep

left  = Motor(forward=17, backward=27, enable=12, pwm=True)
right = Motor(forward=22, backward=23, enable=13, pwm=True)

def stop():
    left.stop(); right.stop()

try:
    print("前进"); left.forward(0.7); right.forward(0.7); sleep(2)
    print("后退"); left.backward(0.7); right.backward(0.7); sleep(2)
    print("左转"); left.backward(0.5); right.forward(0.5); sleep(1.5)
    print("右转"); left.forward(0.5); right.backward(0.5); sleep(1.5)
finally:
    stop()
    print("已停车")

看到什么算成功:车依次前进 → 后退 → 原地左转 → 原地右转 → 停下。原地转向的原理:左右轮一个正转一个反转,车体绕中心自转。

读结果:如果某个方向反了,有两种修法——① 把那台电机的两根输出线(OUT1/OUT2)对调;② 代码里把 forward 与 backward 的引脚号互换。改线更直观,改代码更省事,选一样即可,不要两边都改(改两次等于没改)。

30 秒实验

把 forward 的速度依次改成 0.1、0.2、0.3 各跑 2 秒,观察:

for s in (0.1, 0.2, 0.3):
    print("speed =", s)
    left.forward(s); right.forward(s)
    sleep(2)
    left.stop(); right.stop(); sleep(0.5)

你会看到某个值以下轮子纹丝不动或只嗡嗡响——那就是这台电机+这套电池组合的起步阈值。这个实测值很有用:15-4 的前端滑杆下限就照它设,否则用户会觉得【按了没反应】。

七、常见误区

  1. ENA/ENB 跳线帽不用管 —— 必须拔!留着它 PWM 进不去,速度永远满速,你会以为代码写错了。
  2. 树莓派和电机用同一个电源、图省事 —— 电机启停会把噪声和电压跌落甩到同一个电轨上,轻则重启、重则坏 SD 卡;共地即可,不要共电。
  3. speed 给 0.05 就该微动 —— 真实电机有静摩擦和启动电压,低速不转是物理规律;先做上面的起步阈值实验,再定前端滑杆范围。
  4. 把 L298N 的 5V 输出接到树莓派 5V 脚上省一个充电宝 —— 这是本章最危险的做法:该 5V 由板载 78M05 从电池降压得到,电机负载一变它就波动,会直接冲击树莓派供电;务必让树莓派走自己的电源。
自测三问(点开对答案) 1. 为什么必须共地、却必须分开供电? 共地是给 PWM 信号提供统一电压参考;分开供电是防止电机启停的噪声与电压跌落污染树莓派的电源。 2. ENA 跳线帽为什么必须拔掉? 它把使能脚硬拉到高电平,PWM 信号进不去,导致只能控方向、不能控速度。 3. 电机最低能转到什么速度,是代码决定的吗? 不是。取决于电机静摩擦、启动电压、负载与电池电压——用起步阈值实验实测,再拿去设前端滑杆下限。

相关笔记