PID Control: A Beginner’s Guide with Arduino

PID Control: A Beginner’s Guide with Arduino

Welcome to the exciting world of robotics! As you begin your journey, you’ll soon discover that one of the most fundamental challenges is telling a machine not just what to do, but how to do it precisely and consistently. How can we command a robot to maintain a specific position and orientation, especially in a dynamic environment? The answer lies in a special set of rules called control algorithms.

This guide aims to demystify one of the most common and powerful control algorithms in robotics: PID control. We’ll break down this seemingly complex topic using a simple, everyday analogy and then show you how it works in practice with a hands-on Arduino project. Let’s get started!

1. The Big Idea: Understanding Feedback Control

Before we dive into P, I, D, we need to understand the core concept they are built on: a closed-loop or feedback control system. This is a system that constantly measures its own output and uses that information—the feedback—to adjust its actions and reach a desired goal.

The most intuitive example is a person driving a car. The driver’s goal is to maintain the speed limit. They constantly check the speedometer (feedback) and adjust their pressure on the gas or brake pedals (control action) to match the desired speed.

This simple analogy contains all the key components of a control system.

Key Term Car Analogy Explanation
Setpoint The desired state. For the driver, this is the speed limit.
Plant The system being controlled. In this case, it’s the car.
Output/Feedback The measured, actual state of the system. This is the car’s current speed read from the speedometer.
Error The difference between the Setpoint and the Feedback. Calculated as speed limit - current speed.

The entire goal of a controller is to continuously minimize this “Error” by making intelligent adjustments. The PID controller achieves this by combining three distinct ways of thinking about the error.

2. Meet the Controller: Breaking Down P, I, and D

PID stands for Proportional, Integral, and Derivative. Each term represents a different strategy the controller (our driver) uses to analyze the “error” and decide how to act. By combining these three strategies, the controller can produce a smooth, efficient, and stable response.

2.1 The Proportional (P) Term: The Present-Focused Driver

The Proportional term reacts to the size of the current error. Its response is immediate and directly proportional to how far off the system is from its setpoint.

  • Analogy: A driver will press the gas pedal much harder if they are 20 mph below the speed limit than if they are only 5 mph below. The corrective action is proportional to the size of the mistake.
  • Function: This term provides the primary driving force for correction. A larger error results in a larger corrective push.

2.2 The Integral (I) Term: The Persistent Driver

The Integral term looks at the accumulated error over time. It keeps a running total of all past errors, effectively remembering how long the system has been off its target.

  • Analogy: This term addresses the accumulated error, as if the driver notices they’ve been consistently below the limit for a while (e.g., going up a hill) and gradually applies more throttle to compensate for this persistent drag.
  • Function: This term is crucial for eliminating small, steady-state errors that the Proportional term alone might ignore.

2.3 The Derivative (D) Term: The Predictive Driver

The Derivative term looks at the rate of change of the error. It’s not concerned with the current error or past errors, but rather with how quickly the error is changing. It’s the predictive part of the controller.

  • Analogy: A driver who is rapidly approaching the speed limit will start easing off the gas before they reach it. They anticipate that if they keep accelerating at the same rate, they will overshoot the target. This term acts like a brake to prevent overshooting.
  • Function: This term helps to dampen the system’s response, preventing wild oscillations and overshooting the setpoint.

These three distinct behaviors—reacting to the present, remembering the past, and predicting the future—are combined into a single, highly effective control signal.

3 Arduino’s Secret Weapon: PWM and analogWrite()

Microcontrollers like the Arduino are fundamentally digital; they cannot produce a true, variable analog voltage. To control devices like motors and LEDs that require such signals, an Arduino uses a clever technique called Pulse Width Modulation (PWM). This involves turning a digital pin ON and OFF very rapidly. The percentage of time the pin is ON (known as the duty cycle) determines the average voltage the device receives, effectively simulating an analog signal.

The command for this is analogWrite(pin, value).

  • pin: The PWM-capable pin you want to control (on an Arduino UNO, these are 3, 5, 6, 9, 10, and 11, often marked with a ~).
  • value: The duty cycle, which is an integer from 0 (always off, 0% duty cycle) to 255 (always on, 100% duty cycle). This is an 8-bit resolution by default.

Note that on standard Arduino UNO boards, pins 5 and 6 have a default frequency of 980 Hz, while the others are 490 Hz.

3.1 Project Example: Controlling DC Motor Speed

The project outlined in the source material aims to use a PID controller to precisely manage the speed of a DC motor.

  • Key Hardware:
    • An Arduino board.
    • A DC motor with an encoder (a sensor that measures the motor’s actual speed).
    • A potentiometer (a variable resistor used to set the desired speed).

Below is a breakdown of the key lines from the Arduino loop() function that implement the PID controller.

// 1. Read the potentiometer to get the desired speed (Setpoint)
setpoint = map(analogRead(POT_IN), 0, 1023, 0, 600);

// 2. Read the motor's encoder to get its actual speed (Feedback)
speed = 19.1 * ((60 * 1000 * 10) / pulseIn(ENCODER_A, HIGH));

// 3. Calculate the current error
error = setpoint - speed;

// 4. Accumulate the error for the Integral term
I_error += error;

// 5. Calculate the change in error for the Derivative term
D_error = lastError - error;
lastError = error; // Remember the current error for the next loop

// 6. Compute the final PID output signal
output += KP * error + KI * I_error + KD * D_error;

// 7. Send the control signal to the motor
analogWrite(PWM_OUT, output);

Here is a step-by-step explanation of what’s happening in that code:

  1. Reading the Setpoint: The map(analogRead(...)) line reads the voltage from the potentiometer to get the user’s desired speed. This is our Setpoint.
  2. Getting Feedback: The speed = ... line uses the pulseIn() function to measure the time between pulses from the motor’s encoder and converts this timing into a speed value (e.g., RPM) using a pre-calculated conversion factor. This is our Feedback.
  3. Calculating the Error: This is the simple subtraction of the current speed from the setpoint.
  4. The Integral Term (I): The line I_error += error; accumulates the error over time by adding the current error to a running total, just like our “persistent driver” who remembers how long they’ve been under the speed limit.
  5. The Derivative Term (D): The line D_error = lastError - error; calculates the rate of change in the error from the last loop to the current one. This is the “Derivative” action, acting as our “predictive driver” by looking at how quickly the situation is changing. We then store the current error in lastError to use it in the next cycle.
  6. The Core PID Calculation: This is the heart of the algorithm. It combines the three terms—Proportional (KP*error), Integral (KI*I_error), and Derivative (KD*D_error)—to determine the new control action. The KP, KI, and KD values are constants. Tuning is the art of adjusting these constants to achieve a desired system response—making it fast without being unstable, and accurate without taking too long to settle.
  7. Sending the Control Signal: Finally, the analogWrite() function sends the calculated output value to the motor via a PWM signal, adjusting its speed.

With a simple output = ... calculation, a zero error would result in output = 0, telling the motor to stop completely and immediately creating a new error. The output += ... approach avoids this.

An Important Insight Notice the PID calculation is output += ... instead of output = .... The code sums the previous output with the new calculation. This is a crucial detail for this application. If the error becomes zero (meaning the motor is at the correct speed), a simple output = ... would result in a zero output signal, causing the motor to slow down. By adding to the previous output, the controller ensures that when the error is zero, it continues sending the signal needed to maintain the desired speed.

4. Conclusion

You now have a solid understanding of one of the most fundamental algorithms in robotics and control systems. PID control is a powerful technique that elegantly combines three strategies to achieve a goal: reacting to the present error (Proportional), correcting for past accumulated errors (Integral), and anticipating future trends (Derivative).

With this conceptual and practical foundation, you are well-equipped to start experimenting with PID control in your own projects. Happy building!

Related posts:

Leave a Comment

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