基于位置式PID算法调节PWM占空比实现电机转速控制
一、系统架构设计
1. 硬件组成
模块 | 核心组件 | 功能说明 |
---|---|---|
主控单元 | STM32F407(TIM1+TIM2) | PWM生成与PID运算 |
电机驱动 | TB6612(PWMA/PWMB) | PWM输入控制电机转速 |
反馈装置 | 霍尔编码器(500线) | 转速检测(2000脉冲/转) |
电源模块 | 12V/2A DC电源 | 电机供电 |
2. 电路连接
STM32引脚连接 | 功能说明
----------------------------|----------------------------
TIM1_CH1 (PA8) | 电机PWM输出
TIM2_CH1 (PA0) | 编码器A相信号输入
TIM2_CH2 (PA1) | 编码器B相信号输入
PB6 (BOOT0) | 电机方向控制
3.3V | 编码器供电
GND | 公共地
二、PID算法实现
1. 位置式PID公式
u(k)=Kpe(k)+Kii=0∑ke(i)+Kd[e(k)−e(k−1)]u(k)=Kpe(k)+Kii=0∑ke(i)+Kd[e(k)−e(k−1)]u(k)=Kpe(k)+Kii=0∑ke(i)+Kd[e(k)−e(k−1)]
- 输入变量:目标转速(Setpoint)与实际转速(Feedback)的差值
- 输出变量:PWM占空比(0-100%)
2. 关键参数定义
c
typedef struct {
float Kp; // 比例系数(建议初始值2.0-5.0)
float Ki; // 积分系数(建议初始值0.1-0.5)
float Kd; // 微分系数(建议初始值0.01-0.1)
float integral;// 积分项累加值
float prev_err;// 上一次误差
float max_out; // 输出上限(PWM最大占空比)
} PID_HandleTypeDef;
3. PID初始化函数
c
void PID_Init(PID_HandleTypeDef *pid, float Kp, float Ki, float Kd) {
pid->Kp = Kp;
pid->Ki = Ki;
pid->Kd = Kd;
pid->integral = 0.0f;
pid->prev_err = 0.0f;
pid->max_out = 100.0f; // PWM占空比上限
}
4. PID计算函数
c
float PID_Compute(PID_HandleTypeDef *pid, float setpoint, float feedback, float dt) {
float error = setpoint - feedback;
// 比例项
float Pout = pid->Kp * error;
// 积分项
pid->integral += error * dt;
float Iout = pid->Ki * pid->integral;
// 微分项
float derivative = (error - pid->prev_err) / dt;
float Dout = pid->Kd * derivative;
// 计算总输出
float output = Pout + Iout + Dout;
// 输出限幅
if(output > pid->max_out) {
pid->integral -= error * dt; // 防止积分饱和
output = pid->max_out;
} else if(output < 0) {
output = 0;
}
pid->prev_err = error;
return output;
}
三、硬件驱动实现
1. PWM配置(STM32 HAL库)
c
void MX_TIM1_Init(void) {
TIM_HandleTypeDef htim1;
htim1.Instance = TIM1;
htim1.Init.Prescaler = 84-1; // 84MHz / 84 = 1MHz
htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
htim1.Init.Period = 1000-1; // 1kHz PWM频率
htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
HAL_TIM_PWM_Init(&htim1);
// 配置通道1
TIM_OC_InitTypeDef sConfigOC = {0};
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = 0; // 初始占空比0%
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1);
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);
}
2. 编码器测速
c
volatile uint32_t encoder_count = 0;
volatile float motor_speed = 0.0f;
// 编码器中断处理(TIM2)
void TIM2_IRQHandler(void) {
if(TIM_GetITStatus(TIM2, TIM_IT_CC1) != RESET) {
if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_1) == GPIO_PIN_SET) {
encoder_count++;
}
TIM_ClearITPendingBit(TIM2, TIM_IT_CC1);
}
}
// 计算转速(每100ms更新一次)
void Calc_Speed() {
static uint32_t last_count = 0;
static float rpm = 0.0f;
motor_speed = (encoder_count - last_count) * 60.0f / 0.1f; // 500线编码器
last_count = encoder_count;
}
四、主控制循环
c
int main(void) {
HAL_Init();
SystemClock_Config();
MX_TIM1_Init(); // PWM初始化
MX_TIM2_Init(); // 编码器初始化
PID_HandleTypeDef motor_pid;
PID_Init(&motor_pid, 2.5f, 0.2f, 0.05f); // 初始参数
while(1) {
Calc_Speed(); // 更新转速测量值
float duty = PID_Compute(&motor_pid, 1000.0f, motor_speed, 0.001f); // 1kHz采样
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, duty); // 更新占空比
HAL_Delay(1);
}
}
参考代码 位置式PID调节PWM占空比控制电动机转速 www.youwenfan.com/contentcsj/70961.html
五、参数整定方法
1. Ziegler-Nichols法
步骤 | 操作 | 结果记录 |
---|---|---|
1 | 关闭I/D项(Ki=0, Kd=0) | 基准Kp值 |
2 | 逐渐增大Kp至系统持续振荡 | 记录Ku和Tu |
3 | 计算PID参数: | |
Kp = 0.6*Ku | ||
Ki = 1.2*Ku/Tu | ||
Kd = 0.075KuTu |
2. 实际调试建议
- 初始参数:Kp=2.0, Ki=0.1, Kd=0.01
- 调整顺序:先调P→再调I→最后调D
- 典型调试现象: Kp过小:响应慢,稳态误差大 Kp过大:超调严重,振荡 Ki过大:积分饱和,爬行现象 Kd过大:噪声敏感,产生振荡