Internet of things: Lego-robotar, Azure och Raspberry Pi

Active Solution där jag arbetar är ett väldigt kunskapsintensivt företag. Det vi gör är ju att erbjuda vår kompetens och långa erfarenhet till våra kunder för att hjälpa dem skapa lösningar. Då vill det till att vi håller våra verktyg vässade, hela tiden är på tårna och lär oss mer om ny teknik, nya metoder och förbättrar processer.

Under förra året beslutade vi oss därför för att satsa på något lite annorlunda vad gäller kompetensutveckling. Vi valde att skapa ett antal forsknings- och utvecklingsprojekt, för att tillsammans arbeta med saker som kanske ligger lite utanför det vi gör i vanliga kundprojekt. Hela tiden med målet att dela med oss av våra lärdomar och att arbeta tillsammans med nya roliga tekniker och metoder.

Det här resulterade i flera intressanta projekt med spännande resultat, bl.a. en Team Dashboard som en Chrome Cast-applikation med uppdateringar från Visual Studio Online som kan berätta när du tagit sönder bygget (självklart med Javascript-baserad talsyntes :-) samt att vi blev det första företaget i Sverige som migrerade en EPiServer site i produktion till Azure Web Sites. Det har varit grymt kul, inspirerande och lärorikt att ta del av de olika projekten under våra gemensamma luncher där de olika teamen fått berätta om sina lösningar i “lightning talk”-stil.

LegoMindstormsRobot

Ett av projekten har gått ut på att koppla ihop Lego Mindstorms-robotar med Raspberry Pi-datorer och kontrollera dessa över Internet via Azure.
Kring det här har vi även byggt ett spel som vi har tagit med oss på ett antal konferenser, TechDays, TechX och nu senast den fantastiskt trivsamma Swetugg-konferensen. Vi har fått väldigt många förfrågningar om vi inte kan lägga upp en beskrivning av hur vi integrerat robotarna med Raspberry Pi och hur vi styr dem, så här kommer en beskrivning av lösningen.
All kod som körs i robotarna finns tillgänglig på GitHub.
Själva robotarna består av tre delar:
1. Lego Mindstorms. Delar ihopbyggda från Legos EV3-modell av Mindstorms, i vår egen-patenterade proffsiga Robot-design.
2. Raspberry Pi B med Wifi-dongel. Wifi-donglarna har vi märkt är i lite varierande kvalitet och funkar olika bra med Raspberry Pi. Asus Wifi-donglar har vi märkt fungerar bra med Raspberry Pi B.
3. BrickPi. BrickPi är ett specialbyggt kort för att styra Lego-robotens motorer och läsa av sensorer via en Raspberry Pi. Går att beställa från Robotshopen.se http://www.robotshopen.se/se/art/brickpi-starter-bundle.php
Styrningen av Robotarna sker via en vanlig webbsida som körs i en Azure Web Site. Via Ajax-anrop så skickas meddelanden ut via en SignalR hub. http://signalr.net/
I Raspberry Pi:n kör vi sedan en Node.Js-server som använder ett SignalR-paket för att koppla upp sig via webbsockets mot Azure-siten. När ett meddelande tas emot via SignalR så använder vi ett färdigt C-bibliotek från BrickPi för att kommunicera styrmeddelanden till motorerna.
Här finns en film som beskriver lösningen:

Vi använder även Microsofts Azure SDK för Node.js för att kontinuerligt skicka ”heatbeat”-meddelanden till Azure ServiceBus – för att kontrollera att robotarna lever och är igång.
Från början trodde vi att styrningen av robotarna också skulle kunna hanteras genom att skicka meddelanden via Azure ServiceBus. Det visade sig dock att fördröjningen blev alldeles för lång när vi gjorde så. Det beror inte på ServiceBus:en i sig (den har en fördröjning som mäts i millisekunder) utan berodde på implementationen i Node.js-paketet. I många fall kan man ju leva med en fördröjning på ett par sekunder, men det funkade dåligt för att styra robotar…

Runt vårt Robot-scenario så byggde vi också ett spel: CandyPush. Det går ut på att låta två robotar tävla mot varandra för att putta ner så mycket godis i två hål i en spelplan som möjligt under tidsbegränsning. Sedan har vi två USB-kopplade vågar under spelplanen som mäter hur mycket godis som puttats i. Vågarnas resultat skickas upp i Azure Storage för att avgöra resultatet.

CandyPush in action!

För att prata med vågen används Hid Library, ett generellt bibliotek för kommunikation med USB-enheter. Kod och info finns på github, github.com/mikeobrien/HidLibrary; NuGet-paket under namnet Hid Library.
Enhetens identitet utgörs av tillverkarens Vendor ID samt modellens Product ID. Förutom dessa måste man känna till formen på data som levereras från enheten. I övrigt är kommunikationen enkel.
I nedanstående demokod scannar vi efter anslutna enheter som matchar vågens identitet. Vi initierar kommunikationen och anropar ReadReport med en callback som anropas då vågen har ett värde att rapportera (vilket sker ca 2 ggr per sekund). I call back-metoden ReadHandler kan aktuellt mätvärde läsas ut.

public class Program
{
    private static HidDevice device;

    private static void Main(string[] args)
    {
        ConnectScale();
        Console.ReadLine();
    }

    private static void ConnectScale()
    {
        const int DymoVendorId = 0x0922;
        int[] M5ProductIds = { 0x8005 };

        device = HidDevices.Enumerate(DymoVendorId, M5ProductIds).First();
        // We assume at least one connected scales.

        device.OpenDevice();
        device.ReadReport(ReadHandler);
    }

    private static void ReadHandler(HidReport report)
    {
        if (report.ReadStatus == HidDeviceData.ReadStatus.Success)
        {
// Byte 4-5 contains current scales reading
            var weight = BitConverter.ToUInt16(report.Data, 3);
Debug.WriteLine("Vikt: {0} g", weight);
        }

        device.ReadReport(ReadHandler); // Poll again 
    }
}

Här hittar du koden för att integrera Lego-robotarna med Azure.