Tuesday, March 31, 2020

Interfacing servo motor with pic

This is our  tutorial of Learning PIC microcontrollers using MPLAB and XC8. In this tutorial we will learn How to control Servo Motor with PIC Microcontroller. If you have already worked with Servo motors you can skip the first half of this tutorial but if you are new to servo motor itself then continue reading.

What is a Servo Motor?

Servo Motor is a type of actuator (mostly circular) that allows angular control. There are many types of Servo motors available but in this tutorial let us concentrate on the hobby servo motors shown below.
Servo-motors
Hobby servos are a popular because they are the inexpensive method of motion control. They provide an off-the-shelf solution for most of the R/C and robotic hobbyist's needs. They also eliminate the need to custom design a control system for each application.
Most of the hobby servo motors have a rotational angel of 0- 180° but you can also get 360° servo motor if you’re interested. This tutorial uses a 0- 180° servo motor.  There are two types of Servo motors based on the gear, one is the Plastic Gear Servo Motor and the other is Metal Gear Servo Motor. Metal gear is used in places where the motor is subjected to more wear and tear, but it comes only at a high price.
Servo motors are rated in kg/cm (kilogram per centimetre) most hobby servo motors are rated at 3kg/cm or 6kg/cm or 12kg/cm. This kg/cm tells you how much weight your servo motor can lift at a particular distance. For example: A 6kg/cm Servo motor should be able to lift 6kg if the load is suspended 1cm away from the motors shaft, the greater the distance the lesser the weight carrying capacity. Learn here the Basics of Servo motor.

Interfacing Servo Motors with Microcontrollers:

Interfacing hobby Servo motors with MCU is very easy. Servos have three wires coming out of them. Out of which two will be used for Supply (positive and negative) and one will be used for the signal that is to be sent from the MCU. In this tutorial we will be using a MG995 Metal Gear Servo Motor which is most commonly used for RC cars humanoid bots etc. The picture of MG995 is shown below:
MG995-Metal-Gear-Servo-Motor servo-motor-three-wires
The colour coding of your servo motor might differ hence check for your respective datasheet.
All servo motors work directly with your +5V supply rails but we have to be careful on the amount of current the motor would consume, if you are planning to use more than two servo motors a proper servo shield should be designed. In this tutorial we will simply use one servo motor to show how to program our PIC MCU to control the motor.

Programming Servo Motor with PICF877A PIC Microcontroller:

Before we can start programming for the Servo motor we should know what type of signal is to be sent for controlling the Servo motor.  We should program the MCU to send PWM signals to the signal wire of the Servo motor.  There is a control circuitry inside the servo motor which reads the duty cycle of the PWM signal and positions the servo motors shaft in the respective place as shown in the picture below
servo-rotation

Each servo motor operates on a different PWM frequencies (most common frequency is 50HZ which is used in this tutorial) so get the datasheet of your motor to check the on which PWM period your Servo motor works.
 The details on the PWM signal for our Tower pro MG995 is shown below.
servo-motor-PWM-duty-cycle
From this we can conclude that our motor works with a PWM Period of 20ms (50Hz). So the frequency of our PWM signal should be set to 50Hz. The frequency of the PWM that we had set in our previous tutorial was 5 KHz, using the same will not help us here.
But, we have a problem here. The PIC16F877A cannot generate low frequency PWM signals using the CCP module. According to the datasheet the lowest possible value that can be set for the PWM frequency is 1.2 KHz.  So we have to drop the idea of using CCP module and find a way to make our own PWM signals.
Hence, in this tutorial we will use the timer module to generate the PWM signals with 50Hzfrequency and vary their duty cycle to control the angel of the servo motor.  If you are new to timers or ADC with PIC please fall back to this tutorial, because I will be skipping most of the stuff since we have already covered them there.

We initialize our Timer module with a prescaler of 32 and make it overflow for every 1us. According to our data sheet the PWM should have a period of 20ms only. So our on time and off time together should be exactly be equal to 20ms.
    OPTION_REG = 0b00000100;  // Timer0 with external freq and 32 as prescaler
    TMR0=251;       // Load the time value for 1us delayValue can be between 0-256 only
    TMR0IE=1;       //Enable timer interrupt bit in PIE1 register
    GIE=1;          //Enable Global Interrupt
    PEIE=1;         //Enable the Peripheral Interrupt

So inside our interrupt routine function, we turn on the pin RB0 for the specified time and turn it off for the reaming time (20ms – on_time).  The value of the on time can be specified by using the Potentiometer and ADC module. The interrupt is shown below.
oid interrupt timer_isr()
{  
    if(TMR0IF==1) // Timer has overflown
    {
        TMR0 = 252;     /*Load the timer Value, (Note: Timervalue is 101 instaed of 100 as the
                         TImer0 needs two instruction Cycles to start incrementing TMR0 */
        TMR0IF=0;       // Clear timer interrupt flag
        count++;
    } 
    
    if (count >= on_time)
    {
        RB0=1;  // complement the value for blinking the LEDs
    }
    
    if (count >= (on_time+(200-on_time)))
    {
        RB0=0;
        count=0;
    }
}

Inside our while loop we just read the value of potentiometer by using the ADC module and update the on time of the PWM using the read value.
    while(1)
    { 
        pot_value = (ADC_Read(4))*0.039;
        on_time = (170-pot_value);
    }
This way we have created a PWM signal who’s Period is 20ms and has a variable duty cycle which can be set using a Potentiometer. Complete Code has been given below in code section.
Now, let’s verify the output using proteus simulation and proceed to our hardware.

Circuit Diagram:

If you have already come across the PWM tutorial then the schematics of this tutorial will be same except for which we will be adding a servo motor in place of the LED light.
Interfacing-Servo-Motor-with-PIC-Microcontroller-circuit

Simulation and Hardware Setup:

With the help of Proteus simulation we can verify the PWM signal using a oscilloscope and also check the rotating angel of the Servo motor. Few snapshots of the simulation is shown below, where the rotating angel of the servo motor and PWM duty cycle can be noticed to get changed based on the potentiometer. Further check the Full Video, of rotation at different PWM, at the end.
Servo-Motor-with-PIC-Microcontroller-proteus-simulation-1
Servo-Motor-with-PIC-Microcontroller-proteus-simulation-2

As we can see the servo rotation angel gets changed based on the potentiometer value. Now let us proceed to our hardware setup.
In the hardware setup we have just removed the LED board and added the Servo motor as shown in the schematics above.
The hardware is shown in the picture below:
Interfacing-Servo-Motor-with-PIC-Microcontroller-MPLAB-XC8

The video below shows how the servo motor reacts to the various positions of the potentiometer. 
That is it!! We have interfaced a servo motor with a PIC Microcontroller, now you can use your own creativity and find out applications for this. There are lots of projects out there which use a servo motor
 
Code: 
#define _XTAL_FREQ 20000000
// CONFIG
#pragma config FOSC = HS        // Oscillator Selection bits (HS oscillator)
#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = ON       // Power-up Timer Enable bit (PWRT enabled)
#pragma config BOREN = ON       // Brown-out Reset Enable bit (BOR enabled)
#pragma config LVP = OFF        // Low-Voltage (Single-Supply) In-Circuit Serial Programming Enable bit (RB3 is digital I/O, HV on MCLR must be used for programming)
#pragma config CPD = OFF        // Data EEPROM Memory Code Protection bit (Data EEPROM code protection off)
#pragma config WRT = OFF        // Flash Program Memory Write Enable bits (Write protection off; all program memory may be written to by EECON control)
#pragma config CP = OFF         // Flash Program Memory Code Protection bit (Code protection off)
// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.
#include <xc.h>
//TIMER0    8-bit    $$RegValue = 256-((Delay * Fosc)/(Prescalar*4))$$
char value = 0;
int on_time ;//= 150; //On-Time for the PWM signal
int count; //count gets incremented for every timer overlap
int pot_value;
/*********ADC Functions*********/
void ADC_Init()
{
  ADCON0 = 0x41; //ADC Module Turned ON and Clock is selected
  ADCON1 = 0xC0; //All pins as Analog Input
                //With reference voltages VDD and VSS
}
unsigned int ADC_Read(unsigned char channel)
{
  if(channel > 7) //If Invalid channel selected 
    return 0;     //Return 0
  ADCON0 &= 0xC5; //Clearing the Channel Selection Bits
  ADCON0 |= channel<<3; //Setting the required Bits
  __delay_ms(2); //Acquisition time to charge hold capacitor
  GO_nDONE = 1; //Initializes A/D Conversion
  while(GO_nDONE); //Wait for A/D Conversion to complete
  return ((ADRESH<<8)+ADRESL); //Returns Result
}
  //*************************************************//
void interrupt timer_isr()
{  
    if(TMR0IF==1) // Timer has overflown
    {
        TMR0 = 252;     /*Load the timer Value, (Note: Timervalue is 101 instaed of 100 as the
                         TImer0 needs two instruction Cycles to start incrementing TMR0 */
        TMR0IF=0;       // Clear timer interrupt flag
        count++;
    } 
    
    if (count >= on_time)
    {
        RB0=1;  // complement the value for blinking the LEDs
    }
    
    if (count >= (on_time+(200-on_time)))
    {
        RB0=0;
        count=0;
    }
}
void main()
{    
 /***************I/O PORT Initialization*************/
  TRISB = 0x00; //RB0 used as Servo signal pin
  TRISA = 0xFF; //Analog inputs 
 //*************************************************//
 ADC_Init(); //Initializes ADC Module
  
    OPTION_REG = 0b00000100;  // Timer0 with external freq and 32 as prescaler
    TMR0=251;       // Load the time value for 1us delayValue can be between 0-256 only
    TMR0IE=1;       //Enable timer interrupt bit in PIE1 register
    GIE=1;          //Enable Global Interrupt
    PEIE=1;         //Enable the Peripheral Interrupt
    while(1)
    { 
        pot_value = (ADC_Read(4))*0.039;
        on_time = (170-pot_value);
    }
}

No comments:

Post a Comment