How to tune the PID parameters using Fuzzy Logic?

I previously used the Ziegler method to tune the parameters of my PID controller to control my robot's position. I then implemented fuzzy logic for self-tuning the parameters. I have two inputs to the fuzzy logic controller; one is the position error and the error rate.

I know that my problem might be due to not understanding the effect of each parameter very well.

The problem is that I am confused in setting up the fuzzy rules. When do I need to use high and low values for Kp, Kd and Ki to achieve the best tuning? Is it that Kp must be very low when the error is almost zero (hence, the robot is at the desired position)? The same question applies for all of the three parameters.

• Sorry for the question but if you are working with fuzzy logic why don't you just use it to make a fuzzy logic controller? It's much more capable than a PID, and it can handle non linearities. Nov 4, 2014 at 17:22
• Can you draw a diagram that shows how your sensors, actuators, PID, and fuzzy logic systems would be connected? Why wasn't the PID good enough to control your robot's position?
– Ian
Nov 6, 2014 at 16:08
• could you provide acspid source code for the reference？ thanks in advance. Nov 26, 2017 at 1:45

The paper Controlling of Quadrotor UAV Using a Fuzzy System for Tuning the PID Gains in Hovering Mode by E. Abbasi, M. J. Mahjoob explains how to tune PID gains with fuzzy logic. You can find many papers about singleton tuning but this paper shows totally fuzzy control

1. find PID gains with ziegler-nichols (or another technique)
2. Create a fuzzy PID gain changer which has inputs error (e) and change in error(de)
3. Define fuzzification graphs for inputs and outputs. Define limits (also you can change the shape) like

name [min,peak,max]

very small [-1,-1,-0.6], small [-1,-0.6,0], medium [-0.6,0,0.6], big [0,0.6,1], very big [0.6,1,1]

4. create rules like

if **e** and/or **de** *fuzzyname* (small,big etc.) than KI is fuzzyname (small,big etc.)

5. Defuzzyfy the result.

You can use tools like matlab fuzzy toolbox or python skfuzzy

The tipping problem can be used as Fuzzy-PID just change qualtiy as e and service as de and lastly you can change tip output as KP/ KI/ KD (there is example about tipping problem: python scikit fuzzy - Fuzzy Control Systems: The Tipping Problem)

Note 1: Error ranges should be well defined so you must log the error and change in error. The limits must be in max and min values of these values

Note 2: The output value range is good between -1 and 1.

An example code for Fuzzy-PID in python is here:

# -*- coding: utf-8 -*-
"""
@author: acs
"""

import skfuzzy as fuzz
from skfuzzy import control as ctrl
import acspid
import numpy as np
from matplotlib import pyplot as plt

plt.ion()
fig=plt.figure()

ferr = ctrl.Antecedent(np.arange(-150, 150, 1), 'ferr')
fder = ctrl.Antecedent(np.arange(-150, 150, 1), 'fder')
fout = ctrl.Consequent(np.arange(-1, 1, 0.01), 'fout')

ferr.automf(5)
fder.automf(5)
fout.automf(5)
fout['poor'] = fuzz.trimf(fout.universe, [-1, -1, -0.5])
fout['mediocre'] = fuzz.trimf(fout.universe, [-1, -0.5, 0])
fout['average'] = fuzz.trimf(fout.universe, [-0.1, 0, 0.1])
fout['decent'] = fuzz.trimf(fout.universe, [0, 0.5, 2])
fout['good'] = fuzz.trimf(fout.universe, [0.5, 1, 1])
fout.view()
ferr.view()
fder.view()
plt.show()
plt.pause(0.0001)

#'poor'; 'mediocre'; 'average'; 'decent', or 'good'
rules=[]
rules.append(ctrl.Rule(ferr['average'] | fder['average'] , fout['average']))
rules.append(ctrl.Rule(ferr['decent'] | fder['decent'] , fout['decent']))
rules.append(ctrl.Rule(ferr['good'] | fder['good'] , fout['good']))
rules.append(ctrl.Rule(ferr['mediocre'] | fder['mediocre'] , fout['mediocre']))
rules.append(ctrl.Rule(ferr['poor'] | fder['poor'] , fout['poor']))

fctrl = ctrl.ControlSystem(rules)
fpid = ctrl.ControlSystemSimulation(fctrl)

pid=acspid.pidcont(1.2,0.02,0.01,5,-5)

pid2=acspid.pidcont(1.2,0.02,0.01,5,-5)

d=np.zeros(10)
for i in range(10):
d=np.append(d,np.ones(10)*np.random.uniform(-100,100,1))

print len(d)
m=[]
m.append(0.0)
m2=[]
m2.append(0.0)
e=[]
de=[]
e2=[]
de2=[]

kp=pid.kp
kd=pid.kd
ki=pid.ki
for i in range(len(d)):
pid.setDesired(d[i])
print "e:",pid.error ,"\t de:", pid.ed
fpid.input['ferr'] = pid.error
fpid.input['fder'] = pid.ed
fpid.compute()
newpid=np.abs(fpid.output['fout'])
print "PID:", newpid*pid.kp,"\t",newpid*pid.ki,"\t",newpid*pid.kd
pid.setGains(newpid*kp,newpid*ki,newpid*kd)
newm=pid.update(m[-1])
newm=m[-1]+newm
print i,m[-1],newm
m.append(newm)
e.append(pid.error)
de.append(pid.ed)

pid2.setDesired(d[i])
newm2=pid2.update(m2[-1])
newm2=m2[-1]+newm2
m2.append(newm2)
e2.append(pid2.error)
de2.append(pid2.ed)

ax1 =plt.subplot(2,1,1)
ax1.set_xlim([0, len(d)])
ax1.set_ylim([-200, 200])
plt.grid()
plt.plot(range(len(m)),m,linewidth=5.0)
plt.plot(range(len(m2)),m2,linewidth=2.0)
plt.plot(range(len(d)),d,'g--')

plt.title('Status')
ax2=plt.subplot(2,1,2)
ax2.set_xlim([0, 50])
ax2.set_ylim([-100, 100])
plt.plot(range(len(e)),e,'r-',range(len(de)),de,'g-')
plt.grid()
plt.title('e and ed')
#plt.draw()
plt.show()
plt.pause(0.0001)

Fuzzy input membership functions:

Fuzzy output Membership function:

Status: In the status plot dashed line is target value, red line is PID and green line is Fuzzy-PID

Here the acspid class

class pidcont():
def __init__(self,P,I,D,pmax,pmin):
self.kp=P
self.kd=D
self.ki=I
self.pidmax=pmax
self.pidmin=pmin
self.desired=0.0
self.error=0.0
self.elast=0.0
self.esum=0.0
self.eder=0.0
def update(self,current):
self.error=self.desired-current
self.eder=self.error-self.elast
self.elast=self.error
self.esum=self.esum+self.error
if self.esum>self.pidmax:
self.esum=self.pidmax
elif self.esum<self.pidmin:
self.esum=self.pidmin

self.P=self.kp*self.error
self.D=self.kd*self.eder
self.I=self.ki*self.esum
pid=self.P+self.I+self.D
return pid
def setDesired(self,d):
self.desired=d
def setGains(self,P,I,D):
self.kp=P
self.kd=D
self.ki=I
def setLimits(self,pmax,pmin):
self.pidmax=pmax
self.pidmin=pmin