PID入门保姆级教程:用STM32舵机带你看懂PID的作用(含演示视频) 一、PID介绍1.PID算法简介PID是一种在工业控制、嵌入式、机器人等领域广泛使用的经典控制算法主要用于解决线性系统的自动控制问题。相较于MPC模型预测控制、LQR线性二次型最优控制等高级控制算法PID 最大的优势是原理简单易于理解工程实用性极强。PID三个部分组成P比例Proportional、I积分Integral、D微分Derivative其核心思想是通过不断计算目标值与实际值的误差利用误差实时修正输出最终让系统稳定在目标值附近。2.PID各环节作用2.1 P比例环节将当前误差按比例输出快速减小偏差缺点是无法消除稳态误差系数过大会导致震荡2.2 I积分环节累计过去所有误差并输出能够消除稳态误差缺点是会降低系统响应速度容易产生超调2.3 D微分环节根据误差的变化趋势进行预测能够提前修正控制量同时抑制超调减小震荡让系统更稳定3.PID控制流程图4.PID控制算法伪代码简易版// 初始化状态 last_err : 0 // 上一次的偏差 sum_err : 0 // 偏差累积积分项 // 主控制循环 while True: // 1. 计算当前偏差 err target_val - actual_val // 2. 比例项直接按偏差大小输出 term_p Kp * err // 3. 积分项累积偏差消除静差 sum_err sum_err err * dt term_i Ki * sum_err // 4. 微分项偏差变化率预判趋势 diff_err (err - last_err) / dt term_d Kd * diff_err // 5. 合成最终控制量 control term_p term_i term_d // 6. 更新状态为下一次循环做准备 last_err err // 等待采样周期结束 delay(dt)二、PID简单应用SG90舵机的自适应转动1.应用介绍1.1环境配置华清远见嵌入式ARM实验箱STM32F407IGT6、SG90舵机模块STM32CubeIDE与STM32CubeMX1.2实现效果本项目利用通用定时器TIM12产生PWM脉冲控制舵机转动通过按键调节舵机转动角度引入PID控制算法后舵机呈现“快进慢停”的自适应调速效果初始转动时速度较快随着实际角度离目标角度偏差逐渐减小转速同步减小最后平稳到达目标位置避免了可能的冲头与震荡。1.3SG90舵机转动原理舵机的信号线引脚接GPIO引脚P14通过该引脚输入固定频率、不同占空比的PWM信号舵机即可完成角度转动与定位SG90 所需的标准 PWM 控制参数如下1PWM 频率50Hz对应周期 20ms这是模拟舵机的通用标准2多级角度实现PWM 波脉宽在0.5ms~2.5ms之间线性变化对应角度0°~180°线性切换如图 3-2 所示。例如 1.0ms 对应 45°、2.0ms 对应 135°实现任意多级角度的精准控制。1.4CubeMX定时器TIM12配置参数配置解释1定时器计数器频率84MHz ÷ 84 1MHZ周期1us2PWM脉冲周期1us × 20000 20ms对应SG90舵机PWM周期50Hz3若设置CCR值为1000则PWM脉冲高电平宽度为1000 × 1us 1ms对应舵机45度为方便演示代码设计为按下两个按键目标角度分别增加和减少45度2.未加入PID的主要代码// 舵机角度映射 #define ANGLE_MIN 0 #define ANGLE_MAX 180 #define PULSE_MIN 500 #define PULSE_MAX 2500 // 当前角度 uint8_t current_angle 0; // 角度转CCR值 uint16_t angle2pulse(uint8_t angle) { if(angle ANGLE_MAX) angle ANGLE_MAX; if(angle ANGLE_MIN) angle ANGLE_MIN; return (angle * (PULSE_MAX - PULSE_MIN) / 180 PULSE_MIN); } int main(void) { //相关初始化函数... HAL_TIM_PWM_Start(htim12, TIM_CHANNEL_1); current_angle 0; __HAL_TIM_SET_COMPARE(htim12, TIM_CHANNEL_1, angle2pulse(current_angle)); while (1) { if(HAL_GPIO_ReadPin(GPIOI, GPIO_PIN_9) GPIO_PIN_RESET) { HAL_Delay(20); if(HAL_GPIO_ReadPin(GPIOI, GPIO_PIN_9) GPIO_PIN_RESET) { while(HAL_GPIO_ReadPin(GPIOI, GPIO_PIN_9) GPIO_PIN_RESET); HAL_Delay(20); if(current_angle 45 180) current_angle 45; __HAL_TIM_SET_COMPARE(htim12, TIM_CHANNEL_1, angle2pulse(current_angle)); } } if(HAL_GPIO_ReadPin(GPIOF, GPIO_PIN_11) GPIO_PIN_RESET) { if(HAL_GPIO_ReadPin(GPIOF, GPIO_PIN_11) GPIO_PIN_RESET) { while(HAL_GPIO_ReadPin(GPIOF, GPIO_PIN_11) GPIO_PIN_RESET); HAL_Delay(20); if(current_angle 45) current_angle - 45; __HAL_TIM_SET_COMPARE(htim12, TIM_CHANNEL_1, angle2pulse(current_angle)); } } } }舵机原代码演示视频3.加入PID的主要代码// 简化 PID typedef struct { float target; // 目标角度 float current; // 当前角度 float Kp; // 比例调小,防止震荡 float max_step; // 最大每步变化 } Simple_PID; Simple_PID pid { .target 0, .current 0, .Kp 0.08f, .max_step 15.0f // 每步最多动2度 }; #define ANGLE_MIN 0 #define ANGLE_MAX 180 #define PULSE_MIN 500 #define PULSE_MAX 2500 uint8_t target_angle 0; // 角度转脉冲 uint16_t angle2pulse(float angle) { if(angle ANGLE_MAX) angle ANGLE_MAX; if(angle ANGLE_MIN) angle ANGLE_MIN; return (angle * (PULSE_MAX - PULSE_MIN) / 180.0f PULSE_MIN); } // PID 控制 void servo_pid_control(void) { pid.target target_angle; // 计算误差 float error pid.target - pid.current; // 小比例平滑运动 float adjust error * pid.Kp; // 限幅 if(adjust pid.max_step) adjust pid.max_step; if(adjust -pid.max_step) adjust -pid.max_step; // 更新当前角度 pid.current adjust; // 输出到舵机 __HAL_TIM_SET_COMPARE(htim12, TIM_CHANNEL_1, angle2pulse(pid.current)); HAL_Delay(10); } int main(void) { //相关初始化函数... HAL_TIM_PWM_Start(htim12, TIM_CHANNEL_1); pid.current 0; target_angle 0; while (1) { if(HAL_GPIO_ReadPin(GPIOI, GPIO_PIN_9) GPIO_PIN_RESET) { HAL_Delay(20); if(HAL_GPIO_ReadPin(GPIOI, GPIO_PIN_9) GPIO_PIN_RESET) { while(HAL_GPIO_ReadPin(GPIOI, GPIO_PIN_9) GPIO_PIN_RESET); HAL_Delay(20); if(target_angle 45 180) target_angle 45; } } if(HAL_GPIO_ReadPin(GPIOF, GPIO_PIN_11) GPIO_PIN_RESET) { HAL_Delay(20); if(HAL_GPIO_ReadPin(GPIOF, GPIO_PIN_11) GPIO_PIN_RESET) { while(HAL_GPIO_ReadPin(GPIOF, GPIO_PIN_11) GPIO_PIN_RESET); HAL_Delay(20); if(target_angle 45) target_angle -45; } } //PID servo_pid_control(); } }代码解析由于 SG90 舵机内部已集成硬件闭环控制外部只需使用比例P控制即可实现稳定、平滑的角度调节无需引入积分I和微分D环节。当给定目标角度首先计算目标角度与当前角度的误差误差乘以比例系数系数应较小此处设置为0.08得到本次周期的角度调整量叠加到当前角度上作为当前转动周期的目标角度随后将目标角度转换为对应的PWM比较值通过__HAL_TIM_SET_COMPARE函数更新占空比实现舵机转动。随着舵机转动每一转动周期中的角度误差逐渐变小调整量同步减小因此转速越来越慢从而实现“快进慢停” 的自适应调速效果。舵机Kp0.08演示视频舵机Kp0.15演示视频三、结语本文是我在嵌入式学习过程中的一点收获与总结如有错误欢迎大家指正之后会更新关于FreeRTOS及其应用的内容。如果本文对大家有所帮助麻烦点个关注 点赞 收藏支持一下有任何问题也可以在评论区留言交流