Capturing PWM with a Netduino (Part 2)

So I decided even if I can’t figure out what the signals are saying, at least I could capture the PWMs as they came into the Netduino.

Knowing that the PWM pulse occurs every 20MS, the duration of the pulse determines the direction of the servo.  For example, if the pulse is 2MS, the servo should move up.  If the pulse is 1MS the servo should move down.

The Netduino allows you to capture the leading edge of the pulse and the trailing edge of a pulse.  Theoretically. if you measure the leading edge of pulse 1 to the leading edge of pulse 2, the difference will always be 20MS.    However, the difference between the trailing edge of the pulse and the leading edge of the next pulse (or the trailing edge of the next pulse) will vary depending on the RC receiver’s signal.

That means I need a way to capture the 2 edges of the pulse, calculate the difference between them, and then do something with that information (altering a servio’s position for example).

My first approach was like this

public static void Main()
{

    InterruptPort inputPort = new InterruptPort(Pins.GPIO_PIN_D0,
        true, Port.ResistorMode.Disabled, Port.InterruptMode.InterruptEdgeBoth);

    inputPort.OnInterrupt += new NativeEventHandler(inputPort_OnInterrupt);

    Thread.Sleep(3000);
}

static long leadingEdge = 0;
static void inputPort_OnInterrupt(uint data1, uint data2, DateTime time)
{
    if (data2 == 1)
    {
        leadingEdge = time.Ticks;
    }
    else
    {
        long pulseWidth = (time.Ticks - leadingEdge)/1000;
        Debug.Print(pulseWidth.ToString());
    }
}

With the results like this:

image

I expected to see 20MS, not 14.  In any event, I then ran the same program and moved the stick up and down.  Sure enough, the pulse modulated.

image

However, it did not modulate in discrete values.  Rather, it rose and dropped as if it was analog.

I then added this code to evaluate the rise and fall of the PWM:

 

static OutputPort outputPort = new OutputPort(Pins.ONBOARD_LED, false);

public static void Main()
{
    InterruptPort inputPort = new InterruptPort(Pins.GPIO_PIN_D0,
        true, Port.ResistorMode.Disabled, Port.InterruptMode.InterruptEdgeBoth);

    inputPort.OnInterrupt += new NativeEventHandler(inputPort_OnInterrupt);

    Thread.Sleep(Timeout.Infinite);
}

static long leadingEdge = 0;
static long priorPulseWidth = 0;
static void inputPort_OnInterrupt(uint data1, uint data2, DateTime time)
{
    if (data2 == 1)
    {
        leadingEdge = time.Ticks;
    }
    else
    {
        long currentPulseWidth = (time.Ticks - leadingEdge) / 1000;
        long pulseWidthChange = currentPulseWidth-priorPulseWidth;
        if(pulseWidthChange > 0)
        {
            outputPort.Write(true);
        }
        if(pulseWidthChange < 0)
        {
            outputPort.Write(false);
        }

        priorPulseWidth = currentPulseWidth;
    }
}

Sure enough, the LED went on when I pushed the stick up and turned off when I pulled the stick down – mostly.  I think that I need to smooth out the calculation so that I don’t capture each pulse – perhaps every 5th pulse. 

But the behavior is sporadic.  When I pull the stick down and leave it there, the LED sometimes blinks on and off.  Then it hit me as I was writing this – the reason why is that once the stick says still, the pulse still fires and the value is greater than the value when I was pulling the stick down.  Also, when the stick gets “pinned” to either Max up or down, the LED blinks rapidly.  I need to investigate that more.

 

So I then hooked up 4 digital outputs to represent the up/down of the throttle and the left/right of the turn. 

image

I then added the following code to set up the 2 inputs and the 4 outputs:

static OutputPort _forwardPort = new OutputPort(Pins.GPIO_PIN_D8, false);
static OutputPort _backwardsPort = new OutputPort(Pins.GPIO_PIN_D9, false);

static OutputPort _leftPort = new OutputPort(Pins.GPIO_PIN_D10, false);
static OutputPort _rightPort = new OutputPort(Pins.GPIO_PIN_D11, false);

public static void Main()
{
    InterruptPort leftStickPort = new InterruptPort(Pins.GPIO_PIN_D0,
        true, Port.ResistorMode.Disabled, Port.InterruptMode.InterruptEdgeBoth);
    leftStickPort.OnInterrupt += new NativeEventHandler(leftStickPort_OnInterrupt);

    InterruptPort rightStickPort = new InterruptPort(Pins.GPIO_PIN_D1,
        true, Port.ResistorMode.Disabled, Port.InterruptMode.InterruptEdgeBoth);
    rightStickPort.OnInterrupt += new NativeEventHandler(rightStickPort_OnInterrupt);

    Thread.Sleep(Timeout.Infinite);
}

I then added the following code for the left stick:

static long rightStickLeadingEdge = 0;
static void rightStickPort_OnInterrupt(uint data1, uint data2, DateTime time)
{
    if (data2 == 1)
    {
        rightStickLeadingEdge = time.Ticks;
    }
    else
    {
        long currentPulseWidth = (time.Ticks - rightStickLeadingEdge) / 1000;

        switch (currentPulseWidth)
        {
            case 18:
                {
                    _forwardPort.Write(true);
                    _backwardsPort.Write(false);
                    break;
                }
            case 17:
                {
                    _forwardPort.Write(true);
                    _backwardsPort.Write(false);
                    break;
                }
            case 16:
                {
                    _forwardPort.Write(true);
                    _backwardsPort.Write(false);
                    break;
                }
            case 15:
                {
                    _forwardPort.Write(true);
                    _backwardsPort.Write(false);
                    break;
                }
            case 14:
                {
                    _forwardPort.Write(false);
                    _backwardsPort.Write(false);
                    break;
                }
            case 13:
                {
                    _forwardPort.Write(false);
                    _backwardsPort.Write(true);
                    break;
                }
            case 12:
                {
                    _forwardPort.Write(false);
                    _backwardsPort.Write(true);
                    break;
                }
            case 11:
                {
                    _forwardPort.Write(false);
                    _backwardsPort.Write(true);
                    break;
                }
            default:
                {
                    _forwardPort.Write(false);
                    _backwardsPort.Write(false);
                    break;
                }
        }
    }
}

Sure enough, moving the stick and down saw the expected response from the LEDs.  I went to test the right/left stick

and that also acted as expected.  I then hooked up a relay module to the output and used a higher-voltage power source (the relay can go up to 250) and a small light.  Here is the final rig (note that I am using the Netduino 5.0V for the power source of the RC receiver):

image

Sure enough, I can now control standard household electrical currents using a RC transmitter and receiver.

Leave a comment