Controlling two Futaba servo motors with Atmel ATmega16

I came across this subject while building my school project (a solar tracker). These are some interesting methods of programming hardware for a software-new-media guy like me and so I am very anxious to tell you all about it. Code available for free download.

I use two Futaba S3003, cheap and powerful servos. They feature three wires: power (4.8 – 6V, regulated, red one), ground (black) and control (white). It seems you can tell them the absolute position in angle by the width of a pulse on the control wire. My model has Counter Clockwise/Pulse Traveling 1520-1900usec which means that

  • 1000 usec – maximum right (0 degrees)
  • 1520 usec (can consider 1.5 msec) – center position (90 degrees)
  • 1900 usec (can consider 2msec) – maximum left (180 degrees)
  • Cross-proportion for any other angle

And yes, they only travel 180 degrees when you buy them. They can be modified to do a full round up of 360, but this is not the subject here.

Atmega features 3 timers, one on 8bits, two on 16. We will be using Timer1 on Atmega16 since it is more precise and features phase and frequency correct pulse width modulator (PWM). I don’t know if it matters or not, but most recommend a 50Hz (20ms cycle) frequency for the pulse control, although I’ve seen 6ms cycles in some other source.

We will make the timer’s counter go to a TOP limit and then back down to zero in one cycle of 20 msec. We will make it “pulse” with VCC on an output pin between two equal values of the counter, chosen in such a manner that the interval will last 1 – 2 ms depending on desired angle. We will use the processor’s clock prescaled for input.

desired_frequency = (Input_frequency)/(2*Prescaler*TOP_limit)

  • Desired_frequency = 50 Hz
  • Input_frequency = processor’s clock = 16 000 000 Hz for Atmega16
  • Prescaler – 1, 2, .. 1024

We can choose prescaler = 8 and the resulting Top value will be 20 000, a valid 16-bit integer. Since 20 000 = 20 msec => 1000 for 1 msec and 2000 for 2 msec. Your pulse(phase) function can look like this:

int get_pulse(int degrees){
return (int)((float)degrees*1000/180+1000);
}

Notice how i first convert the first operand to float and then cast the result back to int in order not to lose precision in intermediate truncations.

We will store TOP (20000) value in ICR1 register, select Prescaler (8) in CS12,CS11,CS10 bits of TCCR1B register (there is a description table of values in atmega datasheet, page 113) and a value between 1000 and 2000 in OCR1A for one servo motor and OCR1B for the second one. The output ports are PD4 (OC1B, second motor) and PD5 (OC1A, first motor). Don’t forget to set the ports as outputs (DDRD =1 for bits 4 and 5).

Enough theory, time for wiring. I want to mention my main source of information with great graphics and examples – http://mil.ufl.edu/~achamber/servoPWMfaq.html

Free Download: zip Programming servo motors with atmega16 (64.86 KB, zip) - Example code for controlling 2 PWM servo motors with timer1 of ATmega16 plus a simple Proteus Design. 3803 downloads

  • Pingback: My Solar light tracker – Me Simian

  • dg1223

    hello, i’m new to microcontrolers and servos. I’ve used your code and the program is working fine when I connect LEDs to OC1A and OC1B pins. However, when I connect my servo’s signal wire to these pins (any 1 of the 2), my servo just twitches and nothing happens after that. Also the servo moves a little bit and stops whenever I disconnect and reconnect the signal wire over and over again.

    I’ve supplied 5V to the servo (lost my 7806 regulator) but I guess that shouldn’t be the problem.

    Any kind of help would be greatly appreciated…

    Thanks

    • Anonymous

      I think you need more power for your servo. I am pretty sure the servo drains to much current from your DC supplier and the microcontroller can’t get enough; it probably resets due to low power.

      What type of power source do you use? I recommend an ordinary AC-DC transformer and not usb interfaces from your computer. You can also try using different power sources for microcontroller and servos. See if that works.

      • dg1223

        I’ve tried different power sources for the microcontroller and the servo. For the servo, I used an AC to DC adapter and this time I supplied 6V to the servo. But I’m still getting the same result.

        • Anonymous

          What type/model of servo are you using?

          • dg1223

            I’m using a Futaba S3003 and another metal geared servo which has similar ratings as the Futaba.

          • http://www.mesimian.com Mihnea Simian

            Sorry, I really don’t have a clue.. I used the same servo.

          • 208500879

            The OCR value is set too high or to low for the servo. I’m using a CS sport 60 servo I found the range to be within 0.2ms-1.1ms, Which deviates from the 1-2ms standard

  • Guest189

     Thanks! It works.

    • http://www.mesimian.com Mihnea Simian

       Great! You’re welcome.

  • 123

    Nice clean code, thanks for posting!

  • Jaspreet

    Can you give me code in c for controlling three futaba servo motors with atmega32
     

    • http://twitter.com/mihneasim Mihnea Simian

      Can you do this with ATmega? It only has two timers.. maybe you could somehow share one timer for two motors, but you need some special wiring setup to simulate multiplexing. Have you thought about the wiring of the three motors?

  • rocco

    don’t work, send me a light.hex please :)
    my email is: rockys85@hotmail.it

    thanks :)