1. 直流电机速度闭环PID控制

任务目标

实现基于增量式PID的直流电机速度闭环控制。给定目标转速,通过编码器反馈实际转速,PID控制器输出PWM占空比调节电机电压,使转速稳定在设定值,并观察阶跃响应曲线。

环境与依赖

  • 硬件:直流电机+编码器(如霍尔编码器)、电机驱动板(如L298N)、Arduino UNO(或STM32)
  • 软件:Arduino IDE 或 PlatformIO
  • 无外部库依赖,纯手写PID逻辑

核心实现

以下代码在Arduino上实现完整闭环:编码器中断计数→计算实际转速→增量式PID→PWM输出。采样周期固定为10ms。

// 引脚定义
#define ENC_A 2   // 编码器A相(中断引脚)
#define ENC_B 3   // 编码器B相
#define PWM_PIN 9
#define DIR_PIN 8

// PID参数(需整定)
float Kp = 2.0, Ki = 0.5, Kd = 0.1;
float target_rpm = 120.0;   // 目标转速

// 全局变量
volatile long encoder_count = 0;
float current_rpm = 0.0;
float prev_error = 0.0, integral = 0.0;
unsigned long last_time = 0;
const float PULSES_PER_REV = 20.0;  // 编码器每转脉冲数(根据实际修改)
const float SAMPLE_TIME = 0.01;     // 10ms

void setup() {
  pinMode(ENC_A, INPUT_PULLUP);
  pinMode(ENC_B, INPUT_PULLUP);
  pinMode(PWM_PIN, OUTPUT);
  pinMode(DIR_PIN, OUTPUT);
  attachInterrupt(digitalPinToInterrupt(ENC_A), encoder_isr, RISING);
  Serial.begin(115200);
  last_time = millis();
}

void loop() {
  // 固定采样周期执行
  if (millis() - last_time >= SAMPLE_TIME * 1000) {
    // 1. 计算实际转速(单位:RPM)
    noInterrupts();
    long count = encoder_count;
    encoder_count = 0;
    interrupts();
    current_rpm = (count / PULSES_PER_REV) * 60.0 / SAMPLE_TIME;

    // 2. 增量式PID计算
    float error = target_rpm - current_rpm;
    float output = Kp * error + Ki * integral + Kd * (error - prev_error);
    integral += error * SAMPLE_TIME;
    prev_error = error;

    // 3. 输出限幅(PWM 0~255)
    output = constrain(output, 0, 255);
    analogWrite(PWM_PIN, (int)output);
    digitalWrite(DIR_PIN, HIGH);  // 正转

    // 4. 串口输出用于绘图
    Serial.print(target_rpm);
    Serial.print(",");
    Serial.println(current_rpm);

    last_time = millis();
  }
}

void encoder_isr() {
  // 简单计数,不判断方向(单方向控制)
  encoder_count++;
}

运行与验证

  1. 将代码烧录至Arduino,连接电机、编码器与驱动板。
  2. 打开串口监视器(波特率115200),观察输出格式:目标转速,实际转速。
  3. 使用串口绘图器(Arduino IDE自带)或Python matplotlib读取串口数据绘制曲线。

通过条件:启动后约1~2秒内实际转速稳定在目标值±5%范围内,阶跃响应无明显超调或持续振荡。若转速波动大,增大Kp;若稳态误差大,增大Ki;若响应振荡,增大Kd或减小Kp。

预期输出(示例)

120.00,0.00
120.00,45.32
120.00,98.76
120.00,118.43
120.00,121.05
120.00,119.87
120.00,120.12

以上为代码逻辑直接推出的理想收敛序列,实际值受电机负载与编码器精度影响会有波动。

目标120RPM 时间 (s) 转速 (RPM) 实际转速响应 上升阶段 稳态(±5%) 0

常见问题:若电机不转,检查PWM引脚是否支持analogWrite(Arduino UNO的9/10/11脚支持);若转速测量值跳变剧烈,检查编码器脉冲数配置是否正确,并确认中断引脚连接无误。