Starting with .NET Micro Framework

My current project is a start here robot with .NET Micro Framework using a FEZ Domino board from GHI Electronics. The FEZ Domino is pin compatible to Arduino, but has more processing power (ARM7 core with 72MHz clock), 3 UART, 2SPI USB host and micro SD-Card support.

After building some Arduino based robots I think it's time for a change. Before I start build the robot itself some testings were needed to find out if the FEZ Domino is a worthy successor for the Arduino and can I use my existing Arduino shields.

fez-domino.jpg

First impressions:

I'm very exited how easy it is do develop under Microsoft Visual Studio. Normally I'm not so entusiastic about MS products, but VS is a great developer platform. Best thing at all is, that you can use the debugger on your real hardware using a simple USB cable. No JTAG debugger necessary.

The first program 'blinky':

My first program is the standard 'Hello World' program in the embeded worls, the blinking LED.

 

using System;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using GHIElectronics.NETMF.FEZ;

namespace Test
{
    public class Program
    {
        public static void Main()
        {
            OutputPort LED = new OutputPort((Cpu.Pin)FEZ_Pin.Digital.LED, true);

            while (true)
            {
                LED.Write(true);
                Thread.Sleep(500);
                LED.Write(false);
                Thread.Sleep(500);
            }
        }

    }
}

Really simple, very similar to the Arduino language.

Servos & Motors:

What would a robot be without motors and servos? So the next test programs show how to control a servo and DC motors. You will need an external power supply to attach a servo. It will not run with USB power.

using System;

using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using GHIElectronics.NETMF.Hardware;
using GHIElectronics.NETMF.FEZ;

namespace ServoTest
{
    public class Program
    {
        public static void Main()
        {
            Debug.Print("FEZ Domino ServoTest V0.1");
            PWM servo = new PWM((PWM.Pin)FEZ_Pin.PWM.Di9);

            while (true)
            {
              for (uint i = 1000; i<=2000; i+=250)
              {      
                servo.SetPulse(20 * 1000 * 1000, i * 1000);
                Thread.Sleep(1000);//wait for a second
              }
            }
            Thread.Sleep(-1);
        }

    }
}

One Pin (Pin9 in this case) is needed to control a servo  The SetPulse function excepts 2 parameters, first the lenght of the low impulse in nanseconds (20ms here), second the length of the high pulse (1..2ms). Thats all.

For controlling a DC Motor you will need a motor driver. Here I use the L298 compact motor driver from Solarbotics.The motors just ramps up from 0 to 99% PWM.

c:\cygwin\home\pr\RoombaRFCtrl\src\MotorTest\MotorTest\Program.cs.html using System;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using GHIElectronics.NETMF.Hardware;
using GHIElectronics.NETMF.FEZ;

namespace MotorTest
{
    public class Program
    {
        public static void Main()
        {
            Debug.Print("FEZ Domino MotorTest V0.1");
            PWM m1pwm = new PWM((PWM.Pin)FEZ_Pin.PWM.Di5);
            PWM m2pwm = new PWM((PWM.Pin)FEZ_Pin.PWM.Di6);
            OutputPort m1a = new OutputPort((Cpu.Pin)FEZ_Pin.Digital.Di4, true);
            OutputPort m1b = new OutputPort((Cpu.Pin)FEZ_Pin.Digital.Di3, true);
            OutputPort m2a = new OutputPort((Cpu.Pin)FEZ_Pin.Digital.Di7, true);
            OutputPort m2b = new OutputPort((Cpu.Pin)FEZ_Pin.Digital.Di8, true);

            while (true)
            {
                for (byte i = 1; i < 100; i++)
                {
                    m1pwm.Set(1000, i);
                    m1a.Write(true);
                    m1b.Write(false);
                    Thread.Sleep(100);
                }
                for (byte i = 1; i < 100; i++)
                {
                    m2pwm.Set(1000, i);
                    m2a.Write(true);
                    m2b.Write(false);
                    Thread.Sleep(100);
                }
            }
            Thread.Sleep(-1);
        }

    }
}

3 pins per motor were needed (1 PWM pin, 2 output pins for direction). The pwm Set function needs to parameters, first for the frequency, second for the PWM percentage. Curious, you cannot set PWM to 100%, this will throw an exception, WTF.

Multithreading:

A big highlight of NETMF is the using of threads. Which means you can run many functions quasi in parallel. You only need to pack your single programs into a function. Declare the function as a thread and start the thread. Thats all. The secret behind is the use of the 'thread.Sleep' function. This is the NETMF function for 'delay' in Arduino speech. But NETMF will not simply wait, it will bring another thread into foreground to run on the processor. The other thread will sleep in the background, until the sleep time is finished.

I am running into my first big problem with NETMF when I use the thread functionality. As you can see in the first video, the servo will not do his sweep, as he do when running as a single program. It costs me some hours to find out that this is not a thread problem. After changing the servo lib to the GHI components lib, everything works fine, as you can see in the 2nd video.

c:\cygwin\home\pr\RoombaRFCtrl\src\ThreadTest\ThreadTest\Program.cs.html using System;
using Microsoft.SPOT;
using System.Threading;
using Microsoft.SPOT.Hardware;
using GHIElectronics.NETMF.Hardware;
using GHIElectronics.NETMF.FEZ;

namespace ThreadTest
{
    public class Program
    {
        public static void Main()
        {
            Debug.Print("FEZ Domino Thread Test V0.2");
            // create thread handlers
            Thread LedThreadHandler;
            Thread ServoThreadHandler;
            Thread MotorThreadHandler;
            // create new thread objects
            // and assing to my handlers
            LedThreadHandler = new Thread(LedThread);
            ServoThreadHandler = new Thread(ServoThread);
            MotorThreadHandler = new Thread(MotorThread);
            // start the new threads
            LedThreadHandler.Start();
            ServoThreadHandler.Start();
            MotorThreadHandler.Start();
            /////////////////////////////////
            // Do anything else you like to do here
            Thread.Sleep(Timeout.Infinite);
        }

        public static void LedThread()
        {
            Debug.Print("LED Thread");
            OutputPort LED;
            LED = new OutputPort((Cpu.Pin)FEZ_Pin.Digital.LED, true);
            while (true)
            {
                LED.Write(!LED.Read());
                Thread.Sleep(250);
            }
        }

        public static void ServoThread()
        {
            int distance;
            Debug.Print("Servo Thread");

            FEZ_Components.ServoMotor servo = new FEZ_Components.ServoMotor(FEZ_Pin.Digital.Di9);
            AnalogIn GP2D12 = new AnalogIn((AnalogIn.Pin)FEZ_Pin.AnalogIn.An0);

            while (true)
            {
                for (byte i = 20; i <= 160; i += 10)
                {

                    distance = GP2D12.Read();
                    Debug.Print("Distance = " + distance.ToString());
                    servo.SetPosition(i);
                    Thread.Sleep(500);//wait for a second
                }
                for (byte i = 160; i >= 20; i -= 10)
                {

                    distance = GP2D12.Read();
                    Debug.Print("Distance = " + distance.ToString());
                    servo.SetPosition(i);
                    Thread.Sleep(500);//wait for a second
                }
            }
        }

        public static void MotorThread()
        {
            Debug.Print("Motor Thread");
            PWM m1pwm = new PWM((PWM.Pin)FEZ_Pin.PWM.Di5);
            PWM m2pwm = new PWM((PWM.Pin)FEZ_Pin.PWM.Di6);
            OutputPort m1a = new OutputPort((Cpu.Pin)FEZ_Pin.Digital.Di4, true);
            OutputPort m1b = new OutputPort((Cpu.Pin)FEZ_Pin.Digital.Di3, true);
            OutputPort m2a = new OutputPort((Cpu.Pin)FEZ_Pin.Digital.Di7, true);
            OutputPort m2b = new OutputPort((Cpu.Pin)FEZ_Pin.Digital.Di8, true);

            while (true)
            {
                for (byte i = 10; i < 100; i++)
                {
                    m1pwm.Set(1000, i);
                    m1a.Write(true);
                    m1b.Write(false);
                    m2pwm.Set(1000, i);
                    m2a.Write(true);
                    m2b.Write(false);
                    Thread.Sleep(250);
                }
                for (byte i = 99; i >= 10; i--)
                {
                    m1pwm.Set(1000, i);
                    m1a.Write(true);
                    m1b.Write(false);
                    m2pwm.Set(1000, i);
                    m2a.Write(true);
                    m2b.Write(false);
                    Thread.Sleep(250);
                }
                for (byte i = 10; i < 100; i++)
                {
                    m1pwm.Set(1000, i);
                    m1a.Write(false);
                    m1b.Write(true);
                    m2pwm.Set(1000, i);
                    m2a.Write(false);
                    m2b.Write(true);
                    Thread.Sleep(250);
                }
                for (byte i = 99; i >= 10; i--)
                {
                    m1pwm.Set(1000, i);
                    m1a.Write(false);
                    m1b.Write(true);
                    m2pwm.Set(1000, i);
                    m2a.Write(false);
                    m2b.Write(true);
                    Thread.Sleep(250);
                }
            }
        }
    }
}

The servo.setPosition function only needs 1 parameter, the desired angle.

Thats all for now.

Update 2010-08-19:

The 3rd Video shows how to make sound with the FEZ Domino. I've ported the Arduino RTTTL sketch to NETMF. Porting from C to C# is easy but a crap, better to do it from scratch the C# way.

Of cause you can do multithreading too, play a melody in a background, while ramp the motors or let some LEDs blink.

The complete code example can be found at my Google code page.

 

 

 

https://www.youtube.com/watch?v=Z5q83f3c4KQ