PWM 与电机控制
让树莓派驱动机械:舵机转到指定角度、直流电机调速正反转、步进电机精确定位。关键是别让电机的大电流烧了树莓派。
让树莓派驱动机械:舵机转到指定角度、直流电机调速正反转、步进电机精确定位。关键是别让电机的大电流烧了树莓派。
Servo/AngularServo 类封装了这套编码,直接给角度即可。核心原则一图看懂:信号走 GPIO,动力走外部电源,两边共地。
直流电机、步进电机、大功率舵机的电流都远超 GPIO 的 16mA 上限(甚至超过树莓派整机供电能力)。直接接会导致:欠压死机、SD 卡损坏、烧毁 GPIO 或 SoC。必须用驱动板 + 外部电源。哪怕是小舵机,多个一起动也建议外部 5V 供电。GPIO 永远只发信号。
舵机三根线:棕/黑=GND,红=电源(5V),橙/黄=信号(接 GPIO18 硬件 PWM 脚)。单个小舵机可从树莓派 5V 脚取电,多个则用外部 5V。
# servo.py — 舵机角度控制(AngularServo 直接给角度) from gpiozero import AngularServo from time import sleep # min/max_pulse_width 需按舵机型号微调(单位秒) servo = AngularServo( 18, # GPIO18 硬件 PWM min_angle=0, max_angle=180, min_pulse_width=0.0005, # 0.5ms → 0° max_pulse_width=0.0025, # 2.5ms → 180° ) while True: servo.angle = 0 # 转到 0 度 sleep(1) servo.angle = 90 # 转到 90 度(居中) sleep(1) servo.angle = 180 # 转到 180 度 sleep(1)
用默认软件 PWM 时舵机常轻微抖动(系统调度不稳)。解决:安装 pigpio 守护进程并让 gpiozero 用它作为 pin factory——sudo apt install pigpio; sudo systemctl enable --now pigpiod,然后设环境变量 GPIOZERO_PIN_FACTORY=pigpio。pigpio 用 DMA 生成稳定 PWM,舵机纹丝不动。
L298N 接好后(见上图),gpiozero 的 Motor 类封装了方向+PWM,PWMOutputDevice 控制使能脚调速:
# dc_motor.py — 直流电机调速与换向(L298N) from gpiozero import Motor, PWMOutputDevice from time import sleep # IN1=GPIO23 IN2=GPIO24 控制方向;ENA=GPIO18 控制速度 motor = Motor(forward=23, backward=24) enable = PWMOutputDevice(18) print("正转 50% 速度") enable.value = 0.5 # PWM 占空比 = 速度 motor.forward() sleep(2) print("正转全速") enable.value = 1.0 sleep(2) print("反转 70%") enable.value = 0.7 motor.backward() sleep(2) motor.stop() # 停止 enable.off()
如果驱动板把使能脚直接跳线到高电平(不调速,只控方向),可用更简单的 Motor(..., pwm=True):
# motor 自带 PWM:value 从 -1(全速反) 到 1(全速正) from gpiozero import Motor motor = Motor(forward=23, backward=24, pwm=True) motor.value = 0.6 # 正转 60% motor.value = -0.4 # 反转 40% motor.stop()
以最常见的 28BYJ-48 步进电机 + ULN2003 驱动板为例(4 相,用 4 个 GPIO 控制)。它靠激励序列一步步转动:
# stepper.py — 28BYJ-48 步进电机(ULN2003,半步驱动) from gpiozero import OutputDevice from time import sleep # 4 根信号线接 IN1-IN4 pins = [OutputDevice(p) for p in (6, 13, 19, 26)] # 8 拍半步激励序列(每一行=四个线圈的通断状态) SEQ = [ [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], ] def step(steps, delay=0.002, direction=1): for _ in range(steps): for state in (SEQ if direction > 0 else reversed(SEQ)): for pin, val in zip(pins, state): pin.value = val sleep(delay) # 28BYJ-48 半步一圈约 4096 步 step(4096, direction=1) # 正转一圈 step(2048, direction=-1) # 反转半圈 for p in pins: p.off() # 全部断电(防发热)
| 类型 | 控制方式 | 驱动模块 | 特点 | 适用 |
|---|---|---|---|---|
| 舵机 | 50Hz PWM 定角度 | 无需(直接接) | 可保持角度,0~180° | 云台、机械关节、开关阀门 |
| 直流电机 | 方向脚 + PWM 调速 | L298N / TB6612 | 转速快,无位置反馈 | 轮子、风扇、水泵 |
| 步进电机 | 激励序列脉冲 | ULN2003 / A4988 | 精确定位,扭矩大 | 3D 打印、机械臂、精密进给 |
步进电机保持位置时线圈持续通电会发热(尤其长时间不动)。定位完成后若不需要保持扭矩,把所有线圈引脚 off() 断电,既省电又防止 ULN2003 和电机过热。需要保持位置的场合(如举着重物)才保持通电。
PWM 通过占空比控制平均功率,是电机控制的基础。软件 PWM 任意脚可用但可能抖动,硬件 PWM(GPIO12/13/18/19)稳定,用 pigpio 作 pin factory 可让软件 PWM 也很稳。舵机用 50Hz PWM 编码角度,gpiozero 的 AngularServo 直接给角度;抖动就上 pigpio。直流电机必须经 L298N(H 桥)+ 外部电源驱动,gpiozero 的 Motor 控方向、PWM 使能脚调速。步进电机(28BYJ-48+ULN2003)靠激励序列精确定位,定位后记得断电防热。贯穿全章的铁律:电机的大电流绝不从树莓派取,走外部电源,GPIO 只发信号,两电源必须共地;感性负载注意续流保护。下一章我们接上摄像头,让树莓派"看见"世界。