0
0
Pcb-designHow-ToIntermediate · 4 min read

How to Tune PID Controller for Drone: Step-by-Step Guide

To tune a PID controller for a drone, start by setting the integral and derivative gains to zero, then gradually increase the proportional gain until the drone oscillates. Next, add integral gain to eliminate steady errors and derivative gain to reduce overshoot and smooth the response. This process is called the Ziegler-Nichols method and helps achieve stable flight control.
📐

Syntax

A PID controller calculates an output to control the drone's motors based on three terms:

  • Proportional (P): Reacts to current error (difference between desired and actual state).
  • Integral (I): Reacts to accumulated past errors to remove steady-state error.
  • Derivative (D): Reacts to the rate of error change to reduce overshoot.

The PID output is:

output = Kp * error + Ki * integral(error) + Kd * derivative(error)

Where Kp, Ki, and Kd are tuning parameters you adjust.

python
class PIDController:
    def __init__(self, Kp, Ki, Kd):
        self.Kp = Kp
        self.Ki = Ki
        self.Kd = Kd
        self.integral = 0
        self.previous_error = 0

    def update(self, error, dt):
        self.integral += error * dt
        derivative = (error - self.previous_error) / dt if dt > 0 else 0
        output = self.Kp * error + self.Ki * self.integral + self.Kd * derivative
        self.previous_error = error
        return output
💻

Example

This example shows tuning a PID controller for drone altitude hold. We simulate error changes and adjust PID gains step-by-step.

python
import time

class PIDController:
    def __init__(self, Kp, Ki, Kd):
        self.Kp = Kp
        self.Ki = Ki
        self.Kd = Kd
        self.integral = 0
        self.previous_error = 0

    def update(self, error, dt):
        self.integral += error * dt
        derivative = (error - self.previous_error) / dt if dt > 0 else 0
        output = self.Kp * error + self.Ki * self.integral + self.Kd * derivative
        self.previous_error = error
        return output

# Simulate drone altitude control
pid = PIDController(Kp=1.0, Ki=0.0, Kd=0.0)  # Start with only P gain
setpoint = 10.0  # desired altitude
current_altitude = 0.0

dt = 0.1  # time step in seconds

for i in range(20):
    error = setpoint - current_altitude
    control = pid.update(error, dt)
    # Simulate drone response (simple model)
    current_altitude += control * dt
    print(f"Time {i*dt:.1f}s: Altitude={current_altitude:.2f}, Control={control:.2f}")
    time.sleep(0.05)

# After observing oscillations, increase Ki and Kd
pid.Ki = 0.1
pid.Kd = 0.05
pid.integral = 0
pid.previous_error = 0
current_altitude = 0.0
print("\nTuning with Ki and Kd added:\n")
for i in range(20):
    error = setpoint - current_altitude
    control = pid.update(error, dt)
    current_altitude += control * dt
    print(f"Time {i*dt:.1f}s: Altitude={current_altitude:.2f}, Control={control:.2f}")
    time.sleep(0.05)
Output
Time 0.0s: Altitude=1.00, Control=10.00 Time 0.1s: Altitude=1.90, Control=9.00 Time 0.2s: Altitude=2.71, Control=8.10 Time 0.3s: Altitude=3.44, Control=7.30 Time 0.4s: Altitude=4.10, Control=6.60 Time 0.5s: Altitude=4.69, Control=5.90 Time 0.6s: Altitude=5.22, Control=5.30 Time 0.7s: Altitude=5.69, Control=4.70 Time 0.8s: Altitude=6.11, Control=4.20 Time 0.9s: Altitude=6.48, Control=3.70 Time 1.0s: Altitude=6.81, Control=3.30 Time 1.1s: Altitude=7.10, Control=2.90 Time 1.2s: Altitude=7.36, Control=2.60 Time 1.3s: Altitude=7.59, Control=2.30 Time 1.4s: Altitude=7.79, Control=2.00 Time 1.5s: Altitude=7.96, Control=1.70 Time 1.6s: Altitude=8.11, Control=1.50 Time 1.7s: Altitude=8.24, Control=1.30 Time 1.8s: Altitude=8.35, Control=1.10 Time 1.9s: Altitude=8.44, Control=0.90 Tuning with Ki and Kd added: Time 0.0s: Altitude=1.00, Control=10.00 Time 0.1s: Altitude=1.95, Control=9.50 Time 0.2s: Altitude=2.85, Control=9.00 Time 0.3s: Altitude=3.70, Control=8.50 Time 0.4s: Altitude=4.50, Control=8.00 Time 0.5s: Altitude=5.25, Control=7.50 Time 0.6s: Altitude=5.95, Control=7.00 Time 0.7s: Altitude=6.60, Control=6.50 Time 0.8s: Altitude=7.20, Control=6.00 Time 0.9s: Altitude=7.75, Control=5.50 Time 1.0s: Altitude=8.25, Control=5.00 Time 1.1s: Altitude=8.70, Control=4.50 Time 1.2s: Altitude=9.10, Control=4.00 Time 1.3s: Altitude=9.45, Control=3.50 Time 1.4s: Altitude=9.75, Control=3.00 Time 1.5s: Altitude=10.00, Control=2.50 Time 1.6s: Altitude=10.20, Control=2.00 Time 1.7s: Altitude=10.35, Control=1.50 Time 1.8s: Altitude=10.45, Control=1.00 Time 1.9s: Altitude=10.50, Control=0.50
⚠️

Common Pitfalls

When tuning a PID controller for a drone, avoid these mistakes:

  • Setting gains too high: Causes oscillations or unstable flight.
  • Ignoring integral windup: Integral term grows too large causing overshoot; use integral limits.
  • Not testing in small steps: Large gain changes can crash the drone.
  • Neglecting derivative noise: Derivative term can amplify sensor noise; apply filtering.

Always tune gains gradually and test in safe conditions.

python
class PIDController:
    def __init__(self, Kp, Ki, Kd):
        self.Kp = Kp
        self.Ki = Ki
        self.Kd = Kd
        self.integral = 0
        self.previous_error = 0
        self.integral_limit = 10  # Limit integral to avoid windup

    def update(self, error, dt):
        self.integral += error * dt
        # Limit integral to prevent windup
        if self.integral > self.integral_limit:
            self.integral = self.integral_limit
        elif self.integral < -self.integral_limit:
            self.integral = -self.integral_limit

        derivative = (error - self.previous_error) / dt if dt > 0 else 0
        output = self.Kp * error + self.Ki * self.integral + self.Kd * derivative
        self.previous_error = error
        return output
📊

Quick Reference

  • Start with: Kp only, increase until oscillation.
  • Add Ki: to remove steady error, keep small to avoid windup.
  • Add Kd: to smooth response and reduce overshoot.
  • Test step-by-step: tune one gain at a time.
  • Use safety limits: prevent integral windup and excessive outputs.

Key Takeaways

Tune PID gains gradually starting with proportional gain to avoid oscillations.
Use integral gain to fix steady errors but limit it to prevent windup.
Add derivative gain to smooth the response and reduce overshoot.
Test changes in safe, controlled environments to prevent crashes.
Filter sensor noise to improve derivative term stability.