Academic Integrity: tutoring, explanations, and feedback — we don’t complete graded work or submit on a student’s behalf.

Develop with MATLAB, a fuzzy control system for controlling the power of a motor

ID: 2988306 • Letter: D

Question

Develop with MATLAB, a fuzzy control system for controlling the power of a motor (0-350 rpm) based on the supported load (0-1700 lbs) thereby that at greater load develops more power. The system must contain at least 5 rules, but preferably 7. Assign the appropriate linguistic terms to fuzzy subsets of each variable. Experiment using a system with triangular membership functions and other with some other type of membership function (trapezoidal, general bell, etc) from those available in Matlab, for different values of load. Observe and interpret the results for each type of membership, under the same input values.
Please include in your submission the following:
a. A written description of the designed system
b. The generated FIS editor (output/input) in MATLAB
c. Screen shots for each membership function of both input and output variables for each system event.
d. The rules generated in MATLAB
e. Screen shot of the evaluation diagrams
f. An analysis of the observed results (interpretations)
g. Conclusions about the performance of each system and comparison for at least two more types of membership functions.

Explanation / Answer

void loop()
{
servo2.write(60);
servo4.write(60);
servo6.write(60);
servo8.write(60);
servo10.write(60); // This works!!!
  
  
if( Serial.available() >=2)
{

  
int nr = Serial.read(); // read in servo number
int position = Serial.read(); // read in servo position
switch(nr)
{
case 2:
servo2.write(position);
break;
case 4:
servo4.write(position);
break;
case 6:
servo6.write(position);
case 8:
servo8.write(position);
case 10:
servo10.write(position);
break;
default:
servo2.write(60);
servo4.write(60);
servo6.write(60); // default position
servo8.write(60);
servo10.write(60);
break;
}
}
//sleep(100); // give the servo's some time --> Throws an "'sleep' was not declared in this scope"-error!!!
}


#include "16f877.h"
#include "q_config.h"
#include "encoder.h"
#include "daout.h"
#include "init_qmt.h"

#include <math.h>
#include <string.h>
#include <stdlib.h>

#ZERO_RAM

#define CLK 20000000 //Clock frequency

#use delay(clock = CLK) //Set clock frequency
#use rs232(baud=115200, bits=8, parity=N, xmit=PIN_C6, rcv=PIN_C7, errors) //Setup
serial port

//User defined constants
#define fs 50 //sampling frequency in Hz (10 Hz is the slowest supported
frequency)
#define ts (1/(float)fs) //sampling period in second

//Signal types
#define SIGIMP 1 //Impulse signal
#define SIGSTP 2 //Step signal
#define SIGRMP 3 //Ramp signal
#define SIGPAR 4 //Parabolic signal
#define SIGTRI 5 //Triangle wave signal
#define SIGSAW 6 //Sawtooth wave signal
#define SIGSQA 7 //Square wave signal
#define SIGSIN 8 //Sine wave signal
#define SIGCOS 9 //Cosine wave signal
#define SIGSTR 10 //Stair wave signal

//Signal information
int8 SigType; //Current signal type (see above definitions)
float SigMagRate; //Signal magnitude or rate, depending on signal type
float SigFreq; //Signal frequency (hz), if applicable to current signal type

//Global variables
short int DoControl; //Flag as to whether to do control or not
short int Running; //Flag as to whether we are running or not

long EndCnt; //Count to end the program when reached

long TimeCnt; //Last control time index
float RefSig; //Current reference signal (desired angle or angular velocity)
float RefSigLast; //Last reference signal
float Angle; //Last read angle in radians
float Volt; //Last set motor voltage output
float Current; //Last read motor current in milliamps
float AngleFD; //Last calculated motor angle first derivative (rad/s) using
the direct method
float AngleFDFilt; //Last calculated motor angle first derivative (rad/s) from
the filtering method

long SquareCount;

short int TriSgn; //Current sign of triangle wave (0 means negative and 1 means
positive)

long preset_counter; //Value to set counter to at each interrupt

#define BUFSIZ 5 //Recieving buffer size (DON'T CHANGE!)
char RecDatBuf[BUFSIZ]; //Recieving data buffer
long iRecData; //Next available location in data recieve buffer
short int RecDatAvail; //Flag as to whether data has been recieved
int1 RecErr; //Flag as to wheter a recieve error has occured

int1 FirstTime;

//Setup angular rate filter parameters
float Omega = 300.;
float ca;
float cb;

//Function prototypes
float CalcRefSignal(long TimeCnt);
float GetTri();
float GetSquare();

//#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%
//The following routine will be called at the sample rate to generate the new
//reference signal as well as complete the actual control and write the output
void RunController()
{

float AngleLast;
float VoltLast;
float AngleFDFiltLast;
static float Errors[3];

//-------------------------------------------------------------------------
//Start of controller parameters
//-------------------------------------------------------------------------

//PID controller parameters
const float k = 6.650160854277;
const float a1 = 0.87508921708793;
const float a2 = 0.91901606680500;

//-------------------------------------------------------------------------
//End of controller parameters
//-------------------------------------------------------------------------

DoControl = 0;

//Turn on LED
output_high(LED3);

//Increment output count (as long as this isn't the first time)
if (!FirstTime)
TimeCnt++;

//Read the encoder
AngleLast = Angle;
Angle = read_encoder(ENCODER0, X_AXIS);

//Save current reference signal
RefSigLast = RefSig;

//Get new desired angle
RefSig = CalcRefSignal(TimeCnt);

//Read the current
set_adc_channel(2);
delay_us(20);
Current = ((float)Read_ADC()-512.0)*0.00543*1000;

if (!FirstTime)
{
AngleFD = (Angle-AngleLast)/ts;

AngleFDFiltLast = AngleFDFilt;
AngleFDFilt = ca*(Angle-AngleLast) - cb*AngleFDFiltLast;
}

//-------------------------------------------------------------------------
//Start of controller logic
//-------------------------------------------------------------------------

//Save current voltage
VoltLast = Volt;

//Set all errors to zero the first sample period
if (FirstTime) memset(Errors, 0, sizeof(Errors));

//Save errors for position control
Errors[2] = Errors[1]; //Error two time steps ago
Errors[1] = Errors[0]; //Error at last time step
Errors[0] = RefSig - Angle; //Error at current time step

//Controller logic
Volt = VoltLast + k*(Errors[0] - (a1+a2)*Errors[1] + a1*a2*Errors[2]); //PID

//-------------------------------------------------------------------------
//End of controller logic
//-------------------------------------------------------------------------

//Ouptut controller voltage
daout(Volt);

//Turn LED off
output_low(LED3);

}

//#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%
float CalcRefSignal(long TimeCnt)
{

float NewSig, t;
float TrigX;

t = TimeCnt*ts;

//Figure out the multiplier to the trig signals
if (SigType == SIGSIN || SigType == SIGCOS)
{
TrigX = t*SigFreq;
TrigX = TrigX - floor(TrigX);
}

switch (SigType)
{

//Impulse signal
case SIGIMP:
if (TimeCnt == 0)
NewSig = (SigMagRate/ts);
else
NewSig = 0;

break;

//Step signal
case SIGSTP:
NewSig = SigMagRate;

break;

//Ramp signal
case SIGRMP:
NewSig = SigMagRate*t;
break;

//Parabolic signal
case SIGPAR:
NewSig = SigMagRate*t*t;
break;

//Triangle wave signal
case SIGTRI:
NewSig = GetTri();
break;

//Sawtooth wave signal
case SIGSAW:

NewSig = 2*SigMagRate*((t*SigFreq) - floor((t*SigFreq)+0.5));
break;

//Square wave signal
case SIGSQA:
NewSig = GetSquare();
break;

//Sine wave signal
case SIGSIN:
NewSig = SigMagRate*sin(TrigX*2*PI);
break;

//Cosine wave signal
case SIGCOS:
NewSig = SigMagRate*cos(TrigX*2*PI);
break;

//Stair wave signal
case SIGSTR:
NewSig = SigMagRate*(floor((t*SigFreq)+0.0000001)+1);

}

return NewSig;

}

//#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%
float GetTri()
{

float NewSig, Rate;

if (TimeCnt == 0)
NewSig = 0;
else
{
Rate = 4*SigMagRate*SigFreq;

if (!TriSgn)
Rate = -Rate;

NewSig = RefSigLast + Rate*ts;

if (NewSig > SigMagRate)
{
NewSig = 2*SigMagRate - NewSig;
TriSgn = 0;
}
else if (NewSig < -SigMagRate)

{
NewSig = -2*SigMagRate - NewSig;
TriSgn = 1;
}
}
return NewSig;
}

//#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%
float GetSquare()
{
float NewSig;

if (TimeCnt == 0)
{
SquareCount = fs/(2*SigFreq);
NewSig = SigMagRate;
}
else if (TimeCnt == SquareCount)
{
SquareCount = SquareCount + fs/(2*SigFreq);
NewSig = -RefSigLast;
}
else
NewSig = RefSigLast;

return NewSig;
}

//#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%
void FloatToIEE754(float *Val)
{

int1 Tmp;
int8 *Ptr;

Ptr = Val;

Tmp = shift_left(&Ptr[1], 1, 0);
Tmp = shift_right(&Ptr[0], 1, Tmp);
shift_right(&Ptr[1], 1, Tmp);

}

//#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%
void IEE754ToFloat(float *Val)
{

int1 Tmp;
char *Ptr;

Ptr = Val;

Tmp = shift_left(&Ptr[1], 1, 0);
Tmp = shift_left(&Ptr[0], 1, Tmp);
shift_right(&Ptr[1], 1, Tmp);

}

//#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%
#SEPARATE void OutputFloat(float ValIn)
{

char *c;
float Val;

Val = ValIn;

//Save pointer to float so we can easily access the bytes individually
c = &Val;


//Convert number to IEEE 754
FloatToIEE754(&Val);

//Send data (order of bytes reversed since PC is expecting littleEndian)
putc(c[3]);
putc(c[2]);
putc(c[1]);
putc(c[0]);

}

//#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%
#SEPARATE void OutputLong(long Val)
{

char *c;

//Save pointer to float so we can easily access the bytes individually
c = &Val;

//Send data
putc(c[0]);
putc(c[1]);

}

//#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%
#SEPARATE long GetLong()
{

char *c;
long NewInt;

c = &NewInt;

c[0] = RecDatBuf[1];
c[1] = RecDatBuf[2];

return NewInt;

}

//#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%
#SEPARATE float GetFloat()
{

char *c;
float NewFloat;

c = &NewFloat;

c[0] = RecDatBuf[4];
c[1] = RecDatBuf[3];
c[2] = RecDatBuf[2];
c[3] = RecDatBuf[1];

IEE754ToFloat(&NewFloat);

return NewFloat;

}
//#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%
void SetSampleFrequency(float freq) {
setup_timer_1(T1_INTERNAL | T1_DIV_BY_8);

preset_counter = 65536 - floor(((CLK/8)/4) / freq );
set_timer1(preset_counter);
}

//#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%
void main()
{

//Local variables
long LastOutputCnt; //Index of the last dataset output
char Cmd;
int IntVal;

//Initialize
init_QMT();

//Calculate angular rate filter parameters
ca = 2*omega/(2+omega*ts);
cb = (-2+omega*ts)/(2+omega*ts);

//Choose current ADC channel
set_adc_channel(2);

init_encoder(ENCODER0); //Initialize the encoder

//Initialize outputs
daout(0); //Send 0 voltage to DA output
output_low(LED3); //Set LED3 to low
output_high(LED2); //Set LED2 to high
output_low(PIN_B4); //Enable external D/A

//Initialize variables
DoControl = 0;
RefSig = 0;
RefSigLast = 0;
Volt = 0;
Current = 0;
AngleFD = 0;
AngleFDFilt = 0;

SquareCount = 0;
TriSgn = 1;

iRecData = 0;
RecDatAvail = 0;
RecErr = 0;

EndCnt = 0;
TimeCnt = 0;
LastOutputCnt = 0;

Running = 0;
FirstTime = 1;

enable_interrupts(INT_RDA);

enable_interrupts(GLOBAL); //Enable interrupts globally

while(1)
{

if (Running == 1)
{

//Check if we should do control
if (DoControl == 1)
RunController();

//Check if we need to ouput data
if ((LastOutputCnt != TimeCnt) || FirstTime)
{
putc('d');

OutputLong(TimeCnt);
OutputFloat(RefSig);
OutputFloat(Angle);
OutputFloat(Volt);
OutputFloat(Current);
OutputFloat(AngleFD);
OutputFloat(AngleFDFilt);

LastOutputCnt = TimeCnt;
FirstTime = 0;
}

//Check for end of time
if (TimeCnt >= EndCnt)
break;

}

//Check for data in read buffer
if (RecDatAvail == 1)
{

RecDatAvail = 0;

Cmd = RecDatBuf[0];

if (RecErr)
{
//Ignore bad data
RecErr = 0;
}
else
{

//Run the desired command
if (Cmd == 'S')
{
//This is the new signal type
SigType = GetLong();
}
else if (Cmd == 'M')
{
//This the new signal magnitude or rate
SigMagRate = GetFloat();
}
else if (Cmd == 'F')
{
//This is the new signal frequency
SigFreq = GetFloat();
}
else if (Cmd == 'E')
{
//This is the count at which to end
EndCnt = GetLong();
}
else if (Cmd == 'G')
{
//This is the flag to GO!
output_low(LED2); //Set LED2 to low
Running = 1;

SetSampleFrequency(fs); //Set sample frequency
enable_interrupts(INT_TIMER1); //Turn on timer1 interrupt
enable_interrupts(GLOBAL); //Enable interrupts globally
}
else if (Cmd == 'f')
{
//Sampling frequency request
putc('f');
OutputFloat(ts);
}
}
}
}

//Send flag to tell the computer to stop reading data
putc('X');

//Stop the interrupts
disable_interrupts(GLOBAL); //Disable interrupts globally
disable_interrupts(INT_TIMER1); //Turn off timer1 interrupt
disable_interrupts(INT_RDA); //Turn off receive data available
interrupt

//Stop motor by sending 0 voltage to DA output
daout(0);

//Wait 1 second for motor to stop spinning
delay_ms(1000);

reset_cpu();

}

//Use interrupt to recieve serial data when it is available
#INT_RDA
void ReadSerialData()
{

if ((RS232_ERRORS & 0x7) != 0)
{
//An error ocurred
RecErr = 1;
output_high(LED2);
output_high(LED3);
}
else
{
//Save current transmission
RecDatBuf[iRecData] = getc();
iRecData++;

//Check for full buffer
if (iRecData >= 5)
{
RecDatAvail = 1;
iRecData = 0;
}
}

}
//Signal the compiler that the next function is the timer1 interrupt
#INT_TIMER1
void SetControlFlag()
{

//Reset the counter to the correct count
//This is necessary to achieve the desired sample rate
set_timer1(preset_counter);

DoControl = 1;

}