Kontrol Posisi Motor DC Mengunakan Rotary Encoder Berbasis Mikrokontroler AVR

Secara umum prinsip kerja rotary encoder ini dapat diilustrasikan sebagai berikut.

Dua buah sensor optis (Channel A dan B) pendeteksi “hitam dan putih” digunakan acuan untuk menentukan arah gerakan. Searah jarum jam (clock-wise, CW) atau (counter clock-wise, CCW). Sedangkan jumlah pulsa (baik A atau B) dapat dihitung (menggunakan prinsip counter) sebagai banyak langkah yang ditempuh. Dengan demikian arah gerakan dan posisi dapat dideteksi.

Contoh rotary encoder.

Biasanya encoder ini dipasang segaris dengan poros (shaft) motor, gearbox, sendi datau bagian berputar lainnya. Beberapa tipe encoder memiliki poros berlubang (hollow shaft encoder) yang didesain untuk sistem sambungan langsung ke poros obyek yang dideteksi.

contoh aplikasi control posisi motor DC.

MY DESIGN

Berikut rancangan yang saya buat (bukan yg video di atas tentunya, hanya simulasi, soalnya gk ada modal buat bikin yg real-nya…hehe…curhat… :) tp secara simulasi berhasil…).

Fitur AVR yang dipakai:

  1. UART –> untuk komunikasi data posisi yang diinginkan
  2. Interupt 0 –> menghitung putaran dan arah motor
  3. Timer 0 –> mengontrol motor dengan PID

Berikut programnya menggunakan Codevision AVR.

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

#include <mega32.h>
#include <delay.h>   
#include <stdio.h>  
#include <math.h>

#define pwm OCR1A                   
/*
// Alphanumeric LCD Module functions
#asm
   .equ __lcd_port=0x1B ;PORTA
#endasm
#include <lcd.h>
*/
#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 Receiver buffer
#define RX_BUFFER_SIZE 8
char rx_buffer[RX_BUFFER_SIZE];

#if RX_BUFFER_SIZE<256
unsigned char rx_wr_index,rx_rd_index,rx_counter;
#else
unsigned int rx_wr_index,rx_rd_index,rx_counter;
#endif

// This flag is set on USART Receiver buffer overflow
bit rx_buffer_overflow;

// USART Receiver interrupt service routine
interrupt [USART_RXC] void usart_rx_isr(void)
{
char status,data;
status=UCSRA;
data=UDR;
if ((status & (FRAMING_ERROR | PARITY_ERROR | DATA_OVERRUN))==0)
   {
   rx_buffer[rx_wr_index]=data;
   if (++rx_wr_index == RX_BUFFER_SIZE) rx_wr_index=0;
   if (++rx_counter == RX_BUFFER_SIZE)
      {
      rx_counter=0;
      rx_buffer_overflow=1;
      };
   };
}

#ifndef _DEBUG_TERMINAL_IO_
// Get a character from the USART Receiver buffer
#define _ALTERNATE_GETCHAR_
#pragma used+
char getchar(void)
{
char data;
while (rx_counter==0);
data=rx_buffer[rx_rd_index];
if (++rx_rd_index == RX_BUFFER_SIZE) rx_rd_index=0;
#asm("cli")
--rx_counter;
#asm("sei")
return data;
}
#pragma used-
#endif

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

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

void m_ccw()  //set arah motor
{
        PORTC.0 = 0;
        PORTC.1 = 1;
}
int             encoder
                ,enc_target
                ,error
                ,Kp = 35
                ,Kd = 5
                ,P
                ,error_dif
                ,error_prev;  
unsigned char data_receive_buff;
// External Interrupt 0 service routine
interrupt [EXT_INT0] void ext_int0_isr(void)
{
// Place your code here
 if (PINB.2 == 0)
  // Increase enc
  encoder++;
 else
  // Decrease enc
  encoder--;    
}    

// Timer 0 overflow interrupt service routine
interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
// PID
        error = enc_target - encoder;
        error_dif = error - error_prev;
        error_prev = error;

        P = (Kp*error) + (Kd*error_dif);

        if(P>=0)m_cw();
        else m_ccw();

        if(P<0)
        {
                P*=(-1);
        }  
        if(P>255)P=255;

        pwm = (unsigned char)P;
}

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

//unsigned char kata[16];
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=Out Func3=In Func2=In Func1=In Func0=In
// State7=T State6=T State5=0 State4=0 State3=T State2=T State1=T State0=T
PORTD=0x00;
DDRD=0x30;

// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: 16000.000 kHz
// Mode: Normal top=FFh
// OC0 output: Disconnected
TCCR0=0x01;
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: Inverted
// OC1B output: Inverted
// 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=0xF1;
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: On
// USART Transmitter: On
// USART Mode: Asynchronous
// USART Baud rate: 57600
UCSRA=0x00;
UCSRB=0xD8;
UCSRC=0x86;
UBRRH=0x00;
UBRRL=0x10;

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

// LCD module initialization
//lcd_init(16);
motor_init();
// Global enable interrupts
#asm("sei")

while (1)
      {
      // Place your code here  
         /*    
         lcd_clear();       
         lcd_gotoxy(0,0);
         sprintf(kata,"%d",getchar());
         lcd_puts(kata); */

         data_receive_buff = getchar();
         enc_target += ((((int)data_receive_buff & 0b10000000)>>6)-1)*((int)data_receive_buff & 0b01111111);           
      };
}

_video hasil simulasi

tanpa kontrol lewat serial

motor

 /*****************************************************
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 <math.h>
#include <stdlib.h> //fungsi abs = nilai mutlak 
#include <stdio.h>

#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()    //inisialisasi port sebagai output
{
        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()  //set diam
{
        PORTC.0 = 1;
        PORTC.1 = 1;
}
//inisialisasi variabel
int             encoder
                ,enc_target
                ,error
                ,Kp = 25  //set konstanta Kp
                ,Kd = 23  //set konstanta Kd
                ,Ki = 0   //set konstanta Ki
                ,PID
                ,error_dif
                ,error_prev
                ,error_sum;  
unsigned char V_maks = 255; //set konstanta kecepatan maksimum pwm motor

// External Interrupt 0 service routine
interrupt [EXT_INT0] void ext_int0_isr(void)     //interupt aktif menyela proses dalam mikrokontroler
{
// Place your code here
        if (PIND.3 == 0)   //cek pulsa
                // Increase encoder/ arah putar cw
                encoder++;
        else
                // Decrease encoder/ arah putar ccw
                encoder--;
}

// Timer 0 overflow interrupt service routine
interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
// Place your code here
// PID
        error = enc_target - encoder;     //hitung error
        error_dif = error - error_prev;   //hitung delta error
        error_prev = error;               //masukan error ke error_prev, pada proses selanjutnya adalah error sebelumnya
        error_sum += error;               //akumulasikan error
        PID = (Kp*error) + (Kd*error_dif) + (Ki*error_sum);  //PID   

        printf("%.d|%.d|\n\r",(int)error,(int)error_dif);

        if(PID>0)m_cw();  //jika hasil PID positif maka arah motor cw
        else if(PID<0)m_ccw(); //jika hasil PID negatif maka arah motor ccw
        else stop(); //jika hasil PID 0 maka motor diam

        PID = abs(PID); //karena akan dimasukan sebagai ke dalam PWM, PID harus positif
        if(PID>V_maks)PID=V_maks; // batasi nilai PID dengan nilai V_maks

        pwm = (unsigned char)PID; //PID sudah siap dimasukan ke PWM
}

// 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);   //tunggu 10ms
enc_target = 270; //putar ke arah positif, 270 pulsa
delay_ms(3000);   //tunggu 3s
enc_target = 0;   //putar dari 270 ke 0

while (1)
      {
      // Place your code here

      };
}

jika ingin berada dalam looping, maka simpan dalam while(1)

______________________________

Daftar Pustaka

http://www.timmestein.nl/index.php?page=interface-a-rotary-encoder-with-atmel-avr-interrupt-style

Pitowarno, Endra.2006.”ROBOTIKA: Desain, Kontrol, dan Kecerdasan Buatan”. Percetakan Andi Offset. Yogyakarta. Indonesia

About these ads

54 Responses to Kontrol Posisi Motor DC Mengunakan Rotary Encoder Berbasis Mikrokontroler AVR

  1. agung says:

    bingung mas dengan listingnyam masih awam soalnya..
    channel A dan B maksdnya kabel outA dan B di ecoder ya mas, jadi dihubungkan ke port mana mas?
    kalo lisitng untuk menghitung RPM dengan encoder dan menampilkan ke lCD gmn ya mas?
    maaf ni banyak nanyanya.

    • wangready says:

      yang udah saya coba baru simulasinya, kalo yg real nya sya blm nyoba…kalo dalam algoritma saya, salah satu channel dimasukin ke port interrupt mikro dan satu lagi ke port IO biasa. program fungsi interrupt akan aktif ketika rising edge, sementara pin IO satunya akan memeriksa arah putar. untuk menghitung RPM intinya fungsi ini, tinggal tampilkan di LCD variabel encoder nya…
      // External Interrupt 0 service routine
      interrupt [EXT_INT0] void ext_int0_isr(void)
      {
      // Place your code here
      if (PINB.2 == 0)
      // Increase enc
      encoder++;
      else
      // Decrease enc
      encoder- -;
      }

  2. agung says:

    makasih nh mas atas penjelasannya..
    saya masih ada pertanyaann mas, sudah saya kirim ke email.
    tlg bantuannya
    terima kasih

  3. yui says:

    mas klw kontrol posisi bukan pakek rotari tp pakek potensio tapi itu gimana..?

    • wangready says:

      saya rasa konsepnya sama dengan encoder.
      potensionya dipasang diporos motor, terus baca pake ADC mikro, tinggal input referensi posisi yang diinginkannya mau pake serial, pin biasa atau pake potensio lagi…
      misal saya ingin buat input nya pake potensio, jika potensio input referensi saya putar maka motor akan mengikuti sampai potensio sensor feedback di motor bernilai sama. dan saya menggunakan atmega128 dengan clock 12MHz, pin arah motor di PORTC.0 dan PORTC.1, pwm di OCR0, potensio input masuk pin adc0 dan potensio sensor feedback motor di pin adc1, dan kontrol yang saya gunakan adalah PD (proporsional derivatif) maka kira2 programnya seperti berikut.

      /*****************************************************
      Chip type : ATmega128
      Program type : Application
      AVR Core Clock frequency: 12,000000 MHz
      Memory model : Small
      External RAM size : 0
      Data Stack size : 1024
      *****************************************************/
      #include <mega128.h>
      #include <delay.h>

      #define pwm OCR0

      #define ADC_VREF_TYPE 0x60

      // Read the 8 most significant bits
      // of the AD conversion result
      unsigned char 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 ADCH;
      }

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

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

      int potensio_terbaca
      ,potensio_target
      ,error
      ,Kp = 35 //misal
      ,Kd = 5 //misal
      ,P
      ,error_dif
      ,error_prev;
      T_ = 10; //misal
      void PID()
      {
      // PID
      potensio_target = read_adc(0);
      potensio_terbaca = read_adc(1);
      error = potensio_target – potensio_terbaca;
      error_dif = error – error_prev;
      error_prev = error;

      P = (Kp*error) + (Kd*error_dif);

      if(P>=0)m_cw();
      else m_ccw();

      if(P255)P=255;

      pwm = (unsigned char)P;
      delay_ms(T_); //waktu menunggu respon motor
      }

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

      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=0x10;

      // 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=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
      PORTD=0x00;
      DDRD=0x00;

      // Port E 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
      PORTE=0x00;
      DDRE=0x00;

      // Port F 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
      PORTF=0x00;
      DDRF=0x00;

      // Port G initialization
      // Func4=In Func3=In Func2=In Func1=In Func0=In
      // State4=T State3=T State2=T State1=T State0=T
      PORTG=0x00;
      DDRG=0x00;

      // Timer/Counter 0 initialization
      // Clock source: System Clock
      // Clock value: 11,719 kHz
      // Mode: Phase correct PWM top=0xFF
      // OC0 output: Non-Inverted PWM
      ASSR=0x00;
      TCCR0=0x67;
      TCNT0=0x00;
      OCR0=0x00;

      // Timer/Counter 1 initialization
      // Clock source: System Clock
      // Clock value: Timer1 Stopped
      // Mode: Normal top=0xFFFF
      // OC1A output: Discon.
      // OC1B output: Discon.
      // OC1C 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
      // Compare C Match Interrupt: Off
      TCCR1A=0x00;
      TCCR1B=0x00;
      TCNT1H=0x00;
      TCNT1L=0x00;
      ICR1H=0x00;
      ICR1L=0x00;
      OCR1AH=0x00;
      OCR1AL=0x00;
      OCR1BH=0x00;
      OCR1BL=0x00;
      OCR1CH=0x00;
      OCR1CL=0x00;

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

      // Timer/Counter 3 initialization
      // Clock source: System Clock
      // Clock value: Timer3 Stopped
      // Mode: Normal top=0xFFFF
      // OC3A output: Discon.
      // OC3B output: Discon.
      // OC3C output: Discon.
      // Noise Canceler: Off
      // Input Capture on Falling Edge
      // Timer3 Overflow Interrupt: Off
      // Input Capture Interrupt: Off
      // Compare A Match Interrupt: Off
      // Compare B Match Interrupt: Off
      // Compare C Match Interrupt: Off
      TCCR3A=0x00;
      TCCR3B=0x00;
      TCNT3H=0x00;
      TCNT3L=0x00;
      ICR3H=0x00;
      ICR3L=0x00;
      OCR3AH=0x00;
      OCR3AL=0x00;
      OCR3BH=0x00;
      OCR3BL=0x00;
      OCR3CH=0x00;
      OCR3CL=0x00;

      // External Interrupt(s) initialization
      // INT0: Off
      // INT1: Off
      // INT2: Off
      // INT3: Off
      // INT4: Off
      // INT5: Off
      // INT6: Off
      // INT7: Off
      EICRA=0x00;
      EICRB=0x00;
      EIMSK=0x00;

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

      ETIMSK=0x00;

      // USART0 initialization
      // USART0 disabled
      UCSR0B=0x00;

      // USART1 initialization
      // USART1 disabled
      UCSR1B=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: 750,000 kHz
      // ADC Voltage Reference: AVCC pin
      // Only the 8 most significant bits of
      // the AD conversion result are used
      ADMUX=ADC_VREF_TYPE & 0xff;
      ADCSRA=0x84;

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

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

      motor_init();
      while (1)
      {
      // Place your code here
      PID();
      }
      }

      dan untuk setting PID nya bisa liat di http://wangready.wordpress.com/2012/06/25/kendali-pid/, semoga membantu….

  4. triannurrul says:

    maaf mas, kl keluaran increment atau absolute yang ditampilkan ke lcd gmn programnya?? ini buat proyek akhir saya soalnya, sy pk atmega16. makasi mas..

    • wangready says:

      klo saya biasanya pilih salah satu antara timer atau while(1) yang digunakan untuk kontrol atau untuk interface. sya cenderung menggunakan timer buat kontrol dan while(1) buat interface. jd langsung aja gan taro perintah LCD nya di while(1)
      lcd_clear();
      lcd_gotoxy(0,0);
      sprintf(kata,”%d”,encoder);
      lcd_puts(kata);

  5. dennys says:

    mas kalau rotary encoder digunakan untuk mengetahui posisi di berapa derajad sekarang putarannya, gimana yah algoritmanya????

    Terima kasih

  6. yusuf says:

    mas itu sampling timenya berapa ya untuk sistem kendalinya ?
    apa overtime jadi tiap clock time mcunya,

  7. hasnanbro says:

    Mas iso bantuin aku gak ? buat sistem parkir , kesil2an aja, pake mikro trus ama motor dc… kontrol nya dari pc…

  8. elim says:

    gray code systemnya bagaimana sih mas? untuk rotary encoder.

    untuk dapat sudut putarnya, ada rumusnya ga? terimakasih

    • wangready says:

      dibacanya per lajur jadi nanti didapat nilai bit2 khusus tiap sudutnya. Secara biner biasanya tidak urut, tp bit2 nya berubah 1 bit saja saat geser ke posisi selanjutnya… lengkapnya bisa diliat d en.wikipedia.org/wiki/Gray_code

  9. Pingback: Fuzzy Logic Untuk Kontrol Posisi Motor DC | WanGReadY

  10. dieb says:

    gan motor rotary itu harganya berapa gan minimal??

    • wangready says:

      gk tau gan. tp klo gk salah kata temen sekitar 900K (motor DC yg ada encodernya, tp dulu, dah lama), klo encodernya aja yg bekas 250K…harga tepatnya coba aja agan cari2 di toko online…

  11. irhas says:

    Gan .. kalo encoder nya di counternya pake counter mikro bisa? jadi int0 cuma buat arah aja. counter harus up atau down.. mohon bantuannya gan..

    • wangready says:

      gk tau juga gan kalo beda lg, kalo saya ngikut yg program source code dari encoder HB25…
      emang disain encoder nya agan gmana?

      • irhas says:

        encoder nya sama. kalo counter++ atau — nya pakek interrupt takutnya mikro sibuk. gt.. ane bikin encodernya buat jadi sensor ketinggian air gitu. mekaniknya kaya timba di sumur.

      • wangready says:

        gpp jg pake interrupt gan. keknya mikro masih bisa handle.
        mungkin biar lebih enak, buat feedback sensor posisi nya pake potensiometer yang muternya panjang n gk pake interrupt

  12. Grace says:

    gan, kalo kontrolnya PI aja gimana codenya? makasih gan

  13. odong says:

    Hai gan. Saya mau tanya ni.
    Misal ni gan, saya punya 2 buah motor (di kanan dan di kiri) yang masing2 dilengkapi encoder. Nah yang diinginkan itu, dapat diketahui robot sudah berputar berapa derajat(tanpa dengan kompas dan hanya dengan encoder tadi) gan.
    Tadi kan dibahas tentang mendapatkan nilai increment dari putaran ke kanan atau ke kiri dari 1 encoder gan. Nah sekarang saya punya 2 motor gan. Jika motor kiri bergerak maju dan motor kanan bergerak mundur, bisa kah didapatkan nilai derajat dari perputarannya gan?

    Terimakasih :)

    • wangready says:

      dihitung aja gan encoder nya, satu kali baca encoder ban bergerak berapa cm, trus dari jarak antar kedua motor roda bisa didapat nilai keliling lingkaran yang dibentuk jika robot berputar. kalo udah dapet keliling nya kan bisa didapat
      derajat_putar = ( (encoder_terhitung x pegerakan_encoder_dalam_centimeter)/keliling_lingkaran ) x 360 derajat

      • odong says:

        Hehehehe saya masih bingung gan. Brarti yang dilakukan pertama adalah menjalankan motor sejauh 1cm dan mengambil nilai encoder nya gan?
        Kalau terkait jarak antar kedua motor itu bagaimana ya gan?
        Sebenarnya robot yang digunakan itu mempunyai 4 motor dan 4 encoder gan dengan resolusi 1000 state changes per 3 wheel rotations.
        Mohon bimbingannya gan.

        Terimakasih :)

      • wangready says:

        misal jarah 2 motor = h, ambil aja jarak antara roda kanan dan kiri. jadi nanti lingkaran yang akan terbentuk ketika robot berputar mempunyai keliling : Kb = phi*h
        kalo diketahui resolusi encodernya, berarti bisa dihitung tuh gan dari diameter roda.
        misal diameter roda = d, maka keliling roda: Kr=phi*d
        berarti per satu kali hitung encoder robot bergerak : H=Kr*(3/1000) satuannya cm/stepencoder
        maka bisa didapat sudut putar perencoder
        SPE= (360/Kb)*H satuannya sudut/stepencoder
        nanti untuk mendapat nilai sudut tinggal dihitung :
        sudut=encoder_terhitung*SPE
        gtu gan menurut analisis saya…

  14. odong says:

    Tq toh gan penjelasan nya, detail pula. :) manstapp

  15. odong says:

    Gan, ane punya pertanyaan lagi gan. Kan signal A masuk ke pin interupt, dan signal B dijadiin input mikro yang kemudian akan dilakukan counter up maupun counter down. Berarti yang dibaca itu sebenarnya cuma pulsa dari signal B saja ya gan?

    • wangready says:

      iya bisa jg sperti itu, signal A buat membangkitkan fungsi interrupt aja untuk kemudian membaca signal B….

      • Daniel says:

        Kalau Signal A dan B di XOR dan outputnya ke interrupt gan. Lalu signal A dibandingkan dengan signal B melalui pin input biasa gan. Kalau Signal A high dan Signal B low maka counter up, SIgnal A low dan Signal B high maka counter down. Bedanya dengan membaca signal B saja bagaimana ya gan? Apakah tidak perlu melakukan XOR?

        Thanks gan :)

      • wangready says:

        kalo saya buat hemat pin dan komponen aja, jdinya cuma pake 2 pin. interrupt aktif ketika falling edge, jadi otomatis interrupt function aktif ketika low. maka kita tinggal baca pin satunya untuk counter up ataukah counter down.
        apa yang agan jelaskan di atas juga bisa aja gan, tergantung disain masing2 aja, saya kira hasil nya sama…

  16. Daniel says:

    Gan, ane mau tanya lagi gan. Ane udah coba membuat perhitungannya.
    Kll lintasan= 3.14 * 18.3;
    Kll roda= 3.14 * 16.5;
    stepencoder=Kll roda * (3/1000) * 4;
    sudutlintasan= (stepencoder * 360) / Kll lintasan;
    pulsa= sudut / sudutlintasan;

    Nah saat sudut diberi sudut=40; , perputaran robotnya hanya sekitar 10 derajatan gan. Kesalahan ada dimana ya gan?
    Mohon bantuannya gan. :)

    • wangready says:

      H=Kr*(3/1000) satuannya cm/stepencoder

      sedangkan di persamaan agan, ditambahkan *4

      stepencoder=Kll roda * (3/1000) * 4;

      otomatis nilai stepencoder berubah dan mempengaruhi sudutlintasan sehingga nilai pulsa semakin kecil dari yg seharusnya, yaitu 1/4 nya…

      Kb = phi*h
      misal jarah 2 motor = h
      diameter roda = d
      Kr=phi*d
      H=Kr*(3/1000)
      SPE= (360/Kb)*H
      sudut=encoder_terhitung*SPE

      • Daniel says:

        Saya mengira karena quadrature, resolusi 1 putaran perlu di bagi 4 lagi gan, mk na ane kali 4. Thanks gan koreksinya.
        Tapi saya bingung dengan keliling roda gan. Saya gan menggunakan belt tank gitu gan. Brarti bukan diameter roda tapi diameter belt ya gan?

      • wangready says:

        pake aja diameter gear pada belt yang nyambung ke encoder dan motor gan…

  17. ahmad says:

    mohon bantuannya kk

    listing program kontrol motor dc dengan encoder mnggunakan PID , trus mikrokontroller nya pakai arduino uno( atmega 328) gmn ya ?

    mkasih kk

    • wangready says:

      tinggal masukin aja gan rumusnya…

      • ahmad says:

        ok mksih kk..

        nanya lg kk.. LCD yg d pakai kan dari sinyal encoder,
        lcd nya mau sy ganti pakai LED, cara program nya gmn ?

      • ahmad says:

        maaf kk, LED yg mau sy pasang cuman 3 Led, untuk kondisi putaran motor normal, high & low,.., mohon pnjlsannya

      • wangready says:

        langsung aja gan pake getchar, nanti terjemahkan ke LED, bisa pake

        if(data_receive_buff> 0) && (data_receive_buff <= 10)
        {
        PORTA=0b00000001;//low
        DDRA= 0b00000001;
        }
        data_receive_buff = getchar();
        enc_target += ((((int)data_receive_buff & 0b10000000)>>6)-1)*((int)data_receive_buff & 0b01111111);        
        

        dan seterusnya gan

  18. kk itu program yang di pake di video apa aja ya?
    saya pake isis aja motornya gak muter bingung caranya gimana
    mohon bimbingannya ya maklum newbie heheh

    • wangready says:

      klo yg di video, itu menggunakan input dari virtual seriar port…remove aja bagian program yang serialnya jadi

      while (1)
      {
      enc_target += 90;
      delay_ms(3000);
      };

      • masih gak bisa kk. program yang di video sudut kanan atas, yang kk ganti2 itu apa ya?

      • wangready says:

        ya intinya saya kontrol lewat serial….
        coba masukin yg gk pake serial udah saya post

      • ini program saya kk, masih gak muter kayak video.

        /*****************************************************
        Project :
        Version :
        Date : 26/10/2013
        Author : Mahfie
        Company :
        Comments:

        Chip type : ATmega32
        Program type : Application
        AVR Core Clock frequency: 11,059200 MHz
        Memory model : Small
        External RAM size : 0
        Data Stack size : 512
        *****************************************************/

        #include
        #include
        #include
        #include

        #define pwm OCR1A
        /*
        // Alphanumeric LCD Module functions
        #asm
        .equ __lcd_port=0x1B ;PORTA
        #endasm
        #include
        */
        #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 Receiver buffer
        #define RX_BUFFER_SIZE 8
        char rx_buffer[RX_BUFFER_SIZE];

        #if RX_BUFFER_SIZE<256
        unsigned char rx_wr_index,rx_rd_index,rx_counter;
        #else
        unsigned int rx_wr_index,rx_rd_index,rx_counter;
        #endif

        // This flag is set on USART Receiver buffer overflow
        bit rx_buffer_overflow;

        // USART Receiver interrupt service routine
        interrupt [USART_RXC] void usart_rx_isr(void)
        {
        char status,data;
        status=UCSRA;
        data=UDR;
        if ((status & (FRAMING_ERROR | PARITY_ERROR | DATA_OVERRUN))==0)
        {
        rx_buffer[rx_wr_index]=data;
        if (++rx_wr_index == RX_BUFFER_SIZE) rx_wr_index=0;
        if (++rx_counter == RX_BUFFER_SIZE)
        {
        rx_counter=0;
        rx_buffer_overflow=1;
        };
        };
        }

        #ifndef _DEBUG_TERMINAL_IO_
        // Get a character from the USART Receiver buffer
        #define _ALTERNATE_GETCHAR_
        #pragma used+
        char getchar(void)
        {
        char data;
        while (rx_counter==0);
        data=rx_buffer[rx_rd_index];
        if (++rx_rd_index == RX_BUFFER_SIZE) rx_rd_index=0;
        #asm("cli")
        –rx_counter;
        #asm("sei")
        return data;
        }
        #pragma used-
        #endif

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

        #if TX_BUFFER_SIZE=0)m_cw();
        else m_ccw();

        if(P255)P=255;

        pwm = (unsigned char)P;
        }

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

        //unsigned char kata[16];
        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=Out Func3=In Func2=In Func1=In Func0=In
        // State7=T State6=T State5=0 State4=0 State3=T State2=T State1=T State0=T
        PORTD=0x00;
        DDRD=0x30;

        // Timer/Counter 0 initialization
        // Clock source: System Clock
        // Clock value: 16000.000 kHz
        // Mode: Normal top=FFh
        // OC0 output: Disconnected
        TCCR0=0x01;
        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: Inverted
        // OC1B output: Inverted
        // 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=0xF1;
        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: On
        // USART Transmitter: On
        // USART Mode: Asynchronous
        // USART Baud rate: 57600
        UCSRA=0x00;
        UCSRB=0xD8;
        UCSRC=0x86;
        UBRRH=0x00;
        UBRRL=0x10;

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

        // LCD module initialization
        //lcd_init(16);
        motor_init();
        // Global enable interrupts
        #asm(“sei”)

        while (1)
        {
        enc_target += 90;
        delay_ms(3000);
        };
        }

        diputerin manual juga gak bisa, bingung kk seharian. mohon bantuannya ya kk

      • wahh sep, udah bisa kk. thanks ya

  19. farid says:

    mas, kalau PID gabung FUZZY gimana ya,… boleh minta source codenya mas ?

  20. indra says:

    gan, ane butuh project proteusnya biar bisa langsung dicoba… atau

    bagaimana cara memasukkan codenya ke proteus…

    tolongin ane gan….

    • wangready says:

      gk ada gan filenya lupa nyimpen nya…double click aja di chipnya trus input file .hex atau .cof jangan lupa setting clocknya external sama nilai clocknya isi dengan MHz

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

Follow

Get every new post delivered to your Inbox.