Browse By

NodeJs + Socket.IO + Arduino + SerialPort = Epic win :)

Τις τελευταιες μερες ασχοληθηκα στον ελευθερο μου χρονο με το να γνωρισω μερικα δημοφιλη npm πακετα που συνοδευουν και γενικως κανουν πιο ευκολο το development εφαρμογων με βαση το NodeJs. Αυτο που εφτιαξα παρακατω μπορει να εχει πρακτικη εφαρμογη σε περιβαλλοντα που υπαρχει καποιος server και θελουμε τα δεδομενα που ερχονται την σειριακη του(μπορει να ειναι και USB θυρα) να γινονται διαθεσιμα στο web.

Στο μικρο αυτο project μεσω του controller arduino παιρνουμε την θερμοκρασια μεσω ενος TMP36 σενσορα και την κανουμε διαθεσιμη σε εναν webserver φτιαγμενο σε NodeJs. Το καλυτερο εδω ειναι οτι οι πληροφοριες που παιρνει ο χρηστης της υπηρεσιας ειναι real time. Και οταν λεω real time το εννοω! Οχι οπως οταν συνδεσουμε το arduino σαν http client σε μια υπηρεσια οπως το http://www.cosm.com. Οσοι το δοκιμασατε θα ειδατε καποια delay, καθως και περιορισμους 20 δευτερολεπτων. Για την συνδεση του server side κωδικα με τον browser ωστε να εχουμε αμμεση ανανεωση χρησιμοποιηθηκε το φοβερο πακετο socket.io. Link με πληροφοριες σχετικα με τα πακετα θα βρειτε στο τελος αυτου του post.  Αν αναλογιστειτε ποσες συσκευες εχουν serial port για εξοδο των δεδομενων θα καταλαβετε οτι το πληθος των εφαρμογων ειναι μεγαλο(εχω δει μεχρι και πιεσομετρο με σειριακη!).

Ας ξεκινησουμε με τα βηματα που ακολουθησα και τις λυσεις σε καποια απο τα προβληματα που αντιμετωπισα:

Αρχικα θα πρεπει να φτιαξουμε το μικρο κυκλωμα για την συνδεση του σενσορα στο Arduino. Μπορειτε να ακολουθησετε το παρακατω σχεδιο:

sensorwiring

 

To photocell απλα αγνοηστε το! Χρησιμοποησα αυτη τη συνδεσμονολογια που περιλαμβανει και την χρηση του ARef γιατι δινει ακριβεστερες μετρησεις. Αφου λοιπον κανετε τις συνδεσεις θα εχετε κατι σαν και αυτο:

Arduino_TMP36

Ωρα για μερικες σειρες κωδικα στο Arduino IDE 🙂

#define aref_voltage 3.3 
int tempPin = 1; 
void setup(void) { 
    Serial.begin(9600); 
    analogReference(EXTERNAL);
} 
void loop(void) { 
    int tempReading = analogRead(tempPin); 
    float voltage = tempReading * aref_voltage; 
    voltage /= 1024.0; 
    float temperatureC = (voltage - 0.5) * 100 ; 
    Serial.println(temperatureC); 
    delay(1000);
}

Οπως βλεπετε αυτο που κανουμε ειναι στο setup ανοιγουμε τη συνδεση με τη σειριακη και μετα στο loop καθε ενα δευτερολεπτο μετραμε την ταση στον σενσορα, πολλαπλασιαζουμε με το aref voltage και αυτο που θα βρουμε το διαιρουμε με το 1024. Τελος αφαιρουμε 0.5 , που ειναι το offset και πολλαπλασιαζουμε το αποτελεσμα με το 100. Αυτη ειναι και η θερμοκρασια σε βαθμους κελσιου την οποια περναμε στην σεριακη. Σημαντικη λεπτομερια! Επειδη στη συνεχεια θα χρησιμοποιησουμε το module seriaport αυτο μπορει να διαβασει μια τιμη και μετα να διαβασει την επομενη σε νεα γραμμη. Οποτε προσεξτε οτι αντι για Serial.print() χρησιμοποιησα το Serial.println() που μετα απο καθε μετρηση βαζει την επομενη σε νεα γραμμη. Για να βεβαιωθουμε οτι ολα δουλευουν σωστα μπορουμε να πατησουμε το κουμπακι Serial Monitor στο Arduino IDE και αν ολα πηγαν καλα θα δειτε την τιμη της θερμοκρασιας καθε ενα δευτερολεπτο. Εναλλακτικα μπορειτε να χρησιμοποιησετε και καποιο serial reader utility. Ενα απο αυτα που χρησιμοποιω ειναι αυτο.

serialreader

Για δοκιμη πιασετε το αισθητηριο και θα δειτε την θερμοκρασια να μεταβαλλεται προς τα πανω. Τελειωσαμε λοιπον με τα δεδομενα. Τωρα αυτα θα πρεπει να κανουμε διαθεσιμα σε πραγματικο χρονο στο web. Για να το πετυχω αυτο, χρησιμοποιησα το δημοφιλες NodeJS. Το NodeJs ειναι μια πλατφορμα που για να κατανοηθει χρειαζεται να αφιερωθει χρονος. Ομως να ειστε σιγουροι οτι θα σας αποζημιωσει. Επιγραμματικα θα πω, πως προκειται για ενα περιβαλλον στο οποιο μπορουμε να γραψουμε javascript κωδικα για τη μερια του σερβερ. Ειναι γραμμενο σε C και στηριζεται στην μηχανη της Google V8. Ειναι η ιδια μηχανη που χρησιμοποιει και ο chrome browser. Χρησιμοποιει μοντελο event-driven πραγμα που σημαινει οτι ειναι ιδανικο για εφαρμογες πραγματικου χρονου. Μια απλη αναζητηση στο google για tutorials θα σας επιστρεψει εκαντονταδες links. Σε συνδιασμο με το nodejs θα χρησιμοποιησουμε τα module socket.io καιserialport. Αφου εγκαταστησετε με επιτυχια το nodejs μετα δημιουργηστε ενα φακελο που θα περιεχει το project. Κατοπιν απο Dos κονσολα μεσα σε αυτον τον φακελο πληκτρολογειστε:

1) npm install express Αυτο ειναι ενα πακετο που χρειαζεται για την κατασκευη του web server. Πληροφοριες εδω.

2) npm install socket.io Αυτο ειναι το πακετο για διαβαζουμε και να γραφουμε WebSockets

3) npm install serialport Αυτο ειναι το πακετο με το οποιο μπορουμε να γραφουμε και να διαβαζουμε την σειριακη. ΠΡΟΣΟΧΗ, για να εγκατασταθει με επιτυχια αυτο το πακετο χρειαζεται να υπαρχει εγκατεστημενο στον υπολογιστη σας το Visual Studio 2010 με τις επιλογες για C++ καθως και η Python εκδοση 2.7 εγκατεστημενη στο folder c:\Python27 , διαφορετικα θα παιρνετε μυνηματα λαθους!

Στο φακελο που δημιουργησατε προηγουμενως θα πρεπει τωρα να υπαρχει ενας νεος φακελος με το ονομα node_modules. Εκει βρισκονται αυτα που μολις εγκαταστησαμε. Στη συνεχεια δημιουργουμε ενα νεο καταλογο και μεσα του φτιαχουμε την html σελιδα μας. Εγω εκτος απο την θερμοκρασια προσθεσα και ενα jquery Plugin το οποιο δινει και γραφικη παρασταση. Τα δεδομενα τα παιρνει απο ενα array. Επισης προσθεσα μετα τα 2 λεπτα, καθε δευτερολεπτο να αφαιρει την παλαιοτερη μετρηση απο το array. Μπορειτε να χρησιμοποιησετε το παρακατω, μονο που θα πρεπει να αλλαξετε την πορτα στο socket αν επιθυμειτε καποια αλλη ή αν ειναι ηδη κατελλημενη η 5000 στο δικο σας υπολογιστη.

<!DOCTYPE html>
<html>
    <head>
        <script src="/socket.io/socket.io.js"></script>
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script>
        <script type="text/javascript" src="http://people.iola.dk/olau/flot/jquery.flot.js"></script>
    </head>
    <body>
        <p>Current temp is: <span id="currentTemp"></span></p><br>
        <div id="chart1" style="width:600px;height:300px;"></div>           
        <script>
            // open a connection to the serial server:
            var socket = io.connect('http://localhost:5000');
            array = [];
            count = 0;
             // when you get a serialdata event, do this:
            socket.on('serialEvent', function (data) {
                var element = document.getElementById('currentTemp');                                       
                d2 = [count++,parseFloat(data.value)];

                if(array.length > 120){array.shift();} 
                else{array.push(d2);}

                if(data.value <27){$(element).css("color","blue");} 
                else{$(element).css("color","red");}

                element.innerHTML = data.value;     
                $.plot($("#chart1"), [array]);
            });                 
        </script>
    </body>
</html>

 

Και τωρα το πιο σημαντικο κομματι! Περναμε σε μια μεταβλητη την σειριακη μας πορτα, στην δικια μου περιπτωση το usb το βλεπει σαν COM3(μπορειτε να το δειτε απο το Arduino IDE). Κατοπιν δημιουργουμε τον webserver που ακουει στην πορτα 5000 και με την βοηθεια του express σε καθε request στελνουμε το index.html που φτιαξαμε νωριτερα. Το socket.io λοιπον σε καθε νεο connection αναλαμβανει να περασει τα “φρεσκα” δεδομενα” της σειριακης στον client και κραταει την συνδεση ανοικτη στελνοντας συνεχεια την τιμη της θερμοκρασιας.Αποθηκευστε το στο καταλογο που φτιαξατε νωριτερα με ενα ονομα της επιλογης σας και με καταληξη *.js

var serialport = require("serialport"),             // include the serialport library
    SerialPort  = serialport.SerialPort,            // make a local instance of serial
    app = require('express')(),                     // start Express framework
    server = require('http').createServer(app),     // start an HTTP server
    io = require('socket.io').listen(server);       // filter the server using socket.io

var serialData = {};                                // object to hold what goes out to the client

server.listen(5000);                                // listen for incoming requests on the server

console.log("Listening for new clients on port 5000");

// open the serial port. Change the name to the name of your port, just like in Processing and Arduino:
var myPort = new SerialPort("COM3", { 
    // look for return and newline at the end of each data packet:
    parser: serialport.parsers.readline("\r\n") 
});

// respond to web GET requests with the index.html page:
app.get('/', function (request, response) {
  response.sendfile(__dirname + '/index.html');
});

// listen for new socket.io connections:
io.sockets.on('connection', function (socket) {
    // if there's a socket client, listen for new serial data:  
    myPort.on('data', function (data) {
        // set the value property of scores to the serial string:
        serialData.value = data;
        // for debugging, you should see this in Terminal:
        console.log(data);
        // send a serial event to the web client with the data:
        socket.emit('serialEvent', serialData);
    });
});

Αν ολα πηγαν καλα , τοτε πληκτρολογηστε στο ανοικτο dos παραθυρο node serialServer.js (αυτο ειναι το ονομα που εδωσα εγω στο αρχειο) και ανοιγωντας τον browser σας και πηγαινοντας στηνhttp://localhost:5000 θα δειτε αυτο:

result

Αν αποφασισετε να το κανετε διαθεσιμο και στο web τοτε αυτο που μενει ειναι να ανοιξετε στον router σας την αντιστοιχη πορτα και χρησιμοποιησετε καποια υπηρεσια οπως το DynDNS.Ελπιζω να σας αρεσε το συγκεκριμενο project και να το εφαρμοσετε στις δικες σας ιδεες!

Reference links:

Special Thanks to Tom Igoe!

Leave a Reply

Your email address will not be published. Required fields are marked *