A Fuzzy-Logic Torque Servo



March 01, 1994
URL:http://www.drdobbs.com/a-fuzzy-logic-torque-servo/184402847

March 1994/A Fuzzy-Logic Torque Servo/Figure 1

Figure 1 Fuzzy set for temperature

March 1994/A Fuzzy-Logic Torque Servo/Figure 2

Figure 2 Feedback configuration of a typical torque servo

March 1994/A Fuzzy-Logic Torque Servo/Figure 3

Figure 3 Fuzzy plant for torque servo

March 1994/A Fuzzy-Logic Torque Servo/Figure 4

Figure 4 Fuzzifier rules and membership functions for 8-bit system

March 1994/A Fuzzy-Logic Torque Servo/Figure 5

Figure 5 Example of Fuzzify >=Defuzzify when two rules fire

March 1994/A Fuzzy-Logic Torque Servo/Figure 6

Figure 6 An illustration of de-fuzzification

March 1994/A Fuzzy-Logic Torque Servo/Listing 1

Listing 1 C declaration code for rule table and membership functions

/**************************************************************
       File: fuzzy.h
       Date: 4/3/93
       Author: Jack J. McCauley
       Header file for fuzzy.c
**************************************************************/

/* membership function size */
#define TORQUE_MEMBERS 5
#define DER_MEMBERS 5

/* loop frequency */
#define LOOP_HZ 1

/* integrator constant z-1*/
#define SKIP 1

/* normalized value */
#define NORMAL 255

/* Current ma */
#define MAX_TORQUE 1000
#define MIN_TORQUE -1000

/* derivative */
#define MAX_DERI LOOP_HZ*MAX_TORQUE
#define MIN_DERI LOOP_HZ*MIN_TORQUE

/* pwm 1/10 % */
#define MAX_PWM   255
#define MIN_PWM   0

/* Max and Min */
#define MIN_ERROR   0
#define MAX_ERROR   255

/* size of all arrays */
#define ARRAY_SIZE   256

/* represent a normalized 0 -> 1000 = 0.0 -> 1.0 */
#define FUZZY_RADIX NORMAL

/* fuzzy max (ternary) operator */
#define FUZ_MAX( x, y )    ((x>y) ? x : y)

/* fuzzy min (ternary) operator */
#define FUZ_MIN( x, y )    ((x<y) ? x : y)

/* fuzzy AND operator */
#define FUZ_AND( x, y )    FUZ_MIN( x, y )

/* fuzzy OR operator */
#define FUZ_OR( x, y )     FUZ_MAX( x, y )

/* fuzzy compliment operator */
#define FUZ_NOT( x )       ( FUZZY_RADIX - x )

/* create the membership function space */
/* first is the torque error  fuzzy set */
struct s_torq_members {
      int neg_large[ARRAY_SIZE];
      int neg_med[ARRAY_SIZE];
      int zero[ARRAY_SIZE];
      int pos_med[ARRAY_SIZE];
      int pos_large[ARRAY_SIZE];
      float slope;
      float intercept;
}  torq_members;

/* next is the rate of change fuzzy set torque error */
struct s_deri_members {
      int pos_large[ARRAY_SIZE];
      int pos_med[ARRAY_SIZE];
      int zero[ARRAY_SIZE];
      int neg_med[ARRAY_SIZE];
      int neg_large[ARRAY_SIZE];
      float slope;
      float intercept;
} deri_members;

/* last is the PWM fuzzy set ouput */
struct s_pwm_members {
      int neg_large[ARRAY_SIZE];
      int neg_med[ARRAY_SIZE];
      int zero[ARRAY_SIZE];
      int pos_med[ARRAY_SIZE];
      int pos_large[ARRAY_SIZE];
      float slope;
      float intercept;
} pwm_members;

/* define output rule table members */
#define L            pwm_members.pos_large
#define M            pwm_members.pos_med
#define Z            pwm_members.zero
#define NM           pwm_members.neg_med
#define NL           pwm_members.neg_large

/* finally the fuzzy sets */
/* torque feedback error */
int *dTerr_dt[] = {
              deri_members.pos_large  ,
              deri_members.pos_med    ,
              deri_members.zero       ,
              deri_members.neg_med    ,
              deri_members.neg_large  ,
              };
/* torque (OZ-in) */
int *Terror[] = {
              torq_members.neg_large  ,
              torq_members.neg_med    ,
              torq_members.zero       ,
              torq_members.pos_med    ,
              torq_members.pos_large  ,
              }

/* create the rule table and allocate space */
struct  s_rule {
       int *table[TORQUE_MEMBERS];
} rule[DER_MEMBERS] =
       /* */
       {{Z,   NM,  NM,  NM,  NL },
       {M,    Z,   NM,  NM,  NL },
       { L,   M,   Z,   NM,  NL },
       { L,   M,   M,   Z,   NM  },
       { L,    M,   M,   M,   Z }};
       
The Fuzzy membership functions are stored in a look up table for all input
and output fuzzy sets. Fuzzy variables with three digits of precision are
normalized between 0 and 255 integer corresponding to an 8-bit radix converter
and a fuzzy set 0.0 - 1.0 normalized value. Look up tables increase bandwidth
and allow the servo to run with few floating point calculations.

/****************************************************
       File: fuzzy.c
       Date: 4/3/93
       Author: Jack J. McCauley
       fuzzy torque controller for motor
****************************************************/

#include "stdio.h"
#include "stdlib.h"
#include "conio.h"
#include "proto.h"
#include "fuzz.h"      /* the above file */

/****************************************************
       Routine: calc_slope
       Date: 4/3/93
       Author: Jack J. McCauley
       calcs line slope of two points in a plane
*****************************************************/
float calc_slope( float x1, float x2, float y1, float y2 ) {

       float slope;

       if ( x1 == x2 )
             slope = 10000000.0;
       else if( y1 == y2 )
             slope = 0.0;
       else {
             slope = (y1 - y2)/(x1 - x2);
             if( slope > 100000000.0 )
                    slope = 100000000.0;
       }
       return( slope );
}
/*****************************************************
       Routine: calc_intercept
       Date: 4/3/93
       Author: Jack J. McCauley
       calcs line intercept of two points in a plane
*****************************************************/
float calc_intercept( float x1, float x2, float y1, float y2 ) {

       float intercept;
       
       if ( x1 == x2 )
             intercept = 100000000.0;
       else {
             intercept = (y2*x1 - y1*x2)/(x1 - x2);
             if( intercept > 100000000.0 )
                    intercept = 100000000.0;
       }
       return( intercept );
}
/* end print_array */

/**********************************************************
   Routine: down_load()
   Date: 4/3/93
       Author: Jack J. McCauley
initialize fuzzy membership function tables from serial port DRIVER not shown
***********************************************************/
void down_load( int *membership_function, int len )
{
       int k;
       char buff[32];
       
       /*short, tight loop */
       for( k=0; k< len; k++ ) {
             /* get ascci string from driver */
             gets( buff, 12 );
             *membership_function++: atoi( buff );
       }
}
/* end down_load() */
/********************************************************
   Routine: fuzzy_init
   Date: 4/3/93
       Author: Jack J. McCauley
       initialize fuzzy membership function tables
*********************************************************/
void fuzzy_init( void )
{
   int k;
   long slope;
       long intercept;
       int val;
       
/*
There are several ways to generate these tables:

1) The easiest is to simply use ROM space and store them permanently in memory. FUZZ.H
would need to be modified to reflect the static ROM delecerations for each fuzzy
set and the values would be initialize directly attaching them to the data arrays.

2) Down load the fuzzy sets through the serial port as I did in the
tuning of this servo. In which case I've included that code here (of
course in the ROM version of the system you'll need 1)).

3) Store the slope-intercept form of each membership function and
calculate the line slopes and intercepts
*/

/*
Membership functions are downloaded through the serial port from a file in ASCII
format one set member at a time. In this system I used a spreadsheet and
graphical interface to actually draw the membership functions with a mouse.
This aided in tuning the servo substantailly. In the ROH version of the system,
I wrote a small programm to append the RDM statics memberships to fuzz.h.
*/
       down_load( deri_members.neg_large, ARRAY_SIZE);
       down_load( torq_members.neg_large, ARRAY_SIZE);
       down_load( pwm_members.neg_large, ARRAY_SIZE);
       down_load( deri_members.neg_med, ARRAY_SIZE);
       down_load( torq_members.neg_med, ARRAY_SIZE);
       down_load( deri_members.zero, ARRAY_SIZE);
       down_load( torq_members.zero, ARRAY_SIZE);
       down_load( pwm_members.zero, ARRAY_SIZE);
       down_load( deri_members.pos_med, ARRAY_SIZE);
       down_load( orq_members.pos_med, ARRAY_SIZE);
       down_load( pwm_members.pos_med, ARRAY_SIZE);
       down_load( deri_members.pos_large, ARRAY_SIZE);
       down_load( torq_members.pos_large, ARRAY_SIZE);
       down_load( pwm_members.pos_large, ARRAY_SIZE);
       
       /* slope intercept line calculation */
       

       /* these line equations are used for scaling the
         crisp values from the above arrays */
       deri_members.slope = calc_slope(MIN_DERI, MAX_DERI, 0, ARRAY_SIZE-1 );
       deri_members.intercept = calc_intercept(MIN_DERI, MAX_DERI, 0, ARRAY_SIZE-1
       
       torq_members.slope: calc_slope( MIN_TORQUE, MAX_TORQUE, 0, ARRAY SIZE-1 );
       torq_members.intercept = calc_intercept(MIN_TORQUE, MAX_TORQUE, 0, ARRAY_SIZE-1);
       
       pwm_members.slope = calc_slope(0, ARRAY_SIZE-1, MIN_PWM, MAX_PWM);
       pwm_members.intercept = calc_intercept(0, ARRAY_SIZE-1, MIN_PWM, MAX_PWM);
/*
       for( k=0; k<ARRAY_SIZE; k++ )
             printf("%d %4d %4d %4d %4d
%4d\n["],k,deri_members.pos_large[k],deri_members.pos_med[k],
deri_members.zero[k],deri_members.neg_med[k],deri_memb
ers.neg_large[k]);
*/
}
/* end FUZZINIT */

/***********************************************
       Routine: defuzzify_COA
       Date: 4/3/93
       Author: Jack J. McCauley
       defuzzify using COA
**********************************************/
float defuzzify_COA( int *output ) {
       
       static long k;
       static long numerator, denominator, val;
       
       numerator = 0;
       denominator = 0;
       
       for ( k=0; k<ARRAY_SIZE; k+=SKIP ) {
       
             val = (long)*output;
             output+=SKIP;
             /* look for non-zero values and include in our COA calc */
             if( val ) {
                    denominator += val;
                    /* ROM based later */
                    numerator += val *(long)k;
             }
       }
       /* divide if non-zero x/D */
       if( denominator ) {
             /* return crisp value */
             /* Could be converted from float if desired */
             numerator = (long)((float)(numerator/denominator) * pwm_members.slope +
       pwm_members.intercept);
             return( numerator );
       } else
             return( 0 );

}
/* end COA calc */

/******************************************************
       Routine: fuzzify
       Date: 4/3/93
       Author: Jack J. McCauley
       fuzzifier for our servo
******************************************************/
int fuzzify(    int derr_dt, int err,
             int *p_Terror, int *p_dTerror,
             int *p_out, int *resultant ) {

       static int k, val, alpha_cut, temp, *moe;

              /*         COA method         */
       /*
Get the alpha cut for error and derivative. Use the AND (min) operator and cut the
output , a non-zero fuzzy MIN indicates a rule has fired , write the cut to the result
array by "shadowing" the exisiting using the MAX operator
       */

       /* normalize the output derivative */
       moe: resultant;

       /* Find out if the rule fired. If the rule fired then get the alpha cut */
       if( (alpha_cut = FUZ_AND( p_dTerror[derr_dt], p_Terror[err] )) != 0 ) {
             for ( k=0; k<ARRAY_SIZE; k+=SKIP ) {
             /*
             An interesting effect will be noticed if the skip is set greater than
              1. In this system setting skip to lets say 2 or three will yield
             in most circumstance yield the same defuzzified crisp output if the
              slope of the membership functions are not too steep.
             The other benifit is that the execution speed is increased greatly
             */
                    /* create shadow */
                    val = *p_out;
                    /* don't get bit by shortcuts *./
                    val = FUZ=MIN( alpha_cut, val );
                    temp = *resultant;
                    * resultant = FUZ_MAX( temp, val );
                    resultant+=SKIP;
                    p_out+=SKIP;
             }
             /* rule fired */
             return( 1 );
       } else
             /* rule didn't fire */
             return( 0 );
}
/* end FUZZIFICATION calc */

/********************************************************
       Routine: servo_torque
       Date: 4/3/93
       Author: Jack J. McCauley
       fuzzy servos to torque set point
********************************************************/
/*
Routine would run as an ISR attched to a timer interrupt passed values are read
from and A/D convertor and command torque (serial port etc..)
*/
long servo_torque( int error, int derr_dt )
{
       /* statics for speed */
       static int row, column;
       
       /* pointers to tables */
       static int *p_out, *p_dTerr_dt, *p_Terror;
       
       /* COA container class */
       static int resultant[ARRAY_SIZE];
       
       /* zero fill the array */
       for( row = 0; row<ARRAY_SIZE; row++ )
             resultant[row] = 0;
       
       /* normalizing the error derivative will allow the error to ff
       /* normalize error derivative to look up table RADIX*/
       error = (long)((float)error * torq_members.slope + torq_members.intercept);
       
       /* normalize error derivative*/
       derr_dt = (long)((float)derr_dt*deri_members.slope + deri_members.intercept);
       
       /* MAX and MIN error */
       if( error > MAX_ERROR )
             error = MAX_ERROR;
       else if( error < MIN_ERROR )
             error = MIN_ERROR;
       
       /* MAX and MIN derivative */
       if( derr_dt > MAX_DERI )
             derr_dt = MAX_DERI;
       else if( derr_dt < MIN_DERI )
             derr_dt = MIN_DERI;
       
       /* traverse the rule table and evaluate the rules */
       for( row = 0; row < DER_MEMBERS; row++ ) {
       
             /* get pointers to tables from data structures */
             p_dTerr_dt = dTerr_dt[row];
             for( column = 0; column < TORQUE_MEMBERS; column++ ) {
             
                    /* get pointers to tables from data structures */
                    /* get the output membership function for that rule evaluation */
                    p_out = rule[row].table[column];
                    p_Terror = Terror[column];
                    /* fuzzify the rule */
                    fuzzify( derr_dt, error, p_Terror, p_dTerr_dt, p_out, resultant );
             }
       }
       
       /* defuzzify using COA */
       return( defuzzify_COA( resultant ) );
       
       /* return the fired rules */
}

/*END */

March 1994/A Fuzzy-Logic Torque Servo

A Fuzzy-Logic Torque Servo

Jack J. McCauley


Since receiving a BSEE from UC Berkeley, Jack J. McCauley has been working as a Software Engineering Consultant. His specialty is real-time systems with an emphasis on servo controls and signal processing. He can be reached at (510) 531-1581.

Background

The developer of a control system desires a well-behaved system that is stable throughout the operating spectrum. In the process of designing and debugging the controller, operating regions that exhibit oscillatory or unstable operation are avoided. Nonlinearities are typically modeled using a series of discrete equations developed for the system.

A PID or Proportional Integral Differential controller is an example of a closed-loop system. Implemented discretely, it would compute at z intervals:

T(z) = T(z-1) + Kk * (E(z) - E(z-1))
   + Ki * E(z) + Kd * E(z-2) * (1 + E(z-1))
In this linear example, the z sampled periods for the controller represent discrete time samples and Kk, Ki, and Kd are constants. A nonlinear system designer might attempt to modify Kk, Ki, and Kd as a function of input E(z). This of course would require Kk(z), Ki(z), and Kd(z) (and possibly Kk(z-1, z-2, .... z-n) etc). The designer would compute stability and phase margin in a continuous system and convert these to the discrete world using a Discrete Transform.

After the analysis the designer would proceed to code T(z) into assembler or C and port it to a target. This article describes how to implement a simple fuzzy-logic based servo controller in the C programming language. C language portability allows the controller to run in either a micro-controller based environment or on a PC.

Escaping Brittleness

Brittleness is the bane of the control-system designer. A brittle system is one which "breaks" easily. For example, in the coding of T(z), we defined the output T(z) to be an eight-bit unsigned char that follows the eight-bit radix of our A/D converter. Suppose that several of the terms of T(z) were discreetly nine or ten bits. The result could be truncated and thus produce incorrect output when T(z) was cast to an unsigned char. We must check overflow after every operation of T(z) and perform corrective logical operations.

Besides the implementation issues, PID and PI suffer from some serious real-world problems. In controls, non-linearities are the rule. Factors such as friction and temperature affect the behavior of systems. What appears to be stable under one set of conditions yields poor performance under another.

There are techniques for dealing with changes. One possibility is to sliding-mode modify the PI gain parameters. Experience with this approach has shown that it works very well so long as the inputs are bounded properly. Current thinking, however, indicates that the amount of time invested in developing this approach will not be extracted in performance. What most people do to deal with non-linearities is to add a bunch of testing and branching code to deal with the caveats. In most PID, PI closed-loop systems, it ends up that the majority of the code is dedicated to dealing with these anomalies.

Fuzzy Logic

Fuzzy logic holds promise as a means of handling control-system non-linearities. It provides a unique way of looking at control problems. The control problem is described as a rule base, with a rule input matrix µ(T) and a corresponding output function for that rule. When few rules are to be evaluated, simple linguistic rules can be substituted instead.

One might imagine a fuzzy set µ(T) that describes the outside temperature as "very cold," "cold," "warm," and "hot." The four members of µ(T) are linguistic operators that represent the human inferred description of the space representation of each member of µ(T). The membership function is typically a trapezoid that represents a degree of membership. The degree of membership is a real number between 0.0 and 1.0 with a degree of 1.0 meaning full membership and a degree 0.0 indicating no membership. (See Figure 1. )

Suppose the outside temperature is --50 F. Then according to µ(T) the outside temperature will lie in the domain of "very cold." If the temperature is 12 F, the temperature might not be so much "very cold" as it is just "cold." Membership functions almost always overlap in the domain of µ(T). Fuzzy logic provides a means of dealing with overlapping domains and also domains of overlapping output sets. The math allows us to weigh the cumulative effect of all rules to generate a crisp output. A crisp output is also called a de-fuzzified output.

The typical fuzzy plant (controller) consists of one or more input fuzzy sets, a rule base, and an output fuzzy set. The input sets fuzzify using the rule base, and the output set de-fuzzifies from the inputs, rules, and the output de-fuzzifier function.

An Application

This two-input controller is a torque regulator on a DC motor. The controller topology could easily be extended to any two-input, single-output fuzzy controller.

We desire to regulate the torque applied to the shaft of a permanent-magnet DC brush motor. The torque Tmotor applied to the shaft is a linear function of armature current Imotor and (to a lesser extent which will be ignored here) motor temperature. Armature current is controlled by a Pulse Width Modulated (PWM) amplifier which varies the duty cycle DA from 0 to 100 per cent as a linear function of input voltage.

If a positive voltage is applied to the motor terminals, a positive torque will be applied to the motor shaft. If a negative voltage is applied, a negative torque will be applied to the motor shaft. The job of the servo is to regulate the torque on the motor shaft under varying load conditions. The servo applies an adjustment to DA based on the commanded torque input, Tcmd(z), and the feedback torque input:

Tarm = Imotor(z) * Kmotor(z)
sensed on the motor shaft. (See Figure 2. )

The eight-bit PWM applies a positive voltage to the terminals if the PWM value is between 128 and 255. A negative voltage is applied if the value is between 0 and 126. An eight-bit A/D converter and pre-amp sense the feedback torque. The granularity of the feedback torque is determined by the radix of an eight-bit A/D converter. An eight-bit D/A (PWM) assures coherency between conversion radixes on the input. (See Figure 3. )

Fuzzy Controller for Torque

The fuzzy controller is implemented in C on an inexpensive high-integration micro-controller. A simulation program executes on a PC-AT, to assist debugging of the fuzzy servo prior to porting it to the micro-controller.

In this system the fuzzy plant is a two-input, single-output controller. Three fuzzy sets exist with the input sets occupying two dimensions of the rule base and the output set occupying the action to be performed on each rule, which is the combination pointed to by the input fuzzy set membership functions.

The first input fuzzy variable Terror is the error between the setpoint or command torque at time t, and the feedback torque or:

Terror(z) = Tcmd(z)- Tarm(z)
The second input dTerror/dt is the "rate of change of error" or how quickly the feedback torque at time t is changing with respect to the previous sample at time t--1:

dTerr(z)/dt = Tarm(z) - Tarm(z-1)
The output function µ(DA) determines the action to be performed upon evaluation of the rules. For example, if the instantaneous feedback torque is at the setpoint:

Tcmd(z) ~ Tarm(z)
but the feedback torque derivative is non-zero:

Tarm(z) > Tarm(z-1)
we might wish to apply a slight adjustment to DA so that Terror(z) and dTerr(z)/dt remain zero. The amount of adjustment applied to DA is determined by the inputs and also the output control fuzzy set µ(DA). Which membership function of µ(DA) to apply is determined by the input membership function space and the operator-inferred description of the control problem in the rule-base table. The idea is to maintain zero error and zero error derivative:

dTerr(z)/dt = Terror(z) = 0
The number of inputs and the dimension of each determines the rule base matrix. For example, we have two input fuzzy sets, m(T(Verr) and m(dTerr/dt), with five membership functions each. This yields a 5x5 or 25 rule-base controller. The corresponding action to be performed by the evaluation of each input rule determines the output controlling membership function m(DA). For example, rule (3, 3) is:

IF Terror == M
   AND dTerr/dt == -M
     THEN DA == Z
and rule (3, 2) is:

IF Terror == M
   AND dTerr/dt == Z
     THEN DA == -M
A literal evaluation of rule (3,2) would read, "If the feedback torque is less than the setpoint, and the feedback torque is approaching the setpoint at medium rate, then apply zero bias to the PWM." The key to fuzzy logic control is that the degrees of membership incorporate the amount of bias to apply and the degree of truth to each rule. (See Figure 4. )

When a Rule Fires

A rule fires when a nonzero result is returned upon evaluation of the rule. The degree to which the rule is true is incorporated in the membership functions. If the input values lie within the membership function trapezoid space, then the input is valid. A rule fires when both inputs to the rule are non-zero. A rule is evaluated using ternary operators similar in concept to Boolean operators. The operators logically follow the AND, OR, and NOT constructs.

Rules and rule bases can be built using the operators exactly like those in standard Boolean logic, but because membership functions deal with degrees of truth we must have a mechanism for evaluating the operators:

AND == MINIMUM(Input x, Input y)
OR == MAXIMUM(Input x, Input y)
NOT == 1.0 -Input x
The AND operator returns the minimum of the result of a rule that has fired. The OR operator returns the maximum of the result of a rule that has fired. The NOT operator returns the complement of its input x, which is roughly the analog of ~x in C.

In this application the AND operator is used exclusively to operate on the rule table inputs, and the normalized 0.0 -> 1.0 values are actually normalized eight bit values from 0 to 255.

(let dTerr(z)/dt = -11 and Terr(z) = 90)
In evaluating the fired rules (3, 3) and (3, 2) shown above, we first determined if the inputs lie within the domain of µ(Terror) and µ(dTerror/dt) by examining membership functions for µ(Terror) and µ(dTerror/dt). If the rule fires, we take the a cut for each of the input membership functions M and Z. The a cut graphically slices the top of the output controlling membership function. The AND operator returns the lesser of the two a cuts for the inputs µ(dTerror/dt, L) and µ(Terror, M) for use in the slicing operation. Because of the overlapping domain of the membership functions, more than one rule will typically fire. When this occurs, fuzzy logic provides a mathematical method for dealing with multiple rule findings. The output of each rule is an output membership functions that has been a cut and is then graphically ORed with the accumulated preceding output membership functions. The resultant resembels a "shadow" of each fired rule with the accumulated output overlapping each preceding fired rule. Mathematically, the accumulation is the fuzzy OR operator (MAXIMUM) applied to the current rule that fires and the accumulated fired rules. (See figure 5. )

De-fuzzification

The accumulated result of all firing rules occupies a two-dimensional space which is a fuzzy set with one membership function. The resultant must be converted to real world crisp result which takes into account all applied rules. To do this, a spatial average taken which computes the center of area (COA) of the function. COA is among several methods for computing the average. It is the method used in this application because it executes quickly.

COA = (25*18 + 25*31 + 128*100 + 128*127 + 128*140) /(25 + 25+ 128 + 128 + 128) 
    = 74
So the DA value written to the PWM/D/Ais 74.

C Language Implementation

The membership functions use table look up to follow the example:

µ(dTerror/dt) (in oz-in):
-L WHEN dTerr(z)/dt<=-35
-M WHEN -50 <= dTerr(z)/dt =< 0
ZM WHEN -10 > = dTerr(z)/dt <= 7
M WHEN 0 <= dTerr(z)/dt <= 50
L WHEN dTerr(z)/dt >= 10
All 25 rules evaluated and the rules that fire result in a output according to the COA output de-fuzzifier function. The output array stores the result of the rule firing and the history of predicate rules. Conflicts are resolved using the fuzzy OR MAXIMUM) operator. The resultant outputs contribute to a weighted sum to yield the COA output. This strategy allows for the quick computation of a crisp value using the eight-bit multiples.

For a micro-controller application, It was determined by experimentation that a loop repetition rate of at least 1 KHz would be required for satisfactory performance. Command set-points were entered through a serial port and an oscilloscope measured the response of the loop. Figure 6 shows the measured step response, which is quite adequate.

Conclusion

Fuzzy logic control seems to hold promise as an alternative to standard PID control. Rigid modeling is not required because the servo tuning is done via the fuzzy set membership functions and the rules. The rules incorporate Boolean statements and operator-inferred control rather than strict theoretical modeling. The membership functions allow tuning of the control system by altering the space that they occupy, and the placements of the output membership functions provide the control action to be performed by the rule. The rules use Boolean-like operators that infer a control action depending upon the degree of truth of the rule firing. A rule fires if the fuzzified inputs return a non-zero degree of truth, referred to as the a cut for each input.

Fuzzy logic is not as brittle as standard PID control because of the natural language approach to the control problem. Second-order effects such as temperature can be incorporated directly in the rule by logically appending another fuzzy set for temperature onto the rule. Suppose that we know that an increase in temperature causes the torque to change much more rapidly. By creating a rule base that incorporates temperature, we compensate for the change, as in:

IF Terror == M
   AND dTerr/dt == -M
   AND Temperature == L
     THEN DA = M
In PID control second-order variables such as temperatures are not so easily incorporated into the model.

The fuzzy controller is also less prone to radix overflow and underflow problems. In this application, the controller was implemented using eight-bit LUTs. All mathematical operations were cast to 32-bit long, thus preventing overflow. Because of the averaging nature of COA, it is inherently safe from overflow.

Listing 1: C declaration code for rule table and membership functions

Terms of Service | Privacy Statement | Copyright © 2024 UBM Tech, All rights reserved.