7
$\begingroup$

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.

$\endgroup$
  • $\begingroup$ 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. $\endgroup$ – goncalo luis Nov 4 '14 at 17:22
  • 1
    $\begingroup$ 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? $\endgroup$ – Ian Nov 6 '14 at 16:08
  • $\begingroup$ could you provide acspid source code for the reference? thanks in advance. $\endgroup$ – David Nov 26 '17 at 1:45
9
$\begingroup$

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: enter image description here

Fuzzy output Membership function: enter image description here

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

enter image description here

$\endgroup$
  • $\begingroup$ Link-only answers do not provide any insight into the method. It would be helpful if you can summarize the article instead. $\endgroup$ – Paul Nov 28 '16 at 19:28
  • 2
    $\begingroup$ @Paul, is this enough? $\endgroup$ – acs Nov 28 '16 at 20:26
  • 2
    $\begingroup$ Thanks for a comprehensive answer @acs. When linking though, please try to avoid using This paper or similar as the link text. Links tend to rot and if this happens, the link text doesn't help anyone find the page. Often missing pages haven't been removed, they have just been moved to another location. If you give the page title (and authors for a paper) as the link text then a search for that text will often find the new location. $\endgroup$ – Mark Booth Nov 29 '16 at 11:16
  • 1
    $\begingroup$ @acs in above python code (Fuzzy-PID) there is imported library named (acspid),the code not implemented without it. could you proved it or show it please ,with thanks. $\endgroup$ – Ahmed Faisal Jan 20 at 22:36
  • $\begingroup$ @AhmedFaisal sorry for late answer. I added the acspid class. $\endgroup$ – acs Jan 24 at 20:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.