Codync
무료 오픈소스 1:1 대안, Grok Bot과 Muse 대신
하드웨어에 구애받지 않는 Arduino PID 라이브러리, 독립 인스턴스·안티와인드업·미분 필터링·상태 확인·선택적 릴레이 자동조정 제공
A hardware-agnostic Arduino PID library with independent instances, anti-windup, derivative filtering, state introspection, and an optional relay autotuner.
개발 도구C++ · CGitHub @Kronbii온라인운영자 미확인
써 보셨어요? 한 번만 눌러 주세요. 로그인은 필요 없어요.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기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. |