跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
CNode.js算法

PID 控制原理、整定方法与 C 语言实现

PID 是最常见的闭环控制方法之一,适合温度、速度、位置这类连续调节场景。文章先解释了比例、积分、微分三项各自解决的问题,再对位置式、增量式和微分先行三种形式做了区分。随后给出经验整定和 Ziegler-Nichols 整定法,并附上一段适合嵌入式平台移植的 C 语言位置式 PID 示例。最后总结了稳态误差、震荡、积分饱和和抗干扰差等常见问题,以及对应的处理思路。

全栈工匠发布于 2026/6/300 浏览

在工业控制、机器人运动控制、智能家居温控这些场景里,PID 依然是最常见的闭环控制方案之一。它不复杂,调起来也没那么玄,但真要落到系统里,参数整定和抗干扰才是分水岭。下面把原理、常见形式和一个可直接移植的 C 语言实现串起来看。

一、PID 是什么

PID 是 Proportional(比例)、Integral(积分)、Derivative(微分)的缩写。它做的事很直接:根据设定值和实际值之间的偏差,算出一个控制量,让系统慢慢往目标靠。

比如空调目标是 25℃,当前房间温度是 30℃,偏差就是 25-30 = -5℃。控制器会根据这个偏差调整制冷功率,直到温度回到目标附近。

连续域里,PID 的公式是:

u(t)=Kp·e(t)+Ki·∫₀ᵗ e(τ)dτ+Kd·de(t)/dt

其中:

  • u(t):控制器输出的控制量
  • e(t)=SP−PV:偏差,SP 是设定值,PV 是实际值
  • Kp:比例系数
  • Ki:积分系数
  • Kd:微分系数

实际工程里一般用离散形式,因为控制器是按采样周期运行的:

u(k)=Kp·e(k)+Ki·∑₀ᵏ e(i)T+Kd·T(e(k)−e(k−1))

其中:

  • k:当前采样周期
  • T:采样周期
  • e(k):当前周期偏差
  • e(k−1):上一周期偏差

二、P、I、D 各自解决什么问题

PID 不是三个效果简单叠加,它们各管一件事,少一个都会让控制质量变差。

1. 比例环节 P:先把偏差拉回来

比例项和当前偏差成正比:

Pout=Kp·e(k)

它的作用是立刻给出响应,偏差越大,输出越强。

它的优点是快,缺点也很明显:只靠 P,系统通常会留下一点稳态误差。Kp 太大又容易来回抖,甚至直接振起来。

2. 积分环节 I:专门处理'差一点点'的问题

积分项和偏差累积量成正比:

Iout=Ki·∑₀ᵏ e(i)T

只要偏差一直存在,积分就会一直累积,直到把误差补掉为止。这是它最有用的地方,也正是它最容易出问题的地方。

积分项能消除稳态误差,但 Ki 过大时,系统很容易超调,回调也会变慢。现场调参时,很多'看起来不像 PID 的毛病',最后都能追到积分上。

3. 微分环节 D:提前刹一下

微分项和偏差变化率成正比:

Dout=Kd·T(e(k)−e(k−1))

它盯的是趋势,不是当前值。偏差变化越快,微分输出越大,能提前压住系统冲得太猛。

它的优点是抑制超调,缺点是对噪声很敏感。传感器只要有一点抖动,D 项就会被放大,所以 Kd 往往不能给得太激进。

三、常见的 PID 形式

工程里常见的不是只有一种 PID。

1. 位置式 PID

直接算出当前时刻的控制量:

u(k)=Kp·e(k)+Ki·∑₀ᵏ e(i)T+Kd·T(e(k)−e(k−1))

它的输出是绝对值,比如电机目标转速、阀门开度。写法直观,适合理解和调试,但积分项会不断累积,处理不好就容易积分饱和。

2. 增量式 PID

计算相邻两次控制量的差值:

Δu(k)=u(k)−u(k−1)=Kp[e(k)−e(k−1)]+Ki·e(k)·T+Kd·T(e(k)−2e(k−1)+e(k−2))

它输出的是增量,不直接给绝对控制值。这个形式在步进电机之类的场景里很常见,优点是不会把积分一路堆上去,抗干扰也通常更好一些。

3. 微分先行 PID

把微分项的输入从偏差改成实际值 PV。这样设定值突然变化时,不会让微分项跟着猛跳一把。设定值经常变的系统,比如轨迹跟踪,通常会更愿意用这种处理方式。

四、参数整定怎么做

PID 真正难的地方不在公式,而在 Kp、Ki、Kd 怎么配。理论上没有万能值,实际里还是要靠系统特性和一点经验。

1. 先比例,再积分,最后微分

这是最常见的现场整定思路。

  1. 先令 Ki=0,Kd=0,逐渐增大 Kp,直到系统开始出现轻微震荡,记下临界比例系数 Kcr。
  2. 再把 Kp 调回 0.6∼0.8Kcr,慢慢加 Ki,把稳态误差压掉。
  3. 最后根据超调和响应速度,少量加 Kd,看看能不能把波动压住。

这套方法不花哨,但够实用。很多场景里,问题不是'缺一个高阶算法',而是基础参数根本没收住。

2. Ziegler-Nichols 整定法

这是基于临界震荡参数的一套经验公式。

  1. 令 Ki=0,Kd=0,缓慢增大 Kp,直到系统出现持续等幅震荡,记录此时的 Kcr 和 Tcr。
  2. 按下面的经验公式取值:
控制规律KpKiKd
P0.5Kcr00
PI0.45Kcr1.2Kp/Tcr0
PID0.6Kcr2Kp/TcrKp·Tcr/8

这套公式能给一个起点,但不是终点。系统惯性大、噪声重或者执行器有死区时,后面还是得手工微调。

五、C 语言位置式 PID 实现

下面这份代码是一个比较直接的位置式 PID 写法,适合放到 STM32、51 单片机这类嵌入式平台里。

typedef struct {
    float SetPoint;      // 设定值
    float ActualPoint;   // 实际值
    float Kp;            // 比例系数
    float Ki;            // 积分系数
    float Kd;            // 微分系数
    float Error[3];      // 偏差数组 e(k),e(k-1),e(k-2)
    float Integral;      // 积分累积值
    float Output;        // 控制量输出
} PID_TypeDef;

// PID 初始化
void PID_Init(PID_TypeDef *pid, float kp, float ki, float kd, float set) {
    pid->Kp = kp;
    pid->Ki = ki;
    pid->Kd = kd;
    pid->SetPoint = set;
    pid->Error[0] = 0;
    pid->Error[1] = 0;
    pid->Error[2] = 0;
    pid->Integral = 0;
    pid->Output = 0;
}

// PID 计算函数(位置式)
float PID_Calculate(PID_TypeDef *pid, float actual) {
    pid->ActualPoint = actual;
    // 计算当前偏差
    pid->Error[0] = pid->SetPoint - pid->ActualPoint;
    // 积分项(带积分限幅,防止积分饱和)
    pid->Integral += pid->Error[0];
    // 积分限幅,根据实际系统调整
    if (pid->Integral > 1000) pid->Integral = 1000;
    if (pid->Integral < -1000) pid->Integral = -1000;
    // 位置式 PID 计算
    pid->Output = pid->Kp * pid->Error[0] + pid->Ki * pid->Integral + pid->Kd * (pid->Error[0] - pid->Error[1]);
    // 更新偏差历史值
    pid->Error[2] = pid->Error[1];
    pid->Error[1] = pid->Error[0];
    // 控制量限幅,根据实际系统调整
    if (pid->Output > 2000) pid->Output = 2000;
    if (pid->Output < 0) pid->Output = 0;
    return pid->Output;
}

这段实现里有两个地方比较关键:一是积分限幅,二是输出限幅。它们都不优雅,但在真实系统里很管用。没有这两层保护,PID 很容易在极端偏差下失控。

六、PID 常见应用场景

PID 几乎遍布所有需要闭环控制的地方。

  1. 工业控制:温度、压力、流量、液位控制,比如化工反应釜温控。
  2. 机器人领域:机械臂关节位置控制、AGV 小车速度和航向控制。
  3. 智能家居:空调温控、扫地机器人路径跟踪、热水器温度控制。
  4. 汽车电子:发动机转速控制、车速控制、刹车防抱死系统(ABS)。

七、几个常见问题

PID 的优势是结构简单、实现成本低,不依赖特别精确的系统模型。但它也不是万能的。

  • 稳态误差还在:先看 Ki 是否太小,必要时再加积分分离。
  • 系统震荡明显:通常是 Kp 偏大,或者 Kd 和采样周期没配好。
  • 积分饱和:加积分限幅,或者直接改成增量式 PID。
  • 抗干扰差:先处理传感器噪声,再考虑动 Kd,不然只是把波动放大。

PID 用到最后,拼的往往不是公式,而是你对系统脾气的理解。公式很标准,系统不标准,调参也就没那么教科书。

目录

  1. 一、PID 是什么
  2. 二、P、I、D 各自解决什么问题
  3. 1. 比例环节 P:先把偏差拉回来
  4. 2. 积分环节 I:专门处理“差一点点”的问题
  5. 3. 微分环节 D:提前刹一下
  6. 三、常见的 PID 形式
  7. 1. 位置式 PID
  8. 2. 增量式 PID
  9. 3. 微分先行 PID
  10. 四、参数整定怎么做
  11. 1. 先比例,再积分,最后微分
  12. 2. Ziegler-Nichols 整定法
  13. 五、C 语言位置式 PID 实现
  14. 六、PID 常见应用场景
  15. 七、几个常见问题
  • 免费图片AI生成工具免费生成了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 免费图片视频在线生成30秒,将你的创意变成现实开始设计
  • X/Twitter免费视频下载器免登陆无限额度免费视频解析下载了解详情
  • 100+免费在线小游戏爽一把
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • C++ 植物大战僵尸项目配置与编译说明
  • 三道滑动窗口与子串题的 Python 写法
  • WebRTC 远程控制里的 AI 编排实践
  • 裴蜀定理与扩展欧几里得:从同余到逆元
  • Flutter 应用架构从入门到可扩展的演进实践
  • CPU 也能跑的人脸识别部署实录
  • OpenClaw 本地 Memory 配置:Ubuntu、CUDA、llama.cpp
  • 在浏览器里跑 FRCRN:WebAssembly 轻量化部署实录
  • Vivado AXI4-Stream Data FIFO 配置与仿真记录
  • Web 开发里的 5 种加密算法:原理与代码
  • Python 协程与异步编程实战笔记
  • ASP.NET Core WebAPI 常用配置整理
  • OpenClaw 的安装、启动和联网配置
  • Spring 国际化原理与实战:MessageSource、LocaleResolver、LocaleContextHolder、MessageFormat
  • 安卓本地跑 Stable Diffusion 的开源工具
  • 鸿蒙金融理财全栈:风控、合规与产品实现
  • C++ list 容器的用法与简化实现
  • Java 中 Excel 转 PDF 的几种方案与取舍
  • OpenClaw 飞书机器人部署记录
  • StyleSelectorXL:在 SDXL 里管理 77 种绘画风格

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online