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++;
}
运行与验证
- 将代码烧录至Arduino,连接电机、编码器与驱动板。
- 打开串口监视器(波特率115200),观察输出格式:
目标转速,实际转速。 - 使用串口绘图器(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
以上为代码逻辑直接推出的理想收敛序列,实际值受电机负载与编码器精度影响会有波动。
常见问题:若电机不转,检查PWM引脚是否支持analogWrite(Arduino UNO的9/10/11脚支持);若转速测量值跳变剧烈,检查编码器脉冲数配置是否正确,并确认中断引脚连接无误。