电机编码器反馈:闭环控制系统实战详解

电机编码器反馈:闭环控制系统实战详解

为什么需要闭环控制?

开环控制(比如直接用 PWM 驱动电机)有个致命问题:你不知道电机实际转了多少。负载变化、电压波动、摩擦力变化都会导致实际转速和位置偏离预期。

闭环控制通过编码器实时反馈电机实际状态,与目标值比较后动态调整输出,实现精准控制。这就是为什么 CNC 机床、机器人关节、云台相机都用闭环系统。

编码器类型详解

增量式编码器(Incremental Encoder)

最常见、最便宜。输出两路相位差 90° 的方波(A 相和 B 相),通过计数脉冲数计算转角,通过相位判断方向。

优点: 结构简单、成本低、响应快 缺点: 断电后丢失位置信息,需要回零操作

绝对式编码器(Absolute Encoder)

每个位置对应唯一的二进制编码,断电后位置不丢失。

优点: 无需回零、位置绝对准确 缺点: 价格高、接线复杂

磁编码器 vs 光编码器

类型精度成本抗污染典型分辨率
光电式1000-5000 PPR
磁电式100-4096 PPR
电容式1000-10000 PPR

DIY 项目推荐磁编码器(如 AS5600),便宜又耐造。

硬件清单

部件型号单价数量备注
直流电机N20 减速电机¥251带编码器版本
磁编码器AS5600¥151I2C 接口,12 位分辨率
电机驱动TB6612FNG¥81双路 H 桥,支持 PWM
主控板Arduino Nano¥151或 ESP32
电源12V 2A 适配器¥201根据电机电压选择
杜邦线-¥51 包连接线

总计:约¥88

AS5600 磁编码器接线

AS5600 支持 I2C 和模拟电压输出,这里用 I2C 模式:

AS5600Arduino Nano
VCC5V
GNDGND
SCLA5 (SCL)
SDAA4 (SDA)
OUT悬空(I2C 模式不用)

电机磁铁安装在电机轴上,AS5600 固定在距离磁铁 1-3mm 的位置。

闭环控制原理

闭环控制的核心是 PID 算法

误差 = 目标位置 - 实际位置
输出 = Kp×误差 + Ki×误差积分 + Kd×误差微分
  • P(比例): 误差越大,输出越大。但纯 P 控制会有稳态误差

  • I(积分): 累积历史误差,消除稳态误差。但过大会导致超调

  • D(微分): 预测误差变化趋势,抑制超调。对噪声敏感

完整代码示例

1. 读取编码器角度

#include 
#include 

AS5600 as5600;

void setup() {
  Serial.begin(115200);
  Wire.begin();
  as5600.begin(Wire);
}

void loop() {
  int angle = as5600.readAngle();  // 0-4095 (12 位)
  float degrees = angle * 360.0 / 4096.0;

  Serial.print(\"Angle: \");
  Serial.print(angle);
  Serial.print(\" (\");
  Serial.print(degrees);
  Serial.println(\"°)\");

  delay(100);
}

2. 完整闭环位置控制

#include 
#include 

// 编码器
AS5600 as5600;

// 电机驱动引脚
const int PWM_PIN = 9;
const int IN1_PIN = 7;
const int IN2_PIN = 8;

// PID 参数
float Kp = 2.0;
float Ki = 0.5;
float Kd = 1.0;

// 控制变量
int targetPosition = 0;
int currentPosition = 0;
float integral = 0;
float lastError = 0;
unsigned long lastTime = 0;

void setup() {
  Serial.begin(115200);
  Wire.begin();
  as5600.begin(Wire);

  pinMode(PWM_PIN, OUTPUT);
  pinMode(IN1_PIN, OUTPUT);
  pinMode(IN2_PIN, OUTPUT);

  // 初始化电机停止
  analogWrite(PWM_PIN, 0);
}

void loop() {
  // 读取目标位置(串口输入)
  if (Serial.available()) {
    targetPosition = Serial.parseInt();
    integral = 0;  // 重置积分
    lastError = 0;
    Serial.print(\"Target: \");
    Serial.println(targetPosition);
  }

  // 读取当前位置
  currentPosition = as5600.readAngle();

  // PID 计算
  int error = targetPosition - currentPosition;
  unsigned long currentTime = millis();
  float dt = (currentTime - lastTime) / 1000.0;  // 秒

  if (dt > 0) {
    integral += error * dt;
    float derivative = (error - lastError) / dt;

    float output = Kp * error + Ki * integral + Kd * derivative;

    // 限制输出范围
    output = constrain(output, -255, 255);

    // 驱动电机
    driveMotor(output);

    lastError = error;
    lastTime = currentTime;
  }

  // 调试输出
  Serial.print(\"Pos: \");
  Serial.print(currentPosition);
  Serial.print(\" Err: \");
  Serial.print(error);
  Serial.print(\" Out: \");
  Serial.println((int)output);

  delay(10);  // 100Hz 控制频率
}

void driveMotor(float pwm) {
  if (pwm > 0) {
    digitalWrite(IN1_PIN, HIGH);
    digitalWrite(IN2_PIN, LOW);
    analogWrite(PWM_PIN, pwm);
  } else if (pwm  2048) delta -= 4096;
  if (delta  50) {
  output = (output > 0) ? 20 : -20;
}

实际应用场景

  • 云台相机: 保持相机稳定,抵消手部抖动

  • 机器人关节: 精准控制机械臂角度

  • 平衡车: 实时调整电机保持平衡

  • CNC 进给轴: 精确控制刀具位置

  • 卷扬机: 恒张力控制

总结

闭环控制是电机控制的进阶技能,核心在于:

  1. $1

  2. $1

  3. $1

从开环到闭环,你的项目会从”能动”升级到”精准可控”。

希望这篇博客文章对您有所帮助!