Fuzzy Logic Untuk Kontrol Posisi Motor DC

Pada post sebelumnya https://wangready.wordpress.com/2012/03/03/kontrol-posisi-motor-dc-mengunakan-rotary-encoder-berbasis-mikrokontroler-avr/ saya mencoba kontrol posisi motor DC dengan kontrol PID. Kali ini saya mencoba untuk menggunakan logika fuzzy sebagai kontrol. Berikut blok diagramnya.

Dan berikut rancangan fuzzy-nya menggunakan model fuzzy sugeno orde-0.

Fuzzy_motor1

Sebenarnya hasilnya kurang memuaskan dibanding PID. Tidak ada acuan untuk saya, untuk dapat menentukan settingan fuzzy yang tepat, tidak seperti pada PID. Atau mungkin metode penggunaan yang saya gunakan, yang mengambil nilai error dan delta_error sebagai input tidak tepat. Berikut program yang saya bangun dengan compiler CVAVR.

/*****************************************************
Chip type           : ATmega8535
Program type        : Application
Clock frequency     : 16.000000 MHz
Memory model        : Small
External SRAM size  : 0
Data Stack size     : 128
*****************************************************/

#include <mega8535.h>
#include <delay.h>
#include <stdio.h>
#include <math.h>
#include "Wangready_Fuzzy.c"

#define RXB8 1
#define TXB8 0
#define UPE 2
#define OVR 3
#define FE 4
#define UDRE 5
#define RXC 7

#define FRAMING_ERROR (1<<FE)
#define PARITY_ERROR (1<<UPE)
#define DATA_OVERRUN (1<<OVR)
#define DATA_REGISTER_EMPTY (1<<UDRE)
#define RX_COMPLETE (1<<RXC)

// USART Transmitter buffer
#define TX_BUFFER_SIZE 8
char tx_buffer[TX_BUFFER_SIZE];

#if TX_BUFFER_SIZE<256
unsigned char tx_wr_index,tx_rd_index,tx_counter;
#else
unsigned int tx_wr_index,tx_rd_index,tx_counter;
#endif

// USART Transmitter interrupt service routine
interrupt [USART_TXC] void usart_tx_isr(void)
{
if (tx_counter)
   {
   --tx_counter;
   UDR=tx_buffer[tx_rd_index];
   if (++tx_rd_index == TX_BUFFER_SIZE) tx_rd_index=0;
   };
}

#ifndef _DEBUG_TERMINAL_IO_
// Write a character to the USART Transmitter buffer
#define _ALTERNATE_PUTCHAR_
#pragma used+
void putchar(char c)
{
while (tx_counter == TX_BUFFER_SIZE);
#asm("cli")
if (tx_counter || ((UCSRA & DATA_REGISTER_EMPTY)==0))
   {
   tx_buffer[tx_wr_index]=c;
   if (++tx_wr_index == TX_BUFFER_SIZE) tx_wr_index=0;
   ++tx_counter;
   }
else
   UDR=c;
#asm("sei")
}
#pragma used-
#endif

#define pwm OCR1A
// Declare your global variables here
void motor_init()
{
        DDRC.0 = 1;
        DDRC.1 = 1;
}

void m_cw() //set arah motor
{
        PORTC.0 = 0;
        PORTC.1 = 1;
}

void m_ccw()  //set arah motor
{
        PORTC.0 = 1;
        PORTC.1 = 0;
}

void stop()
{
        PORTC.0 = 1;
        PORTC.1 = 1;
}

float           error,
                delta_error,
                prev_error,
                out_fuzzy;
int             encoder,
                enc_target,
                out_pwm;
unsigned char V_maks = 255;

// External Interrupt 0 service routine
interrupt [EXT_INT0] void ext_int0_isr(void)
{
// Place your code here
        if (PIND.3 == 0)
                // Increase enc
                encoder++;
        else
                // Decrease enc
                encoder--;
}
 //=========================================================
#define LV4_NEG 0
#define LV3_NEG 1
#define LV2_NEG 2
#define LV1_NEG 3
#define LV_ZERO 4
#define LV1_POS 5
#define LV2_POS 6
#define LV3_POS 7
#define LV4_POS 8

  //Fuzzy var linguistik
  #define NEGATIVE 0
  #define ZERO     1
  #define POSITIVE 2

  #define DEL_NEGATIVE 0
  #define DEL_ZERO     1
  #define DEL_POSITIVE 2

float   Error_Negative,
        Error_Zero,
        Error_Positive,
        Delta_Error_Negative,
        Delta_Error_Zero,
        Delta_Error_Positive;
float   out_fuzzy_index[JUMLAH_OUTPUT] = {      -120,
                                                -100,
                                                -80,
                                                -20,
                                                0,
                                                20,
                                                80,
                                                100,
                                                120};
#define batas_error_neg -10
#define batas_error_pos 10
#define batas_delta_error_neg -10
#define batas_delta_error_pos 10
// Timer 0 overflow interrupt service routine
interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
        error = (float)(enc_target - encoder);
        delta_error = (error-prev_error);

        if      (error > batas_error_pos)error = batas_error_pos;
        else if (error < batas_error_neg)error = batas_error_neg;
        if      (delta_error > batas_delta_error_pos)delta_error = batas_delta_error_pos;
        else if (delta_error < batas_delta_error_neg)delta_error = batas_delta_error_neg;

        Error_Negative  = segitiga(-10, -10,  0, error);
        Error_Zero      = segitiga(-10,   0, 10, error);
        Error_Positive  = segitiga(  0,  10, 10, error);
        Delta_Error_Negative    = segitiga(-10, -10,  0, delta_error);
        Delta_Error_Zero        = segitiga(-10,   0, 10, delta_error);
        Delta_Error_Positive    = segitiga(  0,  10, 10, delta_error);
/*
                NEGATIVE        ZERO	    POSITIVE
DEL_NEGATIVE    LV4_NEG         LV1_NEG    	LV2_POS
DEL_ZERO        LV3_NEG         LV_ZERO         LV3_POS
DEL_POSITIVE    LV2_NEG         LV1_POS    	LV4_POS
*/
        min_max_init();
        rule(Error_Negative     ,AND ,Delta_Error_Negative    ,LV4_NEG);
        rule(Error_Negative     ,AND ,Delta_Error_Zero        ,LV3_NEG);
        rule(Error_Negative     ,AND ,Delta_Error_Positive    ,LV2_NEG);
        //----------------------------------------------------------------------------------
        rule(Error_Zero         ,AND ,Delta_Error_Negative    ,LV1_NEG);
        rule(Error_Zero         ,AND ,Delta_Error_Zero        ,LV_ZERO);
        rule(Error_Zero         ,AND ,Delta_Error_Positive    ,LV1_POS);
        //----------------------------------------------------------------------------------
        rule(Error_Positive     ,AND ,Delta_Error_Negative    ,LV2_POS);
        rule(Error_Positive     ,AND ,Delta_Error_Zero        ,LV3_POS);
        rule(Error_Positive     ,AND ,Delta_Error_Positive    ,LV4_POS);

        out_fuzzy = weighted_average(out_fuzzy_index);

        out_pwm = (int)out_fuzzy * 2.12;
        printf("%.d|%.d|\n\r",(int)error,(int)delta_error);
        //printf("%.d \n\r",(int)out_fuzzy);
        if(out_pwm>0) m_cw();
        else if(out_pwm<0) m_ccw();
        else stop();

        out_pwm = abs(out_pwm);
        if(out_pwm>V_maks)out_pwm=V_maks;

        pwm = (unsigned char)out_pwm;
        prev_error = error;
}

// Declare your global variables here

void main(void)
{
// Declare your local variables here

// Input/Output Ports initialization
// Port A initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T
PORTA=0x00;
DDRA=0x00;

// Port B initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T
PORTB=0x00;
DDRB=0x00;

// Port C initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T
PORTC=0x00;
DDRC=0x00;

// Port D initialization
// Func7=In Func6=In Func5=Out Func4=In Func3=In Func2=In Func1=In Func0=In
// State7=T State6=T State5=0 State4=T State3=T State2=T State1=T State0=T
PORTD=0x00;
DDRD=0x20;

// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: 15.625 kHz
// Mode: Normal top=FFh
// OC0 output: Disconnected
TCCR0=0x05;
TCNT0=0x00;
OCR0=0x00;

// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: 15.625 kHz
// Mode: Ph. correct PWM top=00FFh
// OC1A output: Non-Inv.
// OC1B output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer 1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: Off
// Compare B Match Interrupt: Off
TCCR1A=0x81;
TCCR1B=0x05;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;

// Timer/Counter 2 initialization
// Clock source: System Clock
// Clock value: Timer 2 Stopped
// Mode: Normal top=FFh
// OC2 output: Disconnected
ASSR=0x00;
TCCR2=0x00;
TCNT2=0x00;
OCR2=0x00;

// External Interrupt(s) initialization
// INT0: On
// INT0 Mode: Falling Edge
// INT1: Off
// INT2: Off
GICR|=0x40;
MCUCR=0x02;
MCUCSR=0x00;
GIFR=0x40;

// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=0x01;

// USART initialization
// Communication Parameters: 8 Data, 1 Stop, No Parity
// USART Receiver: Off
// USART Transmitter: On
// USART Mode: Asynchronous
// USART Baud rate: 9600
UCSRA=0x00;
UCSRB=0x48;
UCSRC=0x86;
UBRRH=0x00;
UBRRL=0x67;

// Analog Comparator initialization
// Analog Comparator: Off
// Analog Comparator Input Capture by Timer/Counter 1: Off
ACSR=0x80;
SFIOR=0x00;

motor_init();

// Global enable interrupts
#asm("sei")
delay_ms(10);
enc_target = 270;
delay_ms(3000);
enc_target = 0;
delay_ms(3000);

while (1)
      {
      // Place your code here

      };
}

dan ini file c yang saya buat untuk aplikasi fuzzy.

/*======================
 Wangready_Fuzzy.c
wangready.wordpress.com
DAFTAR PUSTAKA:
-Suyanto. 2007.“Artificial Intelegent; Searching, Reasoning, Planing, and Learning”. Penerbit Informatika. Bandung.
-http://en.wikipedia.org/wiki/Fuzzy_logic
-Kusumadewi,Sri.Hartati,Sri.2010."Neuro-Fuzzy: Integrasi Sistem Fuzzy & Jaringan Syaraf Edisi 2".Graha Ilmu.Yogyakarta.
-Kuswadi,Son.2007."Kendali Cerdas: Teori dan Aplikasi Praktisnya".Penerbit ANDI.Yogyakarta.
======================*/
#include <math.h>

#define JUMLAH_OUTPUT 9
#define AND 0
#define OR  1

float   max_value[JUMLAH_OUTPUT],
        min_value[JUMLAH_OUTPUT];

float segitiga(float a, float b, float c, float CRISP)
{
     if(CRISP < a)return(0);
     else
     {
        if(CRISP <= b)
        {
                if(b == a)
                {
                        return(1);
                }
                else
                {
                        return((CRISP-a)/(b-a));
                }
        }
        else
        {
                if(CRISP <= c)
                {
                        if(c == b)
                        {
                                return(1);
                        }
                        else
                        {

                                return(-(CRISP-c)/(c-b));
                        }
                }
                else
                {
                        return(0);
                }
        }
     }
 }

 float trapesium(float a, float b, float c, float d, float CRISP)
{
     if(CRISP < a)return(0);
     else
     {
        if(CRISP <= b)
        {
                if(b == a)
                {
                        return(1);
                }
                else
                {
                        return((CRISP-a)/(b-a));
                }

        }
        else
        {
                if(CRISP < c)  return(1);
                else
                {
                        if(CRISP <= d)
                        {
                                if(d == c)
                                {
                                        return(1);
                                }
                                else
                                {
                                        return(-(CRISP-d)/(d-c));
                                }
                        }
                        else
                        {
                                return(0);
                        }
                }
        }
     }
 }

void rule(float var_linguistik1,unsigned char OPERATOR,float var_linguistik2, unsigned char index_output)
{
        switch(OPERATOR)
        {
                case AND :
                        min_value[index_output] = fmin(var_linguistik1,var_linguistik2);
                        break;
                case OR :
                        min_value[index_output] = fmax(var_linguistik1,var_linguistik2);
                        break;
        }
        max_value[index_output] = fmax(min_value[index_output],max_value[index_output]);
}

void min_max_init()
{
unsigned char i = 0;
        for(i=0;i<JUMLAH_OUTPUT;i++)
        {
                min_value[i] = 0;
                max_value[i] = 0;
        }
}

float weighted_average(float *jum_out)
{
float   num = 0,
        denum = 0;
unsigned char i = 0;

        for(i=0;i<JUMLAH_OUTPUT;i++)
        {
                num += (jum_out[i]*max_value[i]);
                denum += max_value[i];
        }
        return(num/denum);
}

Untuk menggabungkan 2 file c ke dalam 1 project file terlebih dahulu dilakukan setting di Project lalu Configure.

Fuzzy_motor2

Fuzzy_motor3

Rancangan hardware yang saya simulasikan dengan software proteus.

______________________________________________________

DAFTAR PUSTAKA

-Suyanto. 2007.“Artificial Intelegent; Searching, Reasoning, Planing, and Learning”. Penerbit Informatika. Bandung.
-http://en.wikipedia.org/wiki/Fuzzy_logic
-Kusumadewi,Sri.Hartati,Sri.2010.”Neuro-Fuzzy: Integrasi Sistem Fuzzy & Jaringan Syaraf Edisi 2″.Graha Ilmu.Yogyakarta.
-Kuswadi,Son.2007.”Kendali Cerdas: Teori dan Aplikasi Praktisnya”.Penerbit ANDI.Yogyakarta.
-Banks, Walter. Hayward,  Gordon.2002.”Fuzzy Logic in Embedded Microcomputers and Control Systems”. BYTE CRAFT LIMITED. Ontario. Canada

.

14 Responses to Fuzzy Logic Untuk Kontrol Posisi Motor DC

  1. Ari says:

    Permisi Gan..,mau nanya ttg Fuzzy Logic ke CVAVR boleh ga Gan???Terima kasih sebelumnya Gan..,

      • Ari says:

        Gni Gannn…klu contoh d atas kan in fuzzy ny ada 2..nah itu in ny ada 3 Gan???pas ntr d cari nilai terkecilny gmn Gan???
        Trus contih aplikasi fuzzy diatas bisa langsung di pake ga Gan???klu yg d sayany langsung aja masukkn d 1 file fuzzyny…
        Trima kasih sebelumnya Gann

      • wangready says:

        klo yg IN nya tiga edit aja gan koding yg di atas, soalnya gk punya contohnya klo yg 3….
        Klo contoh yg diatas bisa dicoba gan, ane udah uji. cuman kurang setting aja biar hasil kontrolnya bagus…

      • Ari says:

        Baru cek email ne Gan…ia Gan saya liat dri coding d atas..ampir sama ama coding yg saya bikin Gan…thanks masukannya Gab..oy Gann..sedikt kluar dri topik Fuzzy ne Gan…saya mau nanya..saya bikin pendeteksi jarak pake sr04..sbgai in mikro..in ny ini berubah terus kan Gan nilainy..misal saya pengen menyalakan led klu jaraj udah 5cm..nah saya pegen led nyaka trus klu seandainy jarakny udah brubah lagi…bgusnya pke intruksi apa t Gan???

        Tlong ne Gan..mkasi sblumnya Gan

      • wangready says:

        istilahnya seperti metode diferensial yang saya ambil dari aplikasi PID, jadi gunakan waktu sekarang dan sesudah proses, misal

        data_sebelum = 0; 
        while(1)
        {
        //----Sebelum Proses-----
          data_sekarang = get_SRF();
          delta_data = abs(data_sekarang - data_sebelum);//fungsi nilai mutlak
        //----Proses------
          if(delta_data > 0) //akan mengeksekusi jika ada perubahan jarak. nilai sensitifitas bisa diatur untuk perubahan jarak 
        	LED = 1;
          else
        	LED = 0;
        //-----sesudah proses-----
           data_sebelum = data_sesudah;
          delay_ms(1); //menetukan seberapa cepat respon
        }
        
  2. maikal says:

    Gan, mau nanya, maksud sistem kendali fuzzy di atas orde 0 artinya apa ya?
    Tks

    • wangready says:

      itu saya pelajari dari buku Kusumadewi,Sri.Hartati,Sri.2010.”Neuro-Fuzzy: Integrasi Sistem Fuzzy & Jaringan Syaraf Edisi 2″.Graha Ilmu.Yogyakarta halaman 53 gan…
      kalo dalam buku itu dijelaskan ada 2 model untuk sistem inferensi fuzzy dengan metode sugeno ini, yaitu orde-0 dan orde-1.
      orde-0
      IF (x1 is A1).(x2 is A2).(x3 is A3)….(xn is An) THEN z=k
      Ai : himpunan fuzzy ke-i sebagai antisenden, . adalah operator fuzzy (AND atau OR), k adalah konstanta (tegas) sebagai konsekuen.
      orde-1
      IF (x1 is A1).(x2 is A2).(x3 is A3)….(xn is An) THEN z=p1*x1 + … + pn*xn + q
      Ai : himpunan fuzzy ke-i sebagai antisenden, . adalah operator fuzzy (AND atau OR), pi adalah konstanta (tegas) ke-i dan q juga merupakan konstanta dalam konsekuen.
      Lengkapnya ada di bukunya gan….

  3. maikal says:

    Ok gan thanx atas penjelasannya..
    Oiya mau nanya lgi nih gan, apa sih perbedaan inferensi model mamdami dan sugeno?
    Saya sudah browsing dari internet kurang paham gan. Tolong gan penjelasannya dengan mudah dipahami..
    Makasih

  4. gilette says:

    Masbro mo nanya, contoh kasus di atas. Inputnya kan error dan delta error. Klo outputnya apa ya ?

    • wangready says:

      out_fuzzy gan, nantinya dikonversi ke pwm

      • gillete says:

        terus kenapa ada bilangan negatif di outptnpwmnya masbro ? Kya contoh diatas range outputnya antara -120 sampai 120 ? Klo pun mau di ubah nanti ke nilai heksa ada desimal kenapa rangenya gak langsung aja dari 0 -255 atau 0-1023 ?

        Dan kenapa range delta errornya rangenya sama dengan range nilai error ya masbro ? klo ane berpikir nilai delta error pasti lebih kecil dari nilai eror. Oleh karena itu kalo dibikin nilai rangenya sama dengan error, ane ngeliatnya nanti nilai delta error yang aktif paling hanya di daerah delta error_zero.
        Mohon maaf klo ada yang salah. Mohon pencerahannya.

      • wangready says:

        nilai -120 dan 120 nya ane masukin ke fungsi lg untuk menentukan arah putar gan….
        ane kasih range 120 karena ane mau kasih konstanta proporsional di akhir proses untuk memudahkan tunning…
        kalo soal crisp input dan output ane jg hanya mendesain sesuai perkiraan aja ga…
        yg delta error itu kan dipengaruhi domain waktu delta t ( cycle time waktu eksekusi), delta error mendekati nol ketika nilai error hampir sama per delta t….kira2 nya gtu gan….

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s