Zbotic Logo Zbotic Logo
  • Home
  • Shop
  • Sale
  • 3D Print Service
  • PCB Service
  • B2B
  • Blogs
  • Contact Us
0 0

View Wishlist Add all to cart

0 0
0 Shopping Cart
Shopping cart (0)
Subtotal: ₹0.00

View cartCheckout

  • Shop
  • About Us
  • Contact Us
  • Reseller
  • Blogs
020 69134444
1800 209 0998
[email protected]
Help Desk
Facebook Twitter Instagram Linkedin YouTube
Zbotic Logo Zbotic Logo
0 0

View Wishlist Add all to cart

0 0
0 Shopping Cart
Shopping cart (0)
Subtotal: ₹0.00

View cartCheckout

All departments
  • 3D Print Service
  • 3D Printer
  • Batteries & Chargers
  • Development Boards
  • Drone Parts
  • EBike parts
  • Sensor Modules
  • Electronic Components
  • Electronic Modules
  • IoT and Wireless
  • Mechanical Parts and Workbench Tools
  • Motors & Drivers & Pumps & Actuators
  • DIY and Robot Kits
  • Show more
  • Home
  • Shop
  • Sale
  • 3D Print Service
  • PCB Service
  • B2B
  • Blogs
  • Contact Us
Return to previous page
Home Robotics & DIY

PID Controller Tutorial: Theory & Arduino Implementation Guide

PID Controller Tutorial: Theory & Arduino Implementation Guide

March 11, 2026 /Posted byJayesh Jain / 0

A PID controller — Proportional, Integral, Derivative — is the workhorse of industrial and hobbyist control systems. Whether you are building a self-balancing robot, a line follower, a temperature controller, or a motor speed regulator, the PID algorithm provides the closed-loop feedback needed to reach and maintain a target setpoint despite disturbances and system variations. This tutorial explains PID theory from first principles and walks through a complete, tuned Arduino implementation.

Table of Contents

  • PID Theory: P, I, and D Explained
  • PID Mathematics
  • Arduino PID Implementation
  • PID Tuning Methods: Ziegler-Nichols
  • Integral Windup Prevention
  • Real-World Application Examples
  • Recommended Products
  • Frequently Asked Questions

PID Theory: P, I, and D Explained

A PID controller continuously calculates an error value — the difference between the desired setpoint and the measured process variable — and applies a correction based on three terms:

Proportional (P): Applies a correction proportional to the current error. Large error = large correction. If the error is halved, the correction is halved. P control alone results in steady-state error (offset) — the system settles slightly away from the setpoint because the correction needed to counteract friction or gravity requires a non-zero error.

Integral (I): Accumulates the error over time and applies a correction proportional to the accumulated error. This eliminates steady-state error — even a tiny persistent error grows the integral term until the system reaches the exact setpoint. Too much I gain causes oscillation and slow response (the system overshoots and hunts around the setpoint).

Derivative (D): Applies a correction proportional to the rate of change of the error. D control acts as a damper — it counteracts rapid changes in error, reducing overshoot and improving stability. D gain must be tuned carefully: too much D causes the controller to react aggressively to sensor noise, producing unstable oscillations.

PID Mathematics

The PID control output at time t is:

// Continuous PID formula:
// u(t) = Kp*e(t) + Ki*∫e(t)dt + Kd*(de/dt)

// Discrete (digital) version using delta-time dt:
// error = setpoint - measured_value
// P_term = Kp * error
// I_term += Ki * error * dt
// D_term = Kd * (error - previous_error) / dt
// output = P_term + I_term + D_term

The three tuning parameters are:

  • Kp (Proportional gain): Primary response magnitude. Units: output_units / error_units
  • Ki (Integral gain): Eliminates steady-state error. Units: output_units / (error_units × time)
  • Kd (Derivative gain): Damps overshoot. Units: output_units × time / error_units

Arduino PID Implementation

This implementation follows best practices: using delta-time for consistent behaviour regardless of loop speed, clamping output to valid range, and separating the PID class for reusability:

class PID {
private:
  float Kp, Ki, Kd;
  float integral;
  float prevError;
  float outMin, outMax;
  unsigned long prevTime;

public:
  PID(float kp, float ki, float kd, float minOut, float maxOut)
    : Kp(kp), Ki(ki), Kd(kd),
      outMin(minOut), outMax(maxOut),
      integral(0), prevError(0), prevTime(0) {}

  float compute(float setpoint, float measured) {
    unsigned long now = micros();
    float dt = (now - prevTime) / 1e6f;  // Convert µs to seconds

    if (prevTime == 0 || dt <= 0 || dt > 0.5f) {
      // First call or stale timing — skip derivative
      prevTime = now;
      prevError = setpoint - measured;
      return 0;
    }
    prevTime = now;

    float error    = setpoint - measured;
    float dError   = (error - prevError) / dt;
    prevError      = error;

    float pTerm = Kp * error;
    integral   += Ki * error * dt;
    // Clamp integral to prevent windup
    integral    = constrain(integral, outMin, outMax);
    float dTerm = Kd * dError;

    float output = constrain(pTerm + integral + dTerm, outMin, outMax);
    return output;
  }

  void reset() {
    integral  = 0;
    prevError = 0;
    prevTime  = 0;
  }

  void setGains(float kp, float ki, float kd) {
    Kp = kp; Ki = ki; Kd = kd;
  }
};

Example: Motor Speed PID Controller

// Motor speed control using PID
// Encoder on interrupt pins, motor on PWM pin

#include <Arduino.h>

#define ENCODER_A 2   // Interrupt pin
#define MOTOR_PWM 9   // PWM motor control
#define MOTOR_DIR 8   // Motor direction

volatile long encoderCount = 0;

void IRAM_ATTR encoderISR() {
  encoderCount++;
}

PID speedPID(2.0f, 0.5f, 0.1f, -255.0f, 255.0f);

float targetRPM = 60.0f;  // Target speed: 60 RPM

long prevCount = 0;
unsigned long prevMeasTime = 0;

float measureRPM() {
  unsigned long now = millis();
  long count = encoderCount;
  float dt_ms = now - prevMeasTime;

  if (dt_ms < 50) return -1; // Not enough time for accurate measurement

  float pulses = count - prevCount;
  float rpm = (pulses / 20.0f) * (60000.0f / dt_ms); // 20 pulses/rev encoder

  prevCount = count;
  prevMeasTime = now;
  return rpm;
}

void setMotor(float output) {
  if (output >= 0) {
    digitalWrite(MOTOR_DIR, HIGH);
    analogWrite(MOTOR_PWM, (int)output);
  } else {
    digitalWrite(MOTOR_DIR, LOW);
    analogWrite(MOTOR_PWM, (int)(-output));
  }
}

void setup() {
  Serial.begin(115200);
  pinMode(ENCODER_A, INPUT_PULLUP);
  pinMode(MOTOR_PWM, OUTPUT);
  pinMode(MOTOR_DIR, OUTPUT);
  attachInterrupt(digitalPinToInterrupt(ENCODER_A), encoderISR, RISING);
}

void loop() {
  float rpm = measureRPM();
  if (rpm < 0) return;

  float output = speedPID.compute(targetRPM, rpm);
  setMotor(output);

  Serial.print("Target: "); Serial.print(targetRPM);
  Serial.print(" RPM | Actual: "); Serial.print(rpm);
  Serial.print(" RPM | Output: "); Serial.println(output);
}

PID Tuning Methods: Ziegler-Nichols

The Ziegler-Nichols method provides a systematic starting point for PID tuning:

  1. Set Ki = 0 and Kd = 0 (P-only control)
  2. Slowly increase Kp until the system oscillates continuously at a constant amplitude. Record this value as Ku (ultimate gain) and the oscillation period as Tu (ultimate period in seconds)
  3. Apply the Ziegler-Nichols PID formulas:
// Ziegler-Nichols PID starting values:
float Kp = 0.6f * Ku;
float Ki = 2.0f * Kp / Tu;   // = 1.2 * Ku / Tu
float Kd = Kp * Tu / 8.0f;   // = 0.075 * Ku * Tu

Ziegler-Nichols gives a starting point — fine-tune from there. The method tends to produce aggressive response with some overshoot; reduce Kp by 20% and Ki by 30% from the Z-N values for a more conservative, overshoot-free response.

Integral Windup Prevention

Integral windup occurs when the output is saturated (at its maximum/minimum value) but the error persists — the integral keeps accumulating to enormous values. When the system finally reaches setpoint, the large integral causes significant overshoot before it winds down.

Prevention strategies:

  • Clamping: Clamp the integral to [outMin, outMax] — shown in the class above
  • Conditional integration: Only accumulate integral when output is NOT saturated
  • Back-calculation: Reduce integral by the difference between saturated and actual output each time step
// Anti-windup with conditional integration:
float rawOutput = pTerm + integral + dTerm;
if (rawOutput >= outMax || rawOutput <= outMin) {
  // Output is saturated — stop integrating
} else {
  integral += Ki * error * dt;  // Only integrate when not saturated
}

Real-World Application Examples

Self-Balancing Robot

An inverted pendulum (two-wheeled balancing robot) uses PID with the body tilt angle (from MPU6050 IMU) as the measured variable and motor PWM as the output. Typical gains: Kp=50–100, Ki=100–200, Kd=5–20. The MPU6050’s complementary filter or Kalman filter output provides the tilt angle; the PID output drives left and right motor speeds differentially.

Temperature Controller

A PID temperature controller for a reflow oven or PCB hotplate uses a thermocouple or NTC thermistor for temperature measurement and a SSR (Solid State Relay) for heater control. Since temperature changes slowly, the derivative term is often minimal. Typical gains: Kp=2–5, Ki=0.1–0.5, Kd=0.5–2. Time constant is seconds to minutes — sample and update every 500 ms.

Line-Following Robot

A PID line follower uses an array of IR sensors to measure the line position offset from centre (e.g., -100 to +100) as the error, and differential motor speed as the output. Kp=0.5–2.0, Ki=0–0.1, Kd=0.5–3.0. The D term is critical for smooth steering on curved lines.

Recommended Products

Waveshare General Driver Board for Robots (ESP32)

This ESP32-based robot driver board is purpose-built for PID-controlled motor projects. It integrates a dual H-bridge motor driver, encoder interfaces, servo headers, and the ESP32’s hardware PWM timers — all the hardware you need for closed-loop PID motor speed control without external motor driver boards.

View Product

Waveshare 20 kg.cm Bus Servo with 360° Encoder

Bus servos with integrated encoders are ideal for PID position control of robotic arm joints. The 360° magnetic encoder provides real-time position feedback that the PID controller uses to track joint angle targets with precision. The serial bus daisy-chain simplifies multi-joint PID implementation.

View Product

Waveshare DDSM115 Direct Drive Servo Hub Motor

For mobile robot PID speed control, the DDSM115 hub motor provides integrated current sensing and speed feedback — all the signals needed for closed-loop PID wheel speed regulation. The low-noise brushless design eliminates the encoder-jitter issues common with brushed DC motors and optical encoders.

View Product

Waveshare Direct Drive Servo Motor Driver Board (ESP32)

Waveshare’s ESP32-based motor driver board specifically designed for their DDSM-series hub motors. Integrates the ESP32 and motor control circuitry with ESP-NOW 2.4G WiFi support for wireless PID setpoint commands. Perfect for building a PID-controlled differential drive robot with remote speed control.

View Product

Frequently Asked Questions

Should I use the Arduino PID Library or write my own?

The Arduino PID library by Brett Beauregard is excellent and production-tested — it handles edge cases like derivative kick, output clamping, and bumpless parameter changes. Writing your own PID class (as shown in this tutorial) provides deeper understanding and customisation. For beginners, start with the library; once comfortable, implement your own for projects with specific requirements.

Why does my PID system oscillate even with small gains?

Oscillation with small gains usually indicates a measurement delay or sample rate that is too slow for your system’s dynamics. The PID controller responds based on stale measurements, causing phase lag that destabilises the loop. Increase your sample frequency, or reduce sensor averaging that introduces additional lag. Systems with significant actuator delay (e.g., heating elements) need a Smith Predictor or model-predictive control rather than a standard PID.

What is the difference between P, PI, PD, and PID controllers?

P-only: Simple, fast response, but steady-state error remains. PI: Eliminates steady-state error at the cost of some stability margin — most common for slow processes. PD: Fast response with damping, no integral so steady-state error persists — used for position control where gravity is absent. Full PID: Combines all three for the best performance in most applications.

How do I tune a PID controller for a self-balancing robot?

Start with Kp only, raising it until the robot begins to balance but oscillates slightly. Then add Kd (typically 10–20% of Kp) to damp the oscillation. Only add Ki if the robot drifts away from vertical over time; start very small (1–5% of Kp). Use Serial plotter in Arduino IDE to visualise the tilt angle and motor output during tuning.

Can PID work without derivative (PD or PI only)?

Yes — for many applications. Temperature controllers often use PI because temperature changes slowly and derivative action amplifies thermocouple noise. Motor speed controllers use PI with a velocity feed-forward term instead of derivative. Derivative is most valuable for fast mechanical systems (balancing robots, flight controllers) where overshoot must be minimised.

Ready to build your first closed-loop robot? Browse ESP32 boards, servo motors, and robot kits at zbotic.in/robotics-diy — fast delivery across India.
Tags: Arduino, control theory, diy electronics, motor PID, pid controller, Robotics, servo control, Ziegler-Nichols
Share Post
  • Facebook
  • Linkedin
  • Whatsapp
Air Quality AQI Monitor: PMS50...
blog air quality aqi monitor pms5003 dust sensor project 599714
blog esp32 ble beacon room presence tracking for home assistant 599720
ESP32 BLE Beacon: Room Presenc...

Related posts

Svg%3E
Read more

Caterpillar Track Robot: Tank-Drive Build for All Terrain

April 1, 2026 0
When wheels lose grip on sand, gravel, grass, or loose surfaces, caterpillar tracks keep moving. A tank-track robot distributes its... Continue reading
Svg%3E
Read more

RC Car to Robot: Convert a Toy Car into an Autonomous Robot

April 1, 2026 0
That old RC toy car gathering dust can be transformed into an Arduino-controlled autonomous robot with just a few electronic... Continue reading
Svg%3E
Read more

Robotic Arm Kit India: Best Options for Students and Hobbyists

April 1, 2026 0
If you are a student or hobbyist looking to get into robotics, a robotic arm kit is one of the... Continue reading
Svg%3E
Read more

Sumo Robot: Competition Build Guide India

April 1, 2026 0
Sumo robot competitions are among the most exciting events in Indian robotics, pitting small autonomous robots against each other in... Continue reading
Svg%3E
Read more

Robot Arm Build: 6-DOF Servo Arm with Arduino Control

April 1, 2026 0
Building a 6-DOF robot arm with servo motors and Arduino is one of the most rewarding robotics projects you can... Continue reading

Add comment Cancel reply

Your email address will not be published. Required fields are marked

Facebook Twitter Instagram Pinterest Linkedin Youtube

Get the latest deals and more.

Download on Google Play Download on the App Store

Call us: 020 69134444 / 1800 209 0998

Monday - Saturday 09:30 AM - 06:00 PM
For Technical Supports Email: [email protected]
For Sales / Enquiries Email: [email protected]

  • My Account

    • Cart

    • Wishlist

    • Checkout

    • My Orders

    • Track Order

    • My Account

  • Information

    • FAQs

    • Blogs

    • Career

    • About Us

    • Contact Us

    • Payment Options

  • Policies

    • Privacy Policy

    • Terms & Conditions

    • GST Input Tax Credit

    • Shipping Return Policy

    • E-Waste Collection Points

    • Our Sitemap

© Zbotic.in is registered trademark of Moxie Supply Pvt Ltd – All Rights Reserved
Login
Use Phone Number
Use Email Address
Not a member yet? Register Now
Reset Password
Use Phone Number
Use Email Address
Register
Already a member? Login Now