1. Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.
    Dismiss Notice

Driving a servo motor

Discussion in 'Robotics & Mechatronics' started by Wingmax, Nov 25, 2007.

  1. Wingmax

    Wingmax New Member

    Joined:
    Sep 16, 2007
    Messages:
    163
    Likes:
    6
    Location:
    Australia
    In this post I will demonstrate how to connect and drive a servo motor.
    The brain of the servo motor is the input pulse width. The pulse width determines the servo motor's drive position.

    A servo motor only has 3 wires, usually red, black and white. Red and black are +ve and ground connections, and white
    is the drive connection. Usually a pulse width of 1 mS will make the servo motor to drive from one far end, and 2 mS
    to the other end (180 degree). A 1.5 mS will be for middle position. However, bear in mind that every servo motor is different. You have to adjust the pulse
    width accordingly.

    servo1.jpg

    So, all we need to do to drive the servo motor is to generate a pulse train with pulse width (PWM) of 1 mS to 2mS.

    There are many ways to generate Pulse Width Modulation (PWM). We can use 555 or 556 chip, or use software with microcontroller. I like to use micro because it's versatile and it can be used as a central system.
    It can be used to detect input signal and outputs waveforms to drive a motor.

    There are different ways to generate PWM by sofware. We can use delay routine, Timer0, Timer0 and Timer1,
    interrupt, or PWM in CCP module in some PIC micro.

    I will start with the easiest method, ie, by delay routine. Please refer to block diagram and program code.

    View attachment serveDelay_C.txt

    Program code is for Hitec C compiler, and the delay routine can be downloaded from Hitec site. This motor drives more
    than 180 degree.
    The micro used is 16f84A.



    To produce the pulse width:
    PortB.1 is set high, delay for the required time duration then set low,and delay for 15 mS.
    This process is repeated for 50 times. This method of producing PWM is not very accurate, but the pulse period for
    the motor is not that critical, so this method works.
    The program will make the servo motor to go to the far right, back to the middle and to the far left.
    Because it takes bit longer to go to the far right when first starts, so it takes 50 pulses.

    Next time I will use Timer0 method........
     
    Last edited: Dec 6, 2007
  2. HarveyH42

    HarveyH42 Banned

    Joined:
    Feb 25, 2006
    Messages:
    3,442
    Likes:
    18
    Location:
    Not Here
    A servo motor only has 3 wires, usually red, black and white. Red and white are +ve and ground connections, and white
    is the drive connection. Usually a pulse width of 1 mS will make the servo motor to drive from one far end, and 2 mS
    to the other end (180 degree). A 1.5 mS w

    Not to pic at this, but a small edit, white should be black, the image is correct. Would also suggest checking the specific servo's data sheet to make sure, read they are easy to damage if hooked up wrong.
     
  3. Wingmax

    Wingmax New Member

    Joined:
    Sep 16, 2007
    Messages:
    163
    Likes:
    6
    Location:
    Australia

    My apology. It should be red for +ve, black for ground, and white for drive connection. As shown on my diagram. However, I couldn't draw white line as it won't show up on white background. This is based on my experience and usually this is the case. But of course, always check the specs.
    Sorry if I caused any problem for any body regarding this. :D
     
  4. dave

    Dave New Member

    Joined:
    Jan 12, 1997
    Messages:
    -
    Likes:
    0


     
  5. HarveyH42

    HarveyH42 Banned

    Joined:
    Feb 25, 2006
    Messages:
    3,442
    Likes:
    18
    Location:
    Not Here

    I should apologize, I didn't mean to be critical. This is a good thing. You can edit your own past posts and correct typing errors. Figured you were going to keep adding more to this thread.

    Anyway, I've got some interest in micros and servos, but I'm using AVR, and was going to try BASIC (just started learning a few weeks ago).
     
  6. Wingmax

    Wingmax New Member

    Joined:
    Sep 16, 2007
    Messages:
    163
    Likes:
    6
    Location:
    Australia
    The error has been fixed. Thanks for spoting the error.
    I will be adding more new threads regarding different methods of generating pulses.
     
    Last edited: Nov 26, 2007
  7. Mike - K8LH

    Mike - K8LH Well-Known Member

    Joined:
    Jan 22, 2005
    Messages:
    3,642
    Likes:
    109
    Location:
    Michigan, USA
    Hi Harvey,

    If it helps, here's a relatively simple high performance low overhead 8-channel Servo demo' I posted on the Swordfish BASIC Forum awhile ago. Perhaps it will provide ideas for using a similar module on AVR?

    PORTB outputs a servo pulse for the Servo(0) through Servo(7) array element "on times" and the Servo(8 ) array element is used for the period "off time" (20000 usecs minus the cumulative servo "on times").

    Have fun. Mike

    Code (text):
    {
    ****************************************************************
    *  Name    : K8LH_Soft_Servo.BAS                               *
    *  Author  : Mike McLaren, K8LH                                *
    *  Notice  : Copyright (c) 2007 Micro Applications Consultants *
    *          : All Rights Reserved                               *
    *  Date    : 11/28/07                                          *
    *  Version : 1.0 "untested"                                    *
    *  Notes   : Uses CCP1 "compare" mode for 8 servos on PORTB    *
    *          : 1-usec resolution, extended 600-2400 usec pulses  *
    ****************************************************************
    }
     
    Device = 18F452
    Clock = 8
     
    {
    ****************************************************************
    *  Servo(0)..Servo(7) elements hold 600..2400 usec "on times"  *
    *  Servo(8) = period "off time" (20000 - cumulative on times)  *
    ****************************************************************
    }
    Dim Servo(9) As Word            ' 8 servo and 1 period elements
    Dim TMR1 As TMR1L.AsWord        ' promote to 16 bit TMR1H:L
    Dim CCPR1 As CCPR1L.AsWord      ' promote to 16 bit CCPR1H:L
    Dim CCP1IF As PIR1.2            ' the CCP1 interrupt flag bit
    Dim Servx As Byte               ' servo bitmask (only 1 bit hi)
    Dim n As Byte                   ' servo array index
     
    {
    ****************************************************************
    *  K8LH Hi-Rez Soft 8-channel PORTB 'compare' Servo Algorithm  *
    ****************************************************************
    }
    Interrupt Soft_Servo()
      LATB = Servx                  ' output new Servo pulse bit
      CCPR1 = CCPR1 + Servo(n)      ' setup next compare interrupt
      CCP1IF = 0                    ' clear CCP1 interrupt flag
      Servo(8) = Servo(8)- Servo(n) ' adjust end-of-cycle off time
      Servx = Servx << 1            ' and prep for next channel
      Inc(n)                        ' increment servo array index
      If n = 9 Then                 ' if end of 20 msec period
        n = 0                       ' reset array index
        Servo(8) = 20000            ' reset 20 msec period element
        Inc(Servx)                  ' reset Servo shadow to Servo 1
      EndIf
    End Interrupt
     
    {
    ****************************************************************
    *  Init Ports and Variables                                    *
    ****************************************************************
    }
    Sub Init()
       LATB = 0                     ' all PORT B servo outputs '0'
       TRISB = 0                    ' set PORT B all outputs
       ADCON1 = 15                  ' all digital I/O (no analog)
     
       For n = 0 To 7               ' preload the Servo array
         Servo(n) = 1500            ' mid-range 1500 usec position
       Next                         '
       Servo(8) = 20000             ' Servo period = 20 msecs
       n = 0                        ' init ISR array index
       Servx = %00000001            ' init PORT B servo output mask
     
       TMR1 = 0                     ' clear 16 bit TMR1H:L pair
       CCPR1 = 1000                 ' first "compare" interrupt
       T1CON = %00010000            ' pre 2, post 1, 1 usec 'ticks'
       CCP1CON = %00001010          ' setup CCP1 "compare" mode
     
       PIR1 = 0                     ' clear peripheral int flags
       PIR2 = 0                     '
       PIE1 = 0                     ' clear peripheral int enables
       PIE2 = 0                     '
     
       PIE1.2 = 1                   ' enable CCP1 interrupts
       INTCON.6 = 1                 ' enable peripheral interrupts
       T1CON.0 = 1                  ' turn on Timer 1
       Enable(Soft_Servo)           ' set GIE, enable interrupts
    End Sub
     
    {
    ****************************************************************
    *  Main Program                                                *
    ****************************************************************
    }
    Init
    Repeat
    Until 0 = 1
     
    Last edited: Dec 2, 2007
  8. antkids

    antkids New Member

    Joined:
    Dec 6, 2007
    Messages:
    11
    Likes:
    0
    why trun to far right only ?

    i test your program in by using pic16f877a, as you say this program will make that motor to far right then back to middle then to far left, why the motor after trun to far right then direct stop there ?
    :confused: :confused:
     
  9. Wingmax

    Wingmax New Member

    Joined:
    Sep 16, 2007
    Messages:
    163
    Likes:
    6
    Location:
    Australia

    Your program codes are not the same as mine, so you will not get the same result.
    Also your crystal is 20Mhz, much faster than mine.

    According to your codes , your mistake is you use decimal point.
    If you check the delay function, you'll find that there are limits of the delay.e.g delay(x)
    x must not > 255.

    My motor can go as low as 500uS. I can't use 0.5 mS and I can't use 500uS. That's why I used
    DelayUs(250) twice.

    Hope these help. :)
     
  10. antkids

    antkids New Member

    Joined:
    Dec 6, 2007
    Messages:
    11
    Likes:
    0
    Thank for replay !!!
    I am using your program code to test servo motor, because i'm using PIC16F877A and my crystal is 20MHz, so what i should change in your program code ?

    I try to change "#define XTAL 4000000" to "
    #define XTAL 20000000" but the result also same, after move to right just stop there. Why like this ? I also try to change the delay time but the result also same.

    May i add you as friend in hotmail ? Because I can easily ask you the question ?
     
  11. Wingmax

    Wingmax New Member

    Joined:
    Sep 16, 2007
    Messages:
    163
    Likes:
    6
    Location:
    Australia
    Can you show us your codes?
     
  12. antkids

    antkids New Member

    Joined:
    Dec 6, 2007
    Messages:
    11
    Likes:
    0
    Below are my program code :

    #include <pic.h>
    #include "delay.c"
    #include "delay.h"

    __CONFIG(WDTDIS & XT & UNPROTECT);

    #define XTAL 20000000 //crystal frequency- 20MHz


    main()

    {
    int i;
    TRISC = 0; //PortC is output.

    for (i = 0; i < 50; i++) //Send 50 pulses with width 600 uS
    {
    PORTC = 1; //Pulse high for 600uS
    DelayBigUs(600); //since delayUs (x); x<255 so i change to delaybigus
    PORTC = 0; //Pulse low for 20mS
    DelayMs(20);
    }
    DelayMs(100); //Pause for 100mS

    for (i = 0; i < 50; i++) //Send 50 pulses with width 1.5mS
    {
    PORTC = 1;
    DelayMs(1); //Pulse high for 1.5mS
    DelayBigUs(500);
    PORTC = 0;
    DelayMs(20);
    }
    DelayMs(100);

    for (i = 0; i < 50; i++) //Send 50 pulses with width 2ms
    {
    PORTC = 1;
    DelayMs(2);
    PORTC = 0;
    DelayMs(20);
    }
    DelayMs(100);

    while (1); //Stops here, do nothing.

    }

    why send 50 pulses? why motor trun to right then stop there ? Acctually this program code is same as you post on forum, I just change something only.
    What meaning of " __CONFIG(WDTDIS & XT & UNPROTECT); "
    I'm using PIC16F877A, 20Mhz crystal.
     
  13. Wingmax

    Wingmax New Member

    Joined:
    Sep 16, 2007
    Messages:
    163
    Likes:
    6
    Location:
    Australia
    I haven't had much success with DelayBigUs() before, so I don't know if it's OK.

    You're using different PIC, so try use this in your Configuration word:
    __CONFIG(WDTDIS & XT & UNPROTECT & BORDIS & LVPDIS);

    don't forget it's double underscore before the CONFIG.
    If this configuration word isn't set correctly, program won't work properly.

    Hope this will work.
     
  14. antkids

    antkids New Member

    Joined:
    Dec 6, 2007
    Messages:
    11
    Likes:
    0
    Thanks for your help!!!
    After change the code, the result also same. just keep trun in 1 direction that is form left to right. I have change the time but it also get the same result. Why like this ?? The code problem ? Below are the code :

    #include <pic.h>
    #include "delay.c"
    #include "delay.h"

    __CONFIG(WDTDIS & XT & UNPROTECT & BORDIS & LVPDIS);

    #define XTAL 20000000 //crystal frequency- 20MHz


    main()

    {
    int i;
    TRISC = 0; //PortC is output.

    for (i = 0; i < 50; i++) //Send 50 pulses with width 600 uS
    {
    PORTC = 1; //Pulse high for 600uS
    DelayUs(300); //since delayUs (x); x<255 so i change to delaybigus
    PORTC = 0; //Pulse low for 20mS
    DelayMs(20);
    }
    DelayMs(100); //Pause for 100mS

    for (i = 0; i < 50; i++) //Send 50 pulses with width 1.5mS
    {
    PORTC = 1;
    DelayMs(1); //Pulse high for 1.5mS
    DelayBigUs(500);
    PORTC = 0;
    DelayMs(20);
    }
    DelayMs(100);

    for (i = 0; i < 50; i++) //Send 50 pulses with width 2ms
    {
    PORTC = 1;
    DelayMs(2);
    PORTC = 0;
    DelayMs(20);
    }
    DelayMs(100);

    while (1); //Stops here, do nothing.

    }
     
  15. Wingmax

    Wingmax New Member

    Joined:
    Sep 16, 2007
    Messages:
    163
    Likes:
    6
    Location:
    Australia
    This should be a simple program. It shouldn't be that hard. :confused:
    I got a feeling the configuration word hasn't been set correctly. The code on my chip definitely works. Only differences are we used different chip, crystal and delay function.

    Also you haven't included DelayBigUs in your #include section. Wonder why you haven't got errors when you compiled the codes.
     
  16. HarveyH42

    HarveyH42 Banned

    Joined:
    Feb 25, 2006
    Messages:
    3,442
    Likes:
    18
    Location:
    Not Here
    What about the fuse bits? I really don't know a lot about PIC, still little better than a beginner with AVR. But on my setup, burning the program is one thing, and setting the fuses is another. On the AVR, there are several choices that involve the clock (well 2 that I've used and understand). One divides the clock by 8. If PIC has a similar fuse, then the timing in your program wouldn't be set up right. Servos are all about the timing.
     
  17. antkids

    antkids New Member

    Joined:
    Dec 6, 2007
    Messages:
    11
    Likes:
    0
    I sucess make the motor move, is my broad problem.
    Thank for your help.
    If got problem, hope you can help me again !!
     
  18. Wingmax

    Wingmax New Member

    Joined:
    Sep 16, 2007
    Messages:
    163
    Likes:
    6
    Location:
    Australia
    The fuse is done in the Configuration word(or fuse)- internal osc, XTL etc.
    The clock is specified in #define XTAL frequency.
     
  19. antkids

    antkids New Member

    Joined:
    Dec 6, 2007
    Messages:
    11
    Likes:
    0
    Sorry !! need your help again !!
    What is mean of ""__CONFIG(WDTDIS & XT & UNPROTECT & BORDIS & LVPDIS) "" and ""#define XTAL 20000000"" . This must be define ? Inside your code, why Send 50 pulses ??
     
  20. Wingmax

    Wingmax New Member

    Joined:
    Sep 16, 2007
    Messages:
    163
    Likes:
    6
    Location:
    Australia
    I thought you got it working?

    The __CONFIG(.....) is to configure the microcontroller you use. You have to declare this whether you use C or asm. It just to specify what type of osc you use, disable watch dog timer etc. May be you should do some research on the internet. The #define XTAL, you've done it in your program. just to specify the speed of the crystal you use. In your case, it's 20M.

    The reason I use 50 pulses is because the shaft has to rotate from on end to the other end. So at lease 30 pulses is required. 50 pulses just to ensure it has enough time to reach to the other end.

    If all you want is just to drive the servo motor, then may be it's a bit waste to use 16F877?
     
  21. antkids

    antkids New Member

    Joined:
    Dec 6, 2007
    Messages:
    11
    Likes:
    0
    Ya ! I sucess make it work.
    Thank for help !! :) :) :) :) :)
    Acctually I'm doing a robot, control servo motor is one part of my robot, so uisng a pic16f877a is ok cause many port can use and can add more fuction.
    If my robot is sucess build it, I send you the vedio clip about my robot !!!
     

Share This Page