Vous êtes sur la page 1sur 15

Introduction to Fuzzy Controllers

The fuzzy sets package contains five exports which are described below.
>

with( FuzzySets );

Warning, the protected name RealDomain has been redefined and unprotected

Each section describes a separate portion of the package.

Example of a Fuzzy Controller for an Inverted Pendulum


The classic example for demonstrating fuzzy sets is the control of an inverted pendulum
mounted on a carriage.
We have control of the velocity of the carriage and the object is to control the system to keep the
inverted pendulum from falling down.

Let the angle


fuzzy sets
where

be represented by the fuzzy sets

, the derivatives of

and the resulting acceleration by the fuzzy sets


may be one of:

by the

NL
NM
NS
AZ
PS
PM
PL

negative large
negative medium
negative small
approximately zero
positive small
positive medium
positive large

>

restart;

>

with( FuzzySets[RealDomain] ):

Warning, these protected names have been redefined and unprotected: implies,
intersect, minus, plot, subset, union

We define the following fuzzy sets describing the angles in degrees:


>

angleNL,
angleNM, angleNS, angleAZ, anglePS, anglePM,
anglePL
) := (
L( -30, -20 ),
Partition( -30, -20, -10, 0, 10, 20, 30 ),
Gamma( 20, 30 )
):
> plot( [
angleNL, angleNM, angleNS, angleAZ, anglePS, anglePM, anglePL
], -40..40 );

Next, we define the following sets which describe the rate of change of the angle in degrees per
second:

>

derivNL,
derivNM, derivNS, derivAZ, derivPS, derivPM,
derivPL
) := (
L( -30, -20 ),
Partition( -30, -20, -10, 0, 10, 20, 30 ),
Gamma( 20, 30 )
):
> plot( [
derivNL, derivNM, derivNS, derivAZ, derivPS, derivPM, derivPL
], -45..45 );

Finally, we define the acceleration of the carriage carrying the pendulum in metres per second
squared:
>

accelerationNL,
accelerationNM, accelerationNS, accelerationAZ, accelerationPS, accelerationPM,
accelerationPL
) := Partition( -16, -12, -8, -4, 0, 4, 8, 12, 16 ):
> plot( [
accelerationNL, accelerationNM, accelerationNS, accelerationAZ,
accelerationPS, accelerationPM, accelerationPL
], -17..17 );

Now that we have partition the observable and control variables into fuzzy sets, we must
generate a list of rules which map the observables onto the control variables.
For example, the first rule says:
If the angle is negative and medium and the rate of change of angle is approximately zero,

then accelerate the carriage in the negative direction approximately


>

m/s

Rules := Controller( {
[angleNM, derivAZ] = accelerationNM,
[angleNS, derivAZ] = accelerationNS,
[angleAZ, derivAZ] = accelerationAZ,
[anglePS, derivAZ] = accelerationPS,
[anglePM, derivAZ] = accelerationPM,
[angleNM, derivPS] = accelerationNS,
[angleNS, derivPS] = accelerationAZ,
[angleAZ, derivPS] = accelerationPS,
[anglePS, derivPS] = accelerationPM,
[angleNS, derivNS] = accelerationNM,
[angleAZ, derivNS] = accelerationNS,
[anglePS, derivNS] = accelerationAZ,
[anglePM, derivNS] = accelerationPS
}, inference = minimum ):

Suppose we have an angle of


and the rate of change of the angle is
/s. By
applying the Mamdani form of fuzzy rules, the returned fuzzy set suggests what the acceleration
should be.

>

soln := Rules( -13, -2.1 );

>

plot( soln, -17..1, view=[DEFAULT, 0..1], numpoints = 1000 );

We cannot use a fuzzy set to control the acceleration of the carriage, so we must interpret this
fuzzy set as a single real value which we may use as the acceleration. We can convert this fuzzy
set into a real value using the routine Defuzzify :
>

Defuzzify( soln );

Thus, we should accelerate the carriage backward at -5.34 m/s

The following routine simulates an inverted pendulum and returns an animation of the pendulum
over time.
>

InvertedPendulum := proc( initial_angle, initial_angular_velocity, controller, iterations )


local position, velocity, angle, angular_velocity, dt, plotvehicle, plotlist, i, acceleration,
angular_acceleration;
position := 0;
velocity := 0;
angle := evalf( Pi*initial_angle/180 );
angular_velocity := evalf( Pi*initial_angular_velocity/180 );
dt := 60.0/1000.0; # animations run at approximately 1000 frames per minute
plotvehicle := proc( posn, a, angular_velocity )
local x, y;
x := sin(a);
y := cos(a);
plots[display](
plots[pointplot]( [[posn, 0], [posn + x, y]], symbol = circle, symbolsize = 20 ),
plots[pointplot]( [[-1, 0], [1, 0]] ),
plottools[line]( [posn, 0], [posn + x, y] ),
plots[textplot]( [0.5, 1.2, sprintf(
"% 3d deg, % 3d deg/s",
round( evalf( a*180/Pi ) ), round( evalf( angular_velocity*180/Pi ) )
)] ),
scaling = constrained
);
end proc;
plotlist := Vector( 1..iterations + 1 );
plotlist[1] := plotvehicle( position, angle, angular_velocity );
for i from 2 to iterations + 1 do
try
acceleration := Defuzzify(
controller( angle*180/3.14, angular_velocity*180/3.14 ),
-100..100, evalf
);
catch:
acceleration := 0;
end try;
angular_acceleration := 9.8 * sin( angle ) - acceleration * cos( angle );
angular_velocity := angular_velocity + angular_acceleration * dt - 0.02 *
angular_velocity;
angle := angle + angular_velocity * dt;
if i mod 100 = 0 then print( i ); end if;
velocity := velocity + acceleration * dt;
position := position + velocity * dt;
plotlist[i] := plotvehicle( position, angle, angular_velocity );

end do;
plots[display]( seq( plotlist[i], i = 1..(i - 1) ), insequence = true, scaling = constrained );
end proc:
The following function call generates a simulation where the pendulum begins at -10 degrees
and its initial angular speed is 40 degrees per second.
>

InvertedPendulum( -10, 40, Rules, 100 );

This next example uses the product Mamdani inference.


>

ProductRules := Controller( {
[angleNM, derivAZ] = accelerationNL,
[angleNS, derivAZ] = accelerationNS,
[angleAZ, derivAZ] = accelerationAZ,
[anglePS, derivAZ] = accelerationPS,
[anglePM, derivAZ] = accelerationPL,
[angleNM, derivPS] = accelerationNS,
[angleNS, derivPS] = accelerationAZ,
[angleAZ, derivPS] = accelerationPS,
[anglePS, derivPS] = accelerationPL,
[angleNS, derivNS] = accelerationNL,
[angleAZ, derivNS] = accelerationNS,
[anglePS, derivNS] = accelerationAZ,
[anglePM, derivNS] = accelerationPS
}, inference = product ):

>

InvertedPendulum( -10, 40, ProductRules, 100 );

>

solnP := ProductRules( -13, -2.1 );

>

plot( solnP, -20..10, 0..1 );

This next example uses the Sugeno form of fuzzy rules. The first rule may be interpreted as if
the angle is negative and medium and the derivative is approximately zero, accelerate the cart at

-12 m/s
>

SugenoRules := Controller( {
[angleNM, derivAZ] = -12,
[angleNS, derivAZ] = -4,
[angleAZ, derivAZ] = 0,
[anglePS, derivAZ] = 4,
[anglePM, derivAZ] = 12,
[angleNM, derivPS] = -4,
[angleNS, derivPS] = 0,
[angleAZ, derivPS] = 4,
[anglePS, derivPS] = 12,

[angleNS, derivNS] = -12,


[angleAZ, derivNS] = -4,
[anglePS, derivNS] = 0,
[anglePM, derivNS] = 4
}, rules = Sugeno ):
> InvertedPendulum := proc( initial_angle, initial_angular_velocity, controller, iterations )
local position, velocity, angle, angular_velocity, dt, plotvehicle, plotlist, i, acceleration,
angular_acceleration;
position := 0;
velocity := 0;
angle := evalf( Pi*initial_angle/180 );
angular_velocity := evalf( Pi*initial_angular_velocity/180 );

dt := 60.0/1000.0; # animations run at approximately 1000 frames per minute


plotvehicle := proc( posn, a, angular_velocity )
local x, y;
x := sin(a);
y := cos(a);
plots[display](
plots[pointplot]( [[posn, 0], [posn + x, y]], symbol = circle, symbolsize = 20 ),
plots[pointplot]( [[-1, 0], [1, 0]] ),
plottools[line]( [posn, 0], [posn + x, y] ),
plots[textplot]( [0.5, 1.2, sprintf( "% 3d deg, % 3d deg/s", round( evalf( a*180/Pi ) ),
round( evalf( angular_velocity*180/Pi ) ) )] ),
scaling = constrained
);
end proc;
plotlist := Vector( 1..iterations + 1 );
plotlist[1] := plotvehicle( position, angle, angular_velocity );
for i from 2 to iterations + 1 do
acceleration := controller( angle*180/3.14, angular_velocity*180/3.14 );
if acceleration::'undefined' then
acceleration := 0;
end if;
angular_acceleration := 9.8 * sin( angle ) - acceleration * cos( angle );
angular_velocity := angular_velocity + angular_acceleration * dt - 0.02 *
angular_velocity;
angle := angle + angular_velocity * dt;
if i mod 100 = 0 then print( i ); end if;
velocity := velocity + acceleration * dt;
position := position + velocity * dt;
plotlist[i] := plotvehicle( position, angle, angular_velocity );
end do;
plots[display]( seq( plotlist[i], i = 1..(i - 1) ), insequence = true, scaling = constrained );
end proc:
> InvertedPendulum( -10, 40, SugenoRules, 100 );

>

solnP := SugenoRules( -13, -2.1 );

A Faster Fuzzy Controller for an Inverted Pendulum


The RealDomain package is designed to use symbolic algebra, and therefore will be relatively
slow. Generating a package which works with fuzzy subsets of a finite domain is significantly
faster. This example reproduces the example shown in the previous section without the
commentary.
>

restart;

>

FzS := FuzzySets[FiniteDomain]( i, i = -45..45 ):

>

with( FzS ):

Warning, these protected names have been redefined and unprotected: implies,
intersect, minus, plot, subset, union
>

angleNL,
angleNM, angleNS, angleAZ, anglePS, anglePM,
anglePL
) := (
L( -30, -20 ),
Partition( -30, -20, -10, 0, 10, 20, 30 ),
Gamma( 20, 30 )
):
> (
derivNL,
derivNM, derivNS, derivAZ, derivPS, derivPM,

derivPL
) := (
L( -30, -20 ),
Partition( -30, -20, -10, 0, 10, 20, 30 ),
Gamma( 20, 30 )
):
> (
accelerationNL,
accelerationNM, accelerationNS, accelerationAZ, accelerationPS, accelerationPM,
accelerationPL
) := Partition( -16, -12, -8, -4, 0, 4, 8, 12, 16 ):
> Rules := Controller( {
[angleNM, derivAZ] = accelerationNM,
[angleNS, derivAZ] = accelerationNS,
[angleAZ, derivAZ] = accelerationAZ,
[anglePS, derivAZ] = accelerationPS,
[anglePM, derivAZ] = accelerationPM,
[angleNM, derivPS] = accelerationNS,
[angleNS, derivPS] = accelerationAZ,
[angleAZ, derivPS] = accelerationPS,
[anglePS, derivPS] = accelerationPM,
[angleNS, derivNS] = accelerationNM,
[angleAZ, derivNS] = accelerationNS,
[anglePS, derivNS] = accelerationAZ,
[anglePM, derivNS] = accelerationPS
}, inference = minimum ):
> soln := Rules( -13, -2.1 ):
>

plot( soln, -17..1 );

>

Defuzzify( soln );

The defuzzified value is very close to the value found using fuzzy sets on the real domain:
.
>

evalf(%);

>

InvertedPendulum := proc( initial_angle, initial_angular_velocity, controller, iterations )


local position, velocity, angle, angular_velocity, dt, plotvehicle, plotlist, i, acceleration,
angular_acceleration;
position := 0;
velocity := 0;
angle := evalf( Pi*initial_angle/180 );
angular_velocity := evalf( Pi*initial_angular_velocity/180 );
dt := 60.0/1000.0; # animations run at approximately 1000 frames per minute
plotvehicle := proc( posn, a, angular_velocity )
local x, y;

x := sin(a);
y := cos(a);
plots[display](
plots[pointplot]( [[posn, 0], [posn + x, y]], symbol = circle, symbolsize = 20 ),
plots[pointplot]( [[-1, 0], [1, 0]] ),
plottools[line]( [posn, 0], [posn + x, y] ),
plots[textplot]( [0.5, 1.2, sprintf( "% 3d deg, % 3d deg/s", round( evalf( a*180/Pi ) ),
round( evalf( angular_velocity*180/Pi ) ) )] ),
scaling = constrained
);
end proc;
plotlist := Vector( 1..iterations + 1 );
plotlist[1] := plotvehicle( position, angle, angular_velocity );
for i from 2 to iterations + 1 do
try
acceleration := 1.5*Defuzzify( controller( angle*180/3.14, angular_velocity*180/3.14 )
);
catch:
acceleration := 0;
end try;
angular_acceleration := 9.8 * sin( angle ) - acceleration * cos( angle );
angular_velocity := angular_velocity + angular_acceleration * dt - 0.02 *
angular_velocity;
angle := angle + angular_velocity * dt;
if i mod 100 = 0 then print( i ); end if;
velocity := velocity + acceleration * dt;
position := position + velocity * dt;
plotlist[i] := plotvehicle( position, angle, angular_velocity );
end do;
plots[display]( seq( plotlist[i], i = 1..(i - 1) ), insequence = true, scaling = constrained );
end proc:
This command takes 25% the time of the RealDomain version to run.
>

InvertedPendulum( -10, 40, Rules, 100 );

On my computer, this takes approximately one minute to calculate and the animation runs for
approximately one minute. This should not be taken to imply that this package should be used
for real-time systems.
>

InvertedPendulum( -10, 40, Rules, 1000 );

Vous aimerez peut-être aussi