Kendali Motor Servo Menggunakan PWM dari Timer

motor servo adalah sebuah aktuator yang bergerak dalam poros yang mempunyai spesifikasi untuk control posisi sudut yang presisi. Banyak jenis motor servo. Ada yang dikontrol secara serial ataupun dengan PWM. Kali ini kita akan mencoba megatur posisi dari sebuah motor servo dengan menggunakan PWM yang dibangkitkan dari timer1. PWM harus diatur agar memenuhi standar sinyal input untuk motor servo sehingga motor servo dapat bergerak sesuai dengan perintah yang kita kirimkan lewat PWM.

Review motor servo.       servo_1 servo_2

Nilai input PWM pada setiap servo terkadang berbeda sesuai merek. Misalnya saja Servo Futaba tipe Futaba S3003 – Standard Servo.

0.388ms = 0 degree.

1.264ms = 90 degrees. (neutral position)

2.14ms = 180 degrees.

Akan tetapi kita coba dengan setting pada proteus seperti berikut.

servo_3

Mari kita mulai.Buat sebuah folder untuk project yang akan kita buat. Semua file project akan disimpan di folder ini. Buat folder dengan nama motor servo.

Pertama buat new project, lalu masukan chip ATMega8535, ambil dari library.

servo_4

servo_5

masukan juga komponen motor servo

servo_6

Lalu rangkai seperti gambar sirkuit di bawah ini.

servo_7

Untuk komponen VCC dan Ground bisa di drag dari Terminals mode.

servo_8

Sekarang kita beralih ke codevisionAVR. Buat new project. Klik File, lalu New.

servo_9

Kemudian pilih Project, lalu klik OK.

servo_10

Jika muncul pertanyaan seperti di bawah ini. Klik Yes.

servo_11

Setelah itu kita lakukan pengaturan untuk project yang akan kita buat. Pertama setting chip yang akan digunakan. Kita gunakan ATmega8535 dan nilai clock yaitu 16 MHz. (dalam pemrograman, tanda titik berarti koma, untuk memisahkan bilangan decimal. Missal 3,7 maka diketik 3.7 dan begitu pula jika kita memasukan nilai clock 11,059200MHz maka diketik 11.059200 MHz.

Lalu kita lakukan setting pada bagian Timer1. Kita akan gunakan Timer1 ini untuk membangkitkan sinyal PWM yang digunakan untuk mengontrol motor servo. Lakukan setting di bawah ini.

servo_12

kita akan menggunakan mode

// Timer/Counter 1 initialization

// Clock source: System Clock

// Clock value: 250.000 kHz

// Mode: Fast PWM top=ICR1

// 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

Dari informasi diatas kita dapati bahwa counter akan berjalan dalam interval waktu T=1/250kHz yaitu 4us, dan akan menggunaka mode Fast PWM. Dengan nilai TOP counter yaitu ICR1 1387 atau 4999. Hal ini dikarenakan kita membutuhkan sinya PWM dengan lebar perioda 20ms atau frekuensi 50Hz untuk mengendalikan servo. Berikut perhitungannya.

servo_13

servo_14

Sedangkan nilai lebar pulsa high dari PWM atau lebar dutty cycle positif akan ditentukan oleh register OCR1.

servo_15

Dutty cycle: perbandingan lebar perioda HIGH dengan lebar perioda gelombang.

perhitungan OCR1 untuk menghasilkan lebar pulsa dari 1ms – 2ms (sesuai settingan servo di simulasi proteus) adalah.

OCR1A= (((sudut + 90)/90)*1000)/4;

Dimana nilai 1ms – 2ms tersebut akan menghasilkan nilai sudut dari -900 sampai 900. Perhitungan di atas didapat berdasarkan bahwa couter berjalan dalam interval 250kHz atau 4us  sehingga untuk menghasilkan gelombang 1ms – 2ms adalah.

Atau jika kita menggunakan MS-Exel untuk mendapat persamaannya maka setelah membuat table dari data sumbu x untuk sudut x={-90,90} dan y untuk OCR1A={250,500} maka kita bisa mendapatkan persamaan linier dengan cara klik kanan pada garis yang ada di table dan klik Add Trendline.

servo_16

Lalu setting seperti berikut.

servo_17

Maka akan muncul persamaan.

servo_18

y = 1.388x + 375

dan kita ganti nilai x dan y sehingga menjadi.

OCR1A = (unsigned int)((1.388*(float)sudut) + 375);

Sekarang kita masukan ke program.

 /*****************************************************
Chip type               : ATmega8535
Program type            : Application
AVR Core Clock frequency: 16,000000 MHz
Memory model            : Small
External RAM size       : 0
Data Stack size         : 128
*****************************************************/

#include 
#include 

// Declare your global variables here
void set_servo(int sudut)
{
    unsigned int buff_sudut = (unsigned int)((1.388*(float)sudut) + 375);
    OCR1AH = (unsigned char)(((buff_sudut & (unsigned int)0xFF00))>>8); 
    OCR1AL = (unsigned char)  (buff_sudut & (unsigned int)0x00FF);
}

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: Timer 0 Stopped
// Mode: Normal top=0xFF
// OC0 output: Disconnected
TCCR0=0x00;
TCNT0=0x00;
OCR0=0x00;

// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: 250,000 kHz
// Mode: Fast PWM top=ICR1
// OC1A output: Non-Inv.
// OC1B output: Discon.
// 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=0x82;
TCCR1B=0x1B;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x13;
ICR1L=0x87;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;

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

// External Interrupt(s) initialization
// INT0: Off
// INT1: Off
// INT2: Off
MCUCR=0x00;
MCUCSR=0x00;

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

// USART initialization
// USART disabled
UCSRB=0x00;

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

// ADC initialization
// ADC disabled
ADCSRA=0x00;

// SPI initialization
// SPI disabled
SPCR=0x00;

// TWI initialization
// TWI disabled
TWCR=0x00;

while (1)
      {
      // Place your code here
        set_servo(-90);  
        delay_ms(1000);

        set_servo(0); 
        delay_ms(2000);
        
        set_servo(90); 
        delay_ms(1000);
      }
}

Lalu klik Make the project.

servo_19

servo_20

Klik OK, maka akan ter-generate file .hex. File inilah yang akan diupload ke dalam mikrokontroler.

Seperti biasa jangan lupa lakukan pengaturan di chip ATMEGA8535.

servo_21

Klik pada ikon folder Program File. Browse file .hex yang sudah kita generate tadi di codevisionAVR.

servo_22

Atur CKSEL Fuses menjadi Ext. Clock dan Clock Frequency dengan nilai clock 16MHz yang sudah kita atur juga pada codevisionAVR.

Klik OK.

Setelah proses setting selesai, maka langsung saja klik Play.

servo_23

Untuk melihat sinyal yang mengatur motor servo bisa kita tambahkan osiloskop pada rangkaian proteus yang sudah kita buat.

servo_24

Kita capture di jalur input servo.

servo_25

Maka bisa dilihat sinyal PWM-nya.

servo_26

49 Responses to Kendali Motor Servo Menggunakan PWM dari Timer

  1. joan says:

    gan, pils post juga cara kendali servo via uart dgn ngirim data posisi sudut maka servo akan bergerak sesuai posisi yg d input ?

    trimakasih (y)

  2. Prayogo says:

    gan,, rumus 64 (1+TOP) itu maksudnya apa?dapet darimana ya ?

  3. azaz says:

    gan gimana kalo ada 3 servo yang di kendalikan? ada tutorialnya ato website referensi
    trimakasih

  4. irvan says:

    gan ane masih newbee mau tanya
    apa itu cuma bisa lewat port oc1a aja ya?

    • wangready says:

      iya gan, setau ane atmega8535 cuma bisa port tsb, klo port timer yg lain gk cukup buat counter nya…kecuali bikin PWM manual…
      gk tau tp kalo atmega versi lain….

  5. minona says:

    untuk mencari OCR1A
    = (((sudut + 90)/90)*1000)/4

    misal dipakai sudut -90
    (-90 + 90)=0
    0/90*1000/4=0

    kok hasil nya 0 gan ?

  6. roy says:

    gan aku mau buat pintu otomatis pake servo ,,,,gimana supaya mutar 180 drajat gan ???

    • wangready says:

      buat pintu beneran mah harus pake servo gede gan, mending pake pneumatic….
      bukannya servo biasa jg bisa 180 derajat gan, tinggal kasih pwm aja…

  7. Cahyono Hadi says:

    pak, kalo ngontrol motor servo dengan serial itu gmn caranya?

    • wangready says:

      int derajat;
      while(1)
      {
      scanf(“servo=%d”,&derajat);
      servo(derajat);
      }
      jadi tinggal kirim aja lewat serial servo=nilai derajat nya, fungsi servonya ada di atas gan

  8. gan,kalo mau bikin sudutnya 30,60, sama 90 gimana ya?

  9. ian says:

    gan, kalau ngontrol sudut servo dengan pwm melalui interupt gimana caranya??

  10. 082320911955 says:

    gan bagaimana caranya kalau kita ingin menggerakkan 45 derajat kiri dan kanan ??

  11. 082320911955 says:

    sudah saya coba dan simulasikan di proteus gan , saya ubah nilainya di set_sevo -45 dan 45 tapi tetap aja gan di +90 dan -90, apa ada yg harus diubah di timer1nya atau di programnya saja gan,minta solusinya gan???

  12. arfai says:

    gan itu kenapa harus T=1/250KHz = 4?

  13. Nikko says:

    Itu kalau mau menggerakan dari 90 ke 0 ke -90 itu gmana gan?

    • wangready says:

      tinggal panggil aja fungsinya gan….
      set_servo(90); //set servo ke 90 derajat
      delay_ms(1000); //tahan posisi servo selama 1000ms
      set_servo(0); //set servo ke 0 derajat
      delay_ms(1000); //tahan posisi servo selama 1000ms
      set_servo(-90); //set servo ke -90 derajat
      delay_ms(1000); //tahan posisi servo selama 1000ms

  14. yudhie bacho says:

    saya udah buat seperti yang di atas,,, servonya ada bunyi sedikit,, tapi gak muter,, apa suplai powernya yang kurang ya gan,,,mohon dijawab,,, buat skripsi soalnya

  15. Teguh Bima says:

    bro kok punyaku ga bisa di set sudut ya misal di set sudut 30 tetep masuk sudut 90
    gimana ya?

  16. Numpang nanya saya, pake atmega2560 saya ikutin program diatas lalu coba compile muncul error OCR1A undefined symbol, solusinya gimana ya ? apa saya harus gunain OCR1AH ato OCR1AL untuk deklarasi rumus tersebut?

    • wangready says:

      kok error ya, kalo saya pake CVAVR versi 1.xx bisa sih gan… hmmm mungkin bisa coba pake ini:
      void set_servo(int sudut)
      {
      int ConvertOCR = (((sudut + 90)/90)*1000)/4;
      OCR1AL = convertOCR & 255;
      OCR1AH = convertOCR & ‭65280‬;
      }

  17. OCR1A = (unsigned int)((1.388*(float)sudut) + 375);
    gan itu nilai unsigned int diisi berapa?terus nilai float diisi berapa?
    dan nilai 1388, 375 itu didapat dari mana?

    mohon dijawab gan, buat tugas akhir soalnya

  18. angga says:

    Gan, saya coba langsung upload ke sismin tpi muternya gak sampe 90 derajat ya ?
    Terus syaa ganti gradiennya 1.388 jadi 2.5 jdi bisa 180 derajat, ini ada kemungkinan ngerusak gak ??

    • wangready says:

      bisa jd tiap merek nilai perbandingan perioda pwm nya berbeda gan. kalo yg di artikel ini sy hanya simulasi aja. untuk pwm servo merek lain mungkin bisa cari di datasheetnya. keknya gk ngerusak gan…

  19. yona says:

    gan, saya pakai atmega 328 waktu compile muncul undefined symbol OCR1A.
    kalau pakai rumus yang ini, sudut hasil servo tidak sesuai sudut di program dan maks sampai 90 derajat. mohon bantuannya
    void set_servo(int sudut)
    {
    int ConvertOCR = (((sudut + 90)/90)*1000)/4;
    OCR1AL = convertOCR & 255;
    OCR1AH = convertOCR & ‭65280‬;
    }

    • wangready says:

      Compilernya pake apa gan?? CodevisionAVR apa atmel studio?? Coba cek adrressing untuk OCR1A ada apa enggak di compilernya…
      Kalo untuk rumus disesuaikan aja sma spek dari servo…

      • yona says:

        pakai cvavr. anehnya kalau pake atmega 16 ndak error, begitu build baru pake atmega 328 langsung error undefined..
        saya blum paham yg ini
        OCR1AL = convertOCR & 255;
        OCR1AH = convertOCR & ‭65280‬;
        nilai 255 dan 65280 dari perhitungan apa udah dri sananya segitu gan?

      • wangready says:

        Maaf gan ternyata kodingan saya salah. Silahkan coba kodingan di atas. Sudah saya update. compiler saya CVAVR versi 2.
        berikut fungsi servonya:
        unsigned int buff_sudut = (unsigned int)((1.388*(float)sudut) + 375);
        OCR1AH = (unsigned char)(((buff_sudut & (unsigned int)0xFF00))>>8);
        OCR1AL = (unsigned char) (buff_sudut & (unsigned int)0x00FF);
        berdasarkan perhitungan, nilai OCR1A harus antara 250 decimal/0x00F4 hex (-90 derajat) dan 500 decimal/0x01FA hex (90 derajat). Akan tetapi, register OCR1A adalah 16 bit. maka register OCR1A bisa dipecah jadi OCR1AL (low bit) dan OCR1AH (high bit). kalo di atmega8535 kalau pun pake OCR1A (16 bit) langsung tidak error gan. misal saya isi OCR1A = 500;. tapi kalo di agan error, pake yang register OCR1AL dan OCR1AH aja. kalo pake OCR1AL dan OCR1AH urutan kode nya yang high bit dulu:
        OCR1AH = (unsigned char)(((buff_sudut & (unsigned int)0xFF00))>>8);
        OCR1AL = (unsigned char) (buff_sudut & (unsigned int)0x00FF);
        jangan dibalik jadi
        OCR1AL = (unsigned char) (buff_sudut & (unsigned int)0x00FF);
        OCR1AH = (unsigned char)(((buff_sudut & (unsigned int)0xFF00))>>8);
        karena setelah dicompile hasilnya pwmnya gk sesuai walaupun di compiler tidak error. mungkin ini terkait akses register yang tertimpa register sebelumnya.
        Jangan lupa, pastikan memakai nilai oscilator crystal yang sama dengan setingan kodingan di atas, yaitu 16MHz.

      • yona says:

        oke gan saya coba.. makasih infonya 👍👍

  20. royyan says:

    gan cara gerakin microservo dengan waktu yg telah saya tentukan menggunakan rtcds1307, menggunakan aplikasi codevision avr ,, gimana ya caranya , mohon bantuannya gan?

  21. ponijo says:

    masih kurang mengerti di bagian kode berikut :

    unsigned int buff_sudut = (unsigned int)((1.388*(float)sudut) + 375);
    OCR1AH = (unsigned char)(((buff_sudut & (unsigned int)0xFF00))>>8);
    OCR1AL = (unsigned char) (buff_sudut & (unsigned int)0x00FF);

  22. jay says:

    gan ini pake internal oscilator 4Mhz gabisa ya? walau disesuaikan sama nilai – nilai lain

Leave a comment