2
\$\begingroup\$

I am controlling a servo motor using the PIC12F675. The servo rotates in opposite directions.

I controlling the servo as follows:

if(GPIO & (1<<3))
        {
                GPIO |=(1<<2);
            __delay_ms(1);
            GPIO &=~(1<<2);

            }
            else
        {
                GPIO |=(1<<2);
            __delay_ms(2);
            GPIO &=~(1<<2);


            }

            __delay_ms(18); 

I would like to control the rate at which the servo reaches the opposite ends. I tried looking for articles related to speed control, I found it to be too complicated to control the rate of sweep. I am looking for suggestions for the same

\$\endgroup\$
11
  • 1
    \$\begingroup\$ ...and what are GPIO bits 1 and 2? \$\endgroup\$
    – Jason S
    Commented Feb 10, 2012 at 13:56
  • \$\begingroup\$ @Jason I am sorry. GPIO 2 is the output at which the servo is operated. GPIO 3 has a toggle switch. I am planning to use a potentiometer for speed control \$\endgroup\$
    – Sai
    Commented Feb 10, 2012 at 14:02
  • \$\begingroup\$ (right, I meant 2 and 3) -- We still have no idea what GPIO2 is supposed to do. You're creating a pulse... what does that do? \$\endgroup\$
    – Jason S
    Commented Feb 10, 2012 at 14:25
  • \$\begingroup\$ @JasonS I believe GPIO2 is supposed to simulate a PWM signal, in order to control the servo \$\endgroup\$
    – m.Alin
    Commented Feb 10, 2012 at 14:29
  • \$\begingroup\$ @JasonS Yes I am creating a software PWM for the servo motor \$\endgroup\$
    – Sai
    Commented Feb 10, 2012 at 14:36

2 Answers 2

7
\$\begingroup\$

Servos work by listening for 20ms, then adjusting the position based on the duration of the high pulse.

The high pulse (X below) can be between 1ms and 2ms long, with 1.5ms as the neutral or centre position.

 |------------20ms-----------|
 |-X-|                
  ___                         ___
_|   |_______________________|   |___ ...

Depending on your servo, -90° (left of centre) is usually ~1ms, 90° (right of centre) is ~2ms.

If it's at 0° and you send it a 1ms signal, it will try to turn to it's -90° position as fast as it can. The maximum speed varies from servo to servo (data sheets often specify a 0-60° time), and also depends on the voltage you give it (Hitec HS-422 at 4.8V takes 0.21 sec, at 6V takes 0.16 sec).

If you want to vary the speed (not just as fast as it can), you need to tell it to change it's position gradually.

You can do this by sending a series of position signals (each 20ms long with an X ms high pulse).

If we send 50 pulses, slowly from 1.5ms to 1ms stepping down 0.01ms each time, X will equal:

1.50ms, 1.49ms, 1.48ms, ... , 1.02ms, 1.01ms, 1.00ms

then, assuming that it can turn as rapidly as we want it to, it'll take 50 (number of 20ms signals) x 20 ms (length of pulse) = 1s to get from 0° to -90°.


Send a 20ms pulse with x ms high: (psudocode)

function send_signal (x):
    set output high
    wait x ms
    set output low
    wait (20 - x) ms

Make a servo slowly pan from left (-90°) to right (90°)

Psudocode:

loop x from 1 to 2, step 0.01
    send_signal(x)

Or if you prefer, in C (99):

for (float x = 1; x <= 2; x += 0.01) {
    send_signal(x);
}
\$\endgroup\$
2
  • 1
    \$\begingroup\$ Pretty nice answer! \$\endgroup\$
    – m.Alin
    Commented Feb 10, 2012 at 16:23
  • 1
    \$\begingroup\$ Thanks! I thought it might be useful to cover the basics since Jason's answer was quite technical \$\endgroup\$
    – Alex L
    Commented Feb 10, 2012 at 16:30
3
\$\begingroup\$

I would suggest you generalize your system to something like the following:

int T = 200   // 200*100usec = 20msec period
while(1)
{
   u = compute_next_duty_cycle()
   servo_output_on();
   __delay_100us(u)       
   servo_output_off();
   __delay_100us(T-u)
}

where servo_output_xxxx() turns the GPIO on and off. You're almost certainly going to have to improve the granularity of your delays, if you choose to use a software PWM; 1msec delay steps only give you 5% increments in PWM duty cycle for a 20msec loop.

You'll have to ramp u up and down; a fixed slew rate should suffice (more complicated trajectory control would limit acceleration as well):

 pseudocode for ramping u given a position goal ufinal and max slewrate v:

 delta = ufinal - u;
 delta = min(v, max(-v, delta));   // limit delta to +/- v
 u += delta

If you need a very slow ramp, you'll have to internally use a high-resolution state for u, and then divide/shift to get your output command:

 delta = ufinal - u;
 delta = min(v, max(-v, delta));   // limit delta to +/- v
 u += delta
 uout = u >> 8;  // or >> 16 or whatever
 servo_output_on();
 __delay_100us(uout)       
 servo_output_off();
 __delay_100us(T-uout)
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.