<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>控制算法 &#8211; Cloudlay</title>
	<atom:link href="https://cloudlay.cn/tag/%e6%8e%a7%e5%88%b6%e7%ae%97%e6%b3%95/feed/" rel="self" type="application/rss+xml" />
	<link>https://cloudlay.cn</link>
	<description>life</description>
	<lastBuildDate>Sun, 14 Jun 2026 17:08:33 +0000</lastBuildDate>
	<language>zh-Hans</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.0</generator>

<image>
	<url>https://cloudlay.cn/wp-content/uploads/2026/01/avatar.ico</url>
	<title>控制算法 &#8211; Cloudlay</title>
	<link>https://cloudlay.cn</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>从0到1带你打电赛·小车电控篇(六)：PID 入门——从「把速度调稳」开始，一次搞懂 P、I、D</title>
		<link>https://cloudlay.cn/nuedc-car-06-pid-basics/</link>
					<comments>https://cloudlay.cn/nuedc-car-06-pid-basics/#respond</comments>
		
		<dc:creator><![CDATA[云间辞]]></dc:creator>
		<pubDate>Sun, 14 Jun 2026 17:08:33 +0000</pubDate>
				<category><![CDATA[嵌入式]]></category>
		<category><![CDATA[PID]]></category>
		<category><![CDATA[控制算法]]></category>
		<category><![CDATA[智能小车]]></category>
		<category><![CDATA[电赛]]></category>
		<category><![CDATA[调参]]></category>
		<category><![CDATA[速度环]]></category>
		<guid isPermaLink="false">https://cloudlay.cn/nuedc-car-06-pid-basics/</guid>

					<description><![CDATA[📚 本文是 「从 0 到 1 带你打电赛 · 小车电控篇」 系列（共 12 篇）第 6 篇。 第1篇 · 拿奖 [&#8230;]]]></description>
										<content:encoded><![CDATA[<div class="ds-series" style="border:1px solid #4488ff33;background:#4488ff0d;border-radius:8px;padding:.8em 1.1em;margin:1.2em 0">
<p style="margin:0 0 .5em"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4da.png" alt="📚" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 本文是 <strong>「从 0 到 1 带你打电赛 · 小车电控篇」</strong> 系列（共 12 篇）第 6 篇。</p>
<ol style="margin:.2em 0 0;padding-left:1.4em">
<li style="margin:.15em 0"><a href="https://cloudlay.cn/nuedc-car-01-how-to-score/">第1篇 · 拿奖逻辑：把比赛拆成小目标</a></li>
<li style="margin:.15em 0"><a href="https://cloudlay.cn/nuedc-car-02-history/">第2篇 · 赛题进化史与押题</a></li>
<li style="margin:.15em 0"><a href="https://cloudlay.cn/nuedc-car-03-build-and-architecture/">第3篇 · 整车搭建与代码框架</a></li>
<li style="margin:.15em 0"><a href="https://cloudlay.cn/nuedc-car-04-motor-power/">第4篇 · 电机驱动与电源地基</a></li>
<li style="margin:.15em 0"><a href="https://cloudlay.cn/nuedc-car-05-sensing/">第5篇 · 感知：灰度/电磁/编码器/IMU</a></li>
<li style="margin:.15em 0"><strong>第6篇 · PID 入门：搞懂 P/I/D（本篇）</strong></li>
<li style="margin:.15em 0"><a href="https://cloudlay.cn/nuedc-car-07-pid-advanced/">第7篇 · PID 进阶：串级+工程补丁</a></li>
<li style="margin:.15em 0"><a href="https://cloudlay.cn/nuedc-car-08-pid-tuning/">第8篇 · PID 调参实战(核心)</a></li>
<li style="margin:.15em 0"><a href="https://cloudlay.cn/nuedc-car-09-advanced-control/">第9篇 · 进阶控制：几时该上</a></li>
<li style="margin:.15em 0"><a href="https://cloudlay.cn/nuedc-car-10-vision-comm/">第10篇 · K230 视觉与通信协议</a></li>
<li style="margin:.15em 0"><a href="https://cloudlay.cn/nuedc-car-11-architecture-fsm/">第11篇 · 状态机与整车软件</a></li>
<li style="margin:.15em 0"><a href="https://cloudlay.cn/nuedc-car-12-field-manual/">第12篇 · 现场作战+避坑+开源</a></li>
</ol>
</div>
<p>到这一篇，我们终于要碰电控里&#8221;听起来最玄、其实最值钱&#8221;的东西了——PID。</p>
<p>前面几篇，我们给小车装好了电机、电源（电机驱动与电源地基那篇），又装好了灰度、编码器、IMU 这些&#8221;感官&#8221;（感知那篇）。现在小车能动、也能&#8221;知道自己现在多快、偏了多少&#8221;，可它还差最后一口气：不会<strong>自己根据偏差去纠正</strong>。这一步，就是 PID 干的活。</p>
<p>很多人对 PID 有两种相反的误解。一种把它当高深算法，看见公式里的积分微分就头大，绕道走；另一种觉得&#8221;不就三个数嘛，乱试呗&#8221;，结果调了一下午，车还在地上画龙。这篇我们专治这两种病：先用大白话把 P、I、D 三个字母到底在干嘛讲透，建立直觉；再讲清两种最常见的写法（位置式和增量式）到底差在哪、怎么选；最后手把手带你做&#8221;人生第一次调参&#8221;——只调一个电机的速度环，从只有 P 开始，一步步加到能稳稳跟住目标速度。</p>
<div class="ds-callout ds-callout-note" style="border-left:4px solid #448aff;background:#448aff14;padding:.6em 1em;margin:1.2em 0;border-radius:6px">
<p style="margin:0 0 .45em;font-weight:700;color:#448aff"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4dd.png" alt="📝" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 本篇只打地基</p>
<p>这一篇我们只做<strong>单环</strong>（一个电机、一个速度环），目的是建立直觉、跑通流程。真正比赛用的&#8221;方向环 + 速度环串级双环&#8221;，还有那一堆&#8221;不做就翻车&#8221;的工程补丁（积分限幅、抗饱和、微分滤波……），留到 PID 进阶那一篇专门讲。这里别贪多，先把一个环调明白，比啥都强。</p>
</div>
<h2>先搞懂一件事：什么是&#8221;负反馈&#8221;</h2>
<p>在拆 P、I、D 之前，得先有个总画面。PID 本质上是一套<strong>负反馈</strong>的纠错逻辑，一句话概括：</p>
<blockquote>
<p>拿&#8221;你想要的目标&#8221;减去&#8221;传感器测到的实际值&#8221;，得到一个<strong>偏差</strong>；再根据这个偏差算出一个<strong>控制量</strong>去纠正，让实际值往目标靠。偏差越大纠得越狠，偏差归零就收手。</p>
</blockquote>
<p>它一直在转圈：测量 → 算偏差 → 输出 → 再测量……画成图就是这样一个闭环：</p>
<figure class="ds-diagram" style="text-align:center;margin:1.3em 0"><img decoding="async" src="https://cloudlay.cn/wp-content/uploads/dianseiche/54bccefdbae0.png" alt="电赛小车电控 · 示意图" loading="lazy" style="max-width:100%;height:auto;background:#fff;border-radius:8px;padding:6px;box-shadow:0 1px 6px rgba(0,0,0,.25)"></figure>
<p>给它起几个固定名字，后面一直用：</p>
<ul>
<li><strong>目标值（setpoint）</strong>：你希望它达到的值。比如&#8221;电机转速 = 100&#8243;。</li>
<li><strong>实际值（反馈）</strong>：传感器测到的当前值。比如编码器测出来现在只有 60。</li>
<li><strong>偏差（error）</strong>：$e = \text{目标} &#8211; \text{实际}$。上面这例子 $e = 100 &#8211; 60 = 40$。</li>
<li><strong>控制量（output）</strong>：算出来要给执行机构的指令。对电机来说，就是 PWM 占空比。</li>
</ul>
<div class="ds-callout ds-callout-tip" style="border-left:4px solid #00bfa6;background:#00bfa614;padding:.6em 1em;margin:1.2em 0;border-radius:6px">
<p style="margin:0 0 .45em;font-weight:700;color:#00bfa6"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4a1.png" alt="💡" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 一个贯穿全篇的比喻：开车去停车线</p>
<p>你要把车停在前面一条线上。<strong>目标</strong> = 那条线的位置，<strong>实际</strong> = 你现在的位置，<strong>偏差</strong> = 还差多远，你脚下的油门/刹车 = <strong>控制量</strong>。离得远就猛踩油门，快到了松油门、点点刹车——你大脑里其实一直在跑一个&#8221;负反馈&#8221;。PID，就是把这套人脑里的本能，写成了三行可以照抄的公式。</p>
</div>
<p>而 P、I、D，就是从三个不同的时间视角去看同一个偏差：<strong>P 看现在、I 看过去、D 看未来</strong>。下面一个个拆。</p>
<h2>P：看现在——偏差多大就纠多狠（管&#8221;快&#8221;）</h2>
<p>P（Proportional，比例）是最直接的一项：<strong>当前偏差有多大，就按比例给多大的纠正力度</strong>。公式就一行：</p>
<p class="ds-math" style="overflow-x:auto">$$u_P = K_p \cdot e$$</p>
<p>$K_p$ 是你要调的比例系数。偏差大、纠正猛；偏差小、纠正轻；偏差归零，这一项也归零。</p>
<div class="ds-callout ds-callout-example" style="border-left:4px solid #7c4dff;background:#7c4dff14;padding:.6em 1em;margin:1.2em 0;border-radius:6px">
<p style="margin:0 0 .45em;font-weight:700;color:#7c4dff"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f9e9.png" alt="🧩" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 开车的 P</p>
<p>离停车线还有 100 米，你油门踩得很深；还剩 5 米，你只轻轻给一点。&#8221;差得越多、踩得越狠&#8221;，这就是 P。$K_p$ 就是你的&#8221;急脾气程度&#8221;——同样差 100 米，急脾气的人一脚油门到底，慢性子的人才慢慢加速。</p>
</div>
<p>P 决定了系统<strong>反应有多快、有多&#8221;硬&#8221;</strong>。这就是为什么常说 <strong>P 管&#8221;快&#8221;</strong>。</p>
<div class="ds-callout ds-callout-warning" style="border-left:4px solid #ff9100;background:#ff910014;padding:.6em 1em;margin:1.2em 0;border-radius:6px">
<p style="margin:0 0 .45em;font-weight:700;color:#ff9100"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/26a0.png" alt="⚠" class="wp-smiley" style="height: 1em; max-height: 1em;" /> P 不是越大越好</p>
<p>$K_p$ 太小：车反应迟钝、半天到不了目标，慢吞吞。 $K_p$ 太大：纠过头。还没到目标就冲过去了，冲过去又被拉回来，来回<strong>振荡</strong>，甚至越晃越大直接<strong>发散</strong>（车失控冲出去）。 而且，光靠 P 往往会留一条尾巴——<strong>稳态误差</strong>：车最后总是差那么一丢丢，停不到线上。原因是偏差一旦变小，$K_p \cdot e$ 这个力度也跟着变小，小到刚好抵消阻力（摩擦、坡度、风），系统就&#8221;卡&#8221;在那个差一点的地方不动了。这条尾巴，得靠下面的 I 来收拾。</p>
</div>
<h2>I：看过去——把欠的账一点点补上（管&#8221;准&#8221;）</h2>
<p>I（Integral，积分）专治 P 留下的那个&#8221;差一丢丢&#8221;的尾巴。它的逻辑是：<strong>把过去每一拍的残余偏差都累加起来，攒到一定程度，逼着系统把这点欠账补上</strong>。</p>
<p class="ds-math" style="overflow-x:auto">$$u_I = K_i \cdot \sum e$$</p>
<p>只要还有偏差没消掉，这个累加和 $\sum e$ 就一直在涨，对应的纠正力度也越来越大，直到偏差真正归零它才停止增长。所以 I 是专门<strong>消除稳态误差</strong>的，决定了系统最终能不能<strong>精确命中目标</strong>——这就是 <strong>I 管&#8221;准&#8221;</strong>。</p>
<div class="ds-callout ds-callout-example" style="border-left:4px solid #7c4dff;background:#7c4dff14;padding:.6em 1em;margin:1.2em 0;border-radius:6px">
<p style="margin:0 0 .45em;font-weight:700;color:#7c4dff"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f9e9.png" alt="🧩" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 洗澡调水温的 I</p>
<p>你想要 40 度，水管有热损耗，光靠 P（凉了就开大热水）总是卡在 38 度上不去。这时你心里那个&#8221;老差 2 度&#8221;的不爽会一点点累积，最后促使你&#8221;再多拧一点热水&#8221;，把这 2 度补回来。这个&#8221;把长期的小遗憾累加起来、最后一并补上&#8221;的劲儿，就是 I。</p>
</div>
<div class="ds-callout ds-callout-warning" style="border-left:4px solid #ff9100;background:#ff910014;padding:.6em 1em;margin:1.2em 0;border-radius:6px">
<p style="margin:0 0 .45em;font-weight:700;color:#ff9100"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/26a0.png" alt="⚠" class="wp-smiley" style="height: 1em; max-height: 1em;" /> I 调大的后果</p>
<p>$K_i$ 太小：欠账补得太慢，稳态误差迟迟消不掉。 $K_i$ 太大：补过头！因为它会&#8221;闷头攒&#8221;——等偏差终于归零时，前面攒下的那一大坨累加量一时撒不掉，结果<strong>冲过头、超调变大、来回振荡</strong>，整个系统反而<strong>变慢、变得不稳</strong>。 还有一个更隐蔽的坑叫<strong>积分饱和（windup）</strong>：如果偏差长期消不掉（比如车被卡住了、或者 PWM 已经顶到 100% 还不够），这个累加和会一路涨到天上去；等情况好转该收手时，这一肚子&#8221;攒下的火气&#8221;撒不掉，猛地冲过头。这个坑的解法（积分限幅、抗饱和）属于工程补丁，放到 PID 进阶那一篇细讲。本篇你只要记住一句：&#8221;<strong>I 不能贪大，攒过头会反噬</strong>&#8220;。</p>
</div>
<h2>D：看未来——看趋势提前刹车（管&#8221;稳&#8221;）</h2>
<p>D（Derivative，微分）是三项里最&#8221;聪明&#8221;的一项。它不看偏差本身有多大，而看<strong>偏差正在以多快的速度变化</strong>（这一拍的偏差减上一拍的偏差）：</p>
<p class="ds-math" style="overflow-x:auto">$$u_D = K_d \cdot (e_k &#8211; e_{k-1})$$</p>
<p>如果偏差正在飞快缩小，说明你正猛冲向目标，再不收手就要冲过头了——D 这时给一个反向的力，相当于<strong>提前点刹车</strong>，专门用来<strong>抑制超调、增加阻尼、让系统更稳</strong>。所以 <strong>D 管&#8221;稳&#8221;</strong>。</p>
<div class="ds-callout ds-callout-example" style="border-left:4px solid #7c4dff;background:#7c4dff14;padding:.6em 1em;margin:1.2em 0;border-radius:6px">
<p style="margin:0 0 .45em;font-weight:700;color:#7c4dff"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f9e9.png" alt="🧩" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 骑自行车的 D</p>
<p>老司机的口诀是&#8221;<strong>车身往哪倒，龙头往哪拐</strong>&#8220;。注意——你不是等真摔倒了才去救，而是看到车身<strong>正在往左倒</strong>（偏差在往一个方向变化）就提前往左打方向。这种&#8221;盯着趋势、提前动手&#8221;的预判，就是 D 的精髓。</p>
</div>
<div class="ds-callout ds-callout-danger" style="border-left:4px solid #ff1744;background:#ff174414;padding:.6em 1em;margin:1.2em 0;border-radius:6px">
<p style="margin:0 0 .45em;font-weight:700;color:#ff1744"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f525.png" alt="🔥" class="wp-smiley" style="height: 1em; max-height: 1em;" /> D 的最大副作用：放大噪声</p>
<p>$K_d$ 太大，会出大问题。因为 D 是对&#8221;变化量&#8221;做反应，而传感器的噪声（编码器测速的毛刺、陀螺仪角度的抖动）本身就是高频的剧烈变化——D 会把这些噪声<strong>当成真实趋势，放大成控制量的剧烈抖动</strong>，电机/舵机跟着发抖，曲线长满毛刺，越调越糟。 所以 D 一定要<strong>从 0 缓慢往上加</strong>，一旦看到曲线开始长毛刺、电机发抖，立刻停手并回调 10%~20%。如果噪声实在大，正确做法是给 D 项加个低通滤波（叫&#8221;不完全微分&#8221;），而不是一味硬压小 $K_d$——这个技巧同样留到进阶篇。 另外记牢一句：<strong>D 治不了稳态误差</strong>。偏差不变时（$e_k = e_{k-1}$），D 输出为 0，它对&#8221;卡在那不动的尾巴&#8221;完全无能为力，那是 I 的活。</p>
</div>
<h2>三个一起上：完整的 PID</h2>
<p>把三项加起来，就是完整的 PID：</p>
<p class="ds-math" style="overflow-x:auto">$$u(k) = K_p \cdot e(k) + K_i \cdot \sum e(i) + K_d \cdot [e(k) &#8211; e(k-1)]$$</p>
<p>用三个性格来记，特别好用：</p>
<table>
<thead>
<tr>
<th>项</th>
<th>看的是</th>
<th>管什么</th>
<th>性格比喻</th>
<th>调大了会</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>P</strong></td>
<td>现在的偏差</td>
<td><strong>快</strong>（响应速度、刚度）</td>
<td>急性子：差多少补多少，反应快但容易用力过猛</td>
<td>振荡、发散</td>
</tr>
<tr>
<td><strong>I</strong></td>
<td>过去的累计偏差</td>
<td><strong>准</strong>（消稳态误差）</td>
<td>记仇的人：每笔小账都记着，死磕到&#8221;一丝不差&#8221;</td>
<td>超调、积分饱和、变慢</td>
</tr>
<tr>
<td><strong>D</strong></td>
<td>偏差变化的趋势</td>
<td><strong>稳</strong>（抑制超调、阻尼）</td>
<td>预言家：看你冲太快就提前喊停</td>
<td>放大噪声、电机发抖</td>
</tr>
</tbody>
</table>
<div class="ds-callout ds-callout-important" style="border-left:4px solid #00bcd4;background:#00bcd414;padding:.6em 1em;margin:1.2em 0;border-radius:6px">
<p style="margin:0 0 .45em;font-weight:700;color:#00bcd4"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2757.png" alt="❗" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 务必记牢：&quot;P 快、I 准、D 稳&quot;</p>
<p>网上有些资料把它写成&#8221;P 管稳、D 管快&#8221;——这是<strong>说反了</strong>。权威控制教材（密歇根 CTMS、Caltech AM08 等）的结论是统一的：增大 $K_p$ 会<strong>加快</strong>响应（减小上升时间），所以 P 管&#8221;快&#8221;；$K_d$ 增加阻尼、抑制超调、改善稳定性，所以 D 管&#8221;稳&#8221;。只有 <strong>I 管&#8221;准&#8221;</strong> 这一条三方都没争议。照 <strong>P 快 / I 准 / D 稳</strong> 来记，别被对调的版本带偏。</p>
</div>
<h2>两种写法：位置式 vs 增量式</h2>
<p>上面那个公式，是<strong>位置式</strong>的写法。工程上还有一种<strong>增量式</strong>，两者长得不一样、用途也不一样，是新手最容易混的地方。务必搞清楚，否则照抄别人代码会出大问题。</p>
<h3>位置式：直接算出&#8221;绝对的&#8221;控制量</h3>
<p>就是上面那条完整公式，它算出来的 $u(k)$ 是一个<strong>绝对值</strong>——比如&#8221;舵机应该转到 37 度&#8221;。</p>
<p class="ds-math" style="overflow-x:auto">$$u(k) = K_p \cdot e(k) + K_i \sum_{i} e(i) + K_d \cdot [e(k) &#8211; e(k-1)]$$</p>
<p>特点： &#8211; 输出直接对应执行机构的绝对位置/角度，<strong>符合&#8221;我要它在哪&#8221;这种直觉</strong>。 &#8211; 含一个<strong>全历史误差累加</strong> $\sum e$，所以容易<strong>积分饱和</strong>，必须配积分限幅。 &#8211; 一旦某次算错、或者程序重启，因为输出是绝对值，执行机构会直接<strong>跳变</strong>到那个错误位置，有点危险。</p>
<h3>增量式：只算&#8221;在上次基础上加减多少&#8221;</h3>
<p>增量式算的不是绝对值，而是<strong>这一拍相对上一拍要变化多少</strong>（增量 $\Delta u$），最后累加回去：</p>
<p class="ds-math" style="overflow-x:auto">$$\Delta u(k) = K_p[e(k)-e(k-1)] + K_i \cdot e(k) + K_d[e(k)-2e(k-1)+e(k-2)]$$</p>
<p class="ds-math" style="overflow-x:auto">$$u(k) = u(k-1) + \Delta u(k)$$</p>
<p>它只跟<strong>最近 3 拍</strong>的误差有关，不显式累加全部历史。特点： &#8211; <strong>不显式累加 $\sum e$，所以天然规避了那种&#8221;积分项无限膨胀&#8221;的经典饱和</strong>。 &#8211; 某次算错只影响一个增量，<strong>误动作影响小、更安全</strong>，也便于&#8221;手动/自动&#8221;无扰切换。 &#8211; 缺点：靠累加 $\Delta u$ 间接实现积分，可能残留一点稳态误差；而且 3 拍差分对噪声更敏感。</p>
<div class="ds-callout ds-callout-note" style="border-left:4px solid #448aff;background:#448aff14;padding:.6em 1em;margin:1.2em 0;border-radius:6px">
<p style="margin:0 0 .45em;font-weight:700;color:#448aff"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4dd.png" alt="📝" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 别误会成&quot;绝对不会饱和&quot;</p>
<p>严格说，增量式只是<strong>不易</strong>发生显式的积分饱和，不是&#8221;绝对免疫&#8221;。当 $u(k)=u(k-1)+\Delta u$ 这个输出本身被限幅（比如 PWM 顶到 100%）时，照样会出现类似饱和的退出延迟，真较真起来工程上还是要做抗饱和处理。所以准确的说法是&#8221;<strong>天然规避显式积分饱和</strong>&#8220;，而不是&#8221;天生绝不饱和&#8221;。</p>
</div>
<h3>怎么选？</h3>
<p>记住这个比喻就够了：</p>
<div class="ds-callout ds-callout-tip" style="border-left:4px solid #00bfa6;background:#00bfa614;padding:.6em 1em;margin:1.2em 0;border-radius:6px">
<p style="margin:0 0 .45em;font-weight:700;color:#00bfa6"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4a1.png" alt="💡" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 油门 vs 方向盘</p>
<p><strong>位置式像报&#8221;油门踩到第几格&#8221;的绝对值</strong>——你要的就是一个绝对位置（舵机要转到某个绝对角度），适合它；但算错一次或重启就直接跳到错误档位（突变危险），还得记一路的总账（容易饱和）。 <strong>增量式像每次只说&#8221;油门再多/再少一点点&#8221;</strong>——说错一次只差一点点（影响小），不用记总账（不易饱和），对电机 PWM 做&#8221;增/减&#8221;最自然。</p>
<p>所以工程惯例是： &#8211; <strong>电机速度环 → 用增量式</strong>（通常是 PI，测速噪声大一般不加 D），对 PWM 做 <code>pwm += Δu</code> 最顺手； &#8211; <strong>舵机方向环 / 角度环 → 用位置式</strong>（通常是 PD，转向加 I 会延迟、弯道画龙，一般不加 I）。</p>
</div>
<p>这个&#8221;速度环增量式、方向环位置式&#8221;的搭配，是几乎所有智能车队的标配。本篇先把增量式速度环跑通；方向环长啥样、两者怎么串成两级，是 PID 进阶那一篇的主题。</p>
<div class="ds-callout ds-callout-warning" style="border-left:4px solid #ff9100;background:#ff910014;padding:.6em 1em;margin:1.2em 0;border-radius:6px">
<p style="margin:0 0 .45em;font-weight:700;color:#ff9100"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/26a0.png" alt="⚠" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 两种写法的系数不能直接照抄</p>
<p>位置式里乘 $\sum e$ 的 $K_i$，和增量式里乘 $e(k)$ 的 $K_i$，<strong>量纲和数值完全不同</strong>（增量式里乘 $e(k)$ 的那个系数其实承担了&#8221;积分&#8221;的角色）。网上很多博客把两种式子的系数混着贴，你照抄过来会差出十万八千里。<strong>换写法 = 重新整定</strong>。</p>
</div>
<h2>上代码：两种 PID 的最小实现</h2>
<p>光看公式没感觉，看代码就清楚了。先是位置式（最容易懂的入门写法，已经带上积分限幅和输出限幅这两道保险——为什么要加、怎么加得更好，进阶篇讲，这里先照抄）：</p>
<pre><code class="language-c">// 位置式 PID：输出当作绝对量(如舵机角度)
float Position_PID(float target, float measure){
    static float integral = 0, last_err = 0;
    float err = target - measure;          // 偏差 = 目标 - 实际

    integral += err;                       // I：累加历史偏差
    // 积分限幅(防止积分饱和，进阶篇细讲)
    if(integral &gt;  INT_MAX) integral =  INT_MAX;
    if(integral &lt; -INT_MAX) integral = -INT_MAX;

    float out = Kp*err                     // P：看现在
              + Ki*integral                // I：看过去
              + Kd*(err - last_err);       // D：看未来(偏差变化)
    last_err = err;                        // 记住这次偏差，下次算 D 用

    // 输出限幅(必做!否则可能烧电机/舵机)
    if(out &gt;  OUT_MAX) out =  OUT_MAX;
    if(out &lt; -OUT_MAX) out = -OUT_MAX;
    return out;
}</code></pre>
<p>增量式（速度环典型，直接对 PWM 做增减）：</p>
<pre><code class="language-c">// 增量式 PID：输出累加到 PWM 上，适合电机速度环
float Incremental_PID(float target, float measure){
    static float e0=0, e1=0, e2=0;         // 最近三拍误差：这次/上次/上上次
    static float pwm = 0;

    e0 = target - measure;
    float dU = Kp*(e0 - e1)                 // P：这拍与上拍偏差之差
             + Ki*e0                        // I：本拍偏差
             + Kd*(e0 - 2*e1 + e2);         // D：二阶差分
    pwm += dU;                              // 在上次基础上增减

    if(pwm &gt;  PWM_MAX) pwm =  PWM_MAX;      // 输出限幅
    if(pwm &lt; -PWM_MAX) pwm = -PWM_MAX;

    e2 = e1; e1 = e0;                       // 移位，准备下一拍
    return pwm;
}</code></pre>
<div class="ds-callout ds-callout-tip" style="border-left:4px solid #00bfa6;background:#00bfa614;padding:.6em 1em;margin:1.2em 0;border-radius:6px">
<p style="margin:0 0 .45em;font-weight:700;color:#00bfa6"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4a1.png" alt="💡" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <code>static</code> 是关键</p>
<p>注意那几个 <code>static</code> 变量——<code>integral</code>、<code>last_err</code>、<code>e0/e1/e2</code>、<code>pwm</code>。PID 靠&#8221;记住上一次的状态&#8221;工作，这些变量必须<strong>跨函数调用保留</strong>，所以用 <code>static</code>（或者更规范地塞进一个结构体里）。新手最常犯的错就是把它们写成普通局部变量，每次进函数都清零，PID 直接废掉。</p>
</div>
<h2>第一次调参：把一个电机的速度环调稳</h2>
<p>理论讲完，最爽的来了——亲手调一次。目标极其朴素：<strong>让一个电机稳稳地跟住一个目标转速</strong>。不管你设 100 还是 200，它都能快速、平稳、不抖地达到并保持。</p>
<h3>准备工作</h3>
<ol>
<li><strong>架空轮子</strong>。把车架起来或拿一个电机单测，别让它在地上乱窜。第一次调参，安全第一，手边随时能断电。</li>
<li><strong>接通编码器测速</strong>（感知那一篇讲过：用定时器编码器模式，把&#8221;单位周期的脉冲数&#8221;当速度反馈）。</li>
<li><strong>定好控制周期</strong>。用<strong>定时器中断</strong>固定周期跑 PID，不要用 <code>delay</code> 凑！速度环常用 <strong>5~10ms</strong>（100~200Hz）。周期必须严格恒定，否则等效参数会乱漂。</li>
<li><strong>把数据发出来看</strong>。这是调参的眼睛——用 <code>printf</code> 同时发&#8221;目标值&#8221;和&#8221;实际值&#8221;两路，丢给 <a href="https://www.vofa.plus/" target="_blank" rel="noopener noreferrer">VOFA+</a> 或串口示波器画成曲线。<strong>看不到波形，调参就是瞎子摸象。</strong> 具体怎么&#8221;看波形治百病&#8221;，是 PID 调参实战那一篇的核心内容，这里你先把曲线显示出来就行。</li>
</ol>
<div class="ds-callout ds-callout-important" style="border-left:4px solid #00bcd4;background:#00bcd414;padding:.6em 1em;margin:1.2em 0;border-radius:6px">
<p style="margin:0 0 .45em;font-weight:700;color:#00bcd4"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2757.png" alt="❗" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 控制周期决定参数量级</p>
<p>提前打个预防针：PID 系数的大小<strong>强烈依赖控制周期</strong>。粗略地说，采样 1ms 时 $K_p$ 可能在&#8221;1&#8243;这个量级，采样 500ms 时 $K_p$ 可能在&#8221;0.01&#8243;量级——差出 100 倍。所以<strong>别人的参数你不能直接照抄</strong>，只能当个&#8221;数量级参考&#8221;。下面给的数值同理，是起点不是答案。</p>
</div>
<h3>调参顺序：先 P、再 I、最后 D</h3>
<p>有句流传几十年的工程口诀，背下来准没错：</p>
<blockquote>
<p><strong>参数整定找最佳，从小到大顺序查；先是比例后积分，最后再把微分加。</strong></p>
</blockquote>
<p>为什么是这个顺序？因为 P 决定基本响应、必须先立起来；I 是在 P 的基础上去消那条残余尾巴；D 最后用来压超调和抖动。顺序乱了，三者互相干扰，你根本判断不出是谁在捣乱。</p>
<div class="ds-callout ds-callout-note" style="border-left:4px solid #448aff;background:#448aff14;padding:.6em 1em;margin:1.2em 0;border-radius:6px">
<p style="margin:0 0 .45em;font-weight:700;color:#448aff"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4dd.png" alt="📝" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 速度环常常只用 PI</p>
<p>提前说一句：<strong>电机速度环因为测速噪声大，很多时候只用 P 和 I，不加 D</strong>（加了 D 容易把测速毛刺放大成抖动）。所以下面的流程，重点是 P 和 I；D 你可以先不上，或者最后象征性地试一点点。</p>
</div>
<h4>第一步：只调 P，找到&#8221;临界振荡&#8221;再退一档</h4>
<p>把 $K_i$、$K_d$ 都设为 <strong>0</strong>，只留 P。给一个固定目标速度（比如目标 = 100）。</p>
<ul>
<li>从一个很小的 $K_p$ 开始，<strong>逐步加大</strong>。</li>
<li>你会看到：$K_p$ 小的时候，实际转速慢吞吞地往目标爬，还到不了（有稳态误差）；</li>
<li>$K_p$ 加大，响应变快，但开始有超调（冲过头再回来）；</li>
<li>继续加大到某个值，曲线开始<strong>等幅振荡</strong>（绕着目标值上下来回、幅度既不收敛也不发散）——这个点叫<strong>临界点</strong>，记下此时的 $K_p$；</li>
<li>然后把 $K_p$ <strong>退回到临界值的 60%~70%</strong>（或者干脆乘 0.6）。这就是你的 P 起点。</li>
</ul>
<p>这套&#8221;加到临界振荡再退一档&#8221;的做法，其实就是经典的<strong>临界比例度法（Ziegler-Nichols）</strong>的核心思想——它给你一个量级正确的起点，省得你从 0 瞎试。完整的 Z-N 换算表和起步估计，放到 PID 调参实战那一篇。</p>
<div class="ds-callout ds-callout-warning" style="border-left:4px solid #ff9100;background:#ff910014;padding:.6em 1em;margin:1.2em 0;border-radius:6px">
<p style="margin:0 0 .45em;font-weight:700;color:#ff9100"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/26a0.png" alt="⚠" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 往临界振荡推是有风险的</p>
<p>真把车推到等幅振荡，电机/舵机有炸机风险。所以：先低速、先架空轮子、手边随时能断电。&#8221;减半/打六折&#8221;只是个起点，后面还要配合 I、D 微调。</p>
</div>
<h4>第二步：加 I，把稳态误差那条尾巴收掉</h4>
<p>P 调好后，你的转速大概率还差一点点到不了目标（稳态误差）。现在从一个很小的 $K_i$ 开始往上加：</p>
<ul>
<li>经验起点：$K_i$ 大约取 $K_p$ 的 <strong>1/10 ~ 1/5</strong> 起步试。</li>
<li>加 I 之后观察曲线：稳态误差应该慢慢被&#8221;顶&#8221;上去，最终精确贴到目标线上。</li>
<li>$K_i$ 太小：尾巴消得太慢，半天贴不上目标。</li>
<li>$K_i$ 太大：开始超调、甚至振荡——这时往回退。</li>
</ul>
<h4>第三步（可选）：加 D，压一压超调</h4>
<p>如果加了 I 之后超调还是有点大，可以试着加一点点 D（从 0 缓慢加）来增加阻尼、压住超调。但前面说过，速度环测速噪声大，<strong>一旦看到曲线长毛刺、电机发抖，立刻停手回调</strong>。很多速度环这一步直接跳过。</p>
<p>调到这一步，你大概会在曲线上看到下面这几种典型现象，对照着调就行：</p>
<table>
<thead>
<tr>
<th>曲线现象</th>
<th>大概率是谁</th>
<th>怎么动</th>
</tr>
</thead>
<tbody>
<tr>
<td>半天爬不到目标、慢吞吞</td>
<td>$K_p$ 太小</td>
<td>加大 $K_p$</td>
</tr>
<tr>
<td>来回振荡 / 越晃越大</td>
<td>$K_p$ 太大</td>
<td>减小 $K_p$</td>
</tr>
<tr>
<td>稳稳停住，但总差一丢丢（静差）</td>
<td>缺 I / $K_i$ 太小</td>
<td>加大 $K_i$</td>
</tr>
<tr>
<td>冲过头超调大、回不来</td>
<td>$K_i$ 太大</td>
<td>减小 $K_i$，或补一点 D</td>
</tr>
<tr>
<td>曲线长毛刺、电机发抖</td>
<td>$K_d$ 太大（放大噪声）</td>
<td>减小 $K_d$，或给 D 加滤波</td>
</tr>
</tbody>
</table>
<h3>一组真实的电赛参数（仅供感受量级）</h3>
<p>光说&#8221;经验起点&#8221;太抽象，给你看一组 2024 年电赛巡线小车的<strong>真实实测参数</strong>，感受一下数量级（再强调一遍：这是<strong>别人车上的个案值，不能照抄，只能当参照</strong>）：</p>
<table>
<thead>
<tr>
<th>项目</th>
<th>取值</th>
</tr>
</thead>
<tbody>
<tr>
<td>$K_p$</td>
<td>96</td>
</tr>
<tr>
<td>$K_i$</td>
<td>0.01</td>
</tr>
<tr>
<td>$K_d$</td>
<td>1.5</td>
</tr>
<tr>
<td>主循环周期</td>
<td>20ms</td>
</tr>
<tr>
<td>PWM 频率</td>
<td>约 36kHz</td>
</tr>
<tr>
<td>基础速度</td>
<td>260</td>
</tr>
<tr>
<td>速度限幅</td>
<td>±550</td>
</tr>
</tbody>
</table>
<div class="ds-callout ds-callout-example" style="border-left:4px solid #7c4dff;background:#7c4dff14;padding:.6em 1em;margin:1.2em 0;border-radius:6px">
<p style="margin:0 0 .45em;font-weight:700;color:#7c4dff"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f9e9.png" alt="🧩" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 从这组数读出的门道</p>
<p>注意 $K_i$ 被压到 <strong>0.01</strong> 这么小——这说明这辆车的环路<strong>主要靠 P 和 D</strong>，积分作用极弱。原因是巡线/转向场景里，积分稍微大一点，过弯时偏差就会被累加放大，把车顶出赛道。这正好印证了前面那句：&#8221;<strong>转向/方向环里积分要非常克制，甚至不用</strong>。&#8221; （来源：<a href="https://www.cnblogs.com/laideblog/p/18842942" target="_blank" rel="noopener noreferrer">2024 电赛小车记</a>）</p>
</div>
<h3>一个调不出来时的保命心态</h3>
<p>最后讲个真事。有位作者做摄像头跟踪云台（X/Y 双轴 PID，以画面中心为目标、小球坐标为反馈），因为系统太复杂，比赛现场参数怎么都收敛不了，最后他承认&#8221;<strong>开环也未尝不可</strong>&#8220;——退一步用开环或分段控制保底，反而把任务完成了。</p>
<div class="ds-callout ds-callout-tip" style="border-left:4px solid #00bfa6;background:#00bfa614;padding:.6em 1em;margin:1.2em 0;border-radius:6px">
<p style="margin:0 0 .45em;font-weight:700;color:#00bfa6"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4a1.png" alt="💡" class="wp-smiley" style="height: 1em; max-height: 1em;" /> PID 不是万能的</p>
<p>比赛就那么四天三夜，<strong>别在调参上耗死自己</strong>。如果一个闭环死活调不收敛，退一步用更简单的开环/查表/分段控制保底，往往比硬磕一个不收敛的 PID 更靠谱。先能跑、能拿分，再谈优雅。（<a href="https://blog.csdn.net/cyaya6/article/details/132174286" target="_blank" rel="noopener noreferrer">经验来源</a>）</p>
</div>
<h2>几个新手必踩的坑（先记下，进阶篇细讲）</h2>
<p>这篇是入门，下面这些坑你<strong>先有个印象</strong>就好，真正的解法在 PID 进阶和 PID 调参实战两篇里：</p>
<ul>
<li><strong><code>static</code> 状态变量被清零</strong> → PID 失效。这是最低级也最高频的错。</li>
<li><strong>极性搞反</strong>（偏差符号或电机方向反了）→ 不是负反馈而是正反馈，车越偏越猛、直接发散。上电先用很小的增益验一下极性。</li>
<li><strong>用 <code>delay</code> 凑控制周期、或周期被中断打乱</strong> → 相当于采样忽快忽慢，等效参数乱漂，怎么调都不对。一定用定时器固定周期。</li>
<li><strong>照抄别人参数却换了周期/电机/电压</strong> → 量级完全不对。</li>
<li><strong>位置式忘了给积分限幅</strong> → 积分饱和，超调到天上。</li>
<li><strong>D 直接加大</strong> → 放大测速噪声，电机发抖。</li>
</ul>
<h2>小结</h2>
<p>这一篇，我们把 PID 从&#8221;玄学&#8221;拉回了&#8221;直觉&#8221;：</p>
<ul>
<li>它是一套<strong>负反馈纠错</strong>：目标减实际得偏差，再用三路力度去纠。</li>
<li><strong>P 看现在（管快）、I 看过去（管准）、D 看未来（管稳）</strong>——记牢是&#8221;P 快、I 准、D 稳&#8221;，别被对调的版本骗了。</li>
<li><strong>位置式</strong>输出绝对量、适合舵机/方向环；<strong>增量式</strong>输出增量、适合电机速度环，且天然规避显式积分饱和。</li>
<li>调参顺序铁律：<strong>先 P、再 I、最后 D，参数从小到大</strong>。第一次就拿一个电机的速度环练手，把曲线发到上位机上盯着调。</li>
</ul>
<p>你现在已经能让<strong>一个电机</strong>稳稳听话了。但一辆车要跑起来，光有速度还不够——它还得知道&#8221;往哪偏了、该怎么转&#8221;，这就要把<strong>方向环</strong>也加进来，让它和速度环<strong>串成两级</strong>协同工作；而真正让车在赛道上不翻不冲，还得靠一整套工程补丁。这些，我们下一篇 PID 进阶接着聊。</p>
<div class="ds-series" style="border:1px solid #4488ff33;background:#4488ff0d;border-radius:8px;padding:.8em 1.1em;margin:1.2em 0">
<p style="margin:0 0 .5em"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4da.png" alt="📚" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 本文是 <strong>「从 0 到 1 带你打电赛 · 小车电控篇」</strong> 系列（共 12 篇）第 6 篇。</p>
<ol style="margin:.2em 0 0;padding-left:1.4em">
<li style="margin:.15em 0"><a href="https://cloudlay.cn/nuedc-car-01-how-to-score/">第1篇 · 拿奖逻辑：把比赛拆成小目标</a></li>
<li style="margin:.15em 0"><a href="https://cloudlay.cn/nuedc-car-02-history/">第2篇 · 赛题进化史与押题</a></li>
<li style="margin:.15em 0"><a href="https://cloudlay.cn/nuedc-car-03-build-and-architecture/">第3篇 · 整车搭建与代码框架</a></li>
<li style="margin:.15em 0"><a href="https://cloudlay.cn/nuedc-car-04-motor-power/">第4篇 · 电机驱动与电源地基</a></li>
<li style="margin:.15em 0"><a href="https://cloudlay.cn/nuedc-car-05-sensing/">第5篇 · 感知：灰度/电磁/编码器/IMU</a></li>
<li style="margin:.15em 0"><strong>第6篇 · PID 入门：搞懂 P/I/D（本篇）</strong></li>
<li style="margin:.15em 0"><a href="https://cloudlay.cn/nuedc-car-07-pid-advanced/">第7篇 · PID 进阶：串级+工程补丁</a></li>
<li style="margin:.15em 0"><a href="https://cloudlay.cn/nuedc-car-08-pid-tuning/">第8篇 · PID 调参实战(核心)</a></li>
<li style="margin:.15em 0"><a href="https://cloudlay.cn/nuedc-car-09-advanced-control/">第9篇 · 进阶控制：几时该上</a></li>
<li style="margin:.15em 0"><a href="https://cloudlay.cn/nuedc-car-10-vision-comm/">第10篇 · K230 视觉与通信协议</a></li>
<li style="margin:.15em 0"><a href="https://cloudlay.cn/nuedc-car-11-architecture-fsm/">第11篇 · 状态机与整车软件</a></li>
<li style="margin:.15em 0"><a href="https://cloudlay.cn/nuedc-car-12-field-manual/">第12篇 · 现场作战+避坑+开源</a></li>
</ol>
</div>
]]></content:encoded>
					
					<wfw:commentRss>https://cloudlay.cn/nuedc-car-06-pid-basics/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
