NETMF Joystick Shield Driver

Adding a joystick to your NETMF device is easy with the Sparkfun joystick shield and the following code.

/*
Copyright 2011 William Stacey
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. 
*/
using System;
using Microsoft.SPOT;
using GHIElectronics.NETMF.Hardware;
using Microsoft.SPOT.Hardware;
using GHIElectronics.NETMF.FEZ;

namespace RobotJoystickRemote
{
    /// <summary>
    /// Joystick class to control Sparkfun's Joystick Shield kit.
    /// http://www.sparkfun.com/products/9760
    /// This class uses the GHI Button class found here:
    /// http://www.ghielectronics.com/downloads/FEZ/Component/FEZ_Components_Button.cs
    /// </summary>
    public class JoystickShield
    {
        public event FEZ_Components.Button.ButtonPressEventHandler UpClick;
        public event FEZ_Components.Button.ButtonPressEventHandler DownClick;
        public event FEZ_Components.Button.ButtonPressEventHandler LeftClick;
        public event FEZ_Components.Button.ButtonPressEventHandler RightClick;
        public event FEZ_Components.Button.ButtonPressEventHandler JoystickClick;

        AnalogIn xPin;
        AnalogIn yPin;
        FEZ_Components.Button joyClick;
        FEZ_Components.Button up;
        FEZ_Components.Button down;
        FEZ_Components.Button left;
        FEZ_Components.Button right;

        public JoystickShield()
        {
            // Hookup Joystick.
            xPin = new AnalogIn(AnalogIn.Pin.Ain0);
            yPin = new AnalogIn(AnalogIn.Pin.Ain1);
            xPin.SetLinearScale(-100, 101);
            yPin.SetLinearScale(-100, 101);
            joyClick = new FEZ_Components.Button(FEZ_Pin.Interrupt.Di2);
            joyClick.ButtonPressEvent += (FEZ_Pin.Interrupt pin, FEZ_Components.Button.ButtonState state) =>
            {
                var ev = JoystickClick;
                if (ev != null)
                    ev(pin, state);
            };

            // Hookup push buttons.
            up = new FEZ_Components.Button(FEZ_Pin.Interrupt.Di4);
            down = new FEZ_Components.Button(FEZ_Pin.Interrupt.Di5);
            left = new FEZ_Components.Button(FEZ_Pin.Interrupt.Di6);
            right = new FEZ_Components.Button(FEZ_Pin.Interrupt.Di3);
            up.ButtonPressEvent += (FEZ_Pin.Interrupt pin, FEZ_Components.Button.ButtonState state) =>
            {
                var ev = UpClick;
                if (ev != null)
                    ev(pin, state);
            };
            down.ButtonPressEvent += (FEZ_Pin.Interrupt pin, FEZ_Components.Button.ButtonState state) =>
            {
                var ev = DownClick;
                if (ev != null)
                    ev(pin, state);
            };
            left.ButtonPressEvent += (FEZ_Pin.Interrupt pin, FEZ_Components.Button.ButtonState state) =>
            {
                var ev = LeftClick;
                if (ev != null)
                    ev(pin, state);
            };
            right.ButtonPressEvent += (FEZ_Pin.Interrupt pin, FEZ_Components.Button.ButtonState state) =>
            {
                var ev = RightClick;
                if (ev != null)
                    ev(pin, state);
            };
        }

        /// <summary>
        /// Gets joystick X position.
        /// </summary>
        public int X
        {
            get { return xPin.Read(); }
        }

        /// <summary>
        /// Gets joystick Y position.
        /// </summary>
        public int Y
        {
            get { return yPin.Read(); }
        }

        /// <summary>
        /// Sets the X and Y scale of the joystick.
        /// Default scale is -100 minimum to 101 maximum. Max scale is non-inclusive.
        /// </summary>
        public void SetScale(int minX=-100, int maxX=101, int minY=-100, int maxY=101)
        {
            xPin.SetLinearScale(minX, maxX);
            yPin.SetLinearScale(minY, maxY);
        }

        /// <summary>
        /// Gets current X and Y position of joystick.
        /// </summary>
        public JoyPosition Position
        {
            get
            {
                JoyPosition jp = new JoyPosition();
                jp.X = xPin.Read();
                jp.Y = yPin.Read();
                return jp;
            }
        }
    }

    public struct JoyPosition
    {
        public int X;
        public int Y;
        public override string ToString()
        {
            return "X: " + X + " Y: " + Y;
        }
    }
}

Have fun.

Posted in .Net Micro Framework, C#, FEZ, Robotics | Tagged , , , , ,

Saleae Logic Review

Received my Saleae Logic today. Smile

I did not think I would ever need one. But had an issue with PWM and controlling a servo from my FEZ board. Something like a logic analyzer is really the only way to drill down and get hard evidence and stop guessing what is happening.  Can save hours of testing.  Anyway, I like bullet points, so here are the pros and cons.

Pros

  • Nice looking hardware. Compact and elegant design.
  • Nice software. It takes a lot of work to make a really good simple abstraction.  And it shows.
  • Capture and timing accuracy seems right on as one would hope.
  • The micro-hook probes seem are nice quality.  The wires connectors are a bit hard to press into the hooks.
  • Nice case to store everything in.

Cons:

  • Software crashed a few times first couple times I used it. No message, just closed.  Once doing an Export and once after setting another trigger on a different line. The 1.5 Beta seemed to solve those issues.
  • Limited documentation.  Not even a quick start on how to hook it up.  If this is your first analyzer, it is not obvious how to get started.  The wire connector is not keyed, so you can incorrectly connect it (which Spark Fun says could damage it).  Also, Black wire is normally ground, but not on this harness.  Grey is ground and Black is pin 1. Very strange choice considering we have black (or even green) burnt into our brains as GND.  I could guess that you need to hook ground wire to a ground on your circuit and one test wire to what you are testing – but it would be helpful to at least supply a one page document in the product to verify your assumptions instead of hoping your right.
  • They do have some limited documentation for the software online, but it is pretty thin.  For such a well thought out device, the lack of good docs seem odd.
  • Some choices on UX not in my taste.  For example, it would seem natural to click on square wave thinking you will get the details of the wave on the right and to make those details “sticky”.  Instead, clicking on anything on the wave zooms down.  There is no way to make wave details “stick” on right if you want to screen capture the details of that period.

Despite some of the minor cons, this is a great little integrated device and worth the $149.  If you don’t already have one, I would put on your wish list.

Posted in .Net Micro Framework, FEZ, Testing | Tagged , , ,

Simple servo control from FEZ

If you just need the easiest possible way to hook up a servo to FEZ, it does not get easier then this.  No breadboards, mosfets, or resistors.  Just hook the servo wires into the fez and control.  If your servo has a normal 3 pin female connector, then just get some male-to-male jumper wires and your done.  Use a PWM pin to control the servo’s signal wire.  The 5v on the FEZ should be enough for small to medium servos.  If you need more, then power from external supply.

const uint PERIOD = 20 * 1000 * 1000; // 20ms is 20000000ms(nanoseconds)
const uint LowUs = 690;   // min range of servo as microseconds.
const uint HighUs = 2422; // max range of servo as microseconds.

/// <summary>
/// Set servo position.
/// </summary>
/// <remarks>
/// The standard range for 180degree servos is 1 to 2 milliseconds high in a 20ms period, with
/// neutral in the middle at 1.5ms. Exact range varies between servos. Find exact range with
/// a servo tester or PWM range testing.
/// </remarks>
/// <param name="servo">PWM pin of servo control.</param>
/// <param name="highUs">High time in microseconds (e.g. 1500us is 1.5ms or neutral)</param>
public static void SetSimpleServo(PWM servo, uint highUs)
{
    Debug.Print("Set servo nanoseconds: " + highUs);
    servo.SetPulse(PERIOD, highUs * 1000);
}

public static void SetSimpleServoByDegree(PWM servo, byte degree, bool invert)
{
    if (degree < 0 || degree > 180)
        throw new ArgumentOutOfRangeException("angleDegree");

    if (invert)
        degree = (byte)(180 - degree);
            
    // Scale degree (0-180) to servo position. Mult 1K to get to nanoseconds.
    uint pos = ScaleRange((uint)degree, 0, 180, LowUs, HighUs) * 1000;
    servo.SetPulse(PERIOD, pos);

    Debug.Print("Degree:" + degree + " Position ms:" + pos / (double)1000000);
}
        
private static uint ScaleRange(uint oldValue, uint oldMin, uint oldMax, uint newMin, uint newMax)
{
    return ((oldValue - oldMin) * (newMax - newMin) / (oldMax - oldMin)) + newMin;
}

-William

Posted in .Net Micro Framework, C#, FEZ, Robotics, Servo | Tagged , , , ,

Add some sound to your FEZ

So a Piezo speaker is not loud enough for your project, but you don’t want to add an amplifier and external power supply?  How about going middle of the road.  Use your raw 3.3v supply and add the Pololu 2W speaker.  Nice sounding and cheap enough.  Just add a MOSFET and drive sound from a PWM pin.

Tiny Speaker Recipe:

  1. Pololu 2W speaker $3.49 http://www.pololu.com/catalog/product/1258
  2. FEZ or Arduino $40 http://tinyclr.com
  3. MOSFET breakout $3.95 http://www.sparkfun.com/products/10256 
  4. 6 Ohm resistor $0.10
  1. Hook your speaker to Device side of MOSFET.
  2. Add 6 ohm resistor between 3.3v out and positive terminal on MOSFET.
  3. Ground MOSFET to FEZ GND pin.
  4. Bring a PWM pin over to MOSFET Gate pin.
  5. Add code to your project to drive PWM to make notes. I used driver here http://code.tinyclr.com/project/149/tone-buzzer-driver/

The resistor is doing two things.  First, it limits the amount of current that the speaker can draw to under .55amps.  Without it, the MCU will just keep resetting in a loop because the speaker drawing all ~1.5amps of current.  Second, the 6 ohm limits the max watts to just under 2Watts so you don’t over drive the speaker.  Plenty of amps left over for MCU.

This is by no means is a sound demon.  However, it is plenty good for most small projects and better quality sound then a standard tin-can Piezo.

Now crank those Mario notes. Smile

Posted in .Net Micro Framework, C#, FEZ, Sound | Tagged , , ,

Roll Your Own Servo Tester

So you want to test the range of your servos.  Who needs a servo tester/driver?  If you have a MCU, a POT and some wire, you can make one.

Servo Tester Recipe:

  1. Fez MCU (code written for NETMF)
  2. POT or TrimPot
  3. Some jumper wire
  4. Servo to test
  5. Breadboard
  6. 5v-7v battery to power servo.

Hook your pot, servo and wires up as shown.  Pick a free PWM port on your FEZ.  Also pick a free Analog port.  We will use the analog port to read relative pot level.  We will scale the AIn port reading to match the Ms (microsecond) range we want to see for the 0-180 deg range of the servo.  Now just add the following code:

public static void ServoTester()
{
    // Config pin and scale for reading POT voltage.
    AnalogIn ai = new AnalogIn(AnalogIn.Pin.Ain5);
    FEZ_Components.Button but = new FEZ_Components.Button(FEZ_Pin.Digital.LDR);

    // Initially, set your scale a bit beyond servo limits.
    // Kick range numbers down till buzzing stops at each end.
    uint FREQ = 20 * 1000 * 1000; // 20ms Freq.
    int lower = 690 * 1000;
    int upper = 2422 * 1000;
    int neutral = (upper - lower) / 2;
    Debug.Print("Lower: " + lower + " Upper: " + upper + " Neutral: " + neutral);
    ai.SetLinearScale(lower, upper);

    // Set servo line pwm.
    PWM servo = new PWM(PWM.Pin.PWM5);

    uint min = uint.MaxValue;
    uint max = 0;
    while (but.GetState() != FEZ_Components.Button.ButtonState.Pressed)
    {
        // Read pot and set servo.
        uint newPos = (uint)ai.Read();
        if (newPos < min)
        {
            min = newPos;
            Debug.Print("Min: " + min + " Max: " + max);
        }
        if (newPos > max)
        {
            max = newPos;
            Debug.Print("Min: " + min + " Max: " + max);
        }
        servo.SetPulse(FREQ, newPos);
    }
}

Turn everything on.  As you turn the POT back and forth, the value will be converted to a scaled High-Time that we use for SetPulse().  The servo should turn CCW or CW to the value.  Set your linear scale to be a bit outside the edges of your servo’s limits at first.  Get limits from its’ datasheet.  Many common servos are in 1-2ms range with neutral at 1.5ms.  However, I am testing a Medium sized servo from SparkFun.  It is a DGServo from China, so it seems to have different limits.  However, using this simple test rig, I found the limits are around .69-2.43ms.  You know you hit the servos’ edge when it starts buzzing.  It should be able to hold max positions without buzzing.  After you find the values, you may want to back them off a little more to add a small margin.  Going past the limits will drain more current and heat up servo needlessly.

That’s it.  Hope that may be useful.

Posted in .Net Micro Framework, C#, FEZ, Motors, Servo | Tagged , , , | 4 Comments

NETMF electronic speed controller (ESC)

Here is a basic speed controller if you want to replace your RC receiver with your .Net Micro Framework  controller.  I don’t have working ESC to test with currently, so this may need some tweaking.  Please let me know if see a change needed.

using System;
using System.Runtime.CompilerServices;
using System.Threading;
using GHIElectronics.NETMF.Hardware;
using Microsoft.SPOT;

namespace MicroFezRobot
{
    // Common ESC Interface.
    interface IESC
    {
        int Speed { get; set; }
    }

    /// <summary>
    /// Electronic Speed Controller (ESC) driver.
    /// </summary>
    public partial class SpeedController : IESC, IDisposable
    {
        PWM pwm;
        byte rampDelay;
        int currentSpeed;
        byte armPeriod;
        int minSpeed;
        int maxSpeed;
        const int Hz = 20 * 1000 * 1000; // 20ms as nanoseconds.
        const int MIN = 1 * 1000 * 1000;
        const int MAX = 2 * 1000 * 1000;

        /// <summary> 
        /// Create a SpeedController.
        /// </summary>
        /// <param name="pin">The speed pin on ESC.</param> 
        public SpeedController(PWM.Pin pin, byte rampDelay=1, byte armPeriod=1, int minSpeed=MIN, int maxSpeed=MAX)
        {
            if (minSpeed < 0 || (maxSpeed < minSpeed))
                throw new ArgumentOutOfRangeException("maxSpeed");
            this.rampDelay = rampDelay;
            this.armPeriod = armPeriod;
            this.minSpeed = minSpeed;
            this.maxSpeed = maxSpeed;
            pwm = new PWM(pin);
            
            // Set speed to neutral and wait armPeriod to arm/start ESC. ESC specific.
            SetSpeed(0);
            Thread.Sleep(armPeriod);
        }

        /// <summary>
        /// Gets or sets the controller speed. Valid values of -100 to 100 inclusive.
        /// </summary>
        public int Speed
        {
            get { return currentSpeed; }
            set { SetSpeed(value); }
        }

        [MethodImpl(MethodImplOptions.Synchronized)]
        private void SetSpeed(int value)
        {
            Debug.Print("\nSetSpeed: " + value + " CurrentSpeed:" + currentSpeed );
            if (value > 100)
                value = 100;
            if (value < -100)
                value = -100;

            // Gradually ramp up/down speed until we match given value.
            int rampDir = (value > currentSpeed) ? 1 : -1;
            
            while (value != currentSpeed)
            {
                uint newSpeed = (uint)ScaleRange(currentSpeed, -100, 100, this.minSpeed, this.maxSpeed);
                pwm.SetPulse(Hz, newSpeed);
                currentSpeed = currentSpeed + rampDir;
                Debug.Print("New Speed:" + currentSpeed);
                Thread.Sleep(rampDelay);
            }
        }

        [MethodImpl(MethodImplOptions.Synchronized)]
        public void Dispose()
        {
            Stop();
            pwm.Dispose();
        }

        /// <summary>
        /// Stop ESC. Check datasheet.
        /// </summary> 
        private void Stop()
        {
            SetSpeed(0);
            pwm.Set(false);
        }

        /// <summary>
        /// Scale a number within a source range to a new range and return new scaled value.
        /// </summary>
        private static int ScaleRange(int oldValue, int oldMin, int oldMax, int newMin, int newMax)
        {
            return ((oldValue - oldMin) * (newMax - newMin) / (oldMax - oldMin)) + newMin;
        }
    }
}
Posted in .Net Micro Framework, C#, FEZ, Motors, Robotics | Tagged , , , ,

Connect COM port(s) to FEZ via USB

DB9 serial ports on laptops are becoming extinct.  But you may want to add another COM port to your FEZ so as not to interfere with the Debug interface. You can use CDC virtual COM port, but then you need to Break and Run at the right spot to stop the Debug channel load the CDC VCOM driver.  Fortunately, you can just side-step the issue completely by connecting another COM port and use that for FEZ-to-PC serial communication.  But you say, “hey, I still want to use USB”.  That ok, just get a FT232 board (or make one).  For $14 bucks, this one will work great http://www.sparkfun.com/products/718

Now just read the datasheet of your MCU to figure out what pins your COM port uses.  On the Domino, I have used COM1 and COM2.  COM1 does not have CTS/RTS, so use XON/XOFF (software) handshaking. COM2 does have hardware handshaking, so you can also hookup CTS/RTS to the FT232.  A Fritzing diagram is below for COM2 on the Domino. Note the photo looks like a Panda as I did not have a Domino Fritzing part.  You should be able to change easily per your MCU pin configuration.

Recipe:

1) Get at FT232 breakout board.  You can’t really make them cheaper, so save time and buy one from Sparkfun.  Also get a mini-USB cable if you don’t already have one. http://www.sparkfun.com/products/598

2) Solder the headers on the sides as needed.  Pins facing down so you can also plug board into breadboard if needed.  You can use these pins as just jumper wire connect points also if you don’t need BB.

3) Plug USB cable into board and into computer.  Windows should automatically recognize and install driver and a new COM port. Write down the new COM port (i.e. COM22) as you will need this later when writing your PC client code.

4) When you know your FT232 has installed and works, unplug it and connect your header pins to your FEZ pins using diagram 1 as a guide.

5) Write your code on the FEZ to Send/Receive data.  Here is a sample:

public static void TestCom2()
{
    SerialPort com1 = new SerialPort("com2", 9600, Parity.None, 8, StopBits.One);
    com1.Handshake = Handshake.RequestToSend;
    com1.Open();

    Debug.Print("Waiting.");
    string reply = ReadLine(com1);
    Debug.Print("From PC:" + reply);

    string s = "Hello\n";
    byte[] ba = Encoding.UTF8.GetBytes(s);
    com1.Write(ba, 0, ba.Length);
    Debug.Print("Sent");
}

6) Write your code on the PC. Here is sample:

private void button1_Click(object sender, EventArgs e)
{
    SerialPort sp = new SerialPort(this.textBox1.Text, 9600, Parity.None, 8, StopBits.One);
    sp.Handshake = Handshake.RequestToSend; // XOnXOff;
    sp.Open();
    sp.Write("Hello from pc.\n");
    string reply = sp.ReadLine();
    this.richTextBox1.AppendText(reply+"\n");
}

7) Now just finish your project and “Run what you brung”!

–William Stacey

Posted in .Net Micro Framework, C#, FEZ, Robotics, Serial | Tagged , , , , ,