Sql Saturday and MVP Monday

Thanks to everyone who came to my session on F# Type Providers.  The code is found here.

Also, my article on the Eject-A-Bed was selected for MVP Mondays.  You can see a link here.

 

Controlling Servos Using Netdunio and Phidgets

As part of the Terminator program I am creating, I need a way of controlling servos to point the laser (and then gun) and different targets.  I decided to create a POC project and evaluate two different ways of controlling the servos.  As step one, I purchased a pan and tilt chassis from here

image

After playing with the servos from the kit, I decided to use my old stand-by servos that had a much higher quality and whose PWM signals I already know how to use.  With the chassis done, I needed a laser pointer so I figured why not get a shark with fricken laser?

I found one here.

image

So with the servos and laser ready to go, it was time to code.  I started with Netduninos:

public class Program { private const uint TILT_SERVO_STRAIGHT = 1500; private const uint TILT_SERVO_MAX_UP = 2000; private const uint TILT_SERVO_MAX_DOWN = 1000; private const uint PAN_SERVO_STRAIGHT = 1500; private const uint PAN_SERVO_MAX_LEFT = 1000; private const uint PAN_SERVO_MAX_RIGHT = 2000; private static PWM _tiltServo = null; private static PWM _panServo = null; private static uint _tiltServoCurrentPosition = 0; private static uint _panServoCurrentPosition = 0; public static void Main() { SetUpServos(); InputPort button = new InputPort(Pins.ONBOARD_BTN, false, Port.ResistorMode.Disabled); while (true) { if (button.Read()) { MoveServo(); } } } private static void SetUpServos() { uint period = 20000; _tiltServoCurrentPosition = TILT_SERVO_STRAIGHT; _panServoCurrentPosition = PAN_SERVO_STRAIGHT; _tiltServo = new PWM(PWMChannels.PWM_PIN_D3, period, _tiltServoCurrentPosition, PWM.ScaleFactor.Microseconds, false); _tiltServo.Start(); _panServo = new PWM(PWMChannels.PWM_PIN_D5, period, _panServoCurrentPosition, PWM.ScaleFactor.Microseconds, false); _panServo.Start(); } private static void MoveServo() { _panServo.Duration = PAN_SERVO_MAX_LEFT; Thread.Sleep(2000); _panServo.Duration = PAN_SERVO_MAX_RIGHT; Thread.Sleep(2000); _panServo.Duration = PAN_SERVO_STRAIGHT; Thread.Sleep(2000); _tiltServo.Duration = TILT_SERVO_MAX_UP; Thread.Sleep(2000); _tiltServo.Duration = TILT_SERVO_MAX_DOWN; Thread.Sleep(2000); _tiltServo.Duration = TILT_SERVO_STRAIGHT; } }

And sure enough the servos are behaving as expected

I then implemented a similar app using Phidgets.  Because the code is being executed on the PC, I could use F# to code (It does not look like the Netdunino/Microframework supports F#?)

open System open Phidgets let _servoController = new AdvancedServo() let mutable _isServoControllerReady = false let servoController_Attached(args:Events.AttachEventArgs) = let servoController = args.Device :?> AdvancedServo servoController.servos.[0].Engaged <- true servoController.servos.[7].Engaged <- true _isServoControllerReady <- true [<EntryPoint>] let main argv = _servoController.Attach.Add(servoController_Attached) _servoController.``open``() while true do if _isServoControllerReady = true then _servoController.servos.[0].Position<- 100. _servoController.servos.[7].Position<- 100. Console.ReadKey() |> ignore printfn "%A" argv 0

 

The choice then becomes using the Netduino or the Phidgets with my Kinect program.  I decided to defer the decision and use an interface for now.

type IWeaponsSystem = abstract member Activate: unit -> unit abstract member AquireTarget : float*float -> bool abstract member Fire: int -> bool

My decision about using Phidgets or Netduino is a series of trade-offs.  I can code Phidgets in C# or F# but I have to code Netduino in C#.  I would prefer to do this in F# so that makes me learn towards Phidgets.  I can put the Netduino anywhere and have it communicate via an Ethernet signal but I have to have the Phidgets wired to the PC.  Since the targeting system needs to be near the Kinect and the Kinect has to be tethered to the PC also, there is no real advantage of using the mobile Netduino.  Finally, the Phidgets API handles all communication to the servo control board for me, with the Netduino I would have to hook up a router to the Netduino and write the Ethernet communication code.  So I am leaning towards Phidgets, but since I am not sure, the interface allows me to swap in the Netduino at a later point without changing any code.  Love me some O in SOLID…

Up next, integrating the targeting system into the Terminator program.

 

 

The Eject-A-Bed: Part 2

Now that we have a way of controlling the bed via a Netduino, we need a way of controlling the Netduino.  We thought about different scenarios – hacking into an alarm clock, a phone app, some kind of light sensor, etc…  In all of these scenarios, it made sense to make the Netduino Ethernet aware so I went and bought a new Netduino plus.  The two day wait for Amazon prime reminded me how we have come full-circle with getting our goods.  I am going to re-write the lyrics from the Music Man’s Well’s Fargo Wagon to the Amazon Wagon

O-ho the Am Azon Wagon is a-comin‘ down the street,

Oh please let it be for me!

O-ho the Am Azon Wagon is a-comin’ down the street,

I wish, I wish I knew what it could be!

In any event event, with the Netduino plus, I could send signals to the Netduino to move the bed up and down.  I checked Dan Theyer’s post about how build a solid class to cover Ethernet communications and I checked out this article to get a “Hello World’ Ethernet project up and going.

I decided to start with the ground up happy path using the ‘Hello World’ project.  To that end, I added a socket instance to the project

  1. private static Socket _socket = null;

 

I then add the SetUpWebServer method like so:

  1. private static void SetUpWebServer()
  2. {
  3.     _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
  4.     IPEndPoint ipEndpoint = new IPEndPoint(IPAddress.Any, 80);
  5.     _socket.Bind(ipEndpoint);
  6.     _socket.Listen(10);
  7.     ListenForRequest();
  8. }

 

And the ListenForRequest like so:

  1. public static void ListenForRequest()
  2. {
  3.     while(true)
  4.     {
  5.         using (Socket clientSocket = _socket.Accept())
  6.         {
  7.             IPEndPoint clientIP = clientSocket.RemoteEndPoint as IPEndPoint;
  8.             EndPoint clientEndPoint = clientSocket.RemoteEndPoint;
  9.  
  10.             int bytesReceived = clientSocket.Available;
  11.             if (bytesReceived > 0)
  12.             {
  13.                 byte[] buffer = new Byte[bytesReceived];
  14.                 int byteCount = clientSocket.Receive(buffer, bytesReceived, SocketFlags.None);
  15.                 String request = new String(Encoding.UTF8.GetChars(buffer));
  16.                 HandleRequest(clientSocket, request);
  17.                 SendResponse(clientSocket, request);
  18.  
  19.             }
  20.         }
  21.     }
  22. }

You will notice a lack of  exception handling and threading.  Typically, the _socket.Accept() method should be on the main thread and then handling the message should be done on a separate thread so the _socket can get to listening the next message as fast as possible.  However, since the servo is directly tied to individual messages, I thought it was better to make the entire execution serial.  Plus, I am lazy.

In any event, once the Netduino gets a request, it then needs to adjust the servo:

  1. private static void HandleRequest(Socket clientSocket, String request)
  2. {
  3.     String[] chunkedRequest = request.Split('/');
  4.     String verb = chunkedRequest[0];
  5.     String direction = chunkedRequest[1];
  6.     String amount = chunkedRequest[2];
  7.     Int32 duration = Int32.Parse(amount);
  8.  
  9.     ActivateServoForBellows(direction, duration);
  10. }

 

And the actual controlling of the servo we have seen before:

  1. private static void ActivateServoForBellows(String direction, Int32 duration)
  2. {
  3.  
  4.     if (direction == "UP")
  5.     {
  6.         _servo.Duration = 1250;
  7.     }
  8.     else if (direction == "DOWN")
  9.     {
  10.         _servo.Duration = 1750;
  11.     }
  12.  
  13.     Thread.Sleep(duration);
  14.     _servo.Duration = 1500;
  15. }

There can be some confusion about the word “duration”.  duration with a little ‘d’ means how long the servo stays in the non-straight position – effectivly how long the bed is moving.  Duration with the big ‘D’ means the location of the servo as it rotates around the center – how far the servo moves.  When I make this ready for prime time, my covering class will fix this ambiguity because I am a big believer in domain-unique language.  I will also be copying much of Dan’s code.

In any event, I also created a response method so the requestor can see something:

  1. private static void SendResponse(Socket clientSocket, String request)
  2. {
  3.  
  4.     String[] chunkedRequest = request.Split('/');
  5.     String verb = chunkedRequest[0];
  6.     String direction = chunkedRequest[1];
  7.     String amount = chunkedRequest[2];
  8.     Int32 duration = Int32.Parse(amount);
  9.  
  10.     String response = direction + " : " + amount + " was sent.";
  11.     String header = "HTTP/1.0 200 OK\r\nContent-Type: text;charset=utf-8\r\nContent-Length: " +
  12.         response.Length.ToString() + "\r\nConnection: close\r\n\r\n";
  13.  
  14.     clientSocket.Send(Encoding.UTF8.GetBytes(header), header.Length, SocketFlags.None);
  15.     clientSocket.Send(Encoding.UTF8.GetBytes(response), response.Length, SocketFlags.None);
  16. }

 

So now when I send a browser request on my local Ethernet:

image

And sure enough, we can control the servo with my web browser

 

And then put together and using the browser in my phone:

Now if there was only a way to speed up the motor so I can launch my kid out of bed in the morning with more force….

The Eject-A-Bed: Part 1

Some people are born to greatness.  Some people have greatness thrust upon them.  Some people find greatness on Craig’s List.  A couple of months ago, I was killing some time searching for mechanical devices on Craig’s List when I ran into this:

image

So of course I picked it up and put it into the garage.  An interesting side note is that the seller got it at the UNC surplus warehouse.  Apparently, you can get really good deals on used medical and university equipment there.  I need to add it to my Christmas shopping rotation.

My daughter, Sonoma, and I first wanted to understand how the controller works.  We first thought that the controller used PWM so we hooked up our Oscilloscope to the two metal wires that travel from the controller to the bed’s motor.  We moved the controller up and down but no signal was being recorded.  Sonoma then noticed that the “wire” was a hollow tube.  Taking a wild guess, we blew down the pipe.  Sure enough, that made the bed move

image

So now we had to figure out how the controller moved air up and down the pipe.  We opened the controller and there is a small bellow that attaches to the pipe.  Press the controller on 1 side and air is forced down the pipe, press the controller on the other side and air is sucked up the pipe.

image

So we batted around ideas about how to push air up and down the pipe – ideas included using a small electric air compressor, some kind of mechanical pressure plate, etc…  We then decided to try and gluing a servo to the switch and controlling the movement that way.  However, we couldn’t figure how to attach the servo to the existing plastic switch.  So we decided to build our own switch – we used  my son’s erector set to create the harness for the bellows

WP_20130616_003

and we are now into the coding piece of it. 

Step one was to confirm that I hooked up my scope to the Netduino correctly.  I modified the Blinky code (Netduino equiv to ‘Hello World’ to add a pulse on one of the output ports:

  1. OutputPort port = new OutputPort(Pins.GPIO_PIN_D5,false);
  2. OutputPort led = new OutputPort(Pins.ONBOARD_LED,false);
  3. while (true)
  4. {
  5.     port.Write(true);
  6.     led.Write(true);
  7.     Thread.Sleep(250);
  8.     port.Write(false);
  9.     led.Write(false);
  10.     Thread.Sleep(250);
  11. }

 

Sure enough, I am seeing the pulse.

WP_20130619_001

I then wired PWM class to see if the output was what I expected:

  1. private static void ActivateServo()
  2. {
  3.     uint period = 20;
  4.     uint duration = 1;
  5.  
  6.     PWM servo = new PWM(PWMChannels.PWM_PIN_D5, period, duration, PWM.ScaleFactor.Milliseconds, false);
  7.     servo.Start();
  8.  
  9.     Thread.Sleep(Timeout.Infinite);
  10.  
  11. }

 

and sure enough I am getting a pulse every 20 milliseconds with a length of 1 millisecond.

WP_20130619_003

A word to the wise, do NOT use the Cpu.PWMChannel enum as it does not fire – use PWMChannels enum

So now it is a question of hooking this up to my servo.  It is a standard RC plan servo.  I have no idea about the period, pulse and/or duty cycle of this specific servo but it seems that there is a standard in the RC community that periods are 20 MS (as confirmed when I worked on the RC lawnmower) and the pulses are:

  • 1 MS = 180 to one direction
  • 1.5 MS = Top Dead Center
  • 2.0 MS 180 to the other direction

The problem is that the period is an uint – so I can’t set it to 1.5 MS.  I then learned about Duty Cycles where I can pass in a double and have the period adjust.  Basically:

  • 1 MS = Duty Cycle of 5%
  • 1.5 MS = Duty Cycle of 7.5%
  • 2.0 MS = Duty Cycle of 10%
    So to test this, I set up the PWM to have a 20 MS period, a 1 MS duration, and a Duty Cycle of 1.0. 
    1. uint period = 20;
    2. uint duration = 1;
    3.  
    4. PWM servo = new PWM(PWMChannels.PWM_PIN_D5, period, duration, PWM.ScaleFactor.Milliseconds, false);
    5. servo.Start();
    6.  
    7. while (true)
    8. {
    9.     servo.DutyCycle = 1;
    10. }

The problem is that this does not work.  If you use the period/duration constructor for the PWM class, you cannot set the DutyCycle property and get the desired effect.  What you have to do with that constructor is to use the duration property.  So to get the non-integral units, I needed to change the PWM.ScaleFactor to Microseconds and start thinking of things in terms of thousands.  Once I did that, I spent some time figuring out the TDC and the max left and right:

  1.  
  2. private static void TestServoFullRange()
  3. {
  4.     uint period = 20000;
  5.     uint duration = 1500;
  6.  
  7.     PWM servo = new PWM(PWMChannels.PWM_PIN_D5, period, duration, PWM.ScaleFactor.Microseconds, false);
  8.     servo.Start();
  9.     
  10.     Thread.Sleep(2000);
  11.     servo.Duration = 2500;
  12.     Thread.Sleep(3000);
  13.     servo.Duration = 500;
  14.     Thread.Sleep(3000);
  15.     servo.Duration = 1500;
  16. }

 

I then hooked up the servo to the bellow controller:

 

WP_20130619_004

 

and set up a program to activate the bellows for 2 seconds:

  1. private static void ActivateServoForBellows()
  2. {
  3.     uint period = 20000;
  4.     uint duration = 1500;
  5.  
  6.     PWM servo = new PWM(PWMChannels.PWM_PIN_D5, period, duration, PWM.ScaleFactor.Microseconds, false);
  7.     servo.Start();
  8.     Thread.Sleep(2000);
  9.     
  10.     InputPort button = new InputPort(Pins.ONBOARD_BTN, false, Port.ResistorMode.Disabled);
  11.  
  12.     Int32 numberOfPresses = 0;
  13.  
  14.     while (true)
  15.     {
  16.         if (button.Read())
  17.         {
  18.             if (numberOfPresses < 10)
  19.             {
  20.                 servo.Duration = 1250;
  21.                 Thread.Sleep(2000);
  22.                 servo.Duration = 1500;
  23.                 numberOfPresses++;
  24.             }
  25.         }
  26.     }
  27. }

and success.

Why I am dropping my Make subscription

I have been a Make magazine subscriber for over 3 years.  I really enjoyed reading it with my kids and some of projects inspired us to try things at home (Drill Cart, Lawn Bott, etc…).  About 2.5 years ago, my son wanted to build an auto-sensing mailbox for his science fair.  It was about a 5 to 1 ratio of my time (prepping the work area, making sure all of the materials were available and cut to the right length, etc…) to his time (assembling the parts, copying the computer code), but it was well worth it – he might have learned some things and, most importantly, the project reinforced his belief that making things is really cool and fun.

After the science fair, I suggested that he submit this project to Make.  He and I sent some time and wrote this into their on-line form:

Here’s an idea for a story for MAKE:
———————————————
Project title
———————————————
We made a mailbox that uses light signals to let you know when the mail arrives.
———————————————
Description
———————————————
We used the Phidget 0/0/4 interface kit and the Phidget 8/8/8 interface kit.  We wired a regular house lamp to the 0/0/4 and 2 force detectors to the 8/8/8.  We glued the force detectors to the bottom of a mailbox.  <p>
We then hooked both interface kits to the computer and wrote the code to handle the input event from the force detector and to turn on the 0/0/4 circut, which turns the lamp on.<p>
Once the external data is captured, you could do other things with the mail event – Sloan wants to hook up a camera in the mailbox and take a picture of the mailman as he put the mail in.  I think a simple tweet might be an easier next step.<p>
The project is for a beginner – takes about 4-6 hours.  There is appx 20 lines of computer code to write.<p>
Up next is to use Netduino and not use the PC….
———————————————
Submitted by
———————————————
Jamie & Sloan Dixon
———————————————

To our surprise, the Editor And Chief wrote back almost immediately:

I would like to see a video of this in action!

     Best regards,

     Mark XXXXXXX

Editor-in-chief of MAKE

We put together a quick video of what he did here and sent it in.  Within 2 days, I got this back from the editor and chief:

This is great! I’d like to assign it. I can pay $250 for the article.

I can send you an assignment letter with fee and deadline info. First, could you please email me the following information:

— A two-sentence bio describing who you are (Note – If you want your email address to run in the magazine, incorporate it into your bio):

— Your name as you wish it to be printed

— Your legal name (who we make the check out to)

— Your address

— Your phone numbers

— Your preferred email address (and if you’d like it to run in the magazine)

Here is a link to a zip file with three important documents:

 

As you can image we were pretty excited.  We filled out the forms and sent them in.  I then wrote this in:

Is there someone I can work with to make sure the article is up to your standards?  We are trying to follow your guidelines.  We have never done anything like this before (can you tell we are excited?) and want to make sure we do thing right.

Thanks!

And we got the following response:

Paul XXXXX will be your editor. He’ll make sure the article looks and reads great in the magazine. It may be a while before he gets in touch, as this is slated for Vol 32 (October) and we are working on Vol 30 right now.

Thanks!
— Mark

So then we spent a weekend writing an article for Make and sent it in.  About a month later (March 2012), I sent in a reminder asking for the status. I got this from the editor in chief: 

Got your email. Sorry for late reply. I’m cc’ing Paul so he can update you on the status of your project. We are still planning on running it.

Best

Mark

I then sent in this video of my daughter to Mark and got the following response:

This looks cool, too! I’ll ask Paul to give you an assigment.

— Mark

After more waiting (May 2012), I sent in a reminder asking for status from my editor (Paul) and I got this:

This email account is no longer being monitored: contact Gareth XXXXX at XXXXXX@oreilly.com

So I emailed the Editor and Chief

> I read the last Make – sorry we couldn’t make into the home automation

> edition. Hopefully some people enjoy the Phidget twist on the mailbox

> and the home security system. Is there anything else you need for the

> mailbox article? My daughter is almost done with school and she can

> write up the laser system – if you are still interested.

and I got this:

Yes we are running the article. I’m at a conference but when I get access to my schedule I’ll let you know which issue of Make it’s slated for.

Best,

— Mark

So then a month later (June 2012), we got this

Hi James and Sloan,

We’re preparing your article for publication and we’re wondering, did you ever re-do the Auto Mailbox using Netduinos?  It’s not practical to leave a PC out on the street, but I think if we do a Netduino version our readers will like it and build it!

Let me know ASAP please, we need to select articles for the next issue right away.

Best regards,

Keith

So then we answered the question, changed the Phidgets relay to a Netdunino and re-wrote the article.  It was a fun weekend, but it took well, the entire weekend.  We got this back:

Great work, guys!  Simple, useful, novel sensors, relay … I like it a lot, it’s a nice twist on the other smart mailboxes some makers have made. 

I have a few questions, can you help me resolve these ASAP?

1) Will Sloan be in 5th grade this fall?  Our newsstand date for this issue is in October.

So we waited until October 2012 and when it was not in the issue, I emailed Make and I got this back:

I have to rework it as a "getting started with Netduino" article.  It’s slated for Volume 33 now (on sale January 22 2013).

So more waiting until February 2013 when I got another email from Make with our article marked up

Here’s what we’re working with at the moment, I’m going to try to slip it into the mag ASAP.  Can you look it over and make sure it’s OK, and answer any questions marked in red?  

That is the last I heard and I am not really interested in pestering them any more about the article.  My son hasn’t asked about the article since February.  I assume that professional writers deal with this all of the time, but I figured Make might be different because they are not dealing with professional writers – we are professional other things that want to share our passion.  Combine their treatment of me and my son with the fact that that the most of the projects are now waaay harder than they were two years ago (so we can’t even do them), I am dropping my subscription.  I think Popular Mechanics might have a DYI section now?  If so, I will start subscribing to them…

Carolina Code Camp Material

I had a great time presenting and attending Carolina Code Camp.  Hats off the organizers for making such a large event run without a hitch.  I especially want to thank Dan Thyer and Mike Linnen for the BuilderFaire.  What a great time!  The best part of the camp was meeting such smart and innovative people.

My own presentation materials can be found here: https://github.com/jamessdixon/2013CarolinaCodeCamp

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.