Sunday, April 03, 2011

Daftar Situs Penjualan spearpart Robotik

http://www.elektronik-kits.com
http://www.klinikrobot.com
http://www.delta-electronic.com
http://www.digi-ware.com
http://www.ok-elektronik.com
http://www.innovativeelectronics.com
http://www.dt-51.com
http://www.lynxmotion.com

Line Tracer dengan Sistem Kontrol PD (Proportional Derivative)

Line Tracer dengan Sistem Kontrol PD (Proportional Derivative)

Misalkan kita mempunyai susunan sensor, tampak atas, seperti berikut:

(4) ------ (3) - (2) -(1) ------ (0)

Dimana angka menunjukkan pin uC, katakanlah pada PORT C. Jadi kita menggunakan pin PORTC.0 untuk sensor paling kanan, PORTC.1 untuk sensor tengah kanan, dst hingga PORTC.4 untuk sensor paling kiri. Untuk mempermudah, saya biasanya menggunakan data mapping. Jadi kondisi sensor akan di mapping dengan data PWM motor. Katakanlah sensor line tracer itu aktif low, jadi pin uC akan membaca logika 0 saat mengenai garis. Oke, karena ada 5 sensor maka akan ada 2^5 = 32 kemungkinan kondisi sensor. Saya hanya akan membuat kedua robot bergerak maju, sehingga bisa di buat kontroler motor untuk bergerak satu arah saja. Saya akan membuat beberapa nilai sensor (dalam hexa) saja sebagai contoh, sisanya bisa diimpementasikan sendiri. Berikut tabelnya:
Nilai sensor PWM motor kiri PWM motor kanan
0×11 0xEF 0xFF
0×17 0xA0 0xFF
0×1D 0xEF 0×9F
0×0F 0×20 0xFF
0×1E 0xEF 0×2F
dst… dst… dst…

Saya mengimplementasikan PWM dengan menggunakan interrupt timer pada uC, dimana nilai 0xff adalah PWM full speed (100%) dan motor akan berhenti dengan nilai 0. Pada kasus saya, motor kanan dan kiri akan mempunyai nilai PWM yang berbeda untuk kecepatan aktual yang terlihat sama, jika dilihat pada tabel untuk membuat motor maju lurus nilai PWM kanan dan kiri berbeda 15 desimal. Jika merujuk ke sunsunan sensor, nilai 0×11 menunjukkan tiga sensor tengah mengenai garis, sehingga PWM motor diberi hampir full agar bergerak maju lurus. Kondisi 0×17 mengharuskan robot bergerak serong kiri dan kondisi 0×1E mengharuskan robot banting kanan. Dengan cara mapping nilai sensor dari PINC dengan data PWM kita sudah mengimplementasikan sistem kontrol proportional, dimana gain motor akan mempunyai proporsi sesuai nilai sensor yg diinput ke PINC. Untuk menulisnya dengan bahasa C, saya akan menggunakan array untuk menampung data PWM, berikut potongan programnya:

/**
* isikan data PWM motor kiri dan kanan
* sesuai dengan 32 kondisi sensor
*/
unsigned char PWMKiri[32] = { 0x00, 0x00, ... }
unsigned char PWMKanan[32] = { 0x00, 0x00, ... }
unsigned char state;

void scan() {
state = PINC & 0x1F; //baca PINC.0 - PINC.4
/**
* beri nilai PWM motor kiri dengan
* data PWMKiri dan PWMkanan
* dimana indexnya adalah kondisi sensor
*/
PWMKiriVal = PWMKiri[state];
PWMKananVal = PWMKanan[state];
}

Untuk menambahkan kontrol derivative, kita perlu menggunakan delta PWM. Kita perlu mencatat data PWM sebelumnya. Kita bisa mengubah fungsi scan menjadi:

//variabel untuk menampung nilai PWM sebelumnya
unsigned char last_state, d;

//jika dipanggil tanpa argumen, fungsi scan hanya sistem kontrol proportional
void scan(d = false) {
state = PINC & 0x1F;

//jika dipanggil dengan scan(1), aktifkan fungsi proportioal-derivative
if (d) {
PWMKiriVal = PWMKiri[state] + (PWMKiri[state] - PWMKiri[last_state]);
PWMKananVal = PWMKanan[state] + (PWMKanan[state] - PWMKanan[last_state]);
} else { //sistem proportional saja
/* beri nilai PWM motor kiri dan kanan
* dimana indexnya adalah kondisi sensor
*/
PWMKiriVal = PWMKiri[state];
PWMKananVal = PWMKanan[state];
}
last_state = state;
}

Sistem derivative di atas hanya gambaran bagaimana menerapkan sistem kontrol PD, dan agak redundant jika digunakan dalam robot sederhana dengan 5 sensor. Dalam mendesain sistem derivative perlu diperhatikan apakah penyimpangan error dalam kondisi sistem itu cukup signifikan untuk membuat sistem bergerak stabil jika ditambahkan ke dalam sistem kontrol. Jika masih bingung apa itu sistem PID, coba di googling. Sebagai pendahuluan coba baca artikel PID di Wikipedia.

Referensi :
http://gedex.web.id/archives/2008/04/10/line-tracer-dengan-sistem-kontrol-pd-proportional-derivative/

PWM dengan Interrupt Timer

PWM dengan Interrupt Timer

Ada beberapa teman (especially me2t) yang masih bingung bagaimana sebenarnya Interrupt Timer dapat digunakan sebagai PWM (Pulse Width Modulation). Sebelum menjelaskan lebih dalam mengenai Timer, saya akan mengulas balik tentang sumber pencacah (clock source) pada uC AVR. Sumber pencacah untuk AVR itu seperti detak jantung yang diperlukan untuk mengeksekusi instruksi. Pengeksekusian instruksi umumnya membutuhkan satu sampai tiga siklus pencacah (clock cycles). Satu siklus adalah transisi low-hi-low _|¯|_. Jadi semakin cepat pencacah berjalan (menghitung), maka semakin cepat uC bekerja. Jadi jelas uC AVR 16 MHz akan lebih cepat dari uC AVR 1 MHz. Tapi perlu diperhatikan, kecepatan pencacah tidak begitu berarti banyak. Satu prosesor dapat membutuhkan 1 siklus pencacah untuk memindahkan data dari satu register ke register lainnya, tapi prosesor lain dapat saja membutuhkan 2 sikus pencacah untuk melakukan hal yang sama. Hal ini berarti bahwa prosesor ke-2 harus memiliki kecepatan 2x lipat prosesor ke-1 untuk melakukan instruksi yang sama dalam waktu yang sama. Kuncinya disini adalah sebuah penilaian kasar yang disebut MIPS (Milion of Instructions Per Second), yang dapat digunakan untuk menilai secara kasar berapa instruksi yang dapat dilakukan uC dalam satu detik pada frekuensi pencacah tertentu. Jika pada lembar data (datasheet) tertulis “Up to 16 MIPS Throughput at 16 MHz”, kita bisa mengasumsikan secara kasar bahwa dengan pencacah 4 MHz, kita bisa mencapai 4 MIPS (4 juta instruksi per detiknya atau sekitar 1/4 uS untuk eksekusi 1 instruksi, CMIIW). Sebenarnya penjelasan untuk pencacah dapat lebih panjang, tapi sisanya saya serahkan kepada pembaca untuk mengubeknya di google dan datasheet terkait :).

Kembali ke Timer. Secara prinsip, sebuah timer adalah sebuah counter (penghitung). Tugas Timer hanya menghitung, dia selalu menyimpan hitungannya saat menghitung “satu, dua, tiga, …” hingga 255 (8 bit) atau bahkan bisa sampai 65535 (16 bit). Naiknya hitungan Timer dan berapa lama jeda antar hitungan ini ditentukan dari siklus pencacah uC (seperti saya jelaskan di atas), mode Timer dan settingan Timer. Kita bisa menggunakan Timer sebagai pemicu event. Misal kita bisa menset Timer agar menghitung sampai 255. Dan jika sudah 255 Timer (overflow) akan memberikan sinyal, dan kita bisa mengerjakan sesuatu dalam program (disinilah PWM bekerja) dan menyuruh Timer untuk menghitung lagi dari 0. Demikian seterusnya terjadi jika nilai 255 tercapai, dan Timer hanya akan berhenti jika kita memprogramnya untuk berhenti. Sebagai kemudahan saya akan langsung memberikannya contohnya dengan CodeVisionAVR, menggunakan Timer 0 mode normal yang menghitung sampai 255. Besarnya frekuensi PWM itu bisa Anda hitung secara kasar (tidak akurat) dengan rating MIPS chip. Anda bisa menggunakan CodeWizardAVR untuk menghasilkan kode siap pakai, tanpa perlu mengecek datasheet berapa register terkait Timer harus kita berikan nilai. OK, ini langkahnya:

1. Tentukan mode normal untuk Timer 0 dan check overflow interrupt


2. Generate, Save dan Exit. Maka kurang lebih kita mendapatkan deklarasi rutin Timer 0 overflow interrupt seperti berikut:

// Timer 0 overflow interrupt service routine
interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
// Place your code here
}

3. Nilai register terkait Timer 0 yang telah diset

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

4. Timer 0 diinisialisasi pada interrupt mask dan interrupt diaktifkan

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

// Global enable interrupts
#asm("sei")

Apakah Timer 0 sudah mulai menghitung? Ya belum lah. Kita harus menset register Timer Control 0 (TCCR0) agar Timer 0 mulai bekerja. Untuk menjalankan Timer 0 tanpa prescaler beri nilai 0×01 pada TCCR0.

TCCR0 = 0x01;

Nah loh?! Apalagi tuh prescaler? Lalu apa saja sih bit-bit pada TCCR0 dan TIMSK. Nah itu semua sudah sangat jelas di tulis dalam datasheet, silahkan buka datasheet chip terkait jika merasa bingung.

Kembali ke rutin overflow interrupt Timer 0 (pada langkah 2). Rutin tersebut akan dieksekusi jika Timer 0 sudah menghitung sampai TOP atau dalam hal ini 255 / 0xFF. Bagaimana kalau kita menginginkan Timer 0 memulai dari hmm.., katakanlah 100 / 0×64 dan bukan dari 0 ? Ingat bagaimana cara Timer 0 berhitung “satu, dua, tiga, …” ? Hitungan Timer 0 selalu disimpan dalam register TCNT0. Dengan mengakali jarak hitungan Timer, kita dapat memainkan frekuensi PWM. OK, contoh berikut akan mengubah bagaimana Timer 0 akan mulai menghitung dari 192 / 0xc0:

// Timer 0 overflow interrupt service routine
interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
TCNT0 = 0xC0;

}

...

TCNT0 = 0xC0;
OCR0 = 0x00;
TCCR0 = 0x01; //Timer 0 mulai bekerja tanpa prescaler
TIMSK = 0x01; //pantau Timer 0 overflow interrupt service routine

#asm("sei"); //aktifkan global interrupt

...

Nah sekarang bagaimana kita memanfaatkan mode 0 dari Timer 0 agar dapat bekerja sebagai PWM. Katakanlah kita mempunyai 2 pin enable ke motor kiri dan kanan. Kita buat sebuah penampung nilai PWM yang berperan sebagai duty cycle dari PWM. Anggaplah variabel duty cycle PWM ini mempunyai nilai 0 - 255 (unsigned char). Jika duty cycle-nya 100% maka nilai tersebut adalah 255. Dapatkan gambarannya? Full speed adalah 255, half-speed adalah 127 dan no-speed adalah 0. OK, kita tulis kodenya seperti berikut:

...

#define pwmKi PORTC.0
#define pwmKa PORTC.1
#define mKi_plus PORTC.2
#define mKi_min PORTC.3

#define mKa_plus PORTC.4
#define mKa_min PORTC.5

unsigned char pwmKi_val,pwmKa_val,x = 0;

interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{

TCNT0 = 0xC0;

x++;

if (x>=pwmKa_val) {
pwmKa=0;
} else {
pwmKa=1;
}
if (x>=pwmKi_val) {
pwmKi=0;
} else {
pwmKi=1;
}

}

...

Lalu untuk implementasi nya pada program utama bisa dilakukan dengan testing PWM motor.

...

pwmKi = 1;
pwmKa = 1;

mKi_plus = 1;
mKi_min = 0;
mKa_plus = 1;
mKa_min = 0;

while (1) {
pwmKa_val = 0xff;
pwmKi_val = 0x20;
delay_ms(1500);
pwmKa_val = 0x20;
pwmKi_val = 0xff;
delay_ms(1500);
};

...

Jika motor secara bergantian pelan dan cepat setiap 1.5 detik, maka tidak ada masalah dengan implementasi dengan Timer 0 mode 0 dengan overflow interrupt. Perlu diketahui, beberapa chip AVR menyediakan variasi Timer dan modenya. Akan sangat panjang jika ditulis di sini, untuk itu kawan-kawan bisa RTFD (Read The Fucking Datasheet) :p.

Referensi :

- Datasheet ATMega16 / ATmega8535
- http://www.avrfreaks.net/
- http://gedex.web.id/archives/2008/04/11/pwm-dengan-interrupt-timer/