三亩地 三亩地SAN MU DI · CODE DIARY
ARTICLE DETAIL

日记详情

真实记录编程学习的某一天,欢迎挑你感兴趣的翻一翻。

4.PID调参实战:先P后I再D,手把手教你搞定参数整定

4.PID调参实战:先P后I再D,手把手教你搞定参数整定

在嵌入式控制领域,PID控制器是当之无愧的“万能选手”,从温度控制到电机调速,从工业机器人到智能家居,几乎处处都能看到它的身影。但很多开发者在使用PID时都会遇到一个共同的难题:Kp、Ki、Kd这三个参数到底该怎么设?本文将结合视频中的“先P后I再D”调参口诀,配合完整的C语言代码示例,带你彻底掌握PID参数整定的核心方法。

一、PID调参的核心逻辑:不是算出来的,是调出来的

很多初学者会试图通过复杂的数学公式直接计算出PID参数,但实际上,由于实际系统的非线性、时变性等特点,PID参数更像是“经验值”而非“理论值”。视频中提到的“先P后I再D”调参法,是经过无数工程师验证的实用方法,核心步骤可以总结为四句话:

  1. 先P后I再D
  2. P找临界除以二
  3. I加到不震荡
  4. D加到不超调

二、四步调参法详解

第一步:调P(比例项),找到临界增益

  1. 初始设置:将Ki和Kd都设为0,只保留比例控制
  2. 逐步增大Kp:从较小的Kp值开始,慢慢加大,观察系统响应
  3. 找到临界值:当系统开始出现轻微震荡时,记下这个Kp值,这就是临界增益Kc
  4. 设置最终P值:将Kp设为临界增益的一半左右,留出足够的余量

第二步:调I(积分项),消除余差

  1. 保持P值不变:使用第一步得到的Kp值
  2. 逐步增大Ki:从较小的Ki值开始,慢慢加大
  3. 观察系统响应:如果Ki太大,系统会出现震荡(比如温度在目标值上下波动)
  4. 设置最终I值:将Ki调到余差快速消失又不震荡为止

第三步:调D(微分项),抑制超调

  1. 保持P和I值不变:使用前两步得到的Kp和Ki值
  2. 逐步增大Kd:从较小的Kd值开始,慢慢加大
  3. 观察系统响应:如果Kd太大,系统会出现高频抖动
  4. 设置最终D值:将Kd调到系统对突变的响应无超调为止

第四步:验证与微调

在各种工况下测试PID控制器的性能:

  • 初始加热/启动
  • 目标值突变
  • 外部扰动(比如温度控制中打开冷水)

观察系统是否满足:

  • 快速收敛
  • 无余差
  • 不超调

如果不满足,再对Kp、Ki、Kd进行微调,记住:Kp是主力,Ki是辅助,Kd是微调

三、完整C语言PID控制器代码示例

下面是一个完整的C语言PID控制器实现,包含了参数初始化、计算、重置等功能,适用于嵌入式系统:

#include <stdio.h> #include <math.h> // PID控制器结构体 typedef struct { float Kp; // 比例系数 float Ki; // 积分系数 float Kd; // 微分系数 float setpoint; // 目标值 float measure; // 测量值 float error; // 当前误差 float last_error; // 上一次误差 float sum_error; // 误差积分 float output; // 输出值 float out_min; // 输出最小值 float out_max; // 输出最大值 } PID_Controller; /** @brief 初始化PID控制器 @param pid PID控制器指针 @param kp 比例系数 @param ki 积分系数 @param kd 微分系数 @param out_min 输出最小值 @param out_max 输出最大值 */ void PID_Init(PID_Controller *pid, float kp, float ki, float kd, float out_min, float out_max) { pid->Kp = kp; pid->Ki = ki; pid->Kd = kd; pid->setpoint = 0.0f; pid->measure = 0.0f; pid->error = 0.0f; pid->last_error = 0.0f; pid->sum_error = 0.0f; pid->output = 0.0f; pid->out_min = out_min; pid->out_max = out_max; } /** @brief 设置目标值 @param pid PID控制器指针 @param setpoint 目标值 */ void PID_SetSetpoint(PID_Controller *pid, float setpoint) { pid->setpoint = setpoint; } /** @brief 计算PID输出 @param pid PID控制器指针 @param measure 当前测量值 @param dt 控制周期(秒) @return PID输出值 */ float PID_Compute(PID_Controller *pid, float measure, float dt) { // 1. 计算当前误差 pid->measure = measure; pid->error = pid->setpoint - pid->measure; // 2. 计算比例项 float proportional = pid->Kp * pid->error; // 3. 计算积分项(带限幅,防止积分饱和) pid->sum_error += pid->error * dt; if (pid->sum_error > pid->out_max / pid->Ki) { pid->sum_error = pid->out_max / pid->Ki; } else if (pid->sum_error < pid->out_min / pid->Ki) { pid->sum_error = pid->out_min / pid->Ki; } float integral = pid->Ki * pid->sum_error; // 4. 计算微分项 float derivative = pid->Kd * (pid->error - pid->last_error) / dt; // 5. 计算总输出 pid->output = proportional + integral + derivative; // 6. 输出限幅 if (pid->output > pid->out_max) { pid->output = pid->out_max; } else if (pid->output < pid->out_min) { pid->output = pid->out_min; } // 7. 更新上一次误差 pid->last_error = pid->error; return pid->output; } /** @brief 重置PID控制器 @param pid PID控制器指针 */ void PID_Reset(PID_Controller *pid) { pid->error = 0.0f; pid->last_error = 0.0f; pid->sum_error = 0.0f; pid->output = 0.0f; } // 示例:温度控制模拟 int main() { // 初始化PID控制器,Kp=2.0, Ki=0.5, Kd=0.1,输出范围0-100 PID_Controller pid; PID_Init(&pid, 2.0f, 0.5f, 0.1f, 0.0f, 100.0f); // 设置目标温度为50℃ PID_SetSetpoint(&amp;pid, 50.0f); // 模拟系统,初始温度为25℃ float current_temp = 25.0f; float dt = 0.1f; // 控制周期0.1秒 printf("时间(s)\t目标温度(℃)\t当前温度(℃)\tPID输出(%%)\n"); printf("----------------------------------------------------\n"); // 模拟100个控制周期 for (int i = 0; i &lt; 100; i++) { float time = i * dt; float output = PID_Compute(&amp;pid, current_temp, dt); // 简单模拟温度响应:温度变化与PID输出成正比 current_temp += output * 0.05f; // 打印当前状态 printf("%.1f\t\t%.1f\t\t%.1f\t\t%.1f\n", time, pid-&gt;setpoint, current_temp, output); } return 0; }

四、代码使用说明

  1. 初始化:使用PID_Init函数初始化PID控制器,设置Kp、Ki、Kd和输出范围
  2. 设置目标值:使用PID_SetSetpoint函数设置控制目标
  3. 计算输出:在每个控制周期调用PID_Compute函数,传入当前测量值和控制周期,得到PID输出
  4. 重置控制器:如果需要重新开始控制,使用PID_Reset函数重置PID控制器的状态

五、调参实战建议

  1. 从P开始:先只调节比例项,找到系统开始震荡的临界Kp值,然后取其一半作为初始P值
  2. 再调I:在P值确定后,逐步增加Ki,直到余差快速消失且系统不震荡
  3. 最后调D:在P和I确定后,逐步增加Kd,直到系统对突变的响应无超调
  4. 多工况测试:在不同的工况下测试PID控制器的性能,确保在各种情况下都能稳定工作
  5. 耐心微调:PID调参是一个反复迭代的过程,需要耐心和细心,建议每次只改变一个参数,并记录下每次调整后的系统响应,便于对比和回溯
← 返回列表