Servos Program. ( Concurrent needed ? )

Discussion in 'Programmer's Corner' started by wk7au, May 27, 2013.

  1. wk7au

    Thread Starter New Member

    Apr 16, 2013
    15
    0
    void main(void)
    {
    unsigned int i,a;


    TRISB = 0b00000011;
    PORTB = 0b00000000;


    while(1)
    {

    RB7=1;
    for(i=0;i<50;i++)
    {
    RB5=1;
    DelayUs(157);


    RB5=0;
    DelayMs(6);
    DelayUs(250);
    DelayUs(250);
    DelayUs(9);


    }

    for(i=0;i<50;i++)
    {
    RB4=1;
    DelayUs(250);
    DelayUs(250);
    DelayUs(86);


    RB4=0;
    DelayMs(6);
    DelayUs(80);


    }


    This program is running with MPLab. My project is to construct a robot arm, this program works fine but when external force applied (due to the weight of my arm) then the servos will not capable to resist the forces when servos not powered then it will just "fell" off.Hence, I want to know how to send a continuous pulse to instruct the servo stay in position.

    Concurrent program ? But how ?

    THE MAIN POINT IS BOTH RB5 & RB4 CAN RUN TOGETHER

    Thank you.:)
     
  2. Markd77

    Senior Member

    Sep 7, 2009
    2,803
    594
    Just combine the two loops:
    pulse on RB4
    delay
    pulse on RB5
    delay
    then repeat

    I heard that the time between pulses (of each servo) should be 20ms, but if it's working for you use a delay of about 3ms in between each servo pulse.
     
  3. wk7au

    Thread Starter New Member

    Apr 16, 2013
    15
    0
    I tried but the force of motor applied stopped after 1-2 seconds so yea the arm fell too so I am seeking for any other possible solutions perhaps if no then maybe I will try again by combining two loops
     
  4. tubeguy

    Well-Known Member

    Nov 3, 2012
    1,157
    197
    You may know this, but servos normally expect a pulse width which varies from 1 ms - 2ms. 1.5ms width would be the centered position.
     
  5. wk7au

    Thread Starter New Member

    Apr 16, 2013
    15
    0
    I know, I have calibrate all the possible angles for my servo , between 2ms-0.5ms , 45 degree,90 degree etc etc , i have found it all . BUT the problem now is the servo can not receive the continuous pulse which allow my servo to be powered all the time and able to resist the weight of my robot arm then it just tend to move to the position I instruct but after 2 seconds it just fell bcause it doesn't receive anymore pulse (WHY FELL? BECAUSE THE WEIGHT OF MY ROBOT ARM ). THE PROGRAM ABOVE IS BASED ON 1ms 2ms 1.5ms theory and YEAH I KNOW THE THEORY BUT THIS DOESN'T RELATED WITH MY PROBLEM .
     
  6. tubeguy

    Well-Known Member

    Nov 3, 2012
    1,157
    197
    We don't know what you know without asking...
     
  7. tubeguy

    Well-Known Member

    Nov 3, 2012
    1,157
    197
    This is why I mentioned the pulse width specs.
     
    Last edited: May 27, 2013
  8. wk7au

    Thread Starter New Member

    Apr 16, 2013
    15
    0
    Ummm hmm, currently i just want to know how to send the continuous pulse to the servos tgt at the same time, can u suggest the way?
     
  9. tshuck

    Well-Known Member

    Oct 18, 2012
    3,531
    675
    I think this task is better suited toward interrupts. If you know about them, use them, if not, well, then it's probably time to learn.

    With an interrupt, you can interrupts every Xμs. and turn various pins on or off, according to a set of desired servo settings. So, something like:
    Code ( (Unknown Language)):
    1.  
    2. Servo1Value = X;
    3. Servo2Value = K;
    4. Counter = 0;
    5.  
    6. loop: <- occurs every 100μs.
    7.  
    8.     Counter = Counter + 1;
    9.     if (Servo1Value < Counter)
    10.         Servo1 = 1;
    11.     else
    12.         Servo1 = 0;
    13.     if (Servo2 Value < Counter)
    14.         Servo2 = 1;
    15.     else
    16.         Servo2 = 0;
    17. end loop
    18.  
    , could work. 20ms is a long time for a uC to do things....
     
  10. tshuck

    Well-Known Member

    Oct 18, 2012
    3,531
    675
    PWM module will do it, but you have issues with the resolution and adding another servo, depending on how you do it....
     
  11. MMcLaren

    Well-Known Member

    Feb 14, 2010
    759
    116
    Which PIC are you using? If it's an 18F device with two PWM channels you can use them to drive both servos. More on that later. If it's a 16F device you could use the CCP module with timer 1 and implement an interrupt driven 8-channel "soft" servo driver. Here's the basic "engine" code (you'd need to initialize the CCP module and timer 1 in "special event trigger" mode, setup ports, turn on interrupts, etc.);

    Code ( (Unknown Language)):
    1. /*****************************************************************
    2.  *  K8LH Crazy-8 'Soft' 8-channel Servo Controller variables     *
    3.  *****************************************************************/
    4.  
    5. unsigned int Pulse [] = { 1500, 1500, 1500, 1500,
    6.                           1500, 1500, 1500, 1500,
    7.                           20000 };
    8.  
    Code ( (Unknown Language)):
    1.  
    2.  /****************************************************************
    3.   *  K8LH Crazy-8 Hi-Rez Soft 8-channel (PORTB) Servo Algorithm  *
    4.   *                                                              *
    5.   *  1 usec steps, 600-2400 usecs, prescale 1,2,4 (4,8,16 MHz)   *
    6.   ****************************************************************/
    7.   void interrupt()
    8.   { static char n = 0;          //
    9.     static char servo = 1;      //
    10.  
    11.     if (pir1.CCP1IF == 1)       // if "special event" interrupt
    12.     { pir1.CCP1IF = 0;          // clear the interrupt flag
    13.       LATB = Servo;             // output new Servo pulse
    14.       CCPR1 = Pulse[n++];       // setup the CCP1 "match" value
    15.  
    16.       Pulse[8] -= CCPR1;        // adjust end-of-cycle off time
    17.       Servo <<= 1;              // and prep for next channel
    18.  
    19.       if (n == 9)               // if end of a 20-msec period
    20.       { n = 0; Servo = 1;       // reset "n" and "Servo"
    21.         Pulse[8] = 20000;       // reset the 20.0-msec period
    22.       }
    23.     }
    24.   }
    25.  
    This example 8-channel servo "engine" sends each servo pulse out one at a time in succession while keeping track of the amount of time used so that the last (ninth) period can be used to fill out the balance of the 20 msec period. The tricky part about a soft servo driver is that you really should disable interrupts momentarily in your main program when you want to update any individual 16-bit servo pulse width value. Unfortunately, this could interfere with an interrupt and cause jitter during one servo pulse output.

    Hope this helps.

    Cheerful regards, Mike
     
    Last edited: May 27, 2013
  12. MMcLaren

    Well-Known Member

    Feb 14, 2010
    759
    116
    I mentioned using the PWM module in the previous post where you could use both CCP modules on an 18F device to drive two servos at hi-rez with zero pulse and period jitter. While many programmers will suggest that it's difficult to obtain long PWM periods with adequate pulse width resolution, I found that it's relatively easy if you break up the much longer servo period into several much shorter PWM "frames". This requires using a small interrupt driven "helper" program and I'd be happy to elaborate if anyone is interested.

    Another interesting feature, PWM Steering, has turned up on some recent PIC devices. This feature allows you to direct a single PWM output onto any of four output pins. Earlier this year I wrote a hi-rez jitter free 4-channel Servo demo for one of these devices, a fourteen pin (enhanced mid-range) PIC16F1823. While the program is written in assembly language, there are pseudo C code comments which may help if you want to convert the demo program into your favorite version of C. For example, here are the pieced together (BoostC) pseudo C code comments for the interrupt driver;

    Code ( (Unknown Language)):
    1. ;
    2. ;  void interrupt()             // 250-uS (1000 cycle) interrupts
    3. ;  { pir1.TMR2IF = 0;           // clear TMR2 interrupt flag
    4. ;    if(width >= 250)           // if width >= 250 usecs
    5. ;      ccpr1l = 250;            // use a 100% duty cycle
    6. ;    else                       // otherwise
    7. ;      ccpr1l = width;          // use balance of width or 0%
    8. ;    width -= ccpr1l;           // adjust balance
    9. ;
    10. ;    pstr1con = steer | 1<<STR1SYNC;
    11. ;
    12. ;    if(--frame == 0)           // if end of 5 ms period
    13. ;    { frame = 20;              // reset 5 ms counter and
    14. ;      if(!(steer >>= 1))       // if last channel (20 msecs)
    15. ;        steer = 8;             // reset for channel 0
    16. ;      width = servo[index];    // new servo 'width'
    17. ;      index++; index.2 = 0;    // next channel index, 0..3
    18. ;    }
    19. ;  }
    20. ;
    21.  
    I've attached the 16F1823 demo program for anyone who is interested.

    Cheerful regards, Mike
     
    Last edited: May 27, 2013
  13. wk7au

    Thread Starter New Member

    Apr 16, 2013
    15
    0

    I will take a try on this ;)
     
  14. wk7au

    Thread Starter New Member

    Apr 16, 2013
    15
    0

    I am using 16F877A . Hmm so it seems like interrupt is the only possible way?
     
  15. MMcLaren

    Well-Known Member

    Feb 14, 2010
    759
    116
    No, you don't have to use interrupts. There are probably hundreds of other ways to accomplish the same task.

    Good luck on your project.

    Cheerful regards, Mike
     
Loading...