STM32 增量式 PID 电机速度闭环实战:编码器 M 法测速与 5ms 控制周期调参

发布时间:2026/7/10 5:40:55
STM32 增量式 PID 电机速度闭环实战:编码器 M 法测速与 5ms 控制周期调参 STM32 增量式 PID 电机速度闭环实战编码器 M 法测速与 5ms 控制周期调参在智能车、机器人等嵌入式运动控制领域直流有刷电机的速度闭环控制是核心基础技术。本文将基于STM32微控制器通过增量式PID算法实现电机转速的高精度控制重点解析编码器M法测速的实现细节并针对5ms控制周期给出完整的参数整定方案。不同于理论公式的抽象讲解我们将从硬件配置、软件架构到参数调试呈现一套可直接复用的工程实践方案。1. 系统架构设计与硬件配置1.1 整体控制框图典型的电机速度闭环系统包含以下关键组件[PWM驱动器] ←→ [STM32] ←→ [编码器] ↑ ↑ ↓ [电机] [增量式PID] ← [速度反馈]核心数据流编码器实时采集电机转速STM32计算实际转速与目标转速的偏差PID算法输出PWM占空比修正值驱动器调整电机输入电压1.2 关键硬件配置定时器编码器模式配置TIMx为正交编码器接口模式捕获A/B相脉冲// HAL库配置示例以TIM4为例 TIM_Encoder_InitTypeDef encoder_config { .EncoderMode TIM_ENCODERMODE_TI12, .IC1Polarity TIM_ICPOLARITY_RISING, .IC1Selection TIM_ICSELECTION_DIRECTTI, .IC1Prescaler TIM_ICPSC_DIV1, .IC1Filter 6, // 适当滤波防抖动 .IC2Polarity TIM_ICPOLARITY_RISING, .IC2Selection TIM_ICSELECTION_DIRECTTI, .IC2Prescaler TIM_ICPSC_DIV1, .IC2Filter 6 }; HAL_TIM_Encoder_Init(htim4, encoder_config); HAL_TIM_Encoder_Start(htim4, TIM_CHANNEL_ALL);PWM输出配置生成可调占空比的PWM信号驱动电机// 以TIM3_CH1为例 TIM_OC_InitTypeDef pwm_config { .OCMode TIM_OCMODE_PWM1, .Pulse 0, // 初始占空比0% .OCPolarity TIM_OCPOLARITY_HIGH, .OCFastMode TIM_OCFAST_DISABLE }; HAL_TIM_PWM_Init(htim3); HAL_TIM_PWM_ConfigChannel(htim3, pwm_config, TIM_CHANNEL_1); HAL_TIM_PWM_Start(htim3, TIM_CHANNEL_1);注意实际工程中需根据驱动器规格确认PWM频率常见范围为10kHz-20kHz。频率过低会导致电机振动过高可能超出驱动器响应能力。2. 编码器M法测速实现2.1 测速原理M法频率法测速通过在固定时间窗口内统计编码器脉冲数计算转速。对于1024线编码器转速(rpm) (ΔCount × 60) / (1024 × 测速周期(s))其中ΔCount为测速周期内捕获的脉冲数变化量。2.2 中断服务程序实现配置5ms定时器中断进行速度采样// 在SysTick中断中调用1kHz void SpeedMeasure_ISR(void) { static int32_t last_count 0; int32_t current_count __HAL_TIM_GET_COUNTER(htim4); // 计算脉冲差值处理计数器溢出 int32_t delta (current_count - last_count) 0xFFFF; if (delta 32767) delta - 65536; g_motor_speed delta; // 存储全局速度值 __HAL_TIM_SET_COUNTER(htim4, 0); // 计数器清零 last_count 0; }2.3 速度单位换算根据机械结构参数转换为实际转速// 示例减速比30:1轮胎周长20cm float GetRealSpeed(int32_t encoder_delta) { const float gear_ratio 30.0f; const float wheel_circumference 0.2f; // meters const float counts_per_rev 1024.0f; float wheel_rpm (encoder_delta * 60.0f) / (counts_per_rev * gear_ratio * 0.005f); float linear_speed wheel_rpm * wheel_circumference / 60.0f; return linear_speed; // 单位m/s }3. 增量式PID算法实现3.1 算法核心公式增量式PID输出为控制量的变化值Δu(k) Kp×[e(k)-e(k-1)] Ki×e(k) Kd×[e(k)-2e(k-1)e(k-2)]其中e(k): 当前误差目标速度 - 实际速度e(k-1): 上一次误差Kp/Ki/Kd: 比例/积分/微分系数3.2 STM32代码实现typedef struct { float Kp, Ki, Kd; float prev_error, prev_prev_error; int16_t output_limit; // PWM输出限幅值 } PID_Controller; int16_t PID_Compute(PID_Controller* pid, float target, float actual) { float error target - actual; // 计算增量 float delta pid-Kp * (error - pid-prev_error) pid-Ki * error pid-Kd * (error - 2*pid-prev_error pid-prev_prev_error); // 更新历史误差 pid-prev_prev_error pid-prev_error; pid-prev_error error; // 输出限幅 static int16_t output 0; output (int16_t)delta; output (output pid-output_limit) ? pid-output_limit : (output -pid-output_limit) ? -pid-output_limit : output; return output; }3.3 初始化与调用示例PID_Controller speed_pid { .Kp 15.0f, .Ki 0.8f, .Kd 0.5f, .output_limit 950 // 对应PWM寄存器最大值 }; void ControlLoop_5ms(void) { float current_speed GetRealSpeed(g_motor_speed); int16_t pwm PID_Compute(speed_pid, target_speed, current_speed); __HAL_TIM_SET_COMPARE(htim3, TIM_CHANNEL_1, abs(pwm)); // 设置电机方向 HAL_GPIO_WritePin(DIR_GPIO_Port, DIR_Pin, (pwm 0) ? GPIO_PIN_SET : GPIO_PIN_RESET); }4. 参数整定与性能优化4.1 阶跃响应调试法仅比例控制KiKd0逐步增加Kp直到系统出现轻微振荡记录临界增益Kc和振荡周期Pc加入积分控制初始值设为Ki 0.6*Kp/Pc观察消除静差效果避免积分饱和加入微分控制初始值设为Kd Kp*Pc/8抑制超调增强系统稳定性4.2 实测参数对比负载状态KpKiKd超调量调节时间空载120.50.35%80ms半载181.20.88%120ms满载252.01.512%200ms提示实际调试时可先用Ziegler-Nichols法计算初始参数再微调至最佳效果。不同电机特性差异较大建议保存多组参数动态切换。4.3 抗积分饱和策略在PID结构体中增加积分限幅typedef struct { // ...原有成员 float integral_limit; // 新增积分限幅 float integral; // 新增积分累积 } PID_Controller; // 修改后的PID计算 float delta pid-Kp * (error - pid-prev_error) pid-Ki * pid-integral pid-Kd * (error - 2*pid-prev_error pid-prev_prev_error); // 积分项更新前检查限幅 if (fabs(pid-integral error) pid-integral_limit) { pid-integral error; }5. 系统集成与调试技巧5.1 定时器中断配置使用基本定时器实现5ms控制周期// TIM6初始化84MHz主频预分频84-1 htim6.Instance TIM6; htim6.Init.Prescaler 84-1; htim6.Init.CounterMode TIM_COUNTERMODE_UP; htim6.Init.Period 5000-1; // 5ms中断 HAL_TIM_Base_Init(htim6); HAL_TIM_Base_Start_IT(htim6); // 中断服务函数 void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { if (htim-Instance TIM6) { ControlLoop_5ms(); } }5.2 调试接口设计通过串口实时监控关键变量printf(Target:%.1f, Actual:%.1f, PWM:%d\r\n, target_speed, current_speed, pwm_output);或使用SWD接口配合STM32CubeMonitor实时观测波形。5.3 常见问题排查现象电机转速剧烈振荡检查编码器接线是否接触不良降低Kp或增大Kd值现象响应速度慢适当增大Kp检查PWM频率是否过高导致驱动响应延迟现象稳态误差大增大Ki值确认编码器分辨率与测速周期匹配在智能车竞赛中这套方案曾实现±2rpm的速度控制精度。实际项目中建议先用示波器观察PWM波形和编码器信号质量再逐步调整PID参数。