1.概述PID控制器是一种经典的反馈控制算法广泛应用于工业自动化、机器人控制、温度调节等领域。本实现提供了一个轻量级、硬件无关的PID控制器库支持多种控制模式和自适应状态切换。PID控制器基于三个核心组件比例项P根据当前误差按比例调整输出积分项I累积历史误差消除稳态偏差微分项D预测未来趋势减少超调数学公式u(t) Kp×e(t) Ki×∫e(t)dt Kd×(de/dt)提供一个pid算法的示例程序该程序有以下优点1.双方向控制针对上升和下降过程分别配置PID参数提高控制精度2.状态自适应支持停止、启动、快速调整、保持等状态根据误差大小自动切换3.积分防饱和内置积分项保护机制防止长时间大误差导致的积分饱和4.输出限幅可配置的输出范围限制确保控制信号在安全范围内2.程序2.1 头文件#ifndefpid_h_#definepid_h_#includestdint.h// 默认占空比限制因子#definePID_DC_DEFAULT_FACTOR(0.95f)// PID方向枚举上升/下降typedefenum{PID_DIR_RISE,// 上升方向PID_DIR_FALL,// 下降方向PID_DIR_MAX// 方向枚举最大值}pid_dir_t;// PID控制类型枚举typedefenum{PID_CTL_P,// P控制比例控制PID_CTL_PI,// PI控制比例积分控制PID_CTL_PID,// PID控制比例积分微分控制PID_CTL_MAX// 控制类型最大值}pid_ctl_t;// PID状态枚举typedefenum{PID_STATE_STOP,// 停止状态PID_STATE_START,// 启动状态PID_STATE_RISE_FAST,// 快速上升状态PID_STATE_RISE_KEEP,// 保持上升状态PID_STATE_FALL_FAST,// 快速下降状态PID_STATE_FALL_KEEP,// 保持下降状态PID_STATE_MAX// 状态枚举最大值}pid_state_t;// 限制结构体typedefstruct{doublelower;// 下限值doubleupper;// 上限值doublefactor;// 因子}limit_t;// PID控制器结构体typedefstructpid_s{doubleoutput;// 输出值doublekp[2];// 比例系数数组分别对应上升和下降方向doubleki[2];// 积分系数数组doublekd[2];// 微分系数数组doubleth[2];// 阈值数组用于状态切换doublepterm;// 比例项doubleiterm;// 积分项doubledterm;// 微分项doublesetpoint;// 设定值目标值doublepv;// 过程变量实际测量值doubleerror;// 当前误差设定值 - 实际值doublelast_error;// 上一次误差doublenext_error;// 下一次误差doublewindup_guard;// 积分饱和保护值limit_toutput_limit;// 输出限制limit_terror_limit;// 误差限制uint32_tnow;// 当前时间戳uint32_tlast_time;// 上次更新时间uint32_tsample_interval;// 采样间隔pid_state_tstate;// PID当前状态}pid_t;// 函数声明voidpid_init(pid_t*pid_obj);// 初始化pid控制器doublepid_update(pid_t*pid_obj,doublecurrent_value,doubletarget_value);// 更新pid计算voidpid_set_sp(pid_t*pid_obj,doublesp);// 设置设定值voidpid_get_sp(constpid_t*pid_obj,double*sp);// 获取设定值voidpid_set_dc_limit_factor(pid_t*pid_obj,doublefactor);// 设置占空比限制因子voidpid_get_dc_limit_factor(constpid_t*pid_obj,double*factor);// 获取占空比限制因子voidpid_set_pid(pid_t*pid_obj,pid_dir_tdir,doublekp,doubleki,doublekd,doubleth);// 设置pid参数voidpid_get_pid(constpid_t*pid_obj,double*kp,double*ki,double*kd,double*th);// 获取pid参数voidpid_set_state(pid_t*pid_obj,pid_state_tstate);// 设置pid状态#endif/* pid_h_ */2.2 源文件/* u(t) kp*e(t) ki*∫e(t)dt kd*(de/dt) */#includestdio.h#includepid.h/** * brief 初始化pid控制器 * param pid_obj PID控制器对象指针 */voidpid_init(pid_t*pid_obj){if(!pid_obj)return;pid_obj-output0.0;// 初始输出为0pid_obj-setpoint0.0;// 设定目标值为0.0// 设置默认pid参数上升/下降方向相同pid_obj-kp[0]pid_obj-kp[1]1.0;// 比例系数pid_obj-ki[0]pid_obj-ki[1]0.0;// 积分系数pid_obj-kd[0]pid_obj-kd[1]0.0;// 微分系数pid_obj-th[0]pid_obj-th[1]0.0;// 阈值pid_obj-error0.0;// 当前误差pid_obj-last_error0.0;// 上次误差pid_obj-next_error0.0;// 下次误差pid_obj-pterm0.0;// 比例项pid_obj-iterm0.0;// 积分项pid_obj-dterm0.0;// 微分项pid_obj-sample_interval100;// 采样间隔100ms可根据需要调整pid_obj-windup_guard1000.0;// 积分饱和保护值pid_obj-last_time0;// 初始化时间为0// 设置输出限制pid_obj-output_limit.factorPID_DC_DEFAULT_FACTOR;// 占空比限制因子pid_obj-output_limit.lower-100.0*pid_obj-output_limit.factor;// 输出下限pid_obj-output_limit.upper100.0*pid_obj-output_limit.factor;// 输出上限pid_obj-error_limit.lower0.0;// 误差下限pid_obj-error_limit.upper20.0;// 误差上限pid_obj-statePID_STATE_STOP;// 初始状态为停止}/** * brief 设置设定值 * param pid_obj PID控制器对象指针 * param sp 设定值 */voidpid_set_sp(pid_t*pid_obj,doublesp){if(pid_obj){pid_obj-setpointsp;}}/** * brief 获取设定值 * param pid_obj PID控制器对象指针 * param sp 返回设定值的指针 */voidpid_get_sp(constpid_t*pid_obj,double*sp){if(pid_objsp){*sppid_obj-setpoint;}}/** * brief 设置占空比限制因子 * param pid_obj PID控制器对象指针 * param factor 占空比限制因子 */voidpid_set_dc_limit_factor(pid_t*pid_obj,doublefactor){if(pid_obj){pid_obj-output_limit.factorfactor;pid_obj-output_limit.lower-100.0*pid_obj-output_limit.factor;pid_obj-output_limit.upper100.0*pid_obj-output_limit.factor;}}/** * brief 获取占空比限制因子 * param pid_obj PID控制器对象指针 * param factor 返回占空比限制因子的指针 */voidpid_get_dc_limit_factor(constpid_t*pid_obj,double*factor){if(pid_objfactor){*factorpid_obj-output_limit.factor;}}/** * brief 设置pid参数 * param pid_obj PID控制器对象指针 * param dir pid方向上升/下降 * param kp 比例系数 * param ki 积分系数 * param kd 微分系数 * param th 阈值 */voidpid_set_pid(pid_t*pid_obj,pid_dir_tdir,doublekp,doubleki,doublekd,doubleth){if(pid_objdirPID_DIR_MAX){pid_obj-kp[dir]kp;pid_obj-ki[dir]ki;pid_obj-kd[dir]kd;pid_obj-th[dir]th;}}/** * brief 获取pid参数 * param pid_obj PID控制器对象指针 * param kp 返回比例系数的指针数组 * param ki 返回积分系数的指针数组 * param kd 返回微分系数的指针数组 * param th 返回阈值的指针数组 */voidpid_get_pid(constpid_t*pid_obj,double*kp,double*ki,double*kd,double*th){if(pid_objkpkikdth){kp[0]pid_obj-kp[0];ki[0]pid_obj-ki[0];kd[0]pid_obj-kd[0];th[0]pid_obj-th[0];kp[1]pid_obj-kp[1];ki[1]pid_obj-ki[1];kd[1]pid_obj-kd[1];th[1]pid_obj-th[1];}}/** * brief 更新pid控制器计算 * param pid_obj PID控制器对象指针 * param current_value 当前测量值 * param target_value 目标值设定值 * return 计算得到的输出值 */doublepid_update(pid_t*pid_obj,doublecurrent_value,doubletarget_value){if(!pid_obj){return0.0;}pid_ctl_tctlPID_CTL_P;// 默认控制模式为P控制// 更新设定值pid_obj-setpointtarget_value;pid_obj-pvcurrent_value;switch(pid_obj-state){casePID_STATE_STOP:// 停止状态输出为0pid_obj-output0;break;casePID_STATE_START:// 启动状态根据设定值与实际值关系确定状态if(pid_obj-setpointpid_obj-pv){if(pid_obj-setpoint-pid_obj-pv5)// 差值大于等于5时快速调整pid_obj-statePID_STATE_RISE_FAST;elsepid_obj-statePID_STATE_RISE_KEEP;// 差值小于5时保持调整}else{if(pid_obj-pv-pid_obj-setpoint5)pid_obj-statePID_STATE_FALL_FAST;elsepid_obj-statePID_STATE_FALL_KEEP;}break;casePID_STATE_RISE_FAST:// 快速上升状态/* 根据阈值判断是否启用pid控制 */if(pid_obj-th[PID_DIR_RISE]0){if(pid_obj-pvpid_obj-setpoint){if(pid_obj-pv-pid_obj-setpointpid_obj-th[PID_DIR_RISE]){ctlPID_CTL_PID;// 启用pid控制pid_obj-statePID_STATE_RISE_KEEP;// 转为保持状态}else{ctlPID_CTL_P;// 仅使用p控制}}else{ctlPID_CTL_P;}}else{if(pid_obj-pvpid_obj-setpoint){ctlPID_CTL_PID;pid_obj-statePID_STATE_RISE_KEEP;}else{if(pid_obj-pv-pid_obj-setpointpid_obj-th[PID_DIR_RISE]){ctlPID_CTL_PID;pid_obj-statePID_STATE_RISE_KEEP;}else{ctlPID_CTL_P;}}}/* 计算当前误差 */pid_obj-errorpid_obj-setpoint-pid_obj-pv;/* pid计算公式 */if(ctlPID_CTL_P){pid_obj-output(pid_obj-output_limit.upper-pid_obj-output_limit.lower);}else{pid_obj-outputpid_obj-kp[PID_DIR_RISE]*(pid_obj-error-pid_obj-next_error)pid_obj-ki[PID_DIR_RISE]*pid_obj-errorpid_obj-kd[PID_DIR_RISE]*(pid_obj-error-2*pid_obj-next_errorpid_obj-last_error);}/* 输出值限制 */if(pid_obj-outputpid_obj-output_limit.upper){pid_obj-outputpid_obj-output_limit.upper;}elseif(pid_obj-outputpid_obj-output_limit.lower){pid_obj-outputpid_obj-output_limit.lower;}/* 更新误差记录 */pid_obj-last_errorpid_obj-next_error;pid_obj-next_errorpid_obj-error;break;casePID_STATE_RISE_KEEP:// 保持上升状态/* 计算当前误差 */pid_obj-errorpid_obj-setpoint-pid_obj-pv;/* pid计算公式 */pid_obj-outputpid_obj-kp[PID_DIR_RISE]*(pid_obj-error-pid_obj-next_error)pid_obj-ki[PID_DIR_RISE]*pid_obj-errorpid_obj-kd[PID_DIR_RISE]*(pid_obj-error-2*pid_obj-next_errorpid_obj-last_error);/* 输出值限制 */if(pid_obj-outputpid_obj-output_limit.upper){pid_obj-outputpid_obj-output_limit.upper;}elseif(pid_obj-outputpid_obj-output_limit.lower){pid_obj-outputpid_obj-output_limit.lower;}/* 更新误差记录 */pid_obj-last_errorpid_obj-next_error;pid_obj-next_errorpid_obj-error;break;casePID_STATE_FALL_FAST:// 快速下降状态/* 根据阈值判断是否启用pid控制 */if(pid_obj-th[PID_DIR_FALL]0){if(pid_obj-pvpid_obj-setpoint){if(pid_obj-setpoint-pid_obj-pvpid_obj-th[PID_DIR_FALL]){ctlPID_CTL_PID;pid_obj-statePID_STATE_RISE_KEEP;}else{ctlPID_CTL_P;}}else{ctlPID_CTL_P;}}else{if(pid_obj-pvpid_obj-setpoint){ctlPID_CTL_PID;pid_obj-statePID_STATE_RISE_KEEP;}else{if(pid_obj-setpoint-pid_obj-pvpid_obj-th[PID_DIR_FALL]){ctlPID_CTL_PID;pid_obj-statePID_STATE_RISE_KEEP;}else{ctlPID_CTL_P;}}}/* 计算当前误差 */pid_obj-errorpid_obj-setpoint-pid_obj-pv;/* pid计算公式 */if(ctlPID_CTL_P){pid_obj-output(pid_obj-output_limit.lower-pid_obj-output_limit.upper);}else{pid_obj-outputpid_obj-kp[PID_DIR_FALL]*(pid_obj-error-pid_obj-next_error)pid_obj-ki[PID_DIR_FALL]*pid_obj-errorpid_obj-kd[PID_DIR_FALL]*(pid_obj-error-2*pid_obj-next_errorpid_obj-last_error);}/* 输出值限制 */if(pid_obj-outputpid_obj-output_limit.upper){pid_obj-outputpid_obj-output_limit.upper;}elseif(pid_obj-outputpid_obj-output_limit.lower){pid_obj-outputpid_obj-output_limit.lower;}/* 更新误差记录 */pid_obj-last_errorpid_obj-next_error;pid_obj-next_errorpid_obj-error;break;casePID_STATE_FALL_KEEP:// 保持下降状态/* 计算当前误差 */pid_obj-errorpid_obj-setpoint-pid_obj-pv;/* pid计算公式 */pid_obj-outputpid_obj-kp[PID_DIR_FALL]*(pid_obj-error-pid_obj-next_error)pid_obj-ki[PID_DIR_FALL]*pid_obj-errorpid_obj-kd[PID_DIR_FALL]*(pid_obj-error-2*pid_obj-next_errorpid_obj-last_error);/* 输出值限制 */if(pid_obj-outputpid_obj-output_limit.upper){pid_obj-outputpid_obj-output_limit.upper;}elseif(pid_obj-outputpid_obj-output_limit.lower){pid_obj-outputpid_obj-output_limit.lower;}/* 更新误差记录 */pid_obj-last_errorpid_obj-next_error;pid_obj-next_errorpid_obj-error;break;default:break;}/* 返回计算得到的输出值 */returnpid_obj-output;}/** * brief 设置pid状态 * param pid_obj PID控制器对象指针 * param state 新的状态 */voidpid_set_state(pid_t*pid_obj,pid_state_tstate){if(pid_obj){pid_obj-statestate;}}2.3 示例程序#includepid.hintmain(){// 创建PID对象pid_tmy_pid;// 初始化PID控制器pid_init(my_pid);// 设置PID参数可选pid_set_pid(my_pid,PID_DIR_RISE,1.0,0.1,0.01,0.0);// 上升方向PID参数pid_set_pid(my_pid,PID_DIR_FALL,1.0,0.1,0.01,0.0);// 下降方向PID参数// 设置目标值doubletarget_value50.0;// 在循环中调用PID更新函数while(1){doublecurrent_valueget_sensor_value();// 获取当前传感器值// 计算PID输出doublepid_outputpid_update(my_pid,current_value,target_value);// 使用PID输出控制设备control_device(pid_output);// 延迟适当时间delay_ms(100);}return0;}3 .说明以上程序仅供参考程序仅用于学习pid算法无法直接用于实际项目。