Codync
免費、開源的 1:1 替代方案,取代 Grok Bot 與 Muse。從 iPhone、Mac 或 Linux 桌面將 Claude Code、Codex、Cursor 與 40+ 程式碼代理人作為持續機器人傳訊。群組聊天、主題串…
AI 翻譯
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證Hardware-agnostic Arduino PID controller library on the Arduino Library Manager: independent instances, automatic or explicit timing, anti-windup, derivative filtering, per-term introspection and an optional relay autotuner.
翻譯準備中
取自儲存庫 README
正在載入完整 README。
檢視完整 README ↗A hardware-agnostic PID controller for Arduino that makes timing, saturation, noise and its own internal state part of the interface, not an afterthought.
#include <easyPID.h>
// Kp, Ki, Kd, and the output limits of a PWM pin
PIDController pid(2.0, 0.5, 0.1, 0.0, 255.0);
void setup() {
pid.begin();
pid.setAntiWindup(ANTIWINDUP_CLAMP);
}
void loop() {
float measurement = analogRead(A0) / 4.0;
float output = pid.update(100.0, measurement); // setpoint, measurement
analogWrite(9, (int)output);
delay(100); // a fixed 10 Hz loop
}
The library's BasicPID example, adapted to read a sensor on A0 and drive pin 9.
Most introductions to PID control end at the formula. Real embedded control starts after it: the loop runs late, the actuator saturates, sensor noise swamps the derivative, a second controller has to coexist with the first, and whoever is tuning needs to see what each term is doing instead of guessing from the output.
I wrote easyPID to handle those parts. Each controller is its own object with no global state. It can measure time itself or take the time step from your scheduler, it bounds its output and protects its integral, it can filter the derivative, and it exposes the P, I and D contributions so tuning becomes diagnosis. An optional relay autotuner can find starting gains, with its operating conditions written down.
It grew out of my two-axis light tracker, and it is the PID library used in my drone-control bootcamp, where every lab runs on it.
| Distribution | Arduino Library Manager, contributed Device Control library |
| Releases | 1.0.0 listed 15 January 2026; 1.1.0 on 9 August 2026 |
| Instances | as many as you need, each with its own gains and state |
| Timing | automatic from millis(), or an explicit time step in milliseconds |
| Saturation | output limits, optional integral limits, anti-windup by clamping or back-calculation |
| Noise | optional first-order (EMA) low-pass filter on the derivative |
| Introspection | error, P, I and D contributions, and the last output |
| Autotuning | opt-in relay (limit-cycle) tuner with four tuning rules |
| Boards | architecture *; CI compiles every example for Uno, Mega 2560 and ESP32 |
flowchart LR
SP[setpoint] --> E((error))
PV[measurement] --> E
E --> P[P: Kp · e]
E --> I[I: Ki · ∫e dt<br/>integral limits, anti-windup]
E --> D[D: Kd · de/dt<br/>optional EMA filter]
P --> S((Σ))
I --> S
D --> S
S --> L[output limits] --> OUT[actuator]
L -. saturated .-> I
PIDController with its own gains, limits and state, so two or ten loops never share anything.update(setpoint, measurement) measures the elapsed time from millis(). update(setpoint, measurement, dtMs) takes the step from you, which lets a scheduler or a test harness own the clock and makes simulations repeatable.getPterm(), getIterm() and getDterm() show what each term contributes. If the integral is carrying the system, or the derivative is amplifying noise, you can see it.PIDTuner drives the process into a controlled oscillation with a relay, measures the ultimate gain and period, and turns them into gains with Ziegler–Nichols, Tyreus–Luyben, Pessen or a no-overshoot rule.Arduino IDE. Open Tools → Manage Libraries…, search for easyPID, and install it. The examples then appear under File → Examples → easyPID.
Arduino CLI.
arduino-cli lib install easyPID
Manually. Download this repository as a ZIP and use Sketch → Include Library → Add .ZIP Library…, or clone it into your sketchbook's libraries folder:
git clone https://github.com/Kronbii/easyPID.git ~/Arduino/libraries/easyPID
The sketchbook is ~/Arduino on Linux and Documents/Arduino on Windows and macOS. Restart the IDE afterwards.
The snippet at the top is the whole pattern: a constructor, begin() in setup(), and one update() per sample. update() returns the previous output if no whole millisecond has passed, so it is safe to call from a fast loop().
From the MultiLoopPID example: two independent controllers, the second with back-calculation anti-windup and a filtered derivative, both given the sample period explicitly.
#include <easyPID.h>
const unsigned long SAMPLE_TIME_MS = 100;
PIDController pid1(1.5, 0.8, 0.05, 0.0, 255.0); // fast process
PIDController pid2(3.0, 0.3, 0.2, 0.0, 255.0); // slow, noisy process
unsigned long lastTime = 0;
void setup() {
pid1.begin();
pid2.begin();
pid1.setAntiWindup(ANTIWINDUP_CLAMP);
pid2.setAntiWindup(ANTIWINDUP_BACKCALC);
pid2.setDerivativeFilter(FILTER_EMA, 0.7);
}
void loop() {
unsigned long now = millis();
if (now - lastTime >= SAMPLE_TIME_MS) {
lastTime = now;
float out1 = pid1.update(80.0, analogRead(A0) / 4.0, SAMPLE_TIME_MS);
float out2 = pid2.update(120.0, analogRead(A3) / 4.0, SAMPLE_TIME_MS);
analogWrite(9, (int)out1);
analogWrite(10, (int)out2);
}
}
The time step is in milliseconds, not seconds.
Include PIDTuner.h and run the relay until it completes, then hand the gains to the controller. On a unipolar actuator such as a heater or a PWM pin, pass an output bias that holds the process near the setpoint; without it the relay spends half of each period at a drive the hardware clips to zero and tuning times out. This follows the AutoTunePID example:
#include <easyPID.h>
#include <PIDTuner.h>
const float SETPOINT = 37.0;
PIDController pid(1.0, 0.0, 0.0, 0.0, 255.0);
PIDTuner tuner(pid);
bool tuned = false;
void setup() {
pid.begin();
// setpoint, relay amplitude, noise band, output bias
tuner.start(SETPOINT, 50.0, 5.0, 127.0);
}
void loop() {
float measurement = analogRead(A0) / 4.0;
if (tuner.getState() == TUNER_RELAY_STEP) {
analogWrite(9, (int)tuner.update(measurement));
} else if (tuner.isComplete()) {
if (!tuned) {
tuned = tuner.applyTunings(TUNING_ZIEGLER_NICHOLS); // also resets pid
}
analogWrite(9, (int)pid.update(SETPOINT, measurement));
} else if (tuner.getState() == TUNER_FAILED) {
analogWrite(9, 0); // no usable oscillation was measured
}
delay(50);
}
The autotuner deliberately makes the process oscillate. Only run it with safe actuator limits, on a process that tolerates repeated oscillation, and with someone ready to stop it. Treat its gains as a starting point.
All three examples, BasicPID, MultiLoopPID and AutoTunePID, run on a simulated plant, so they need no hardware.
PIDController (#include <easyPID.h>)| Method | What it does |
|---|---|
PIDController(kp, ki, kd, outMin, outMax) | Creates a controller. Defaults: ANTIWINDUP_CLAMP, no derivative filter, DIRECT, no integral limits. |
begin() | Initialises state and timing. Call it in setup(). |
update(setpoint, measurement) | Computes the output, measuring the time step from millis(). |
update(setpoint, measurement, dtMs) | Computes the output with a time step you supply, in milliseconds. |
setSetpoint(sp), setMeasurement(pv), compute() | The same computation in three calls, for code that sets values in different places. |
setTunings(kp, ki, kd) | Changes the gains at runtime. |
setOutputLimits(min, max) | Clamps the output. Ignored if min >= max. |
setIntegralLimits(min, max) | Bounds the raw error-time accumulator (the I term is Ki times it). Off until called. |
setAntiWindup(mode) | ANTIWINDUP_NONE, ANTIWINDUP_CLAMP or ANTIWINDUP_BACKCALC. |
setDerivativeFilter(mode, alpha = 0.8) | FILTER_NONE or FILTER_EMA; a higher alpha filters more, clamped to 0–0.999. |
setDirection(dir) | DIRECT or REVERSE (for example, cooling). Switching at runtime is bumpless. |
setSampleTime(ms) | Records the expected period. Advisory only: it does not gate update(). |
reset() | Clears the integral, derivative and error history and restarts the timing reference. |
getError() | setpoint - measurement, in either direction. |
getPterm(), getIterm(), getDterm() | Each term's contribution; they sum to the output before clamping. |
PIDTuner (#include <PIDTuner.h>, optional)| Method | What it does |
|---|---|
PIDTuner(pid) | Attaches a tuner to a controller. |
start(setpoint, relayAmplitude, noiseBand = 0.5, outputBias = 0) | Starts a run. The relay swings over outputBias ± relayAmplitude. Returns false if a run is in progress or the arguments are invalid. |
update(measurement) | Returns the relay output to apply while the state is TUNER_RELAY_STEP, and 0 otherwise. |
getState() | TUNER_IDLE, TUNER_RELAY_STEP, TUNER_ANALYZING, TUNER_COMPLETE or TUNER_FAILED. |
isComplete(), getProgress() | Whether results are ready; fraction of the required cycles collected. |
getTunings(kp, ki, kd, rule) | Writes the gains for a rule into your variables. |
applyTunings(rule) | Applies the gains to the attached controller and resets it. |
getUltimateGain(), getUltimatePeriod() | The measured Ku and Pu (in seconds). |
cancel() | Stops a run. |
Tuning rules: TUNING_ZIEGLER_NICHOLS, TUNING_TYREUS_LUYBEN, TUNING_PESSEN, TUNING_NO_OVERSHOOT.
DIRECT and REVERSE collide with the macros of the PID_v1 library. If a sketch uses both, include easyPID.h first; the header stops with a clear error otherwise.
src/ easyPID.h/.cpp (PIDController), PIDTuner.h/.cpp (autotuner)
examples/ BasicPID, MultiLoopPID, AutoTunePID
docs/tuning_guide.md choosing gains, anti-windup, filtering, autotuning, pitfalls
extras/test/ host tests with a virtual clock; no board needed
library.properties Library Manager metadata
CHANGELOG.md release notes
The host tests run on your computer with make -C extras/test test. Before a pull request, please read AGENTS.md and CONTRIBUTING.md.
Built by Rami Kronbi — ramikronbi.com
getOutput() |
| The last computed output. |