Arduino电机PWM控制与编码器读取实战指南:从基础到精准调速

1次阅读
没有评论

共计 1435 个字符,预计需要花费 4 分钟才能阅读完成。

image.webp

背景痛点

刚接触 Arduino 电机控制时,我遇到了几个头疼的问题:

Arduino 电机 PWM 控制与编码器读取实战指南:从基础到精准调速

  • 速度波动大 :用 PWM 直接驱动电机,负载变化时转速像坐过山车
  • 编码器读数跳变 :手拨电机转轴时,计数器显示的值总莫名其妙乱跳
  • 驱动模块发烫 :L298N 接上没几分钟就开始烫手,有次还烧了保险丝

后来发现这些都不是个例——开环控制没有反馈,电机当然会 ” 自由发挥 ”;编码器信号线没做消抖,Arduino 读取的自然是 ” 毛刺版 ” 数据;而驱动模块发热多半是接线错误导致的短路。

硬件设计

驱动芯片选型

先对比两款常用驱动:

特性 L298N TB6612FNG
工作电压 4.5-46V 2.5-13.5V
峰值电流 2A(每路) 1.2A(连续)
效率 较低 (需散热片) 高 (内置 MOSFET)
价格 ¥15 左右 ¥25 左右

新手建议 :预算有限选 L298N,追求效率用 TB6612FNG

电路设计

这是带光耦隔离的经典接法(防止电机干扰 MCU):

[VCC]---[10Ω]---[LED]---[光耦输入端]
              |
             [220Ω]
              |
             [GND]

编码器消抖电路更简单——在信号线对地接个 0.1μF 电容就行,成本不到五毛钱。

软件实现

PWM 频率设置

Arduino 默认 PWM 频率是 490Hz,但电机响应更好的配置:

// 对于 Timer1 控制的引脚 (D9,D10)
TCCR1B = (TCCR1B & 0b11111000) | 0x02; // 设置频率为 3.9kHz

编码器中断服务

这个带滤波的例程能稳定计数:

constexpr uint8_t ENCODER_PIN = 2; // 使用 D2(中断 0)
volatile int32_t pulseCount = 0;

void setup() {attachInterrupt(digitalPinToInterrupt(ENCODER_PIN), []{
    static uint32_t lastTime = 0;
    uint32_t now = micros();
    // 防抖时间阈值 (根据实际调整)
    if(now - lastTime > 200) pulseCount++;
    lastTime = now;
  }, RISING);
}

PID 闭环控制

核心算法其实就三行:

error = targetSpeed - currentSpeed;
integral += error * dt;
output = Kp*error + Ki*integral + Kd*(error-lastError)/dt;

避坑指南

  1. 电源去耦 :在驱动模块电源引脚并接 100uF 电解电容 +0.1uF 陶瓷电容
  2. 中断保护 :在读取 pulseCount 前先 noInterrupts(),读完再 interrupts()
  3. 软启动 :用 for 循环逐步增加 PWM 占空比,别直接给最大值

验证测试

用这个代码通过串口输出转速 (单位:RPM):

void loop() {
  static uint32_t lastPrint = 0;
  if(millis() - lastPrint > 100) {
    // 编码器 500 线,计算转速公式:float rpm = (pulseCount*60000.0)/(500*100);
    Serial.println(rpm);
    pulseCount = 0;
    lastPrint = millis();}
}

在串口绘图器里能看到漂亮的阶跃响应曲线。测试发现 PWM 频率在 3 -8kHz 时电流纹波最小。

进阶思考

  1. 如何用两个编码器实现位置同步控制?
  2. 电机堵转时怎样自动降低 PWM 占空比?
  3. 能否用蓝牙模块实现无线调速?

经过两周折腾,我的小车现在能稳稳保持设定速度了。建议新手先用旧电机做实验——我已经烧坏三个电机才摸索出这些经验 (笑)。

正文完
 0
评论(没有评论)