Controlling servo motor with AVR

Servo motors are a type of electromechanical actuators that do not rotate continuously like DC/AC motors. They used to position and hold some object. They are used where continuous rotation is not required so they are not used to drive wheels. In contrast they are used where something is needed to move to particular position and then stopped and hold there. Most common use is to position the rudder of aircrafts and boats etc. Servos can be used effectively here because the rudders do not need to move full 360 degrees nor they require continuous rotation like a wheel. Servos are DC motors with built in gearing and feedback control loop circuitry.

Most servo motors can rotate about 90 to 180 degrees. Some rotate through a full 360 degrees or more. Servos that can rotate 360 degrees are required mainly for building RC helicopters.

Servo motor

Most commonly available servos have a three wire connector. One wire supplies positive DC voltage – usually 5 to 6 volts. The second wire is for voltage ground, and the third wire is the signal wire. The receiver “talks” to the servo through this wire by means of a simple on/off pulsed signal. In this tutorial, we will be using the servo which have a three wire connector i.e. power, ground and control. Also every servo will have different torque, speed and response time rating. Before purchasing, please check the ratings based on your applications.

Unlike other motors, Servo motors don’t require any driver. When a PWM signal is applied to its control pin the, the shaft rotates to a specific angle depending on the duty cycle of the pulse. PWM stands for pulse width modulation. It is basically a modulation technique, in which the width of the carrier pulse is varied in accordance with the analog message signal. As described above, it is commonly used to control the power fed to an electrical device, whether it is a motor, an LED, speakers, etc.

The main thing that is important in the PWM is the duty cycle. It’s defined as

duty cycle formula

This is just a theoretical formula. Practically, imagine a motor that requires 5v to run at certain RPM. Let the RPM be 300. If the voltage is applied 5v then motor will take 300rounds per minute. However when the voltage applies is 2.5v the motor will take only 150 rounds per minute. Again if the voltage applied is 3.75v, the motor will run at 225 rpm. To achieve this, we use PWM. Let’s say the microcontroller is running at 5v. At a certain time you apply stream of pulses which have equal turn off and turn on time i.e. they have a 50% duty cycle. The pulses are fed to the motor. However, since the duty cycle is 50% the motor will have an input of 2.5V instead of 5V due to continuously being switch on and off with equal time interval. In general the ratio of input voltage to the motor and the output of the microcontroller will be equal to duty cycle ration that is ratio of time the pulses are on and the total time period. For ex if the duty cycle is 75% then duty cycle ratio is 75/100 and that will be equal to ratio of input to motor and output of microcontroller. Since the output of microcontroller is 5v, the input to the motor will be 3.75V.

For the servo I am using, I found out the following timings. The relation between the width of pulse and servo angle is given below. Please note that the timing of the servo will be different for different servo. You can easily find the data on the manufacture datasheet or even on GOOGLE

  • 0.388ms = 0 degree.
  • 1.264ms = 90 degrees. (Neutral position)
  • 2.14ms = 180 degrees.

In this tutorial, the PWM will automatically lock the servo and CPU will be free to do other task. Before proceeding, kindly make sure you are familiar with using timers of AVR

We will be using TIMER1 which is a 16 bit channel and has two PWM channels. Also the pre-scaler will be set to 64. So the frequency of the timer will be 250 kHz that is 4us period.  Also the timer will be setup in MODE14 which is a fast PWM mode with a top value of ICR1.

Fast PWM is useful for outputting PWM values quickly, at a loss of phase correctness – changes to the duty cycle will be reflected immediately, with the new signal being phase incorrect. When selected, the timer will count up from BOTTOM to TOP, with TOP being fixed at the bit-width of the fast PWM — we are given a choice of 8, 9 or 10 bits depending on the timer bit width (8 bit timers will obviously not offer Fast PWM in more than 8-bits). The timer, when started, will count up continuously until TOP is reached, when it wraps back to BOTTOM and starts again. Inside this period when the counter reaches the COMPARE value, the output pin is set when the correct value is reached (and cleared when the timer wraps back from TOP to BOTTOM), so that varying COMPARE we get a PWM of a fixed frequency but a variable duty cycle. For the crystal value of 16MHz and frequency of PWM as 50HZ we get the TOP value as 4999.

So we set up ICR1A=4999, this gives us PWM period of 20ms (50 Hz). Compare Output Mode is set by correctly configuring bits COM1A1, COM1A0 (For PWM Channel A) and COM1B1, COM1B0 (For PWM Channel B)

The above setting will clear the OC1A or OC1B on compare match and set at bottom. These settings will give us the NON inverted PWM output

The duty cycle can be set by OCR1A AND OCR1B register.  Remember the period of timer is 4us, we can calculate values required for servo angle by dividing the required on time mentioned above by 4us.

Therefore for 0 degrees we get 97, 90 degrees we get 316 and for 180 degree it’s 535.

Circuit diagram:

AVR servo motor circuit

Code:

#define F_CPU 16000000
#include <avr/io.h>
#include <util/delay.h>
void Wait()
{
   uint16_t i;
   for(i=0;i<50;i++)
   {
      _delay_loop_2(0);
      _delay_loop_2(0);
      _delay_loop_2(0);
   }
}
void main()
{
  //FOR TIMER1
   TCCR1A|=(1<<COM1A1)|(1<<COM1B1)|(1<<WGM11);        //NON Inverted PWM
   TCCR1B|=(1<<WGM13)|(1<<WGM12)|(1<<CS11)|(1<<CS10); //PRESCALER=64 MODE 14(FAST PWM)
   ICR1=4999;  //fPWM=50Hz 
   DDRD|=(1<<PD4)|(1<<PD5);   //PWM Pins as Output
   while(1)
   {
      OCR1A=316;  //90 degree
      Wait();
      OCR1A=97;   //0 degree
      Wait();
     OCR1A=535;  //180 degree
      Wait();
   }
}

Download AVRStudio project here: Servo

By: Tushar Gupta

Read

Bookmark the permalink.
Add Comment Register



Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>