Driving Hobby Servos

From Dynomotion

Jump to: navigation, search

Hobby RC Servo modules like this can be controlled from KFLOP.


HobbyServo.png


Most Servo Modules require a 1-2ms pulse at 50Hz to command their position.  


HobbyServoPulse.png


This is somewhat difficult to generate with normal PWM generators as high Time resolution is required at a slow rate.  KFLOP Hardware PWM generators have a minimum frequency of 254Hz.


A KFLOP User C Program can be used to enable and disable a PWM generator in a way that one pulse is output only every N PWM cycles.  PWM gernerator #1 is sacrificed to generate a fixed long PWM pulse that the C Program can monitor to count cycles as well as determine when the next PWM cycle for all the PWM generators will begin.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
#include "KMotionDef.h"
 
void ServiceHobbyPWM(void);
 
int ncycles, v1, v2;
 
main()
{
    int LowClocks, scaler=150;
    float PWMPeriod, BaseFreq=16.6667e6, PulseGap=20e-3, SafetyTime=200e-6;
    // Set base PWM to be high for entire time less 200us
     
    LowClocks = SafetyTime * BaseFreq / scaler;
    PWMPeriod = 256.0*scaler/BaseFreq;
    ncycles = PulseGap/PWMPeriod;
    printf("PWM Period = %fus\n", PWMPeriod*1e6);
    printf("Low Clocks = %d\n", LowClocks);
    printf("Skip Cycles = %d\n", ncycles);
     
    SetBitDirection(26,1);  // define bit as an output
    ClearBit(26);
    SetBitDirection(27,1);  // define bit as an output
    ClearBit(27);
    SetBitDirection(28,1);  // define bit as an output
    ClearBit(28);
     
    FPGA(IO_PWMS_PRESCALE) = scaler;    // divide clock by 256 (250Hz)
    FPGA(IO_PWMS) = 255-LowClocks;      // Mostly high pulse
    FPGA(IO_PWMS+1) = 1;            // Enable
    ClearBit(26);
     
    v1 =  800e-6 * BaseFreq / scaler;  // set Pulse time
    v2 = 1700e-6 * BaseFreq / scaler;  // set Pulse time
 
    printf("PWM settings v1 = %d v2 = %d\n", v1,v2);
 
    for (;;)
    {
        ServiceHobbyPWM();
    }
}
 
 
void ServiceHobbyPWM(void)
{
    static int i=0;
    static WaitLevel=0;
     
    if (!WaitLevel) // waiting for low?
    {
        if (!ReadBit(26)) // yes is it low?
        {
            WaitLevel=1;  // yes, change state
            if (++i == ncycles)  // count mostly high pulses, special cycle?
            {
                FPGA(IO_PWMS+2) = v1;   // Pulse size
                FPGA(IO_PWMS+3) = 1;    // Enable
                FPGA(IO_PWMS+4) = v2;   // Pulse size
                FPGA(IO_PWMS+5) = 1;    // Enable
                i=0;
            }
            else
            {
                FPGA(IO_PWMS+3) = 0;   // Disable
                FPGA(IO_PWMS+5) = 0;   // Disable
            }
        }
    }
    else
    {
        if (ReadBit(26)) // no, waiting for high, is it high?
        {
            WaitLevel=0; // yes, change state
        }
    }
}

The code above prints this:


PWM Period = 2303.995425us
Low Clocks = 22
Skip Cycles = 8
PWM settings v1 = 88 v2 = 188


It generates the timing shown below.  Note the yellow trace is the reference PWM used by the C Program to count the cycles.  Two PWM pulses are emitted every 8 cycles.  The cyan trace shows a pulse width of 780us (specified in the program to be 800us) with a period of 18.5ms.  The magenta trace shows a pulse width of 1.7ms (specified in the program to be 1700us) with a period of 18.5ms.


HobbyServoTwoPulses.png