Tuesday, January 17, 2012

Project updates - 16 Jan

Over the last week or so, we've had some fun and made some progress on a couple projects.

Last week we went to the Omaha Maker's Group meeting.  This was our first trip down there.  It's a nice location full of neat projects and interesting people.  We watched a fun presentation on an attempt at a high-altitude rocket build and launch.  The kids have been asking when the next one is scheduled for.  :)

Speaking of the OMG, we're going there on the 7th of Feb to demo our little robot and maybe a couple other Netduino projects (maybe HID and MQTT).

On the robot front, we got our new IR sensor in the other day.  Tonight Steven got the new sensor installed and then I added some button support (on/off) and re-calibrated the code for the new sensor (a bit more near-sighted (our choice) than the last one we used).  I then did a brief write-up on how everything works and a pin-out chart in case something happens in-route - because he's taking the robot to school to show his in-school robotics class!



On the MQTT front, I got the publishing bit all done and am now in the process of adding subscription support.  I really need to get this completed in the next couple of days, because I have a NeTV en-route to me and I know as soon as I get that - I'll be up all night fooling with that instead of MQTT.  :)

We ran to Harbor Freight this weekend and got our free screw-driver set plus picked up a $8 rotary tool and a couple bins for when my Futurlec order gets here.

Finally, we've got Valentine's Projects to get to work on as soon as the parts for them arrive.  I need to find a place in town that can do plastic work - we could use some cut plastic sheet to dress our projects up a bit...

I have so many projects going on - we'd better get some snow soon.  :)

But that's it for us, for now.

Monday, January 2, 2012

Half-Baked MQTT Publisher for Netduino Plus

UPDATE:  This has been moved to GitHub: https://github.com/danielan/NetduinoMQTT

I received a Netduino Plus for Christmas this year. So, I needed a project to put this to work. After working my way through the O'Reilly/Make book, "Getting Started with the Internet of Things" book, I decided to implement a MQTT publisher for my Netduino Plus.

Now, MQTT is a really cool protocol that can be used for all sorts of things and supports all sorts of neat features.  This isn't that sort of program.  :)

All this does, in a weak way, is connect to a message broker, publish a message without QoS and then disconnect.  This is NOT how you should do it.  This doesn't work for long topics, long messages, etc.  It doesn't retry if there is a problem, etc.

This is intended only for my use - ultimately publishing a temperature from a sensor over and over - but I'm back to work tomorrow, so this will probably be idle for some time.

I hope this helps - but don't use it expecting it to be useful without more work. 

So, enough disclaimers... :)

MQTT

I learned of MQTT from this post at AdaFruit: http://www.adafruit.com/blog/2011/11/08/ibm-open-sources-potential-internet-of-things-protocol/

And the learned more from this Series on "ReadWriteWeb":
http://www.readwriteweb.com/hack/2011/11/ibms-andy-piper-negotiating-th.php
http://www.readwriteweb.com/hack/2011/11/ibms-andy-piper-part-2-how-mqt.php
http://www.readwriteweb.com/hack/2011/11/ibms-andy-piper-part-3-the-tax.php

There's also a web site at: http://mqtt.org/

And the quite useful official specification is over here: http://public.dhe.ibm.com/software/dw/webservices/ws-mqtt/mqtt-v3r1.html

Demoing MQTT

To use MQTT you need a "Broker" - I used "Really Small Message Broker" from here: https://www.ibm.com/developerworks/community/groups/service/html/communityview?communityUuid=d5bedadd-e46f-4c97-af89-22d65ffee070

To demo this, download rsmb from there and unzip it.  Then open 4 "cmd" windows and make your working directory in the folder "windows" (assuming Windows) in the rsmb directory you just extracted.

In one cmd window run: broker.exe

In the next cmd window run: stdinpub.exe test
In another cmd window run: stdoutsub.exe test --clientid one
In the last cmd window run: stdoutsub.exe test --clientid two

"test" is the name of our topic. The client ids are necessary because, I assume, there is a bug in the windows stdoutsub.exe binary - the names are supposed to be unique by default*, but aren't.

* "Help" for stdoutsub.exe: "--clientid <clientid> (default is hostname+timestamp)"  But in reality they seem to default to "stdout-subscriber" - I'll see if I can find someone to report this to.

Now, if you type something into the stdinpub.exe window - you should see it show up in the two stdoutsub.exe windows.  This is, simplistically, what MQTT is for (lightweight publisher/subscriber model comms).

(These windows will also be useful to see if our program is working.)

The Code

There's a library available for MQTT on all sorts of languages and software, but I couldn't find anything for the Netduino Plus (although maybe the .NET one would work?)

It would probably be a good idea to read through the standard first.  I used hex for flags and numbers where they made more sense.  I started to do constants, but didn't get finished yet...

(Note - the flags are easier to decipher if you remember that for hex you use 4 bits per hex digit.)

While keeping in mind that this is not appropriate for actual use....

Here is the code for the "library".

using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using Microsoft.SPOT;
using Socket = System.Net.Sockets.Socket;

namespace Netduino_MQTT_Client_Library
{
    static class Constants
    {
        public const int MQTTVERSION = 3;
    }

    public static class MQTTClient
    {
        // From Sample Code (SockClient.cs) Copyright Microsoft
        public static Socket ConnectSocket(String server, Int32 port)
        {
            // Get server's IP address.
            IPHostEntry hostEntry = Dns.GetHostEntry(server);

            // Create socket and connect to the server's IP address and port
            Socket socket = new Socket(AddressFamily.InterNetwork,
                SocketType.Stream, ProtocolType.Tcp);
            socket.Connect(new IPEndPoint(hostEntry.AddressList[0], port));
            return socket;
        }
        // End of Microsoft Copyright sample code

        public static void ConnectMQTT(Socket mySocket, String clientID)
        {

            int index=0;
            byte[] buffer = null;
            buffer = new byte[16 + clientID.Length];
            // Fixed Header (2.1)
            buffer[index++] = 0x10; // Fixed header flags
            buffer[index++] = (byte)(14 + clientID.Length); // Remaining Length
            // End Fixed Header
            // Connect (3.1) 
            // Protocol Name
            buffer[index++] = 0;       // String (MQIsdp) Length MSB
            buffer[index++] = 6;       // Length LSB
            buffer[index++] = (byte)'M';  // M
            buffer[index++] = (byte)'Q';  // Q
            buffer[index++] = (byte)'I';  // I
            buffer[index++] = (byte)'s';  // s
            buffer[index++] = (byte)'d';  // d
            buffer[index++] = (byte)'p';  // p
            // Protocol Version
            buffer[index++] = Constants.MQTTVERSION;
            // Connect Flags
            buffer[index++] = 0x02;
            //Keep alive (20 seconds)
            buffer[index++] = 0;     // Keep Alive MSB
            buffer[index++] = 20;    // Keep Alive LSB
            // ClientID
            buffer[index++] = 0;                        // Length MSB
            buffer[index++] = (byte)clientID.Length;    // Length LSB
            for (var i = 0; i < clientID.Length; i++) 
            {
                buffer[index++] = (byte)clientID[i]; 
            }
            mySocket.Send(buffer, index, 0);

        }

        public static void PublishMQTT(Socket mySocket, String topic, String message)
        {

            int index = 0;
            byte[] buffer = null;
            buffer = new byte[4 + topic.Length + message.Length];
            // Fixed header
            //      Publish (3.3) fixed header flags
            buffer[index++] = 0x30;
            //      Remaining Length (variable header + payload)
            buffer[index++] = (byte)(2 + topic.Length + message.Length);
            // End of fixed header 
            // Variable header (topic)
            buffer[index++] = 0;                   // Length MSB
            buffer[index++] = (byte)topic.Length;  // Length LSB
            // End of variable header
            for (var i = 0; i < topic.Length; i++)
            {
                buffer[index++] = (byte)topic[i];
            }
            // Message (Length is accounted for in the fixed header)
            for (var i = 0; i < message.Length; i++)
            {
                buffer[index++] = (byte)message[i];
            }
            mySocket.Send(buffer, buffer.Length, 0);
        }

        public static void DisconnectMQTT(Socket mySocket)
        {
            byte[] buffer = null;
            buffer = new byte[2];
            buffer[0] = 0xe0;
            buffer[1] = 0x00;
            mySocket.Send(buffer, buffer.Length, 0);
        }
    }
}

Here is the code to use this library (Don't forget to change to your IP (where broker.exe is running)).


using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using SecretLabs.NETMF.Hardware;
using SecretLabs.NETMF.Hardware.NetduinoPlus;
using Netduino_MQTT_Client_Library;

namespace NetduinoMQTT
{
    public class Program
    {
        public static void Main()
        {
            // This is where you would do your work
            Socket mySocket = MQTTClient.ConnectSocket("192.168.1.1",1883);
            MQTTClient.ConnectMQTT(mySocket,"tester123");
            MQTTClient.PublishMQTT(mySocket, "test", "testme12");
            Thread.Sleep(1000);
            MQTTClient.DisconnectMQTT(mySocket);
        }
    }
}

Deploy this to your Netduino Plus and you should see the message, "testme12" appear in your stdoutsub.exe windows (and some connection messages in your broker.exe window).


To Do

If you wanted to use this for anything, probably at a minimum you should account for connect failures, longer topics, longer messages, maybe QoS, maybe authentication, maybe use the SSL version, etc.  Since it is a "library" it would be good to support the whole subscription thing, etc.

Conclusion

So, that's it!  VERY simplistic MQTT publishing from a Netduino Plus to RSMB.  When I get around to setting up my temperature sensor maybe I'll make this a bit more robust and re-visit this.

I hope you enjoyed this post.

Saturday, December 31, 2011

Netduino "Robot"

Over the past month or so my son and I built a "Robot" with our Netduino.



Parts:

Physical Assembly:

First, we mounted the 8 pin headers upside down in the motor driver breakout like this:


We did this so that we could easily mount this into the breadboard and see the pin descriptions.  We didn't insert it all of the way into the breadboard - rumor has it that these get hot - although ours does not seem to.

Next, we assembled the robot chassis.  Some of the parts have tight tolerances, but everything fit together fine.

We attached the battery holders to the lower platform and the Netduino and breadboard onto the top platform.  Then we mounted the IR sensor to the "front" (the end with the 2 wheels).

Do NOT mount the IR sensor like it is in the picture above.  Our first day we managed to drive it under a kitchen cabinet and it cracked the circuit board of the IR sensor.  :(  When our replacement arrives, I think we will mount it on the lower deck so it is safer.

Wiring:

We wired it like this:

IR sensor yellow wire to the Netduino AIN0
IR sensor black to ground on Netduino
IR sensor red to Netduino 5V

9 volt power to Netduino
6 volt power black to ground on Netduino (via the RadioShack connector and some hookup wire)
6 volt power red to motor driver VM (same as above)

Netduino to TB6612FNG breakout
DIO0 = Standby (This needs to be high (true))
DIO1 = AIN1
DIO2 = AIN2
DIO5 = PWMA
DIO6 = PWMB
DIO8 = BIN1
DIO9 = BIN2
Ground to ground

TB6612FNG breakout to motors
AO1 = Red motor lead (Right)
AO2 = Black motor lead (Right)
BO2 = Black motor lead (Left)
BO1 = Red motor lead (Left)

Code:

Now it was time to code a little bit.  As usual, the path was paved by the great authors in the communities at Netduino.com (http://forums.netduino.com/index.php?/forum/4-netduino/).

We used the library provided from this post: http://forums.netduino.com/index.php?/topic/493-netduino-tankbot/page__view__findpost__p__3665 from user ajcg1973.


using System;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using SecretLabs.NETMF.Hardware;
using SecretLabs.NETMF.Hardware.Netduino;
// make sure you include the library - ours was (messily) inline

namespace IRRobot
{
    public class Program
    {
        static AnalogInput analogInput = new AnalogInput(Pins.GPIO_PIN_A0);
        public static void Main()
        {

            OutputPort stby = new OutputPort(Pins.GPIO_PIN_D0, true);
            AjbMotorTB6612FNG motors = new AjbMotorTB6612FNG(Pins.GPIO_PIN_D5, Pins.GPIO_PIN_D1, Pins.GPIO_PIN_D2, Pins.GPIO_PIN_D6, Pins.GPIO_PIN_D8, Pins.GPIO_PIN_D9);
            motors.Motor1Direction = AjbMotorTB6612FNG.MotorDirection.Forward;
            motors.Motor1Speed = 50;  // Set the motor to 50% speed
            motors.Motor2Direction = AjbMotorTB6612FNG.MotorDirection.Forward;
            motors.Motor2Speed = 50;  // Set the motor to 50% speed
            while (true)
            {
                Thread.Sleep(250); // pause to gather analog sample
                int analogValue = 1024 - analogInput.Read();
                Debug.Print(analogValue.ToString());
                if (analogValue < 550)
                {
                    motors.Motor1Direction = AjbMotorTB6612FNG.MotorDirection.Reverse;
                    motors.Motor1Speed = 30;  // Set the motor to 30% speed
                    motors.Motor2Direction = AjbMotorTB6612FNG.MotorDirection.Forward;
                    motors.Motor2Speed = 30;  // Set the motor to 30% speed
                    Thread.Sleep(1000);
                    motors.Motor1Direction = AjbMotorTB6612FNG.MotorDirection.Forward;
                    motors.Motor1Speed = 50;  // Set the motor to 50% speed
                    motors.Motor2Direction = AjbMotorTB6612FNG.MotorDirection.Forward;
                    motors.Motor2Speed = 50;  // Set the motor to 50% speed
                }

            }

        }

    }
}

This still needs some tweaking.  Or a whole re-write.  :)  But it shows how to drive the motors using ajcg1973's library and how to read the IR sensor.  We flipped forward and reverse in the library - this might mean we are driving backwards.  :)

You might want to watch the IR output values for a bit to get a feel for what it can see - ours is a bit far sighted so it runs into things some times. :) 

Conclusion:

This was a fun project.  The kids loved the little robot as it scooted across the floor avoiding obstacles.  We'll probably enhance our software and try some different sensors over the next few weeks.

We hope that you enjoyed this post.

References:

Original library code: http://forums.netduino.com/index.php?/topic/493-netduino-tankbot/page__view__findpost__p__3665
We got wiring help from this thread at the Netduino forum: http://forums.netduino.com/index.php?/topic/2396-control-dc-motor-with-dual-motor-driver/