You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

树莓派4 L298N驱动电机机器人如何添加PWM调速控制

树莓派L298N驱动电机50%功率调速实现

核心逻辑

L298N电机驱动的调速引脚为ENA(控制A通道即左电机)、ENB(控制B通道即右电机),之前代码电机满速是因为直接将这两个引脚置为高电平,没有通过PWM占空比调节输出功率。用RPi.GPIO库自带的PWM功能即可实现调速,PWM频率选1000Hz是L298N适配的常用值,不会产生明显电机啸叫。

PWM初始化与功率设置函数

PWM对象只需要在程序启动时初始化一次,不需要每次运动重复创建。功率设置函数接收0-100的数值,对应电机输出0%-100%的满功率,要实现50%功率传值50即可。

import RPi.GPIO as GPIO
import time

# 引脚定义 按实际接线修改为对应的BCM编号
IN1 = 17  # 左电机正转控制
IN2 = 27  # 左电机反转控制
IN3 = 22  # 右电机正转控制
IN4 = 23  # 右电机反转控制
ENA = 12  # 左电机PWM调速引脚
ENB = 13  # 右电机PWM调速引脚

# 全局PWM实例 初始化后全局复用
pwm_left = None
pwm_right = None

def init_hardware():
    global pwm_left, pwm_right
    GPIO.setmode(GPIO.BCM)
    GPIO.setwarnings(False)
    # 所有控制引脚设为输出模式
    for pin in [IN1, IN2, IN3, IN4, ENA, ENB]:
        GPIO.setup(pin, GPIO.OUT)
    # 初始化PWM 频率1000Hz 初始占空比0(上电静止)
    pwm_left = GPIO.PWM(ENA, 1000)
    pwm_right = GPIO.PWM(ENB, 1000)
    pwm_left.start(0)
    pwm_right.start(0)

def set_motor_power(percent):
    """设置所有电机输出功率,percent取值0-100对应0%-100%满功率"""
    # 边界校验 防止输入超范围触发报错
    percent = max(0, min(100, percent))
    pwm_left.ChangeDutyCycle(percent)
    pwm_right.ChangeDutyCycle(percent)

运动逻辑中的调用方法

所有运动控制函数(前进、后退、左转、右转)在设置完四个方向引脚的电平后,直接调用set_motor_power(50)即可让电机以50%功率运转;停止时调用set_motor_power(0)切断动力输出。

def forward(run_time):
    # 方向设置:双电机正转
    GPIO.output(IN1, GPIO.HIGH)
    GPIO.output(IN2, GPIO.LOW)
    GPIO.output(IN3, GPIO.HIGH)
    GPIO.output(IN4, GPIO.LOW)
    # 设置50%功率
    set_motor_power(50)
    time.sleep(run_time)
    # 到达运行时间后停车
    stop()

def backward(run_time):
    # 方向设置:双电机反转
    GPIO.output(IN1, GPIO.LOW)
    GPIO.output(IN2, GPIO.HIGH)
    GPIO.output(IN3, GPIO.LOW)
    GPIO.output(IN4, GPIO.HIGH)
    set_motor_power(50)
    time.sleep(run_time)
    stop()

def left_rotate(run_time):
    # 原地左转:左电机反转、右电机正转
    GPIO.output(IN1, GPIO.LOW)
    GPIO.output(IN2, GPIO.HIGH)
    GPIO.output(IN3, GPIO.HIGH)
    GPIO.output(IN4, GPIO.LOW)
    set_motor_power(50)
    time.sleep(run_time)
    stop()

def right_rotate(run_time):
    # 原地右转:左电机正转、右电机反转
    GPIO.output(IN1, GPIO.HIGH)
    GPIO.output(IN2, GPIO.LOW)
    GPIO.output(IN3, GPIO.LOW)
    GPIO.output(IN4, GPIO.HIGH)
    set_motor_power(50)
    time.sleep(run_time)
    stop()

def stop():
    # 所有方向引脚拉低 功率设为0
    for pin in [IN1, IN2, IN3, IN4]:
        GPIO.output(pin, GPIO.LOW)
    set_motor_power(0)

完整可运行代码

import RPi.GPIO as GPIO
import time

# 引脚定义 请根据实际接线修改BCM编号
IN1 = 17
IN2 = 27
IN3 = 22
IN4 = 23
ENA = 12
ENB = 13

pwm_left = None
pwm_right = None

def init_hardware():
    global pwm_left, pwm_right
    GPIO.setmode(GPIO.BCM)
    GPIO.setwarnings(False)
    for pin in [IN1, IN2, IN3, IN4, ENA, ENB]:
        GPIO.setup(pin, GPIO.OUT)
    pwm_left = GPIO.PWM(ENA, 1000)
    pwm_right = GPIO.PWM(ENB, 1000)
    pwm_left.start(0)
    pwm_right.start(0)

def set_motor_power(percent):
    percent = max(0, min(100, percent))
    pwm_left.ChangeDutyCycle(percent)
    pwm_right.ChangeDutyCycle(percent)

def forward(run_time):
    GPIO.output(IN1, GPIO.HIGH)
    GPIO.output(IN2, GPIO.LOW)
    GPIO.output(IN3, GPIO.HIGH)
    GPIO.output(IN4, GPIO.LOW)
    set_motor_power(50)
    time.sleep(run_time)
    stop()

def backward(run_time):
    GPIO.output(IN1, GPIO.LOW)
    GPIO.output(IN2, GPIO.HIGH)
    GPIO.output(IN3, GPIO.LOW)
    GPIO.output(IN4, GPIO.HIGH)
    set_motor_power(50)
    time.sleep(run_time)
    stop()

def left_rotate(run_time):
    GPIO.output(IN1, GPIO.LOW)
    GPIO.output(IN2, GPIO.HIGH)
    GPIO.output(IN3, GPIO.HIGH)
    GPIO.output(IN4, GPIO.LOW)
    set_motor_power(50)
    time.sleep(run_time)
    stop()

def right_rotate(run_time):
    GPIO.output(IN1, GPIO.HIGH)
    GPIO.output(IN2, GPIO.LOW)
    GPIO.output(IN3, GPIO.LOW)
    GPIO.output(IN4, GPIO.HIGH)
    set_motor_power(50)
    time.sleep(run_time)
    stop()

def stop():
    for pin in [IN1, IN2, IN3, IN4]:
        GPIO.output(pin, GPIO.LOW)
    set_motor_power(0)

if __name__ == "__main__":
    try:
        init_hardware()
        # 测试流程:前进2s -> 后退2s -> 左转1s -> 右转1s -> 停车
        forward(2)
        time.sleep(0.5)
        backward(2)
        time.sleep(0.5)
        left_rotate(1)
        time.sleep(0.5)
        right_rotate(1)
    except KeyboardInterrupt:
        # Ctrl+C中断时安全停车
        stop()
    finally:
        GPIO.cleanup()

常见踩坑提醒

  • L298N上ENA、ENB默认插的跳线帽必须拔掉,否则PWM信号被短路,电机永远满速,调占空比完全无效
  • PWM初始化只需要在程序启动时执行一次,别在每个运动函数里重复创建PWM对象,不然会触发GPIO占用错误,电机还会莫名抖动
  • 如果两个电机转速不一致,可以单独给左右电机的PWM实例设不同占空比做校准,不需要强制两个电机功率完全一致
  • 运行代码需要用sudo权限,否则RPi.GPIO库无法操作硬件引脚

内容的提问来源于stack exchange,提问作者Olteanu Vasile

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.01 18:42:33