【PID】STM32通过闭环PID控制电机系统
一、系统方案设计
1. 硬件架构
-
主控芯片:STM32F4/F3系列(带高级定时器,如TIM1/TIM8)。
-
电机类型:直流有刷电机(带正交编码器反馈)。
-
驱动器:H桥驱动芯片(如L298N或DRV8833),支持PWM调速和方向控制。
-
反馈装置:增量式正交编码器(分辨率:1000 PPR)。
-
通信接口:可选UART/USB用于调试和参数调整。
2. 控制流程
-
编码器读取:通过定时器硬件捕获编码器脉冲,计算实时转速。
-
PID计算:根据设定转速与反馈转速的偏差,计算PWM输出。
-
PWM输出:调整占空比控制电机转速,形成闭环。
二、关键代码配置及函数详解
1. 定时器配置(PWM生成)
// TIM1初始化,通道1输出PWM
void MX_TIM1_Init(void) {
TIM_HandleTypeDef htim1;
TIM_OC_InitTypeDef sConfigOC = {0};
htim1.Instance = TIM1;
htim1.Init.Prescaler = 0; // 无分频
htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
htim1.Init.Period = 8399; // PWM频率=84MHz/(8400)≈10kHz
htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
HAL_TIM_PWM_Init(&htim1);
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = 0; // 初始占空比0%
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1);
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1); // 启动PWM
}
2. 编码器接口配置(定时器编码器模式)
// TIM2初始化,编码器模式
void MX_TIM2_Init(void) {
TIM_Encoder_InitTypeDef sEncoderConfig = {0};
TIM_HandleTypeDef htim2 = {0};
htim2.Instance = TIM2;
htim2.Init.Prescaler = 0;
htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
htim2.Init.Period = 0xFFFF; // 16位计数器
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
// 配置编码器模式(正交解码)
sEncoderConfig.EncoderMode = TIM_ENCODERMODE_TI12;
sEncoderConfig.IC1Polarity = TIM_ICPOLARITY_RISING;
sEncoderConfig.IC1Selection = TIM_ICSELECTION_DIRECTTI;
sEncoderConfig.IC1Prescaler = TIM_ICPSC_DIV1;
sEncoderConfig.IC1Filter = 0;
sEncoderConfig.IC2Polarity = TIM_ICPOLARITY_RISING;
sEncoderConfig.IC2Selection = TIM_ICSELECTION_DIRECTTI;
sEncoderConfig.IC2Prescaler = TIM_ICPSC_DIV1;
sEncoderConfig.IC2Filter = 0;
HAL_TIM_Encoder_Init(&htim2, &sEncoderConfig);
HAL_TIM_Encoder_Start(&htim2, TIM_CHANNEL_ALL); // 启动编码器
}
3. 定时器中断配置(PID周期计算)
// TIM3初始化,10ms中断触发PID计算
void MX_TIM3_Init(void) {
TIM_HandleTypeDef htim3;
htim3.Instance = TIM3;
htim3.Init.Prescaler = 8400 - 1; // 84MHz/8400=10kHz
htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
htim3.Init.Period = 100 - 1; // 10kHz/100=100Hz(10ms)
HAL_TIM_Base_Init(&htim3);
HAL_TIM_Base_Start_IT(&htim3); // 启动中断
}
4. PID算法实现
typedef struct {
float Kp, Ki, Kd;
float integral, prev_error;
} PIDController;
float PID_Compute(PIDController *pid, float setpoint, float measurement) {
float error = setpoint - measurement;
pid->integral += error * 0.01f; // 积分项(10ms周期)
float derivative = (error - pid->prev_error) / 0.01f; // 微分项
float output = pid->Kp * error + pid->Ki * pid->integral + pid->Kd * derivative;
pid->prev_error = error;
// 输出限幅(0~100%占空比)
if (output > 8399) output = 8399;
else if (output < 0) output = 0;
return output;
}
5. 中断服务函数(关键逻辑)
// 定时器中断回调函数(10ms执行一次)
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
if (htim->Instance == TIM3) {
static int32_t prev_count = 0;
int32_t curr_count = TIM2->CNT; // 读取编码器计数值
int32_t delta = curr_count - prev_count;
prev_count = curr_count;
// 计算转速(假设编码器1000PPR,10ms周期)
float speed_rpm = (delta * 6000.0f) / (1000 * 4); // 4倍频处理
// PID计算并更新PWM
float output = PID_Compute(&pid, target_speed, speed_rpm);
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, (uint32_t)output);
}
}
三、关键配置注意事项
-
编码器接口
-
使用定时器的编码器模式(如TIM2/TIM3),自动处理A/B相信号的正交计数。
-
注意编码器倍频(4倍频常见),需在转速计算时修正。
-
-
PWM频率选择
-
电机驱动器支持的频率范围(通常1kHz-20kHz),避免高频噪声或驱动损耗。
-
-
中断优先级
-
PID计算中断(TIM3)需高于编码器计数中断(TIM2),确保实时性。
-
-
抗积分饱和
-
在PID结构体中加入输出限幅,或使用积分分离算法。
-
-
方向控制
-
若需双向控制,可通过GPIO设置电机方向,或配置互补PWM通道。
-
四、调试步骤
-
开环测试:先验证PWM输出和电机转向。
-
编码器读数:手动旋转电机,检查TIM2计数值变化。
-
PID参数整定:
-
先设
Ki=0, Kd=0
,逐步增大Kp
至系统震荡,然后减小到80%。 -
加入
Ki
消除稳态误差,最后加入Kd
抑制超调。
-
通过此方案,可实现高精度的电机闭环控制