Download as pdf or txt
Download as pdf or txt
You are on page 1of 29

LAPORAN

FUZZYFIKASI, EVALUASI RULE & DEFUZZYFIKASI PADA


MIKROKONTROLLER ARDUINO NANO MENGGUNAKAN ISIS
PROTEUS
MATA KULIAH SISTEM KENDALI CERDAS
Dosen Pengampu : Dr. Ir. Fatchul Arifin, M.T.

Disusun Oleh :
Prasetyo 17502241005

PENDIDIKAN TEKNIK ELEKTRONIKA


JURUSAN PENDIDIKAN TEKNIK ELEKTRONIKA DAN
INFORMATIKA
UNIVERSITAS NEGERI YOGYAKARTA
2019
A. Skematik

Gambar 1. Skematik Rangkaian Pada Proteus

Tabel 1. Daftar Komponen


Nama Komponen Nama Komponen di Proteus
Arduino Nano Arduino Nano
LCD 20 x 4 LM044L
Potensiometer POT-HG
Push Button Button
Motor DC Motor
Driver Motor L293D

Tabel 2. Konfigurasi Pin


Pin Arduino Pin Trainer Pin Arduino Pin Trainer
LCD Driver Motor L293D
8 D7 2 IN1
9 D6 3 IN2
10 D5 6 EN1 (KANAN)
11 D4 4 IN3
12 E 7 IN4
13 RS 5 EN2 (KIRI)
Push Button Potensiometer
A2 S1 A0 ERROR
A3 S2 A1 D_ERROR
A4 S3
B. Listing Program
//motor kanan
#define IN1 2
#define IN2 3
#define pwm_kanan 6
//motor kanan

//motor kiri
#define IN3 4
#define IN4 7
#define pwm_kiri 5
//motor kiri

//lcd
#include <LiquidCrystal.h>
LiquidCrystal lcd(13, 12, 11, 10, 9, 8);
/*
* The circuit:
* LCD RS pin to digital pin 12
* LCD Enable pin to digital pin 11
* LCD D4 pin to digital pin 5
* LCD D5 pin to digital pin 4
* LCD D6 pin to digital pin 3
* LCD D7 pin to digital pin 2
*/
//lcd

//variabel global
int a,b,i,j,speed_left,speed_right,sensorA,sensorB;
float x, y, error, d_error;
float z1=60,z2=80,a1=-145.5556,a2=-80,a3=0;
float a4=80,a5=145.5556; //z = luas dan a = COA out;
float u_error[3],u_d_error[3],u[3][3], errorneg, errorzero, errorpos, d_errorneg,
d_errorzero,d_errorpos;
float nilai_awal,beda_pwm, validasi, pembilang, penyebut;
//variabel global

void setup() {
lcd.begin(20, 4);
Serial.begin(9600);
pinMode(IN1, OUTPUT);
pinMode(IN2, OUTPUT);
pinMode(IN3, OUTPUT);
pinMode(IN4, OUTPUT);
pinMode(pwm_kanan, OUTPUT);
pinMode(pwm_kiri, OUTPUT);
pinMode(16, INPUT_PULLUP);
pinMode(17, INPUT_PULLUP);
pinMode(18, INPUT_PULLUP);
}
void loop() {
nilai_awal = 100;
baca_sensor(); //membaca nilai error dan d_error
fuzzyfikasi();
rule();
defuzzyfikasi();
kendali_motor(speed_left,speed_right);
int tombol_fuzzyfikasi = digitalRead(16);
int tombol_rule = digitalRead(17);
int tombol_defuzzyfikasi = digitalRead(18);
if(tombol_fuzzyfikasi==0 && tombol_rule==1 && tombol_defuzzyfikasi==1) {
display_fuzzyfikasi();
} //menampilkan data proses fuzzyfikasi
if(tombol_fuzzyfikasi==1 && tombol_rule==0 && tombol_defuzzyfikasi==1) {
display_rule();
} //nenampilkan implikasi setiap rule
if(tombol_fuzzyfikasi==1 && tombol_rule==1 && tombol_defuzzyfikasi==0) {
display_defuzzyfikasi();
}//menampilkan output tegas dan nilai kecepatan motor kiri dan kanan
if(tombol_fuzzyfikasi==1 && tombol_rule==1 && tombol_defuzzyfikasi==1) {
lcd.clear();
}//clear tampilan LCD
}

void baca_sensor()
{
sensorA = analogRead(A0);
sensorB = analogRead(A1);
a = map(sensorA, 0, 1023, 0, 255); //maping error
b = map(sensorB, 0, 1023, 0, 255); //maping d_error
if(a>=241) {error=8;}
else if(a>=227) {error=7;}
else if(a>=213) {error=6;}
else if(a>=199) {error=5;}
else if(a>=185) {error=4;}
else if(a>=171) {error=3;}
else if(a>=157) {error=2;}
else if(a>=143) {error=1;}
else if(a>=129) {error=0;}
else if(a>=115) {error=-1;}
else if(a>=101) {error=-2;}
else if(a>=87) {error=-3;}
else if(a>=73) {error=-4;}
else if(a>=59) {error=-5;}
else if(a>=45) {error=-6;}
else if(a>=31) {error=-7;}
else if((a<31)&&(a>=0)) {error=-8;}

if(b>=248) {d_error=16;}
else if(b>=241) {d_error=15;}
else if(b>=234) {d_error=14;}
else if(b>=227) {d_error=13;}
else if(b>=220) {d_error=12;}
else if(b>=213) {d_error=11;}
else if(b>=206) {d_error=10;}
else if(b>=199) {d_error=9;}
else if(b>=192) {d_error=8;}
else if(b>=185) {d_error=7;}
else if(b>=178) {d_error=6;}
else if(b>=171) {d_error=5;}
else if(b>=164) {d_error=4;}
else if(b>=157) {d_error=3;}
else if(b>=150) {d_error=2;}
else if(b>=143) {d_error=1;}
else if(b>=136) {d_error=0;}
else if(b>=129) {d_error=-1;}
else if(b>=122) {d_error=-2;}
else if(b>=115) {d_error=-3;}
else if(b>=108) {d_error=-4;}
else if(b>=101) {d_error=-5;}
else if(b>= 94) {d_error=-6;}
else if(b>= 87) {d_error=-7;}
else if(b>= 80) {d_error=-8;}
else if(b>= 73) {d_error=-9;}
else if(b>= 66) {d_error=-10;}
else if(b>= 59) {d_error=-11;}
else if(b>= 52) {d_error=-12;}
else if(b>= 45) {d_error=-13;}
else if(b>= 38) {d_error=-14;}
else if(b>= 31) {d_error=-15;}
else if((b<31)&&(b>= 0)) {d_error=-16;}
}

void fuzzyfikasi_error()
{
x = error;
//u_error[0] = Negatif 1
//u_error[1] = Zero 1
//u_error[2] = Positif 1
if(x >= 5)
{
u_error[0]=0;
u_error[1]=0;
u_error[2]=1;
}
else if(x >= 0)
{
u_error[0]=0;
u_error[1]=(5-x)/5;
u_error[2]=(x-0)/5;
}
else if(x >= -5)
{
u_error[0]=(0-x)/5;
u_error[1]=(x+5)/5;
u_error[2]=0;
}
else if(x < -5)
{
u_error[0]=1;
u_error[1]=0;
u_error[2]=0;
}
errorneg = u_error[0];
errorzero = u_error[1];
errorpos = u_error[2];
}

void fuzzyfikasi_perubahan_error()
{
y = d_error;
// u_d_error[0]=Negatif 2
// u_d_error[1]=Zero 2,
//u_d_error[2]=Positif 2
if(y >= 8)
{
u_d_error[0]=0;
u_d_error[1]=0;
u_d_error[2]=1;
}
else if(y >= 0)
{
u_d_error[0]=0;
u_d_error[1]=(8-y)/8;
u_d_error[2]=(y-0)/8;
}
else if(y >= -8)
{
u_d_error[0]=(0-y)/8;
u_d_error[1]=(y+8)/8;
u_d_error[2]=0;
}
else if(y < -8)
{
u_d_error[0]=1;
u_d_error[1]=0;
u_d_error[2]=0;
}
d_errorneg = u_d_error[0];
d_errorzero = u_d_error[1];
d_errorpos = u_d_error[2];
}

void fuzzyfikasi()
{
fuzzyfikasi_error();
fuzzyfikasi_perubahan_error();
}

void rule() // basis aturan


{
for(i=0;i<=2;i++){
for(j=0;j<=2;j++){
if(u_error[i]<u_d_error[j]){
u[i][j]=u_error[i]; // menggunakan operator AND
}
else{
u[i][j]=u_d_error[j];
}
}
}
}

void defuzzyfikasi()
{
//menggunakan metode mamdani dan defuzzyfikasi meggunakan metode centroid of
area
pembilang
=(u[0][0]*a5*z1)+(u[0][1]*a4*z2)+(u[0][2]*a3*z2)+(u[1][0]*a4*z2)+(u[1][1]*a3*z2
)+(u[1][2]*a2*z2)+(u[2][0]*a3*z2)+(u[2][1]*a2*z2)+(u[2][2]*a1*z1);
penyebut
=(u[0][0]*z1)+(u[0][1]*z2)+(u[0][2]*z2)+(u[1][0]*z2)+(u[1][1]*z2)+(u[1][2]*z2)+(u
[2][0]*z2)+(u[2][1]*z2)+(u[2][2]*z1);
validasi=pembilang/penyebut; // perhitungan defuzzyfikasi dengan menggabungkan
seluruh nilai min yang sudah didapatkan
Serial.print("validasi= ");
Serial.println(validasi);
beda_pwm = validasi;
speed_left = nilai_awal-beda_pwm;
speed_right = nilai_awal+beda_pwm;
}

void kendali_motor(float pwm_ki,float pwm_ka)


{
if(pwm_ki>=0){ //motor kiri maju
analogWrite(pwm_kiri, pwm_ki);
digitalWrite(IN3, LOW);
digitalWrite(IN4, HIGH);
//IN3 = 0;
//IN4 = 1;
}
else if(pwm_ki<0){
analogWrite(pwm_kiri, -pwm_ki);
digitalWrite(IN3, HIGH);
digitalWrite(IN4, LOW);
//IN3 = 1;
//IN4 = 0;
}

if(pwm_ka>=0){ //motor kanan maju


analogWrite(pwm_kanan, pwm_ka);
digitalWrite(IN1, LOW);
digitalWrite(IN2, HIGH);
//IN1 = 0;
//IN2 = 1;
}
else if(pwm_ka<0) //motor kanan mundur
{
analogWrite(pwm_kanan, -pwm_ka);
digitalWrite(IN1, HIGH);
digitalWrite(IN2, LOW);
//IN1 = 1;
//IN2 = 0;
}
}

void display_fuzzyfikasi()
{
lcd.setCursor(0, 0);lcd.print("er=");
lcd.setCursor(3, 0);lcd.print(error);
lcd.setCursor(9, 0);lcd.print("d_er=");
lcd.setCursor(14, 0);lcd.print(d_error);
lcd.setCursor(0, 1);lcd.print("neg=");
lcd.setCursor(4, 1);lcd.print(errorneg);
lcd.setCursor(9, 1);lcd.print("neg=");
lcd.setCursor(14, 1);lcd.print(d_errorneg);
lcd.setCursor(0, 2);lcd.print("zer=");
lcd.setCursor(4, 2);lcd.print(errorzero);
lcd.setCursor(9, 2);lcd.print("zer=");
lcd.setCursor(14, 2);lcd.print(d_errorzero);
lcd.setCursor(0, 3);lcd.print("pos=");
lcd.setCursor(4, 3);lcd.print(errorpos);
lcd.setCursor(9, 3);lcd.print("pos=");
lcd.setCursor(14, 3);lcd.print(d_errorpos);
}

void display_rule()
{
lcd.setCursor(0, 0);lcd.print("er=");
lcd.setCursor(3, 0);lcd.print(error);
lcd.setCursor(9, 0);lcd.print("d_er=");
lcd.setCursor(14, 0);lcd.print(d_error);
lcd.setCursor(0, 1);lcd.print("1=");
lcd.setCursor(2, 1);lcd.print(u[0][0]);
lcd.setCursor(7, 1);lcd.print("2=");
lcd.setCursor(9, 1);lcd.print(u[0][1]);
lcd.setCursor(14, 1);lcd.print("3=");
lcd.setCursor(16, 1);lcd.print(u[0][2]);
lcd.setCursor(0, 2);lcd.print("4=");
lcd.setCursor(2, 2);lcd.print(u[1][0]);
lcd.setCursor(7, 2);lcd.print("5=");
lcd.setCursor(9, 2);lcd.print(u[1][1]);
lcd.setCursor(14, 2);lcd.print("6=");
lcd.setCursor(16, 2);lcd.print(u[1][2]);
lcd.setCursor(0, 3);lcd.print("7=");
lcd.setCursor(2, 3);lcd.print(u[2][0]);
lcd.setCursor(7, 3);lcd.print("8=");
lcd.setCursor(9, 3);lcd.print(u[2][1]);
lcd.setCursor(14, 3);lcd.print("9=");
lcd.setCursor(16, 3);lcd.print(u[2][2]);
}

void display_defuzzyfikasi()
{
lcd.setCursor(0, 0);lcd.print("er=");
lcd.setCursor(3, 0);lcd.print(error);
lcd.setCursor(9, 0);lcd.print("d_er=");
lcd.setCursor(14, 0);lcd.print(d_error);
lcd.setCursor(0, 1);lcd.print("Output =");
lcd.setCursor(15, 1);lcd.print(beda_pwm);
lcd.setCursor(0, 2);lcd.print("Speed_Right =");
lcd.setCursor(15, 2);lcd.print(speed_right);
lcd.setCursor(0, 3);lcd.print("Speed_Left =");
lcd.setCursor(15, 3);lcd.print(speed_left);
}
Pembahasan 1. Deklarasi Awal
//motor kanan
#define IN1 2
#define IN2 3
#define pwm_kanan 6

//motor kiri
#define IN3 4
#define IN4 7
#define pwm_kiri 5

//lcd
#include <LiquidCrystal.h>
LiquidCrystal lcd(13, 12, 11, 10, 9, 8);

//variabel global
int a,b,i,j,speed_left,speed_right,sensorA,sensorB;
float x, y, error, d_error;
float z1=60,z2=80,a1=-145.5556,a2=-80,a3=0;
float a4=80,a5=145.5556; //z = luas dan a = COA out;
float u_error[3],u_d_error[3],u[3][3], errorneg, errorzero, errorpos, d_errorneg,
d_errorzero,d_errorpos;
float nilai_awal,beda_pwm, validasi, pembilang, penyebut;
//variabel global

Di sini dapat terlihat bahwa terdapat deklarasi pin awal #define


untuk motor kanan dan kiri, selanjutnya adalah difinisi untuk include dan
pin-pin LCD. Dan yang terakhir adalah mendeklarasikan variable global
yang diperlukan. Pada program terlihat juga komentar z=luas dan a=COA
out, ini adalah penggunaan metode defuzzyfikasi yaitu Center of Area.

Pembahasan 2. Setup
void setup() {
lcd.begin(20, 4);
Serial.begin(9600);
pinMode(IN1, OUTPUT);
pinMode(IN2, OUTPUT);
pinMode(IN3, OUTPUT);
pinMode(IN4, OUTPUT);
pinMode(pwm_kanan, OUTPUT);
pinMode(pwm_kiri, OUTPUT);
pinMode(16, INPUT_PULLUP);
pinMode(17, INPUT_PULLUP);
pinMode(18, INPUT_PULLUP);
}

Di setup ini diatur penggunaan input dan output serta inisialisasi


awal komponen seperti LCD dan Serial monitor.
Pembahasan 3. Main Program
void loop() {
nilai_awal = 100;
baca_sensor(); //membaca nilai error dan d_error
fuzzyfikasi();
rule();
defuzzyfikasi();
kendali_motor(speed_left,speed_right);
int tombol_fuzzyfikasi = digitalRead(16);
int tombol_rule = digitalRead(17);
int tombol_defuzzyfikasi = digitalRead(18);
if(tombol_fuzzyfikasi==0 && tombol_rule==1 && tombol_defuzzyfikasi==1)
{
display_fuzzyfikasi();
} //menampilkan data proses fuzzyfikasi
if(tombol_fuzzyfikasi==1 && tombol_rule==0 && tombol_defuzzyfikasi==1)
{
display_rule();
} //nenampilkan implikasi setiap rule
if(tombol_fuzzyfikasi==1 && tombol_rule==1 && tombol_defuzzyfikasi==0)
{
display_defuzzyfikasi();
}//menampilkan output tegas dan nilai kecepatan motor kiri dan kanan
if(tombol_fuzzyfikasi==1 && tombol_rule==1 && tombol_defuzzyfikasi==1)
{
lcd.clear();
}//clear tampilan LCD
}

Pada main program, program akan lilakukan berulang-ulang


sehingga pembuatan program bertuliskan void loop(){}; di sini mula-mula
akan memberikan nilai_awal=100; kemudian setelah itu program secara
berurutan akan melaksanakan sub program baca_sensor(); fuzzyfikasi();
rule(); defuzzyfikasi(); dan kendali_motor();
Setelah melakukan sub program tadi secara berurutan maka program
akan mendeklarasikan variable tombol_fuzzyfikasi, tombol_rule dan
tombol_defuzzyfikasi dengan variable int dan langsung diisikan dengan
pembacaan pin Digital 16, 17 dan 18.
Jika pembacaan nilai pin digital selesai maka akan masuk ke
decision, di sini ada 4 decision yaitu :
1) Jika tombol_fuzzyfikasi bernilai 0, tombol_rule bernilai 1
dan tombol_defuzzyfikasi bernilai 1. Maka akan menjalankan
sub program display_fuzzyfikasi();
2) Jika tombol_fuzzyfikasi bernilai 1, tombol_rule bernilai 0
dan tombol_defuzzyfikasi bernilai 1. Maka akan menjalankan
sub program display_rule();
3) Jika tombol_fuzzyfikasi bernilai 1, tombol_rule bernilai 1
dan tombol_defuzzyfikasi bernilai 0. Maka akan menjalankan
sub program display_defuzzyfikasi();
4) Jika tombol_fuzzyfikasi bernilai 1, tombol_rule bernilai 1
dan tombol_defuzzyfikasi bernilai 1. Maka akan menjalankan
perintah lcd.clear(); yang berguna untuk membersihkan
tampilan lcd.

Pembahasan 4. Sub Program baca_sensor()


void baca_sensor()
{
sensorA = analogRead(A0);
sensorB = analogRead(A1);
a = map(sensorA, 0, 1023, 0, 255); //maping error
b = map(sensorB, 0, 1023, 0, 255); //maping d_error
if(a>=241) {error=8;}
else if(a>=227) {error=7;}
else if(a>=213) {error=6;}
else if(a>=199) {error=5;}
else if(a>=185) {error=4;}
else if(a>=171) {error=3;}
else if(a>=157) {error=2;}
else if(a>=143) {error=1;}
else if(a>=129) {error=0;}
else if(a>=115) {error=-1;}
else if(a>=101) {error=-2;}
else if(a>=87) {error=-3;}
else if(a>=73) {error=-4;}
else if(a>=59) {error=-5;}
else if(a>=45) {error=-6;}
else if(a>=31) {error=-7;}
else if((a<31)&&(a>=0)) {error=-8;}

if(b>=248) {d_error=16;}
else if(b>=241) {d_error=15;}
else if(b>=234) {d_error=14;}
else if(b>=227) {d_error=13;}
else if(b>=220) {d_error=12;}
else if(b>=213) {d_error=11;}
else if(b>=206) {d_error=10;}
else if(b>=199) {d_error=9;}
else if(b>=192) {d_error=8;}
else if(b>=185) {d_error=7;}
else if(b>=178) {d_error=6;}
else if(b>=171) {d_error=5;}
else if(b>=164) {d_error=4;}
else if(b>=157) {d_error=3;}
else if(b>=150) {d_error=2;}
else if(b>=143) {d_error=1;}
else if(b>=136) {d_error=0;}
else if(b>=129) {d_error=-1;}
else if(b>=122) {d_error=-2;}
else if(b>=115) {d_error=-3;}
else if(b>=108) {d_error=-4;}
else if(b>=101) {d_error=-5;}
else if(b>= 94) {d_error=-6;}
else if(b>= 87) {d_error=-7;}
else if(b>= 80) {d_error=-8;}
else if(b>= 73) {d_error=-9;}
else if(b>= 66) {d_error=-10;}
else if(b>= 59) {d_error=-11;}
else if(b>= 52) {d_error=-12;}
else if(b>= 45) {d_error=-13;}
else if(b>= 38) {d_error=-14;}
else if(b>= 31) {d_error=-15;}
else if((b<31)&&(b>= 0)) {d_error=-16;}
}

Yang dimaksud sensor di sini adalah potensio maka dari itu dalam
sub program ini merupakan pemetaan nilai potensio dari 0-1023 dipetakan
ke nilai 0-255 lalu dipetakan kembali secara manual kedalam range -8 s/d
8 untuk error dan -16 s/d 16 untuk d_error.

Pembahasan 5. Sub Program fuzzyfikasi_error()


void fuzzyfikasi_error()
{
x = error;
//u_error[0] = Negatif 1
//u_error[1] = Zero 1
//u_error[2] = Positif 1
if(x >= 5)
{
u_error[0]=0;
u_error[1]=0;
u_error[2]=1;
}
else if(x >= 0)
{
u_error[0]=0;
u_error[1]=(5-x)/5;
u_error[2]=(x-0)/5;
}
else if(x >= -5)
{
u_error[0]=(0-x)/5;
u_error[1]=(x+5)/5;
u_error[2]=0;
}
else if(x < -5)
{
u_error[0]=1;
u_error[1]=0;
u_error[2]=0;
}
errorneg = u_error[0];
errorzero = u_error[1];
errorpos = u_error[2];
}

Dalam program fuzzyfikasi error ini didasarkan pada x=error


(pembacaan sensor/potensio error) dan membership fungtion variable error
yang terlihat pada gambar di bawah

Grafik diatas bisa didapatkan dari melihat syarat decision program


terdapat 3 angka yang menjadi syarat yaitu -5, 0 dan 5. Program decision
yang memberi syarat x>=5 serta syarat x<-5 langsung memberi nilai
ErrorPos=1 untuk x>=5 dan ErrorNeg=1 untuk x<-5 karena terlihat pada
grafik bahwa pada nilai tersebut hanya 1 garis yang memiliki nilai dan itu
bernilai 1.
Untuk syarat x>=0 ErrorNeg sudah jelas bernilai 0, dan nilai dari
ErrorZero dapat dicari dengan rumus (c-x)/(c-b) {5 merupakan titik c,
dengan a=-5, b=0 dan c=5), maka pada program dapat dituliskan (5-x)/5.
Sedangkan untuk mencari ErrorPos dapat dicari dengan rumus (b-x)/(b-c),
maka dalam program dapat dituliskan (x-0)/5, karena (b-x) negatif dan (b-
c) juga negatif maka negatif bisa dihilangkan.
Untuk syarat x>=-5 ErrorPos sudah jelas bernilai 0, dan nilai dari
ErrorZero dapat dicari dengan rumus (b-x)/(b-a) {5 merupakan titik c,
dengan a=-5, b=0 dan c=5), maka pada program dapat dituliskan (0-x)/5.
Sedangkan untuk mencari ErrorNeg dapat dicari dengan rumus (a-x)/(a-b),
maka dalam program dapat dituliskan (x+5)/5, karena (a-x) negatif dan (a-
b) juga negatif maka negatif bisa dihilangkan.
Pembahasan 6. Sub Program fuzzyfikasi_perubahan_error()
void fuzzyfikasi_perubahan_error()
{
y = d_error;
// u_d_error[0]=Negatif 2
// u_d_error[1]=Zero 2,
//u_d_error[2]=Positif 2
if(y >= 8)
{
u_d_error[0]=0;
u_d_error[1]=0;
u_d_error[2]=1;
}
else if(y >= 0)
{
u_d_error[0]=0;
u_d_error[1]=(8-y)/8;
u_d_error[2]=(y-0)/8;
}
else if(y >= -8)
{
u_d_error[0]=(0-y)/8;
u_d_error[1]=(y+8)/8;
u_d_error[2]=0;
}
else if(y < -8)
{
u_d_error[0]=1;
u_d_error[1]=0;
u_d_error[2]=0;
}
d_errorneg = u_d_error[0];
d_errorzero = u_d_error[1];
d_errorpos = u_d_error[2];
}

Proses yang dilakukan pada fuzzyfikasi perubahan error ini mirip


atau mungkin bisa dibilang sama dengan fuzzyfikasi error, hanya saja
perubahan error=y dan range grafik mambership fungtionnya berubah
yaitu menjadi seperti pada gambar dibawah
Dari grafik mambership fungtion di atas dapat dilihat bahwa range
pada perubahan error adalah -8, 0 dan 8 yang berarti memiliki nilai a=-8,
b=0 dan c=8. Maka pada program decision yang memberi syarat y>=8
serta syarat y<-8 langsung memberi nilai ErrorPos=1 untuk y>=8 dan
ErrorNeg=1 untuk y<-8.
Untuk mencari nilai syarat y>=0 ErrorNeg sudah jelas bernilai 0, dan
nilai dari ErrorZero dapat dicari dengan rumus (c-y)/(c-b) {8 merupakan
titik c, dengan a=-8, b=0 dan c=8), maka pada program dapat dituliskan
(8-y)/8. Sedangkan untuk mencari ErrorPos dapat dicari dengan rumus (b-
y)/(b-c), maka dalam program dapat dituliskan (y-0)/8, karena (b-y)
negatif dan (b-c) juga negatif maka negatif bisa dihilangkan.
Untuk syarat y>=-8 ErrorPos sudah jelas bernilai 0, dan nilai dari
ErrorZero dapat dicari dengan rumus (b-y)/(b-a) {8 merupakan titik c,
dengan a=-8, b=0 dan c=8), maka pada program dapat dituliskan (0-y)/8.
Sedangkan untuk mencari ErrorNeg dapat dicari dengan rumus (a-y)/(a-b),
maka dalam program dapat dituliskan (y+8)/5, karena (a-y) negatif dan (a-
b) juga negatif maka negatif bisa dihilangkan.

Pembahasan 7. Sub Program fuzzyfikasi ()


void fuzzyfikasi()
{
fuzzyfikasi_error();
fuzzyfikasi_perubahan_error();
}

Sub program ini hanya akan menjalankan sub program


fuzzyfikasi_error(); dan fuzzyfikasi_perubahan_error(); secara berurutan
saja.

Pembahasan 8. Sub Program rule ()


void rule() // basis aturan
{
for(i=0;i<=2;i++){
for(j=0;j<=2;j++){
if(u_error[i]<u_d_error[j]){
u[i][j]=u_error[i]; // menggunakan operator AND
}
else{
u[i][j]=u_d_error[j];
}
}
}
}
Di sini terlihat penggunaan 2 buah for, ini berguna untuk mengakses
matriks u dengan deklarasi u[i][j]. Di sini terdapat program yang
bertuliskan u[i][j]=u_error[i]; dan u[i][j]=u_d_error[i]; ini adalah perintah
perkalian matriks, pada arduino untuk mengalikan matriks hanya perlu
menuliskan seperti apa yang ada pada program di atas. Matriks ini
dikalikan karena dalam rule menggunakan operator AND.
Pada program, decision yang diberikan adalah jika error lebih kecil
dari perubahan error maka pengali yang digunakan adalah error sedangkan
untuk error lebih besar atau sama dengan perubahan error maka
menggunakan pengali perubahan error. Karena matriks u merupakan
matriks 3x3 (dapat dilihat di deklarasi awal) maka jumlah rule yang
dihasilkan ada 9 buah rule. Lebih jelas dibahas dibawah.

Pembahasan 9. Sub Program defuzzyfikasi ()


void defuzzyfikasi()
{
//menggunakan metode mamdani dan defuzzyfikasi meggunakan metode centroid
of area
pembilang
=(u[0][0]*a5*z1)+(u[0][1]*a4*z2)+(u[0][2]*a3*z2)+(u[1][0]*a4*z2)+(u[1][1]*a
3*z2)+(u[1][2]*a2*z2)+(u[2][0]*a3*z2)+(u[2][1]*a2*z2)+(u[2][2]*a1*z1);
penyebut
=(u[0][0]*z1)+(u[0][1]*z2)+(u[0][2]*z2)+(u[1][0]*z2)+(u[1][1]*z2)+(u[1][2]*z2
)+(u[2][0]*z2)+(u[2][1]*z2)+(u[2][2]*z1);
validasi=pembilang/penyebut; // perhitungan defuzzyfikasi dengan
menggabungkan seluruh nilai min yang sudah didapatkan
Serial.print("validasi= ");
Serial.println(validasi);
beda_pwm = validasi;
speed_left = nilai_awal-beda_pwm;
speed_right = nilai_awal+beda_pwm;
}

Menggunakan metode mamdani dan defuzzyfikasi menggunakan


Centroid of Area, oleh karena itu terdapat variable z1 dan z2 serta a1
sampai a5 ini digunakan untuk perhitungan titik tengah tiap anggota /
membership fungtionnya. Lebih jelas dibahas dibawah.

Pembahasan 10. Sub Program kendali_motor ()


void kendali_motor(float pwm_ki,float pwm_ka)
{
if(pwm_ki>=0){ //motor kiri maju
analogWrite(pwm_kiri, pwm_ki);
digitalWrite(IN3, LOW);
digitalWrite(IN4, HIGH);
//IN3 = 0;
//IN4 = 1;
}
else if(pwm_ki<0){
analogWrite(pwm_kiri, -pwm_ki);
digitalWrite(IN3, HIGH);
digitalWrite(IN4, LOW);
//IN3 = 1;
//IN4 = 0;
}

if(pwm_ka>=0){ //motor kanan maju


analogWrite(pwm_kanan, pwm_ka);
digitalWrite(IN1, LOW);
digitalWrite(IN2, HIGH);
//IN1 = 0;
//IN2 = 1;
}
else if(pwm_ka<0) //motor kanan mundur
{
analogWrite(pwm_kanan, -pwm_ka);
digitalWrite(IN1, HIGH);
digitalWrite(IN2, LOW);
//IN1 = 1;
//IN2 = 0;
}
}

Kendali motor pada program ini memerlukan 2 variable baru yaitu


pwm_ki dan pwm_ka dalam tipe data float yang nantinya akan diisikan
dengan speed kiri dan kanan dengan penyebutan program
kendali_motor(speed_left,speed_right); speed ini didapatkan dari proses
defuzzyfiksai. Di sini akan ada beberapa decision untuk menentukan
tindakan sesuai syarat yaitu:
1) Speed kiri / pwm_ki >=0 maka motor kiri akan bergerak
maju oleh karena itu IN3=0 dan IN4=1, dan mengisikan
pwm_kiri dengan speed kiri / pwm_ki agar kecepatan sesuai
program (analogWrite(pwm_kiri, pwm_ki); pwm_ki sudah di
replace dengan speed_left).
2) Speed kiri / pwm_ki <0 maka motor kiri akan bergerak
mundur oleh karena itu IN3=1 dan IN4=0, dan mengisikan
pwm_kiri dengan -speed kiri / -pwm_ki agar kecepatan
sesuai program dan memiliki arah terbalik
(analogWrite(pwm_kiri, -pwm_ki); pwm_ki sudah di replace
dengan speed_left).
3) Speed kanan / pwm_ka >=0 maka motor kanan akan
bergerak maju oleh karena itu IN1=0 dan IN2=1, dan
mengisikan pwm_kanan dengan speed kanan / pwm_ka agar
kecepatan sesuai program (analogWrite(pwm_kanan,
pwm_ka); pwm_ka sudah di replace dengan speed_right).
4) Speed kanan / pwm_ka <0 maka motor kanan akan bergerak
mundur oleh karena itu IN1=1 dan IN2=0, dan mengisikan
pwm_kanan dengan -speed kanan / -pwm_ka agar kecepatan
sesuai program dan memiliki arah terbalik
(analogWrite(pwm_kanan, -pwm_ka); pwm_ka sudah di
replace dengan speed_right).

Pembahasan 11. Sub Program Display


void display_fuzzyfikasi()
{
lcd.setCursor(0, 0);lcd.print("er=");
lcd.setCursor(3, 0);lcd.print(error);
lcd.setCursor(9, 0);lcd.print("d_er=");
lcd.setCursor(14, 0);lcd.print(d_error);
lcd.setCursor(0, 1);lcd.print("neg=");
lcd.setCursor(4, 1);lcd.print(errorneg);
lcd.setCursor(9, 1);lcd.print("neg=");
lcd.setCursor(14, 1);lcd.print(d_errorneg);
lcd.setCursor(0, 2);lcd.print("zer=");
lcd.setCursor(4, 2);lcd.print(errorzero);
lcd.setCursor(9, 2);lcd.print("zer=");
lcd.setCursor(14, 2);lcd.print(d_errorzero);
lcd.setCursor(0, 3);lcd.print("pos=");
lcd.setCursor(4, 3);lcd.print(errorpos);
lcd.setCursor(9, 3);lcd.print("pos=");
lcd.setCursor(14, 3);lcd.print(d_errorpos);
}

void display_rule()
{
lcd.setCursor(0, 0);lcd.print("er=");
lcd.setCursor(3, 0);lcd.print(error);
lcd.setCursor(9, 0);lcd.print("d_er=");
lcd.setCursor(14, 0);lcd.print(d_error);
lcd.setCursor(0, 1);lcd.print("1=");
lcd.setCursor(2, 1);lcd.print(u[0][0]);
lcd.setCursor(7, 1);lcd.print("2=");
lcd.setCursor(9, 1);lcd.print(u[0][1]);
lcd.setCursor(14, 1);lcd.print("3=");
lcd.setCursor(16, 1);lcd.print(u[0][2]);
lcd.setCursor(0, 2);lcd.print("4=");
lcd.setCursor(2, 2);lcd.print(u[1][0]);
lcd.setCursor(7, 2);lcd.print("5=");
lcd.setCursor(9, 2);lcd.print(u[1][1]);
lcd.setCursor(14, 2);lcd.print("6=");
lcd.setCursor(16, 2);lcd.print(u[1][2]);
lcd.setCursor(0, 3);lcd.print("7=");
lcd.setCursor(2, 3);lcd.print(u[2][0]);
lcd.setCursor(7, 3);lcd.print("8=");
lcd.setCursor(9, 3);lcd.print(u[2][1]);
lcd.setCursor(14, 3);lcd.print("9=");
lcd.setCursor(16, 3);lcd.print(u[2][2]);
}

void display_defuzzyfikasi()
{
lcd.setCursor(0, 0);lcd.print("er=");
lcd.setCursor(3, 0);lcd.print(error);
lcd.setCursor(9, 0);lcd.print("d_er=");
lcd.setCursor(14, 0);lcd.print(d_error);
lcd.setCursor(0, 1);lcd.print("Output =");
lcd.setCursor(15, 1);lcd.print(beda_pwm);
lcd.setCursor(0, 2);lcd.print("Speed_Right =");
lcd.setCursor(15, 2);lcd.print(speed_right);
lcd.setCursor(0, 3);lcd.print("Speed_Left =");
lcd.setCursor(15, 3);lcd.print(speed_left);
}

Program untuk menampilkan tulisan pada LCD, adapun yang


ditampilkan adalah nilai error, d_error, bagian negatif, zero dan positif,
rule, output dan kecepatan motor.

C. Data Hasil
Tabel 1. Hasil Percobaan Variable Error
error negatif zero positif
-8 1 0 0
-7 1 0 0
-6 1 0 0
-5 1 0 0
-4 0,8 0,2 0
-3 0,6 0,4 0
-2 0,4 0,6 0
-1 0,2 0,8 0
0 0 1 0
1 0 0,8 0,2
2 0 0,6 0,4
3 0 0,4 0,6
4 0 0,2 0,8
5 0 0 1
6 0 0 1
7 0 0 1
8 0 0 1
Tabel 2. Hasil Percobaan Variable D_Error
d_error negatif zero positif d_error negatif zero positif
-16 1 0 0 0 0 1 0
-15 1 0 0 1 0 0,88 0,12
-14 1 0 0 2 0 0,75 0,25
-13 1 0 0 3 0 0,63 0,37
-12 1 0 0 4 0 0,5 0,5
-11 1 0 0 5 0 0,37 0,63
-10 1 0 0 6 0 0,25 0,75
-9 1 0 0 7 0 0,12 0,88
-8 1 0 0 8 0 0 1
-7 0,88 0,12 0 9 0 0 1
-6 0,75 0,25 0 10 0 0 1
-5 0,63 0,37 0 11 0 0 1
-4 0,5 0,5 0 12 0 0 1
-3 0,37 0,63 0 13 0 0 1
-2 0,25 0,75 0 14 0 0 1
-1 0,12 0,88 0 15 0 0 1
0 0 1 0 16 0 0 1

Tabel 3. Hasil Percobaan Rule dan Output


Error : 5 D_error_negatif D_error_zero D_error_positif
D error : 7 0 0,12 0,88
Error _Negatif Rule 1 Rule 2 Rule 3
0 0 0 0
Error _Zero Rule 4 Rule 5 Rule 6
0 0 0 0
Error _Positif Rule 7 Rule 8 Rule 9
1 0 0,12 0,88
-------------------
Output Fuzzy -135
Speed Motor Kanan -35
Speed Motor Kiri 235

Error : 3 D_error_negatif D_error_zero D_error_positif


D error : 7 0 0,12 0,88
Error _Negatif Rule 1 Rule 2 Rule 3
0 0 0 0
Error _Zero Rule 4 Rule 5 Rule 6
0,4 0 0,12 0,4
Error _Positif Rule 7 Rule 8 Rule 9
0,6 0 0,12 0,6
-------------------
Output Fuzzy -97,7
Speed Motor Kanan 2
Speed Motor Kiri 197

Error : 1 D_error_negatif D_error_zero D_error_positif


D error : 5 0 0,37 0,63
Error _Negatif Rule 1 Rule 2 Rule 3
0 0 0 0
Error _Zero Rule 4 Rule 5 Rule 6
0,8 0 0,37 0,63
Error _Positif Rule 7 Rule 8 Rule 9
0,2 0 0,2 0,2
-------------------
Output Fuzzy -65
Speed Motor Kanan 34
Speed Motor Kiri 165

Error : -2 D_error_negatif D_error_zero D_error_positif


D error : 3 0 0,63 0,37
Error _Negatif Rule 1 Rule 2 Rule 3
0,4 0 0,6 0,37
Error _Zero Rule 4 Rule 5 Rule 6
0,6 0 0,4 0,37
Error _Positif Rule 7 Rule 8 Rule 9
0 0 0 0
-------------------
Output Fuzzy 1,14
Speed Motor Kanan 101
Speed Motor Kiri 98

Error : -2 D_error_negatif D_error_zero D_error_positif


D error : -4 0,5 0,5 0
Error _Negatif Rule 1 Rule 2 Rule 3
0,4 0,4 0,4 0
Error _Zero Rule 4 Rule 5 Rule 6
0,6 0,5 0,5 0
Error _Positif Rule 7 Rule 8 Rule 9
0 0 0 0
-------------------
Output Fuzzy 68,04
Speed Motor Kanan 168
Speed Motor Kiri 31
Error : -5 D_error_negatif D_error_zero D_error_positif
D error : -9 1 0 0
Error _Negatif Rule 1 Rule 2 Rule 3
1 1 0 0
Error _Zero Rule 4 Rule 5 Rule 6
0 0 0 0
Error _Positif Rule 7 Rule 8 Rule 9
0 0 0 0
-------------------
Output Fuzzy 145,5
Speed Motor Kanan 245
Speed Motor Kiri -45

Error : 6 D_error_negatif D_error_zero D_error_positif


D error : 15 0 0 1
Error _Negatif Rule 1 Rule 2 Rule 3
0 0 0 0
Error _Zero Rule 4 Rule 5 Rule 6
0 0 0 0
Error _Positif Rule 7 Rule 8 Rule 9
1 0 0 1
-------------------
Output Fuzzy -145
Speed Motor Kanan -45
Speed Motor Kiri 245

Error : 2 D_error_negatif D_error_zero D_error_positif


D error : 6 0 0,25 0,75
Error _Negatif Rule 1 Rule 2 Rule 3
0 0 0 0
Error _Zero Rule 4 Rule 5 Rule 6
0,6 0 0,25 0,6
Error _Positif Rule 7 Rule 8 Rule 9
0,4 0 0,25 0,4
-------------------
Output Fuzzy -79,7
Speed Motor Kanan 20
Speed Motor Kiri 179
Error : 0 D_error_negatif D_error_zero D_error_positif
D error : 4 0 0,5 0,5
Error _Negatif Rule 1 Rule 2 Rule 3
0 0 0 0
Error _Zero Rule 4 Rule 5 Rule 6
1 0 0,5 0,5
Error _Positif Rule 7 Rule 8 Rule 9
0 0 0 0
-------------------
Output Fuzzy -40
Speed Motor Kanan 60
Speed Motor Kiri 140

Error : -2 D_error_negatif D_error_zero D_error_positif


D error : -1 0,12 0,8 0
Error _Negatif Rule 1 Rule 2 Rule 3
0,4 0,12 0,4 0
Error _Zero Rule 4 Rule 5 Rule 6
0,6 0,12 0,6 0
Error _Positif Rule 7 Rule 8 Rule 9
0 0 0 0
-------------------
Output Fuzzy 45,66
Speed Motor Kanan 145
Speed Motor Kiri 54

Error : -2 D_error_negatif D_error_zero D_error_positif


D error : -5 0,63 0,37 0
Error _Negatif Rule 1 Rule 2 Rule 3
0,4 0,4 0,37 0
Error _Zero Rule 4 Rule 5 Rule 6
0,6 0,6 0,37 0
Error _Positif Rule 7 Rule 8 Rule 9
0 0 0 0
-------------------
Output Fuzzy 73,74
Speed Motor Kanan 73
Speed Motor Kiri 26
D. Pembahasan
1. Spesifikasi Fuzzy
a) Input
Pada unit fuzzy logic control kali ini kita menggunakan 2
varable Input yaitu Error dan D_Error, pada hardware
digunaka 2 buah potensiometer (x dan y).
b) Output
Untuk mendapat output maka kita perlu mengubah besaran
fuzzy ke bentuk bentuk tegasnya (crisp) kembali. Hal ini
diperlukan sebab dalam aplikasi nyata yang dibutuhkan
adalah nilai tegas (crisp). Prosesnya adalah sebagai berikut:
suatu nilai fuzzy output yang berasal dari rule evaluation
diambil kemudian dimasukkan ke dalam suatu membership
function output.
Output yang dihasilkan pada modul yang digunakan adalah nilai
perubahan kecepatan motor DC dengan nilai awal 100. Di sini
terdapat 5 linguistik value seperti pada gambar dibawah

Nilai titik pada grafikdi atas didapatkan dari deklarasi z dan a


yang memungkinkan untuk menghitung titik yang ada. Pada
program output disimpan dalam variable beda_pwm; yang bisa
didapatkan dari nilai validasi. Untuk pembahasan defuzzyfikasi
dapat dilihat di point e.
c) MF
Membership function untuk tiap input dan output adalah:
- ErrorNeg, ErrorZero dan ErrorPos untuk input x
- ErrorNeg, ErrorZero dan ErrorPos untuk input y
- Pada program variable ini disimpan pada u_error[i]
untuk input Error dan u_d_error[i] untuk input D_Error
dengan i=0,1,2; i=0 ErrorNeg / DerrorNeg, i=1
ErrorZero / DerrorZero, i=2 ErrorPos / DerrorPos
d) Rule
Dari perbandingan Membership Function kedua input maka
kita bisa mendapatkan posisi nilai linguistik value dari output
sebagai berikut
D_Error→
DerrorNeg DerrorZero DerrorPos
Error↓
Positive
Positive Big Zero
ErrorNeg Small
(R1) (R3)
(R2)
Positive Small Zero Negative
ErrorZero
(R4) (R5) Small (R6)
Negative
Zero Negative Big
ErrorPos Small
(R7) (R9)
(R8)

Berdasarkan tabel di atas maka dapat dirimuskan tiap- tiap


rule sebagai berikut
Jika error (ErrorNeg) dan perubahan error (DerrorNeg)
1
maka perubahan kecepatan akan (Positive Big).
Jika error (ErrorNeg) dan perubahan error (DerrorZero)
2
maka perubahan kecepatan akan (Positive Small).
Jika error (ErrorNeg) dan perubahan error (DerrorPos)
3
maka perubahan kecepatan akan (Zero).
Jika error (ErrorZero) dan perubahan error (DerrorNeg)
4
maka perubahan kecepatan akan (Positive Small).
Jika error (ErrorZero) dan perubahan error (DerrorZero)
5
maka perubahan kecepatan akan (Zero).
Jika error (ErrorZero) dan perubahan error (DerrorPos)
6
maka perubahan kecepatan akan (Negative Small).
Jika error (ErrorPos) dan perubahan error (DerrorNeg)
7
maka perubahan kecepatan akan (Zero).
Jika error (ErrorPos) dan perubahan error (DerrorZero)
8
maka perubahan kecepatan akan (Negative Small).
Jika error (ErrorPos) dan perubahan error (DerrorPos)
9
maka perubahan kecepatan akan (Negative Big).

Saat error atau perubahan error negatif maka menambah


kecepatan / Positive, ini sudah terbukti di hasil percobaan,
pembahasan lebih lanjut dibawah.
Karena menggunakan metode mamdani maka rule
menggunakan operator AND maka μA ∩ μB = min (μA[x],
μB[y]).

e) Defuzzyfikasi
Input dari proses defuzzifikasi adalah suatu himpunan
fuzzy yang diperoleh dari komposisi aturan-aturan fuzzy.
Metode defuzzyfikasi yang digunakan adalah metode
centroid atau juga dikenal dengan Center of Area (COA).
Pada metode ini, solusi crisp diperoleh dengan cara
mengambil titik pusat daerah fuzzy. Output yang dihasilkan
akan digunakan sebagai variable penentu perubahan
kecepatan motor.
Seperti yang tertulis di atas tadi, output memiliki 5 buah
linguistik variable, setelah diketahui nilai titik dari grafik
output maka dicari luas daerah dan titik tengah masing-
masing anggota. Untuk menghitung Luas daerah anggota
Negative Small, Zero dan Positive Small digunakan rumus
luas segitiga karena ketiganya berbentuk segitiga.

Contoh untuk NegativeSmall maka bisa dihitung titik


tengahnya adalah -80 dan pada program ini dideklarasikan
dengan float a2=-80;
Luas daerahnya jika dihitung dengan rumus luas segitiga
maka L=((axt)/2)=((160x1)/2)=80
Untuk 2 segitiga lain memiliki nilai luas yang sama dan
titik tengah yang sudah tertulis di program.
Untuk NegativeBig dan PositiveBig kita hanya perlu
mengganti dari mencari luas segitiga menjadi luas trapesium
saja. Sedangkan untuk mencari titik tengah anggota Negative
Big dan Positive Big menggunakan rumus (nilai titik terjauh
dari Negative Big atau Positive Big - COA Negative Small
atau Positive Small / 2) setelah itu hasilnya ditambahkan ke
nilai COA Negative Small atau Positive Small.
Dengan keterangan lebih lengkap

Kemudian untuk mendapatkan nilai output dilakukan


perhitungan

Keterangan
rule : hasil fungsi implikasi dari kedua input
coa : titik tengah anggota
luas : luas daerah anggota
n : jumlah rule yang dipakai
i : data ke-n

2. Analisis Data Hasil


Dari data percobaan Tabel 1. Dapat diketahui bahwa perhitungan
nilai errorneg, errorzero dan errorpos benar seperti pada teori.
Karena dari percobaan didapatkan nilai yang tidak melebihi 1 serta
saat nilai x melebihi 5 atau kurang dari -5 maka nilai errorpos atau
errorneg akan bernilai 1 dan jika bukan maka memiliki 2 nilai
kecuali saat posisi nol. Hal ini berlaku juga untuk percobaan Tabel 2.
Karena hanya berbeda range saja.
Untuk percobaan Tabel 3. Bisa diketahui bahwa nilai output
hanya akan mendapat nilai positif saat errornya dan derrornya
cenderung negatif, itu bertujuan untuk menghilangkan error yang
ada. Nilai kecepatan yang dihasilkan oleh motor kiri dan kanan dapat
dihitung dengan rumus
▪ Nilai kecepatan motor kanan = nilai awal - perubahan kecepatan
▪ Nilai kecepatan motor kiri = nilai awal + perubahan kecepatan
Tetapi tidak semua kecepatan yang dihasilkan sesuai, itu
dikarenakan tipe data untuk kecepatan merupakan tipe data integer
sedangkan tipe data untuk output merupakan float, maka pada proses
penjumlahan atau pengurangan akan mengabaikan nilai setelah tanda
koma.

E. Kesimpulan
Dari percobaan yang telah dilakukan dapat disimulkan bahwa,
penggunaan fuzzy logic sebagai unit controller merupakan keputusan yang
baik, dikarenakan jika kita bisa merancang sistem fuzzy yang baik maka
data yang didapatkan akan cenderung presisi. Selain itu dari praktikum ini
dapat kita lihat bahwa:
1. Hasil antara perhitungan dan percobaan relatif cocok
2. Penggunaan metode yang baik sehingga mendapatkan hasil yang
relatif presisi
3. Mudah untuk dipahami
4. Dapat dibayangkan variable yang digunakan dengan melihat
program yang ada

You might also like