Membuat Robot Line Follower Sederhana

Membuat Robot Line Follower Sederhana

A.    Mekanika

   
   

Bagian utama badan robot terbuat dari plat alumunium. Untuk gearbox dan motor menggunakan bagian dari mainan tamiya. Dan bagian badan lainnya adalah PCB dan bahan acrilic.

Pada bagian roda menggunakan gearbox dari tamiya. Gearbox ini berguna untuk menaikan torsi dari motor yang mempunyai torsi lemah.

 B.     Elektronika

1.      Sensor

Untuk rangkaian elektronika sensor menggunakan 8 sensor proximity dengan output tegangan analog yang kemudian akan dijadikan input oleh mikrokontroler sebagai input untuk PORT ADC. Rangkaian proximity sendiri sederhananya terdiri dari bagian transmitter (dalam hal ini LED) dan receiver (dalam hal ini phototransistor). Cara kerjanya, ketika LED menyala, maka akan memantul di permukaan arena yang berwarna putih dan garis hitam. Respon terhadap warna putih, pantulan cahaya akan sempurna. Sedangkan terhadap warna hitam pantulan intensitas cahaya berkurang. Hal itu akan mempengaruhi aktivasi dari phototransistor yang mempunyai prinsip kerja sebagai saklar sederhana, jika ada cahaya maka tersambung, jika tidak ada cahaya maka tidak tersambung.

Dari rangkaian di atas, jika mengenai warna putih maka output tegangan akan lebih kecil daripada output tegangan sensor-mengenai warna hitam yang memberikan pantulan dengan intensitas cahaya rendah.

      Rangkaian lainnya yang mempunyai prinsip sebagai sensor adalah rangkaian push button yang kelak berguna untuk melakukan setting pada robot.

 

      Terdapat empat buah push button yang masing-masing berguna sebagai tombol enter, cancel, arah_plus, dan arah_minus. Cara kerjanya adalah pada keadaan awalnya titik pb1..4 diberi tegangan high atau 5V oleh mikrokontroller dan keadaan tersebut dibaca juga oleh mikrokontroler. Sehingga data pada keadaan tersebut terbaca logic 1 oleh mikrokontroller. Jika tombol ditekan, maka otomatis jalur pb1..4 akan terhubung dengan ground. Sehingga otomatis tegangan di jalur tersebut menjadi 0V dan oleh mikrokontroller akan terbaca sebagai logic 0. Begitulah mikrokontroler membedakan kondisi tombol tidak ditekan dan ditekan.

2.      Prosesor

Rangkaian prosesor disini menggunakan sistem minimum dari ATMega32. Berikut schematicnya.

Dalam mikrokontroller inilah algoritma program akan dimasukan. Mengolah data dari input sensor sehingga menghasilkan output ke aktuator.

3.      Aktuator

Aktuator disini adalah motor DC. Untuk menggerakan motor DC diperlukan sebuah rangkaian motor driver yang biasa disebut H-bridge. Rangkaian ini berguna untuk mengontrol motor yang mempunyai tegangan operasi yang lebih besar.

 
   

Dalam rangkaian ini kita gunakan H-bridge dalam kemasan IC yaitu L298. Berikut rangkaian untuk L298.

Disini yang termasuk aktuator juga adalah speaker yang berguna sebagai indikator dari push button.

4.      Regulator Voltase

Rangkaian ini berguna untuk menurunkan tegangan batere yang dibutuhkan untuk mikrokontroler dan rangkaian sensor. Dikarenakan tegangan batere lebih dari 5V, sedangkan tegangan yang dibutuhkan mikrokontroler dan sensor 5V. Dalam hal ini digunakan regulator LM2576 yang mempunyai kapasitas arus 3A.

Berikut keseluruhan dari rangkaian elektronika.

 C.    Algoritma & Pemrograman

Terdapat 2 bagian, bagian setting dan run. bagaian setting berguna untuk mengatur beberapa konstanta tuning dan bagian run adalah bagian fungsi utama robot yaitu mengikuti garis.  Pada program yang dibuat setiap tombol diberi indikator nada dengan menggunakan library wangready_tone_lib untuk avr gcc.

Algoritma kontrol yang digunakan yaitu PID. Sensor yang dibaca dikonversi kedalam angka-angka yang akan menjadi input PID. Di PID data diolah sehingga mempunyai output berupa PWM (pulse width modulation) yang akan mengatur kecepatan motor sebagai responnya terhadap garis. Berikut persamaan PID dalam bentuk matematis.

Kp: Proportional gain, a tuning parameter

Ki: Integral gain, a tuning parameter

Kd: Derivative gain, a tuning parameter

e: Error = SPPV

t: Time or instantaneous time (the present)

Berikut pseudo code dari persamaan di atas.

previous_error = setpoint - process_feedback
integral = 0
start:
  wait(dt)
  error = setpoint - process_feedback
  integral = integral + (error*dt)
  derivative = (error - previous_error)/dt
  output = (Kp*error) + (Ki*integral) + (Kd*derivative)
  previous_error = error
  goto start

Berikut block diagram sistem kontrol yang saya gunakan dengan mengadopsi dari persamaan di atas dengan menghilangkan nilai feedback sehingga nilai error ditiadakan.

Berikut kode utama yang saya buat dengan menggunakan WinAVR+AVR Studio 4 dengan bahasa C.

#include
#include
#include
#include "lcd_lib.h"
#include 	//untuk sprintf
#include  //untuk rand
#include
#include "wangready_tone_lib.h"

#define ADC_VREF_TYPE 0x40

// Read the AD conversion result
unsigned int read_adc(unsigned char adc_input)
{
ADMUX=adc_input | (ADC_VREF_TYPE & 0xff);
// Delay needed for the stabilization of the ADC input voltage
_delay_us(10);
// Start the AD conversion
ADCSRA|=0x40;
// Wait for the AD conversion to complete
while ((ADCSRA & 0x10)==0);
ADCSRA|=0x10;
return ADCW;
}

#define RPWM OCR1A
#define LPWM OCR1B

uint8_t buff[33];

void nada_enter()
{
	nada_c1(32);
	nada_f1(32);
	nada_a1(8);
}

void nada_cancel()
{
	nada_a1(32);
	nada_f1(32);
	nada_c1(8);
}

void nada_plus()
{
	nada_c1(8);
}

void nada_minus()
{
	nada_g1(8);
}

void music()
{
//8d1 8- 8d1 8- 16g1 16- 16g1 16- 16#f1 16- 8d1 8- 8d1 8- 8d1 8d1
	nada_d1(8);
	jeda(8);
	nada_d1(8);
	jeda(8);
	nada_g1(16);
	jeda(16);
	nada_g1(16);
	jeda(16);
	nada_f1_kres(16);
	jeda(16);
	nada_d1(8);
	jeda(8);
	nada_d1(8);
	jeda(8);
	nada_d1(8);
	nada_d1(8);
}

unsigned char get_button(unsigned char select)
{
	switch(select)
	{
		case 1:	if((PINB&0b00001000)==0)
				{
					nada_enter();
					return(1); 	//OK
				}
				else return(0);
				break;
		case 2:	if((PINB&0b00000100)==0)
				{
					nada_plus();
					return(1);	// +
				}
				else return(0);
				break;
		case 3:	if((PINB&0b00000010)==0)
				{
					nada_minus();
					return(1);	// -
				}
				else return(0);
				break;
		case 4:	if((PINB&0b00000001)==0)
				{
					nada_cancel();
					return(1);	//cancel
				}
				else return(0);
				break;
	}
}

// additional custom LCD characters
const uint8_t panah_kanan[8] PROGMEM=
{
0b00000000,//back slash
0b00011000,
0b00011110,
0b00011111,
0b00011110,
0b00011000,
0b00000000,
0b00000000
};

const uint8_t panah_kiri[8] PROGMEM=
{
0b00000000,//back slash
0b00000011,
0b00001111,
0b00011111,
0b00001111,
0b00000011,
0b00000000,
0b00000000
};

const uint8_t blank[8] PROGMEM=
{
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000
};

float EEMEM var_Kp;
float EEMEM var_Ki;
float EEMEM var_Kd;
unsigned int EEMEM var_Ts ;
unsigned char EEMEM var_max_speed;

float Kp;
float Ki;
float Kd;
unsigned int Ts;
unsigned char max_speed;

#define pnh_kiri_char 1
#define pnh_kanan_char 2

void init_char()
{
	LCDdefinechar(blank,0);
	LCDdefinechar(panah_kiri,1);
	LCDdefinechar(panah_kanan,2);
}

void disp_max_speed()
{
	LCDclr();//clears LCD

   	LCDGotoXY(0,0);
	LCDsendChar(pnh_kiri_char);
   	LCDGotoXY(15,0);
	LCDsendChar(pnh_kanan_char);

	LCDGotoXY(0,1);
	LCDsendChar('-');
   	LCDGotoXY(15,1);
	LCDsendChar('+');

	LCDGotoXY(2,0);
	sprintf(buff,"Set Maxspeed");
   	LCDstring(buff,12);

	_delay_ms(300);

	if(get_button(1) == 1)//jika OK
	{
		while(get_button(4)==0)
		{
			if(get_button(2)==1)max_speed += 5; 	//+
			if(get_button(3)==1)max_speed -= 5;	//-		

			LCDclr();//clears LCD
			LCDGotoXY(1,1);
			sprintf(buff,"Max Speed=%d", max_speed);
    		LCDstring(buff,13);

			_delay_ms(1);
		}
		eeprom_write_byte(&var_max_speed,max_speed);
	}
}

void disp_Kp()
{
	LCDclr();//clears LCD

	LCDGotoXY(15,0);
	LCDsendChar(pnh_kanan_char);

	LCDGotoXY(0,1);
	LCDsendChar('-');
   	LCDGotoXY(15,1);
	LCDsendChar('+');

	LCDGotoXY(4,0);
	sprintf(buff,"Set Kp");
   	LCDstring(buff,6);

	_delay_ms(300);

	if(get_button(1) == 1)//jika OK
	{
		while(get_button(4)==0)
		{
			if(get_button(2)==1)Kp += 1; 	//+
			if(get_button(3)==1)Kp -= 1;	//-		

			LCDclr();//clears LCD
			LCDGotoXY(4,1);
			sprintf(buff,"Kp=%2.2f", Kp);
    		LCDstring(buff,8);

			_delay_ms(1);
		}
		eeprom_write_float(&var_Kp,Kp);
	}
}

void disp_Ki()
{
	LCDclr();//clears LCD

   	LCDGotoXY(0,0);
	LCDsendChar(pnh_kiri_char);
   	LCDGotoXY(15,0);
	LCDsendChar(pnh_kanan_char);

	LCDGotoXY(0,1);
	LCDsendChar('-');
   	LCDGotoXY(15,1);
	LCDsendChar('+');

	LCDGotoXY(4,0);
	sprintf(buff,"Set Ki");
   	LCDstring(buff,6);

	_delay_ms(300);

	if(get_button(1) == 1)//jika OK
	{
		while(get_button(4)==0)
		{
			if(get_button(2)==1)Ki += 0.1; 	//+
			if(get_button(3)==1)Ki -= 0.1;	//-	

			LCDclr();//clears LCD
			LCDGotoXY(4,1);
			sprintf(buff,"Ki=%2.2f", Ki);
   			LCDstring(buff,8);

			_delay_ms(1);
		}
		eeprom_write_float(&var_Ki,Ki);
	}
}

void disp_Kd()
{
	LCDclr();//clears LCD

   	LCDGotoXY(0,0);
	LCDsendChar(pnh_kiri_char);
   	LCDGotoXY(15,0);
	LCDsendChar(pnh_kanan_char);

	LCDGotoXY(0,1);
	LCDsendChar('-');
   	LCDGotoXY(15,1);
	LCDsendChar('+');

	LCDGotoXY(4,0);
	sprintf(buff,"Set Kd");
   	LCDstring(buff,6);

	_delay_ms(300);

	if(get_button(1) == 1)//jika OK
	{
		while(get_button(4)==0)
		{
			if(get_button(2)==1)Kd += 0.1; 	//+
			if(get_button(3)==1)Kd -= 0.1;	//-	

			LCDclr();//clears LCD
			LCDGotoXY(4,1);
			sprintf(buff,"Kd=%2.2f", Kd);
   			LCDstring(buff,8);

			_delay_ms(1);
		}
		eeprom_write_float(&var_Kd,Kd);
	}
}

void disp_Ts()
{
	LCDclr();//clears LCD

   	LCDGotoXY(0,0);
	LCDsendChar(pnh_kiri_char);
   	LCDGotoXY(15,0);
	LCDsendChar(pnh_kanan_char);

	LCDGotoXY(0,1);
	LCDsendChar('-');
   	LCDGotoXY(15,1);
	LCDsendChar('+');

	LCDGotoXY(4,0);
	sprintf(buff,"Set Ts");
   	LCDstring(buff,6);

	_delay_ms(300);

	if(get_button(1) == 1)//jika OK
	{
		while(get_button(4)==0)
		{
			if(get_button(2)==1)Ts++; 	//+
			if(get_button(3)==1)Ts--;	//-			

			LCDclr();//clears LCD
			LCDGotoXY(4,1);
			sprintf(buff,"Ts=%ums", Ts);
   			LCDstring(buff,8);

			_delay_ms(1);
		}
		eeprom_write_word((void *)&var_Ts,Ts);
	}
}

unsigned int sens[8];
unsigned int treshold = 200;
unsigned char warna_garis;

unsigned int EEMEM var_sens[8];
unsigned char EEMEM var_warna_garis;

unsigned int compare_var_uint_high(unsigned int A, unsigned int B)
{
	if(A>=B)return(A);
	else if(B>A)return(B);
}

unsigned int compare_var_uint_low(unsigned int A, unsigned int B)
{
	if(A sens[urut])return(1);
		else return(0);
	}
	else if(warna_garis == 1)//putih adc kecil
	{
		if(read_adc(urut) < sens[urut])return(1);
		else return(0);
	}
}

void cek_sensor()
{
unsigned char i,buff_sens;

	LCDclr();//clears LCD

	LCDGotoXY(0,0);
	LCDsendChar(pnh_kiri_char);
   	LCDGotoXY(15,0);
	LCDsendChar(pnh_kanan_char);

	LCDGotoXY(0,1);
	LCDsendChar('-');
   	LCDGotoXY(15,1);
	LCDsendChar('+');

	LCDGotoXY(2,0);
	sprintf(buff,"Cek Sensor");
   	LCDstring(buff,10);	

	_delay_ms(300);

	if(get_button(1) == 1)//jika OK
	{
		while(get_button(4)==0)
		{
			LCDclr();
			for(i=0;i 0))count_menu--;

			switch(count_menu)
			{
				case 0:	disp_Kp();
					break;
				case 1:	disp_Ki();
					break;
				case 2:	disp_Kd();
					break;
				case 3:	disp_Ts();
					break;
				case 4:	disp_max_speed();
					break;
				case 5:	auto_calibrate();
					break;
				case 6:	tipe_garis();
					break;
				case 7:	cek_sensor();
					break;
				case 8: LCDclr();//clears LCD

						LCDGotoXY(0,0);
						LCDsendChar(pnh_kiri_char);\

						LCDGotoXY(0,1);
						LCDsendChar('-');
   						LCDGotoXY(15,1);
						LCDsendChar('+');

						LCDGotoXY(4,0);
						sprintf(buff,"Start");
   						LCDstring(buff,5);	

						if(get_button(1) == 1)goto akhir;

						_delay_ms(300);

					break;
			}
		}
}
}

void init_var()
{
unsigned char i;

	max_speed 	= eeprom_read_byte(&var_max_speed);
	Kp 			= eeprom_read_float(&var_Kp);
	Ki 			= eeprom_read_float(&var_Ki);
	Kd 			= eeprom_read_float(&var_Kd);
	Ts 			= eeprom_read_word(&var_Ts);
	for(i=0;i max_speed)speed_kanan = max_speed;
		else if	(speed_kanan < (-(max_speed)))speed_kanan = (-(max_speed)); 		if		(speed_kiri > max_speed)speed_kiri = max_speed;
		else if	(speed_kiri < (-(max_speed)))(-(max_speed));			 		if(speed_kanan>=0)
		{
			RPWM = (unsigned char)speed_kanan;
			PORTD = 0b00000000;
		}
		else
		{
			PORTD = 0b00001000;
			RPWM = 255 + (unsigned char)speed_kanan;
		}

		if(speed_kiri>=0)
		{
			LPWM = (unsigned char)speed_kiri;
			PORTD += 0b00000000;
		}
		else
		{
			PORTD += 0b00000100;
			LPWM = 255 + (unsigned char)speed_kiri;
		}

		//LCDGotoXY(0,0);
		//sprintf(buff,"%d=%d",(unsigned char)speed_kiri,(unsigned char)speed_kanan);
   		//LCDstring(buff,16);
	}

	RPWM = 0;
	LPWM = 0;
}

int main(void)
{

PORTB 	= 0xFF;
DDRD 	= 0xFF;

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

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

// ADC initialization
// ADC Clock frequency: 1000.000 kHz
// ADC Voltage Reference: AVCC pin
ADMUX=ADC_VREF_TYPE & 0xff;
ADCSRA=0x84;

tone_wr_init();
LCDinit();//init LCD bit, dual line, cursor right
LCDcursorOFF();
init_char();
init_var();

	while(1)
	{
		menu();
		PID();
	}
return 0;
}

Daftar Pustaka

http://en.wikipedia.org/wiki/PID_controller

http://insansainsprojects.wordpress.com/2008/06/05/h-bridge-driver-kontrol-arah-motor/

http://www.societyofrobots.com/mechanics_gears.shtml

Line Tracker Robot using AVR Microcontroller Created by Hendawan Soebhakti on Desember 2007

https://wangready.wordpress.com

_____________________________

File Download

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