1. 项目概述
直流电机调速控制在工业自动化、机器人、智能家居等领域有着广泛应用。传统的开环控制方式虽然简单,但存在转速波动大、抗干扰能力差等问题。这次我选择在STM32平台上实现基于PID算法的闭环调速控制,主要解决以下三个核心问题:
- 如何通过编码器准确获取电机实时转速
- PID控制器的参数整定与算法实现
- PWM输出与电机驱动的硬件接口设计
这个方案特别适合需要精确控制转速的场景,比如3D打印机送料系统、智能小车驱动、传送带控制等。相比开环控制,闭环调速可以将转速误差控制在±2%以内,响应时间缩短50%以上。
2. 硬件系统设计
2.1 核心器件选型
电机驱动部分我选用L298N双H桥模块,主要考虑以下几点:
- 支持5-35V宽电压输入
- 峰值电流可达2A
- 内置续流二极管保护电路
- 价格低廉(约15元/片)
编码器选用增量式光电编码器,分辨率为500线/转。通过STM32的定时器编码器接口模式,可以实现四倍频计数,最终达到2000脉冲/转的测量精度。
注意:L298N模块需要加装散热片,长时间工作建议配合散热风扇使用。我在实测中发现,当电流超过1A时,芯片温度会迅速升至60℃以上。
2.2 STM32外围电路设计
关键电路包括:
- PWM生成电路:使用TIM1的CH1通道,频率设置为20kHz
- 编码器接口电路:配置TIM2为编码器模式
- 过流保护电路:在电机电源回路串联0.1Ω采样电阻
电路原理图如下:
c复制// PWM输出配置
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8; // TIM1_CH1
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// 编码器接口配置
TIM_EncoderInterfaceConfig(TIM2, TIM_EncoderMode_TI12,
TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);
3. PID算法实现
3.1 离散化PID公式
采用位置式PID算法,离散化公式为:
code复制u(k) = Kp*e(k) + Ki*∑e(j) + Kd*[e(k)-e(k-1)]
其中:
- u(k):当前控制量输出
- e(k):当前误差(设定转速-实际转速)
- Kp/Ki/Kd:比例、积分、微分系数
在STM32中的代码实现:
c复制typedef struct {
float Kp, Ki, Kd;
float integral;
float prev_error;
} PID_Controller;
float PID_Update(PID_Controller* pid, float setpoint, float measurement) {
float error = setpoint - measurement;
pid->integral += error;
float derivative = error - pid->prev_error;
float output = pid->Kp * error
+ pid->Ki * pid->integral
+ pid->Kd * derivative;
pid->prev_error = error;
return output;
}
3.2 参数整定方法
采用试凑法进行参数整定:
- 先将Ki和Kd设为0,逐步增大Kp直到系统出现等幅振荡
- 记录此时的临界增益Ku和振荡周期Tu
- 根据Ziegler-Nichols公式:
- Kp = 0.6*Ku
- Ki = 2*Kp/Tu
- Kd = Kp*Tu/8
实测参数:
- 对于我的直流电机(12V/3000RPM):
- Ku=1.2, Tu=0.15s
- 最终参数:Kp=0.72, Ki=9.6, Kd=0.0135
经验分享:积分项容易导致超调,实际使用时需要对积分项做限幅处理。我设置积分限幅为±1000,有效避免了"积分饱和"现象。
4. 软件架构设计
4.1 主程序流程
mermaid复制graph TD
A[系统初始化] --> B[外设配置]
B --> C[PID参数初始化]
C --> D[开启定时器中断]
D --> E[主循环等待]
4.2 定时器中断服务
每10ms执行一次控制循环:
c复制void TIM3_IRQHandler(void) {
if(TIM_GetITStatus(TIM3, TIM_IT_Update)) {
// 1. 读取编码器值计算转速
uint16_t encoder = TIM_GetCounter(TIM2);
float rpm = (encoder * 6000) / (2000 * 0.01); // 2000脉冲/转,10ms采样
// 2. PID计算
float pwm = PID_Update(&pid, target_rpm, rpm);
// 3. 输出PWM
TIM_SetCompare1(TIM1, (uint16_t)pwm);
TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
}
}
5. 调试与优化
5.1 常见问题排查
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| 电机抖动 | PWM频率过低 | 提高至20kHz以上 |
| 转速不稳 | 机械负载变化大 | 增加微分系数 |
| 响应迟缓 | PID参数过小 | 按3.2节重新整定 |
| 超调严重 | 积分项过大 | 减小Ki或加积分限幅 |
5.2 性能优化技巧
- 使用DMA传输编码器数据,减轻CPU负担
- 将PID计算移出中断,改用RTOS任务
- 添加软件滤波处理编码器噪声:
c复制// 移动平均滤波
#define FILTER_SIZE 5
float filter_buf[FILTER_SIZE];
float moving_average(float new_val) {
static uint8_t index = 0;
filter_buf[index++] = new_val;
if(index >= FILTER_SIZE) index = 0;
float sum = 0;
for(uint8_t i=0; i<FILTER_SIZE; i++) {
sum += filter_buf[i];
}
return sum / FILTER_SIZE;
}
6. 实测数据对比
测试条件:空载,目标转速1500RPM
| 控制方式 | 稳态误差 | 调节时间 | 超调量 |
|---|---|---|---|
| 开环PWM | ±120RPM | - | - |
| 纯P控制 | ±25RPM | 0.8s | 15% |
| PI控制 | ±10RPM | 0.5s | 8% |
| PID控制 | ±5RPM | 0.3s | 3% |
从实测数据可以看出,完整的PID控制将转速波动从开环时的±120RPM降低到±5RPM,控制精度提升24倍。
7. 扩展应用
基于这个核心框架,还可以实现以下功能扩展:
- 多电机同步控制:通过CAN总线协调多个电机
- 位置伺服控制:将转速环作为内环,外环增加位置控制
- 自适应PID:根据负载变化自动调整参数
我在实际项目中曾用类似方案实现过雕刻机主轴控制,转速稳定性直接影响加工表面质量。通过加入温度补偿算法,在长时间工作时机轴温升导致的转速漂移从原来的8%降低到1%以内。