Skip to content
Arpad Kovac edited this page Jun 14, 2019 · 1 revision

GRBL vezérlő felhasználói felülete REACT.jS technológiával Razvoj GRBL upravljackog interfejsa REACT.JS tehnologijom Grbl control interface development with REACT.JS

Hallgató

Mentor Kovács Árpád

dr. Pintér Róbert

Szabadka, 2019

Absztrakt Az absztraktot magyar nyelven kell megfogalmazni. Az absztrakt terjedelme 100 - 200 szó. Az absztrakt tartalmazza a feladat rövid leírását, a problémákat, célokat, valamint a feladat eredményeit.

Tartalomjegyzék Absztrakt 2 Jelmagyarázat 4 Köszönetnyilvánítás 5 A szakdolgozat témája 6 Bevezető 7 2. Szakirodalmi áttekintés 8 3. Problémamegoldás 10 3.2.1 Webszerver 10 3.2.2 Soros kommunikáció 11 3.2.3 Fájlbeolvasás 13 3.2.4 Az objektumok megjelenítése a képernyőn 14 3.2.5 Program futattása 15 3.2.6 Kézi vezérlés 16 3.2.7 A szoftver telepítése 17 Program kód minta... 20 4 Következtetés 21 5. Összegzés 22 Irodalom 23 Önéletrajz 24 Mellékletek 25

Jelmagyarázat Jelzés/Rövidítés Jelmagyarázat Node.JS JavaScript alapú web szerver oldali környezet Socket.IO Egy valós idejű támogatást biztosíŧó könyvtár JavaScript Egy böngészőben futó szkript nyelv HTML HyperText Markup Language CSS Cascading Style Sheets Bootstrap CSS könyvtár G kód A G kód az a nyelv ahol, az emberek meghatározzák, hogy az automatizált gép mit csináljon [1] Köszönetnyilvánítás Köszönettel tartozom Dr. Pintér Róbert tanár úrnak, a mentorom volt a feladat megvalósítása során. Amikor felötlött bennem a szakdolgozat témája, hozzá fordultam és a véleményét kértem róla. Miután elmagyaráztam, hogy mit is szeretnék akkor alaposan átbeszéltük a részleteket és még bővítettük a már amúgy is vaskos teendők listáját. Megbeszéltük, hogy az elkészült projektnek minden olyan eszközön működnie kell amelyen a vezető modern böngészők valamely változata fut. A Rehák kollégium volt és jelenlegi lakóinak. Valamint köszönettel tartozom még a családomnak, akik nagyban támogattak és hozzájárultak ahhoz, hogy eljuthattam idáig és megírhatom ezt a szakdolgozatot.

A szakdolgozat témája A szakdolgozatnak ezt a részét a mentor határozza meg. A fejezet kötelezően tartalmazza a probléma rövid leírását és a várható eredményeket. A várható eredmény kötelezően saját, originális megoldást kell, hogy tartalmazzon.

  1. Bevezető

1.1 A probléma leírása Atechnológia fejlődése és a tömegtermelés lehetővé teszik, hogy korábban nehezen beszerezhető és drága eszközeközet bárki beszerezhet, most már elfogadható áron. Egy ilyen eszköz a szakdolgozathoz használt marókészülék is mely egy házilag épített gép. Ez a készülék is ugyanúgy mint sokmás hasonló eszköz, vezérlőegységgel érkezik. A vezérlés megvalósítása, a programok fejelsztése és telepítése mind gyártótól függ. Sokszor találkozhatunk limitált képességű vezérlőegységekkel, olyanokkal például ahol nincs vizualizálva a megmunkálás folyamata. Ezek az "apró" hiányosságok kihatnak az eszköz hatékonyságára. Mivel legtöbb ilyen eszköz szabványos protokollokkal kommunikál a vezárlőegységgel, ebben a szakdolgozatban egy olyan megoldás kifejlesztésén lesz a hangsúly, amely helyettesítené egy marógép vezérlőjét, ezzel biztosítva olyan lehetőségeket, amelyek az eredeti vezérlőben nem szerepeltek. A szakdolgozat alapvetően két részre osztható, mint ahogyan azt már az előszóban is említettem. Az első rész a böngészőben futó kliens program, a második rész pedig a hozzá tartozó web és soros kommunikáció alapú szerver. A feladatnak az alapja egy Node.JS technonológiára épülő G kód küldő és fogadó, hálózaton keresztül elérhető „Real time” alkalmazás megírása. Az első probléma ami felmerült az nem más volt mint az alkalmazásnak részében multiplatformnak kell lennie, ugyanúgy el kell, hogy fusson számítógépen akár egy Raspberry PI 3-as vezérlőn. Ehhez igénybe kellet, hogy vegyem SerialPort könyvtárat melyel a kommunikációt megvalósítottam az eszköz és a GRBL vezérlő között. 1.2 A szakdolgozat céljai A szakdolgozat célja elkészíteni egy rendszert amely tartalmaz egy klienst és egy web alkalmazást. Valamint az, hogy a rendszer kielégítse a leendő felhasználók a rendszerrel szemben támasztott elvárásait. További cél volt még, hogy a rendszer működő képes legyen a ma létező vezető böngészők mint asztali mint mobil verzióján is. 1.3 Módszerek A szakdolgozat megvalósításához a következő technológiákat használtam fel: • HTML5 • JavaScript • Jquery • Ajax • Node.js • Php • Css • Three.JS

  1. Szakirodalmi áttekintés 2.1 Node.JS A Node.js egy szoftverrendszer, melyet skálázható internetes alkalmazások, mégpedig webszerverek készítésére hoztak létre. A programok JavaScript-ben írhatók, eseményalapú, aszinkron I/O-val a túlterhelés minimalizálására és a skálázhatóság maximalizálására. 2.2 Serialport A Serialport könyvtár egy C++-ban íródott könyvtár a Node.JS-hez mely multiplatform alkalmázoknál UNIX, Windows és OSX alapú rendszerek közötti soros kommunikációt támogatja. 2.3 Express.JS Az Express.JS ami webszervert támogatja az alkalmazásban melyen keresztül megjelenití a HTML weboldalat. 2.4 Electron Az Electron egy olyan könyvtárra Node.JS-nek mely egy Chromium böngészőbe belefordítja az aktuális programot. S azon keresztül a használatát vezérli. Az Electron alapú alkalmazások multiplatform támogatottságúak. 2.5 Socket.IO A Socket.IO egy olyan esemény hajtott könyvtár melyen keresztül a program (node alapú szerver) kapcsolódik hasonlóan az AJAX alapú rendszerekhez a kívánt weboldalhoz melyen keresztüli vezérlés valós időben történik. Magyarul ha a felhasználó rákattint egy gombra akkor a Socket.IO elküldi ezt a szervernek melynek a kívánt eseményre válaszol. Ezzel a technológiával lett megírva a szünet gomb is. 2.6 Three.JS A Three.JS könyvtár egy 3D megjelenítő könyvtár melyen keresztül az adott modellt megjelenítjük a böngészőben. 2.7 React.JS Facebook által fejlesztett könyvtár csomag melyett kifejezeten egy oldalas applikációk számára fejlesztettek ki. 2.7 GRBL Vezérlő A GRBL Vezérlő program az ATMEL ATMEGA328P vezérlőre írt CNC vezérlő program. Egy nagy teljesítményű CNC marógép program. 2.8 Fejlesztőkörnyezet - Visual Studio Code Ez egy a Microsoft által fejlesztett IDE. Amely integrált fejlesztő környezetet jelent. A Visual Studio Code talán napjaink egyik legfejlettebb IDE-je, minden eszköz a fejlesztő rendelkezésére áll. Található benne: • Debugger • Automatikus kód kiegészítés • Különféle fejlesztői tesztek • Szintaxis kiemelés • Automatikus kód formázás A Visual Studio Code azért is rendkívül jó IDE mert rengeteg programozási nyelvet támogat. Csak, hogy néhányat említsek: • JavaScript • Node.js • HTML • CSS • C# • C++ • F# • CoffeScript • TypeScript Én a szakdolgozat megvalósításánál ebben készítettem a JavaScript, Node.js, HTML és CSS részeket. Azért is esett a Visual Studio -ra a választásom mert a főiskola tanulóinak ingyenesen beszerezhető
  2. Problémamegoldás Ebben a fejezetben fogom ismertetni a szakdolgozat megvalósítását. A szakdolgozat két részből áll. Az első maga a szerver elkészítése, a második a pedik a kliens alkalmazás elkészítése. Mivel mind a két rész igen terjedelmes és összetett ezért csak a fontosabb részeket fogom ismertetni. A többi rész megtalálható forráskóddal együtt a cd mellékletben. Valamint röviden befogom a fejlesztésre használt eszközöket. Először is talán kezdjük ezzel.

3.1 A technológiai megvalósítás A program az említett Node.JS technológiával fut az eszközön ez adja a webszerverét a rendszernek. A SerialPort nevű könyvtáron keresztül soros porton keresztül kommunikál esetünkben USB. A SerialPort által összegyűjtött kommunikáció egy statikus HTML weboldalon keresztül jelenik meg Socket.IO könyvtár segítségével melyeket Real Time alkalmazásoknál szoktak használni. A Socket.IO nem csak a kommunikációt jeleníti meg hanem a parancsokat is ezen keresztül adja át az applikációnak. Amikor egy G-file beolvasásra kerül akkor az elküldi a G-code ellenörző fájlnak ami átfutja a fájlt és azután a G-code viewer-en keresztül megjelenítjük a fájl tartalmát. Ez a fájl azután beolvasásra kerül és megjelenítődik a szöveg szerkesztőben. A szöveg szerkesztője a programnak beolvassa fájlt és Socket.IO-ról vissza csatolja a TextArea mezőben ahol lehet szerkeszteni a fájlt. Megjelenítődik a Three.JS-ben a tervezett mozgása az említett modellnek és az aktuális koordinátája a gépnek. Ha elkezdenénk a műveleteket magyarul akkor megjelenítí a program aktuális állását, valamint az parancsok számát. A program Linux alatt lett tesztelve virtuális gép alatt, mely a /dev/ttyACM0 portot csatoltam rá a virtuális gépre majd azon teszteltük az adott komunikációt. Valamint a kézi írányítást is hozzáadtam a rendszerhez vagyis kurzor nyílakkal képessek vagyunk a mikrovezérlőt irányítani. A valós környeztben egy Raspberry PI 3-ason kell, hogy fusson ezért szükséges volt egy olyan lehetőleg opensource operációs rendszerre melyen a kívánt szoftver el képes futni. Ehhez egy könyített linux disztrubiciót választottunk még pedig a Linux Manjarot. 3.2 Magyarázat 3.2.1 Webszerver A webszerver felülete Node.JS-el dolgozik, amely egy statikus webszerver felületet add a rendszernek. app.listen(config.webPort); var fileServer = new static.Server('./fsserver');

function handler (req, res) {

console.log(req.url);

if (req.url.indexOf('/api/uploadGcode') == 0 && req.method == 'POST') {
	// this is a gcode upload, probably from jscut
	console.log('new data from jscut');
	var b = '';
	req.on('data', function (data) {
		b += data;
		if (b.length > 1e6) {
			req.connection.destroy();
		}
	});
	req.on('end', function() {
		var post = qs.parse(b);
		
		io.sockets.emit('gcodeFromJscut', {'val':post.val});
		res.writeHead(200, {"Content-Type": "application/json"});
		res.end(JSON.stringify({'data':'ok'}));
	});
} else {
	fileServer.serve(req, res, function (err, result) {
		if (err) console.log('fileServer error: ',err);
	});
}

}.

De a kommunikációért fontos rész és ami lekezeli a kéréseket az nem más mint a Socket.IO könyvtár. Ez gyakorlatilag a Node.JS szerver részét képzi mint a kommunikációban legfontossabb könyvtárak egyike. A kliensben található részével párhuzamosan kommunikál és megkülönbözteti őket. A megvalósításban szükséges volt a kommunikációnak valós idejűnek lenni ezért. A statikus HTML fájlba beépített kliens felét azonosítja és létrehozza a kommunikációt vele.

3.2.2 Soros kommunikáció Először is szükséges kilistázni a rendszerben található aktuális kommunikációs portokat. serialport.list(function (err, ports) { allPorts = ports;

for (var i=0; i<ports.length; i++) {
!function outer(i){

	sp[i] = {};
	sp[i].port = ports[i].comName;
	sp[i].q = [];
	sp[i].qCurrentMax = 0;
	sp[i].lastSerialWrite = [];
	sp[i].lastSerialReadLine = '';
	
	sp[i].handle = new serialport.parsers.Readline({delimiter: '\r\n'});
	// 1 means clear to send, 0 means waiting for response
	sp[i].port = new serialport(ports[i].comName, {
		baudRate: config.serialBaudRate
	});
	// write on the port
	sp[i].port.pipe(sp[i].handle);
	sp[i].sockets = [];

	sp[i].port.on("open", function() {

		console.log('connected at '+config.serialBaudRate, sp[i].port.path);

		// loop for status ?
		setInterval(function() {
			//console.log('writing ? to serial');
			sp[i].port.write('?');
		}, 1000);

	});

	// line from serial port
	sp[i].handle.on("data", function (data) {
		//console.log('got data', data);
		serialData(data, i);
	});

}(i)
}

});

A program sorok küldésére szükséges szkript. function sendFirstQ(port) {

if (sp[port].q.length < 1) {
	// nothing to send
	return;
}
var t = sp[port].q.shift();

// remove any comments after the command
tt = t.split(';');
t = tt[0];
// trim it because we create the \n
t = t.trim();
if (t == '' || t.indexOf(';') == 0) {
	// this is a comment or blank line, go to next
	sendFirstQ(port);
	return;
}
//console.log('sending '+t+' ### '+sp[port].q.length+' current q length');

// loop through all registered port clients
for (var i=0; i<sp[port].sockets.length; i++) {
	sp[port].sockets[i].emit('serialRead', {'line':

'SEND: '+t+''+"\n"}); } sp[port].port.write(t+"\n") sp[port].lastSerialWrite.push(t); } Mivel a karakterek HTML környezetben másképp szerepelnek ezért szükséges az átalakítás ANSII karakterekből HTML karakterekbe. function ConvChar( str ) { c = {'<':'<', '>':'>', '&':'&', '"':'"', "'":''', '#':'#' }; return str.replace( /[<&>'"#]/g, function(s) { return c[s]; } ); }

3.2.3 Fájlbeolvasás A fájlbeolvást a kliens kezeli. A fájl beolvasását az alábbi szkript végzi el. A technológia jQuery támogatottsággal rendelkezik ez miatt a böngésző drag and drop funkcióval van ellátva. if (window.FileReader) {

	var reader = new FileReader ();

	// drag and drop
	function dragEvent (ev) {
		ev.stopPropagation (); 
		ev.preventDefault ();
		if (ev.type == 'drop') {
			reader.onloadend = function (ev) {
				document.getElementById('command').value = this.result;
				openGCodeFromText();
			};
			reader.readAsText (ev.dataTransfer.files[0]);
		}  
	}

	document.getElementById('command').addEventListener ('dragenter', dragEvent, false);
	document.getElementById('command').addEventListener ('dragover', dragEvent, false);
	document.getElementById('command').addEventListener ('drop', dragEvent, false);

	// button
	var fileInput = document.getElementById('fileInput');
	fileInput.addEventListener('change', function(e) {
		reader.onloadend = function (ev) {
			document.getElementById('command').value = this.result;
			openGCodeFromText();
		};
		reader.readAsText (fileInput.files[0]);
	});

} else {
	alert('your browser is too old to upload files, get the latest Chromium or Firefox');
}

}); Majd ha beolvasás megtörtént akkor meghívásra kerül az OpenGcodeFromText függvény. Ez az a szkript mely meghívja Three.JS G-code viewer G kód megjelenítő szkriptjét. A createObject függvényt. function openGCodeFromText() { var gcode = $('#command').val(); if (document.hasFocus()) { createObject(gcode); //console.log('adding object with existing focus'); } else { // wait for focus, then render //console.log('waiting for focus'); $(window).bind('focus', function(event) { createObject(gcode); //console.log('focus exists'); // unbind for next object load $(this).unbind(event); }); } } 3.2.4 Az objektumok megjelenítése a képernyőn A G kód megjelenítése a Three.JS könyvtár segítségével történik meg. Mint az előbb említett createObject függvény segítségével történik a megjelenítés. E parancs folyamán ellenőrzésre kerül a G kód szintaktikai helyessége melyet a G code library segítségével történik meg. Valamint ábrázolásra kerül a kívánt model is. A sorról sorra való történéskor a poziciókat a program elmenti és majd a 2 vége között létrehoz egy Vektort ezáltal a program ábrázolja a kívánt alakzatott, majd pusholja a modellnak a tömbjébe amíg az eszköz aktív ezt figyelemmel lehet követni (...) var lastLine = { x: 0, y: 0, z: 0, e: 0, f: 0, // set to true for cnc, no extruder extruding: true };

var layers = [];
var layer = undefined;
var bbbox = {
    min: {
        x: 100000,
        y: 100000,
        z: 100000
    },
    max: {
        x: -100000,
        y: -100000,
        z: -100000
    }
};

function newLayer(line) {
    layer = {
        type: {},
        layer: layers.length,
        z: line.z,
    };
    layers.push(layer);
}

function getLineGroup(line) {
    if (layer == undefined)
        newLayer(line);
    var speed = Math.round(line.e / 1000);
    var grouptype = (line.extruding ? 10000 : 0) + speed;
    var color = new THREE.Color(line.extruding ? 0x33aadd : 0x228B22);
    if (layer.type[grouptype] == undefined) {
        layer.type[grouptype] = {
            type: grouptype,
            feed: line.e,
            extruding: line.extruding,
            color: color,
            segmentCount: 0,
            material: new THREE.LineBasicMaterial({
                opacity: line.extruding ? 0.8 : 0.8,
                transparent: true,
                linewidth: 2,
                vertexColors: THREE.FaceColors
            }),
            geometry: new THREE.Geometry(),
        }
    }
    return layer.type[grouptype];
}

function addSegment(p1, p2) {
    var group = getLineGroup(p2);
    var geometry = group.geometry;

    group.segmentCount++;
    geometry.vertices.push(new THREE.Vector3(p1.x, p1.y, p1.z));
    geometry.vertices.push(new THREE.Vector3(p2.x, p2.y, p2.z));
    geometry.colors.push(group.color);
    geometry.colors.push(group.color);
    //if (p2.extruding) {
// do this for all lines, not just extruding on cnc
        bbbox.min.x = Math.min(bbbox.min.x, p2.x);
        bbbox.min.y = Math.min(bbbox.min.y, p2.y);
        bbbox.min.z = Math.min(bbbox.min.z, p2.z);
        bbbox.max.x = Math.max(bbbox.max.x, p2.x);
        bbbox.max.y = Math.max(bbbox.max.y, p2.y);
        bbbox.max.z = Math.max(bbbox.max.z, p2.z);
    //}
}
var relative = false;

function delta(v1, v2) {
    return relative ? v2 : v2 - v1;
}

function absolute(v1, v2) {
    return relative ? v1 + v2 : v2;
}

Természetesen a program nem támogatja az összes parancsot köztük a görbére alkalmazott kódok ábrázolását valamint a több tengely megoldásoknak (3 tengelytől) több tengely ábrázolásást is. 3.2.5 Program futattása A program a beolvasás után lefutatthatóvá válik, ahol soron lehet követni az aktuális sorszámot valamint a kliensben szerkeszteni is. A megállítást úgy szintén kliens kezeli mert a szerver csak az aktuális sort fogadja. Ezért szükséges egy-egy kapcsolatnak fent állni a programmal. A következő szkript a leállítást mutatja be. $('#pause').on('click', function() { if ($('#pause').html() == 'Pause') { // pause queue on server socket.emit('pause', 1); $('#pause').html('Unpause'); $('#clearQ').removeClass('disabled'); } else { socket.emit('pause', 0); $('#pause').html('Pause'); $('#clearQ').addClass('disabled'); } });

$('#clearQ').on('click', function() {
	// if paused let user clear the command queue
	socket.emit('clearQ', 1);
	// must clear queue first, then unpause (click) because unpause does a sendFirstQ on server
	$('#pause').click();
});

Az aktuális állás program mutatás szkriptje. socket.on('serialRead', function (data) { if ($('#console p').length &gt; 300) { // remove oldest if already at 300 lines $('#console p').first().remove(); } $('#console').append('

'+data.line+'

'); $('#console').scrollTop($("#console")[0].scrollHeight - $("#console").height()); }); 3.2.6 Kézi vezérlés A kézi vezérlést a kurzor billenyűkkel lett megoldva, amíg telefon nézetben irányító gombok jelennek meg. // WASD and up/down keys $(document).keydown(function (e) { var keyCode = e.keyCode || e.which;
	if ($('#command').is(':focus')) {
		// don't handle keycodes inside command window
		return;
	}

	switch (keyCode) {
	case 65:
		// a key X-
		e.preventDefault();
		$('#xM').click();
		break;
	case 68:
		// d key X+
		e.preventDefault();
		$('#xP').click();
		break;
	case 87:
		// w key Y+
		e.preventDefault();
		$('#yP').click();
		break;
	case 83:
		// s key Y-
		e.preventDefault();
		$('#yM').click();
		break;
	case 38:
		// up arrow Z+
		e.preventDefault();
		$('#zP').click();
		break;
	case 40:
		// down arrow Z-
		e.preventDefault();
		$('#zM').click();
		break;
	}
}).

Ehhez szükséges volt a CSS-t úgy testreszabni, hogy a dinamikusan változzon a felhasználónak az aktuális eszközére. A felület Bootstrap könyvtárral lett megformázva ezért ... A programnak szükséges még az aktuális poziciót mutatnia ezért a program folyamatosan lekérdezi a GRBL vezérlőt az aktuális állásról, és a felületen megjeleníteni. A kliens oldalon: socket.on('machineStatus', function (data) { $('#mStatus').html(data.status); $('#mX').html('X: '+data.mpos[0]); $('#mY').html('Y: '+data.mpos[1]); $('#mZ').html('Z: '+data.mpos[2]); }); A szerver oldalon: var t = data.substr(1); t = t.substr(0,t.length-2); t = t.split(/,|:/); emitToPortSockets(port, 'machineStatus', {'status':t[0], 'mpos':[t[2], t[3], t[4]]); return; }

3.2.7 A szoftver telepítése Először is szoftverhez szükséges függőséggek: • Node.js (a SerialPort könyvtár miatt 8.x verzió) • Yarn alkalmazás • git kliens

Leklónozzuk a git tárolóból[4] az applikációt: Majd a Yarn a segítségével telepítjük a függőséggeket:

Az applikáció elinditása:

3.2.8 A felhasználói felület A felhasználói felület építése során az egyszerűségre törekedtünk. Ezáltal minimalizálva a hiba lehetőségeket és az áttekinthetőség növelhetőségét.et

A program tesztelve lett több böngészőre is Vivaldi-ban lett tesztelve de ezen kívül fut Firefox és Google Chrome, Opera böngészőkben. A régebbi típusú Internet Expolorer böngészőket nem támogatja a szoftver, s azokat sem melyeknél nincs javascript támogatottság.

Program kód minta... A program kódokat Normal program code stílusban írj ák. A program kódokat ugyancsak lehet Normal program code framed stílusban írni. 4 Következtetés Úgy vélem, hogy a szakdolgozat még nem teljesen kész, de azok a modulok amik találhatóak benne tökéletesen működik. A szerverben is és a web alkalmazásban is sikerült azokat a funkcionalitásokat megvalósítanom amelyeket a fejlesztés elején kitűztem. Persze a rendszer úgy lett kialakítva, hogy a jövőben bármikor tovább lehessen a fejleszteni azt. Erre a felhasználók javaslatokat is tehetnek a Github oldalon amelyeket megfontolok, és ha úgy vélem érdemes belerakni az alkalmazásba akkor belerakom. 5. Összegzés 5.1 GRBL vezérlő felhasználói felülete Node.JS technológiával

5.2 Razvoj GRBL upravljackog interfejsa Node.JS tehnologijom

5.3 GRBL control interface development with Node.JS

Irodalom [1] G-code https://en.wikipedia.org/wiki/G-code [2] Čović Zlatko (2008). Elektronikus ügyvitel – Példatár. Szabadka, Szabadkai Műszaki Szakfőiskola [3] Čović Zlatko (2005). Internet technológiák – Pédatár.Szabadka, Szabadkai Műszaki Szakfőiskola [4] Php oldala http://php.net [5] w3c okató oldala http://www.w3schools.com/ [6] A vertexekről https://en.wikipedia.org/wiki/Vertex_(geometry) [7] Git tároló https://github.com/karpad2/grblinterface

Önéletrajz Kovács Árpád 1997 január 26.-án született Újvidéken. 2004-től 2012-ig a péterrévei Samu Mihály Általános Iskola tanulója volt. 2012 szeptemberétől 2016 júniusáig az adai Műszaki Iskola tanulója volt számítógépek elektrotechnikusa szakon. Majd 2016-ban a Szabadkai Műszaki Szakfőiskola hallgatója lett Műszaki Informatika szakon. Mellékletek Nyomtatott melléklet Különálló táblázatok, képek és ábrák, program kódok, stb. Elektronikus melléklet DVD vagy más hordozható elektronikus adattár mely tartalmazza a szakdolgozat szövegét valamint a mellékletek tartalmát.

Clone this wiki locally