Nodejs ile Arduino

 

Konu içeriğinde anlatılan Nodejs Seri Port kütüphanesi yenisi ile güncellenmiştir. Konu sonundaki github linkinden yeni yazılıma ulaşabilirsiniz. 

Merhabalar…

Bu konuda nesnelerin interneti kapsamında çokça kullanılmaya başlanan Nodejs’ e, Nodejs ile server kurmaya ve kütüphaneler yardımı ile basit bir uygulamaya yer vereceğiz. Öncelikle Node JS’ in ne olduğuna değinelim.

Node JS Javascprit V8 Motoru’ nu kullanan non-blocking yapıda bir V8 kütüphanesidir. Non- Blocking yapıda olmasının diğer platformlara bir çok avantajı ve dezavantıjı bulunmaktadır. Bu yapının en önemli avantajı işlemi bitirmeye çalışan Thread’ ın işlemci performansını en iyi şekilde kullanmaya çalışmasıdır ki bu da bize gömülü sistemlerde çokça avataj sağlar. Ancak non blocking yapı, iki işlemi paralel gerçekleştirmek istediğimiz zaman iki ayrı javascript dosyası oluşturup bunları birbiri ile ilişkilendirerek kullanmamıza neden olacaktır. Bunu uygulamayı aşağıda gördüğünüzde üstte kurduğum cümle kadar zor olmadığını göreceksiniz.. :)

Eğer Local ağda çalışacaksınız Node Js gerçekten çok kolay kullanıma sahip bir yapıdır. Ancak Local ağ dışında bir sunucuya veri aktarmak için sadece Nodejs kullanmaya çalışıyorsanız bence yanlış yoldasınız. Global ağ kullanımı için internet iletişim protokollerini çok iyi biliyor olmanız gereklidir. Oysaki firebase gibi cloud tabanlı yapıları Nodejs ile birlikte kullanmak bu iş için son derece kolaylık sağlayacaktır.

Şimdi gelelim local ağda kullanmak üzere yapacağımız basit bir uygulamaya. Bu uygulamada bazı framework’ ler kullanacağız. Peki ya framework nedir? Framework kütüphanelerin biraz daha büyük halidir. Kütüphane bir iş için özelleşmişken framework bir çok işi bir arada yapabilir. Buna en basit örnek internette de sıkça karşılaşabileceğiniz sınıfların bir araya gelmesi ile oluşan yapı namespace ise, namespace’ lerin bir ara gelmesi ile oluşan yapı framework’ tur. Peki biz hangi framework leri kullanacağız?

 -Express

 -Socket.io

Serialport

Express bir backend framework’ udur. Oluşturacağımız sitenin backend kısmı yani server kısmı bu framework içerisinde bulunur. Bu framework olmadan da biz server’ i oluşturabilirdik. Ancak işlemlerimiz biraz daha karmaşık ve zor olurdu. Detaylı dokümantasyona buradan ulaşabilirsiniz.

Socket.io ,frontend ile backend’ in haberleşmesini sağlayan framework’ tur. Alternatifleride bulunmaktadır. Adın da anlaşıldığı gibi server ile client arası socket oluşturur.

Serialport ise seri port üzerinden bağlı olan bir cihaz ile oluşturacağımız server’ ın haberleşmesini sağlayan framework’ tur.

Kütüphanelerden de anlaşıldığı gibi yapmak istediğimiz uygulama arduino gibi seri port ta bağlı bir denetleyiciden okuğumuz veriyi web sitesine yazacağız.

Arduino için gereken koda linkten ulaşabilirsiniz. Bunu siz ihtiyacınıza göre değiştirebilirsiniz.

Şimdi gelelim javascript kısmına. Öncelikle gerekli tanımlamarı yapalım.

var express = require('express');		//express framework unu çağırdık
var app = express();
var http = require('http').Server(app);         //http serverı çağırıp express a bağladık
var path = require('path');                     //serverin kurulu olduğu dizine ulaşmak için 
                                                //bu kütüphaneyi kullandık
var socket = require('socket.io')(http);        //socket' imizi http server a bağladık
var port = 3000;                                //kullanacağımız portu belirledik

Bu işlemlerden bi aşağıdaki fonksiyonu kullanmalıyız.

app.use(express.static(path.join(__dirname)));

Bu fonksiyon server’ ın bulunduğu dizinde html dosyasının istediği ek dosyaları (css, resim ve alt klasörler) client’ e gönderir. Daha sonra client’ in serverdan hangi dizini istediğini ve ona göre html dosyası gönderme işlemini yapalım.

app.get('/', function(req ,res) {
	res.sendfile (__dirname + '/index.html');   //index.html dosyasını client' e '/' 
                                                    //isteği üzerine gönderdik
});

Bu fonksiyon yardımı ile adres çubuğuna “www.elektrobot.net/” yazıldığında gönderilecek html dosyasını belirleyebiliriz.

 Bunu yaptıktan sonra port’ u bulup Arduino’ ya bağlanalım. Bu aşamadan sonra işlemler kalıp olarak ilerlediği için parça parça anlatmayacağım. Kodu biraz incelemeniz halinde yorum satırları yardımı ile de rahatça anlaşılabilir.

Bazı arkadaşlardan portun açılmaıdğı şeklinde bazı geri bildirimler aldım. Bunun en büyük sebebi portu açabilmek izin vermiyor olmanızdır. Bu izni bu şekilde porta verebilirsiniz.

sudo chmod a+x /dev/tty*

NOT: Bu nodejs de kullanılan bir fonksiyon değil bash komutudur. Yani ubuntu işletim sisteminde terminalden girmelisiniz!!! En sondaki tty* ifadesi tüm portlara izin verilmesini sağlar. Arduino’ nun bağlı olduğu portu biliyorsanız tty* ifadesini port ismi ile değiştirerek sadece o porta izin verilmesini sağlayabilirsiniz.

Şimdi koda geçebiliriz.

var com = require("serialport"); 	//seri port kütüphanesini çağırdık
var portName = "/dev/ttyACM0";		//default port adı
var serialPort;

var ledDurum = false;


//var olan portları arayıp sonuncuya bağlandık
//eğer bağlantı hatası alıyorsanız bu kısmı silin ve portu kendiniz girin
com.list(function (err, ports) {
	ports.forEach(function(port) {
    //console.log(port.comName);

    	portName = port.comName;
	});
});

//eğer üstteki kodda hata ile karşılaşırsanız burayı kendinize göre değiştirin
//portName = /dev/ttyACM0

//portun bulunabilmesi için 1 sn gecikme verdik
setTimeout(function(){
	serialPort = new com.SerialPort(portName, {
		baudrate: 9600,
		parser: com.parsers.readline('\r\n')
	});

	//hata varsa hatayı gösterdik yoksa porta bağlandık
	serialPort.on('open',function(error) {
		if(error)
			console.log("failed to open" + error);
		else
    		console.log('Port open');
  	});
}, 1000);

 Ben uygulamada bütün kodu tek bir javascript dosyasında toplayacağım. Ancak siz daha büyük projeler de bu dosyası ayrı bir javascript dosyasında çalıştırarak sanki bir kütüphaneymiş gibi server’ ın kuluru olduğu javascript dosyasından çağırabilirsiniz. Bunun için “module.exports” ile fonksiyonları dışarıdan kullanılabilir hale getirebilirsiniz ki benim tavsiyem bu şekilde kullanamızdan yanadır. Çünkü sürekli olmasını istediğiniz işlemlerde (döngüler) bütün işlemi tek bir javascript toplamanız sorun oluşturacaktır. Çünkü yukarıda da belirttiğimiz Node Js non-blolcking yapıdadır ve siz herhangi bir sonsuz döngü tanımlarsanız diğer işlemler aksayacaktır.

 

Bağlantımızı yapıp veri alış verişine hazır hale geldikten sonra socket bağlantısını oluşturabiliriz. Bunu aşağıdaki şekilde basitçe yapabiliriz.

socket.on('connection', function(io){
	console.log("Biri baglandı");
	//led butonuna basılmışsa led durumunu değiştir
	io.on('_led', function(){		//client ten gelen _led isimli event
		console.log("Butonuna basıldı");
		if(serialPort.isOpen())
		{
			serialPort.write("#\n");	//arduino ya led yanması için # gönderdik
			ledDurum = !ledDurum;
			io.emit('_ledRes', ledDurum == true ? "Led yandı" : "Led sondu");
		}
	});

	//pot butonuna basılmışsa pottaki değeri okuyup geri dön
	io.on('_pot', function(){		//client ten gelen _pot isimli event
		console.log("Butona basıldı");
		if(serialPort.isOpen())
		{
			serialPort.write("$\n");	//arduino ya A0 dan veri okuması için $ gönderdik
			serialPort.on('data', function(_data)
			{
				io.emit('_potRes', _data);		//client e geri arduino dan data
												//gönderdik
			});			
		}
	})
});

Not: Örnekte “$” ve ” #” işaretleri ile arduino’ ya işlem yaptırma benim arduino için yazdığım kod ile ilgilidir. Siz bunları kendinize göre değiştirebilirsiniz(1,2, a, s, !, * …. yapabilirsiniz). Yani siz arduino’ ya benim verdiğim programı yüklemezseniz yada ona benzer bir iletişim kurmazsanız # ve $ işaretini seri porttan göndermeniz ile herhangi bir işlem gerçekleşmeyecektir. 

Burada soketlerde kullanılan ‘_led’, ‘_pot’, ‘_ledRes’, ‘_potRes’ tamamen benim atamış olduğum isimlerdir. Bunları soketlere verdiğimiz isimler olarak düşünebilirsiniz. Eğer ki siz bir soket bağlantısı oluşturmak istiyorsanız server ve client’ te aynı isimli soketiniz olmalıdır. Aksi taktirde iletişim kuramazlar.

‘connection’ socket.io’ da tanımlı bağlanma event’ idir. Birisi sokete bağlandığında varsa bu event çağrılır ve içerisindeki işlemler gerçekleştirilir. Farklı event’ ler için socket’io‘ nun sitesine bakabilirsiniz.

“on” socket.io’ da tanımlı uyanma fonksiyonudur. “emit” ise gönderme fonksiyonudur. Yani siz ’emit’ ile gönderdiğiniz bir değeri client yada server tarafından on ile almanız gereklidir.Tersi şekilde kullanılmazlar. Farklı fonksiyonlar için socket.io‘ nun sitesine bakabilirsiniz.

Son olarak da portu dinlemeye başladık.

http.listen(port,function(){
	console.log("Listeining: ", port);
});

Server kısmındaki kodun tamamına buradan ulaşabilirsiniz.

Web (client) kısmında ise haberleşme için sadece javascript kısmını göstereceğim. Siz HTML ve CSS ‘ i istediğiniz gibi düzenleyebilirsiniz.

        var socket = io.connect("http://localhost:3000");

        //pot butonu basılmışsa _pot event i gönderdik
        function potFunction()
        {
            socket.emit('_pot', { });
        }

        //led butonunas basılmışsa _led event i gönderdik
        function ledFunction()
        {
            socket.emit('_led', { });
        }

        //A0 daki değeri geri okuduk
        socket.on('_potRes', function(_data)
        {
            document.getElementById('potDeger').innerHTML = _data;
        });

        //ledin durumunu geri okuduk
        socket.on('_ledRes', function(_data){
            document.getElementById('led').innerHTML = _data;
        });

Client kısmındaki kodun tamamına buradan ulaşabilirsiniz.

Server kısmındaki kodun tamamına buradan ulaşabilirsiniz.

İşlemler gördüğünüz üzere son derece basit. Farklı işlemler için istediğiniz gibi özelleştirebilir ve istediğiniz yerde kullabilirsiniz. Buna en güzel okulumuz araç takımı ile yaptığımız aracın telemetri sisteminde buna benzer bir yapı kullanarak verileri internet ortamına aktardık ve her yerden erişilebilir hale getirdik. Tabi bu firebase’ i öğrenmeden önceydi.. :)

Umarım yardımcı olabilmişimdir.

Teşekkürler..

 

10 Comments

Add a Comment

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir