用Arduino给玩具小车装个“油门”:手把手实现PWM调速电机

想象一下,当你按下遥控器上的加速按钮,玩具小车从静止逐渐加速到飞驰——这种平滑的速度变化背后,正是PWM(脉冲宽度调制)技术在发挥作用。不同于简单的"开/关"控制,PWM让Arduino具备了模拟"油门踏板"的能力,通过精确调节电机的能量输入来实现无级变速。本文将带你用最常见的L298N驱动模块和直流减速电机,构建一个可交互的调速系统,无论是用旋钮电位器还是按键控制,都能体验到真实的速度反馈。

1. 项目核心:为什么PWM是电机调速的最佳选择

直接连接Arduino引脚到电机时,你会发现两个致命问题:一是数字引脚仅能输出40mA电流,而即便是小型电机启动时也需要200mA以上;二是即使使用大电流引脚,电机也只能全速或停止,无法实现速度调节。这就是PWM技术的关键应用场景—— 用数字信号模拟模拟量输出

PWM通过快速切换高低电平(通常频率在500Hz-20kHz),利用占空比(高电平时间占比)来控制平均电压。例如:

  • 25%占空比 = 平均电压1.25V(假设电源5V)
  • 75%占空比 = 平均电压3.75V

对于电机而言,这种高频开关人耳听不见(超过18kHz),但转速会忠实反映电压变化。实际测试表明,在12V供电下:

占空比 平均电压 空载转速(RPM) 带载转速(RPM)
20% 2.4V 800 300
50% 6V 2100 1500
80% 9.6V 3500 2800

提示 :实际项目中建议使用16kHz以上PWM频率,可避免电机线圈产生的可闻噪音

2. 硬件搭建:L298N模块的智能接线方案

2.1 材料清单与安全准备

  • 主控 :Arduino Uno(其他型号需确认PWM引脚)
  • 驱动模块 :L298N双路电机驱动板(支持3A峰值电流)
  • 电机 :12V直流减速电机(带编码器版本可扩展测速功能)
  • 电源 :18650锂电池组(7.4V-12V范围)
  • 控制输入 :10KΩ线性电位器或轻触按键
  • 保护元件 :100uF电解电容(并联在电机端子)

2.2 关键接线步骤

  1. 电源隔离 :将Arduino的USB供电与电机电源完全分离

    • 驱动板的12V输入接锂电池正极
    • GND同时连接电池负极和Arduino的GND(共地必须!)
  2. 信号连接

    // Arduino引脚 => L298N信号端
    #define PWM_PIN 9   // 必须是带~的PWM引脚
    #define IN1 8       // 方向控制1
    #define IN2 7       // 方向控制2
    #define POT_PIN A0  // 电位器模拟输入
    
  3. 电机接口

    • 电机两根线接L298N的OUT1和OUT2
    • 启用板载5V稳压(跳帽保持连接)

警告 :务必先接好所有线再上电,避免电机反电动势损坏元件

3. 代码实现:从基础调速到交互优化

3.1 电位器线性控制(基础版)

void setup() {
  pinMode(PWM_PIN, OUTPUT);
  pinMode(IN1, OUTPUT);
  pinMode(IN2, OUTPUT);
  digitalWrite(IN1, HIGH);  // 设定旋转方向
  digitalWrite(IN2, LOW);
}

void loop() {
  int potValue = analogRead(POT_PIN);  // 0-1023
  int pwmValue = map(potValue, 0, 1023, 0, 255);
  analogWrite(PWM_PIN, pwmValue);
  delay(20);  // 降低采样频率
}

3.2 按键阶梯调速(进阶版)

int speedLevel = 0;  // 0-5档
const int speeds[] = {0, 60, 120, 180, 220, 255};

void loop() {
  if(digitalRead(UP_BTN) == LOW) {
    speedLevel = min(speedLevel+1, 5);
    analogWrite(PWM_PIN, speeds[speedLevel]);
    delay(300);  // 防抖
  }
  // 同理处理减速按钮...
}

3.3 加入加速度平滑处理

直接跳变PWM值会导致电机冲击,添加过渡效果:

void smoothWrite(int target) {
  static int current = 0;
  int step = (target > current) ? 1 : -1;
  while(current != target) {
    current += step;
    analogWrite(PWM_PIN, current);
    delay(10);  // 调节此值改变加速曲线
  }
}

4. 调试技巧与性能优化

4.1 常见问题排查表

现象 可能原因 解决方案
电机抖动不转 PWM频率过低 修改Timer预分频寄存器
只有全速/停止两档 电位器接触不良 更换为编码器或优质电位器
驱动模块发热严重 电机堵转或过载 检查机械结构是否卡死

4.2 高级技巧:改变PWM频率

Arduino默认PWM频率约490Hz,修改Timer1可提升至31kHz:

// 在setup()中添加
TCCR1B = (TCCR1B & 0b11111000) | 0x01; 

频率对比实验:

  • 490Hz:电机有明显啸叫,但扭矩稳定
  • 31kHz:完全静音,但低速时可能振动

4.3 扩展思考:如何实现闭环控制

通过电机编码器反馈实时转速,PID算法动态调整PWM:

#include <PID_v1.h>
double Setpoint, Input, Output;
PID myPID(&Input, &Output, &Setpoint, 2,5,1, DIRECT);

void setup() {
  myPID.SetMode(AUTOMATIC);
  Setpoint = 2000;  // 目标转速RPM
}

void loop() {
  Input = readEncoder();  // 获取实际转速
  myPID.Compute();
  analogWrite(PWM_PIN, Output);
}
Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐