Arduino直流电机编码器测速实战:从硬件连接到算法优化

1次阅读
没有评论

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

image.webp

硬件方案

编码器选型建议

在直流电机测速场景中,增量式编码器的选择直接影响测量精度。根据实际项目经验,推荐以下规格:

Arduino 直流电机编码器测速实战:从硬件连接到算法优化

  • 分辨率 :200-600 CPR(每转脉冲数),兼顾精度与处理负担
  • 输出类型 :正交 AB 相输出(带 Z 相归零信号更佳)
  • 供电电压 :5V 兼容型号(如 HEDM-5500 系列)

接线与抗干扰设计

典型连接示意图:

[编码器] ----> [Arduino]
  A 相 ---------- D2(外部中断 0)B 相 ---------- D3(外部中断 1)VCC ---------- 5V
  GND ---------- GND

关键抗干扰措施:

  • 在编码器输出线并联 104 陶瓷电容(0.1μF)
  • 使用双绞线传输信号
  • 电机电源与逻辑电源地线单点共接

软件实现

中断服务程序设计

  1. 引脚初始化配置

    const byte encoderPinA = 2;  // 中断 0 对应引脚
    const byte encoderPinB = 3;  // 中断 1 对应引脚
    volatile long pulseCount = 0;
    
    void setup() {pinMode(encoderPinA, INPUT_PULLUP);
      pinMode(encoderPinB, INPUT_PULLUP);
      attachInterrupt(digitalPinToInterrupt(encoderPinA), isrA, CHANGE);
      attachInterrupt(digitalPinToInterrupt(encoderPinB), isrB, CHANGE);
    }

  2. 正交解码中断处理

    void isrA() {
      // 根据 B 相状态判断方向
      if(digitalRead(encoderPinB) == digitalRead(encoderPinA)) {pulseCount++;} else {pulseCount--;}
    }
    
    void isrB() {
      // 反向逻辑处理
      if(digitalRead(encoderPinA) != digitalRead(encoderPinB)) {pulseCount++;} else {pulseCount--;}
    }

转速计算算法

采用定时采样法,每 100ms 计算一次转速:

  1. 时间基准设置

    unsigned long lastTime = 0;
    const long sampleInterval = 100; // 毫秒 

  2. 带滤波的转速计算

    float calculateRPM() {
      static float filteredRPM = 0;
      static long lastCount = 0;
    
      unsigned long currentTime = millis();
      if(currentTime - lastTime >= sampleInterval) {
        long deltaCount = pulseCount - lastCount;
        lastCount = pulseCount;
    
        // 原始 RPM 计算(60000ms/min / 脉冲数每转 / 采样间隔 ms)float rawRPM = (deltaCount * 60000.0) / (200 * sampleInterval); 
    
        // 一阶低通滤波(α=0.2)filteredRPM = 0.8 * filteredRPM + 0.2 * rawRPM;
    
        lastTime = currentTime;
        return filteredRPM;
      }
      return -1; // 未到采样时间
    }

避坑指南

中断冲突预防

  • 避免在中断中调用 delay() 等阻塞函数
  • 关键变量使用 volatile 修饰(如 pulseCount)
  • 中断服务程序执行时间控制在 10μs 以内

信号毛刺处理

实际示波器捕捉到的典型干扰波形:

 正常信号:______|¯¯|____|¯¯|____
毛刺信号:___|¯|_|¯¯¯|__|¯|___

解决方法:

  1. 硬件方案:如前所述添加滤波电容
  2. 软件方案:在中断中增加去抖延时
    void isrA() {
      static unsigned long lastTrigger = 0;
      if(micros() - lastTrigger < 200) return; // 200μs 消抖
      lastTrigger = micros();
      // ... 原有逻辑...
    }

性能验证

测试数据(200CPR 编码器):

设定转速 (RPM) 测量均值 波动范围
300 298.6 ±2.1
800 795.3 ±4.7
1500 1482.1 ±8.9

滤波算法效果对比(1500RPM 工况):

  • 原始数据波动:±132 RPM
  • 滤波后波动:±8.9 RPM

扩展思考

多电机系统扩展

  1. 使用中断引脚更多的控制器(如 Arduino Mega)
  2. 采用多路复用器扩展中断输入
  3. 为每个电机分配独立计数器变量

与 PID 控制器集成

转速测量代码可直接作为 PID 反馈输入:

#include <PID_v1.h>

double setpoint = 500, input, output;
PID myPID(&input, &output, &setpoint, 2,5,1, DIRECT);

void setup() {myPID.SetMode(AUTOMATIC);
}

void loop() {input = calculateRPM();
  myPID.Compute();
  analogWrite(motorPWMpin, output);
}

进阶实践问题

  1. 如何利用 Z 相信号实现绝对位置校准?
  2. 当转速超过编码器最大响应频率时,有哪些替代测速方案?
  3. 怎样通过 FFT 分析判断机械传动系统异常?

通过本方案的实施,我们在 AGV 小车项目中实现了±1% 的转速测量精度。特别提醒注意:电机碳刷火花是主要干扰源,必要时可增加磁环抑制高频噪声。希望这篇实战总结能为您的电机控制项目提供有效参考。

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