Splošna shema kontrolnega sistema za kontrolo pozicije enosmernega motorja je prikazana na naslednji sliki. Razviti sistem nam bo omogočal analizo različnih kontrolnih algoritmov. Klasičen del kontrolnega sistema je prikazan pod zeleno črtkano črto.
Izgled vezave s ploščico za prototipiranje je prikazan na naslednji sliki. Pri realizaciji skušamo slediti razporedu elementov, kot je to prikazano na sliki. Ustrezna razporeditev nam bo omogočila primerjavo med abstraktno shemo ter realnim sistemom.
Realizacija sistema je prikazana na naslednjih slikah:
Pri realizaciji so na naslednji sliki označeni ključni elementi kontrolnega sistema:
Pri zapisu kode izhajamo iz primera, kjer smo brali vrednost dveh potenciometrov.
Najprej dodamo dodatno spremenljivko v .js datoteko, ki bo uporabljena pri kontrolnem algoritmu:
var faktor =0.1; // faktor, ki določa hitrost doseganja želenega stanjaOmogočiti moramo ustrezne pine:
var board = new firmata.Board("/dev/ttyACM0", function(){ console.log("Aktiviramo analogni pin 0"); board.pinMode(0, board.MODES.ANALOG); console.log("Aktiviramo analogni pin 1"); board.pinMode(1, board.MODES.ANALOG); console.log("Aktiviramo pin 2"); board.pinMode(2, board.MODES.OUTPUT); // pin za smer na H-mostu console.log("Aktiviramo pin 3"); board.pinMode(3, board.MODES.PWM); // Pulse Width Modulation - hitrost});V .js datoteko dodamo funkcijo kontrolniAlgoritem:
function kontrolniAlgoritem () { pwm = faktor*(želenaVrednost-dejanskaVrednost); if (pwm > 255) {pwm = 255}; // omejimo vrednost pwm na 255 if (pwm < -255) {pwm = -255}; // omejimo vrednost pwm na -255 if (pwm > 0) {board.digitalWrite(2,0)}; // določimo smer če je > 0 if (pwm < 0) {board.digitalWrite(2,1)}; // določimo smer če je < 0 board.analogWrite(3, Math.abs(pwm)); // zapišemo abs vrednost na pin 3 if (dejanskaVrednost < 200 || dejanskaVrednost > 850) { stopKontrolniAlgoritem(); }}Funkcijo startKontrolniAlgoritem:
function startKontrolniAlgoritem () { if (kontrolniAlgoritemVključen == 0) { kontrolniAlgoritemVključen = 1; intervalCtrl = setInterval(function(){kontrolniAlgoritem();}, 30); // kličemo alg. na 30ms console.log("Zagon kontrolnega algoritma"); }}Ter funkcijo stopKontrolniAlgoritem
function stopKontrolniAlgoritem () { clearInterval(intervalCtrl); // brišemo interval klica kontrolnega algoritma board.analogWrite(3, 0); kontrolniAlgoritemVključen = 0; console.log("Kontrolni algoritem zaustavljen.");};Nato moramo preveriti:
V primeru, da rotacija ni ustrezna preverimo vezje in program.
Izgled uporabniškega vmesnika je prikazan na naslednji sliki:
V nadaljevanju je izpisan del kode na strani strežnika: .js
var http = require("http").createServer(handler); // ob zahtevi req -> handlervar firmata = require("firmata");var fs = require("fs"); // knjižnjica za delo z datotekami (File System fs)var io = require("socket.io").listen(http); // knjiž. za komunik. prek socket-a console.log("Priklop Arduina");var board = new firmata.Board("/dev/ttyACM0", function(){ console.log("Aktiviramo analogni pin 0"); board.pinMode(0, board.MODES.ANALOG); console.log("Aktiviramo analogni pin 1"); board.pinMode(1, board.MODES.ANALOG); console.log("Aktiviramo pin 2"); board.pinMode(2, board.MODES.OUTPUT); // pin za smer na H-mostu console.log("Aktiviramo pin 3"); board.pinMode(3, board.MODES.PWM); // Pulse Width Modulation - hitrost});function handler(req, res) { fs.readFile(__dirname + "/primer14.html", function(err, data) { if (err) { res.writeHead(500, {"Content-Type": "text/plain"}); return res.end("Napaka pri nalaganju html strani!"); } res.writeHead(200); res.end(data); });}http.listen(8080); // strežnik bo poslušal na vratih 8080var želenaVrednost = 0; // želeno vrednost postavimo na 0var dejanskaVrednost = 0; // dejansko vrednost postavimo na 0var faktor =0.1; // faktor, ki določa hitrost doseganja želenega stanjavar pwm = 0;var kontrolniAlgoritemVključen = 0; // spremenljivka, ki določa ali je ctrl. alg. vključenvar intervalCtrl; // spremenljivka za setInterval v globalnem prostoruconsole.log("Zagon sistema"); // izpis sporočila o zagonuboard.on("ready", function(){ console.log("Plošča pripravljena"); board.analogRead(0, function(value){ želenaVrednost = value; // neprekinjeno branje pina A0 }); board.analogRead(1, function(value){ dejanskaVrednost = value; // neprekinjeno branje pina A1 }); //startKontrolniAlgoritem(); // poženemo kontrolni algoritem io.sockets.on("connection", function(socket){ setInterval(pošljiVrednosti, 40, socket); // na 40ms pošlj. vred. socket.on("startKontrolniAlgoritem", function(){ startKontrolniAlgoritem(); }); socket.on("stopKontrolniAlgoritem", function(){ stopKontrolniAlgoritem(); }); }); // konec socket.on("connection") }); // konec board.on("ready")function kontrolniAlgoritem () { pwm = faktor*(želenaVrednost-dejanskaVrednost); if (pwm > 255) {pwm = 255}; // omejimo vrednost pwm na 255 if (pwm < -255) {pwm = -255}; // omejimo vrednost pwm na -255 if (pwm > 0) {board.digitalWrite(2,0)}; // določimo smer če je > 0 if (pwm < 0) {board.digitalWrite(2,1)}; // določimo smer če je < 0 board.analogWrite(3, Math.abs(pwm)); // zapišemo abs vrednost na pin 3 if (dejanskaVrednost < 200 || dejanskaVrednost > 850) { stopKontrolniAlgoritem(); }}function startKontrolniAlgoritem () { if (kontrolniAlgoritemVključen == 0) { kontrolniAlgoritemVključen = 1; intervalCtrl = setInterval(function(){kontrolniAlgoritem();}, 30); // kličemo alg. na 30ms console.log("Zagon kontrolnega algoritma"); }}function stopKontrolniAlgoritem () { clearInterval(intervalCtrl); // brišemo interval klica kontrolnega algoritma board.analogWrite(3, 0); kontrolniAlgoritemVključen = 0; console.log("Kontrolni algoritem zaustavljen.");};function pošljiVrednosti(socket) { socket.emit("klientBeriVrednosti", { "želenaVrednost": želenaVrednost, "dejanskaVrednost": dejanskaVrednost, "pwm": pwm });};Koda na strani klienta (.html):
<!DOCTYPE html><meta charset = utf8><html><head> <title>Primer z grafom</title></head><body onload="load()">Kontrolni sistem P - kontroler<br><canvas id="cv" width = "200" height = "100" style="border: 1px dashed #00c3c3;"></canvas><p></p><button id="startKontrolniAlgoritem" onClick="startKontrolniAlgoritem();">Start Ctrl Alg</button><button id="stopKontrolniAlgoritem" onClick="stopKontrolniAlgoritem();">Stop Ctrl Alg</button><div id="divZaIzpis"></div><script type="text/javascript" src="/socket.io/socket.io.js"></script><script type="text/javascript">var x1 = new Array(); // polje za spremenljivko x1var y1 = new Array(); // polje za spremenljivko y1var x2 = new Array(); // polje za spremenljivko x2var y2 = new Array(); // polje za spremenljivko y2var canvas;var ctx;var potVrednost1; // vrednost prvega potenciometravar potVrednost2; // vrednost drugega potenciometravar divZaIzpis = document.getElementById("divZaIzpis"); // var za div el.var štVrsticPredPomikom = 10;var števecIzpisanihVrstic = 0;var socket = io.connect("192.168.1.136:8080"); // povezava na strež.function load() { canvas = document.getElementById("cv"); ctx = canvas.getContext("2d"); // izrišemo prvo časovno vrsto za želene vrednosti ctx.lineWidth = "1"; ctx.strokeStyle = "#ff0000"; for (var i = 0; i<200; i++) { x1[i] = i; // x1 gre od 0, 1, ... 199 y1[i] = 0; // za y podamo vrednost 0 } ctx.beginPath(); // za začetek izrisa črte for (var i=0; i<200; i++) { ctx.lineTo(x1[i],y1[i]); } ctx.stroke(); // izrišemo drugo časovno vrsto za dejanske vrednosti ctx.lineWidth = "1"; ctx.strokeStyle = "#00ff00"; for (var i = 0; i<200; i++) { x2[i] = i; // x2 gre od 0, 1, ... 199 y2[i] = 0; // za y podamo vrednost 0 } ctx.beginPath(); // za začetek izrisa črte for (var i=0; i<200; i++) { ctx.lineTo(x2[i],y2[i]); } ctx.stroke(); }socket.on("klientBeriVrednosti", function(value){ potVrednost1 = value.želenaVrednost; // žel. vr. iz strežnika potVrednost2 = value.dejanskaVrednost; // dej. vr. iz strežnika // Graf izris ********************************************************** ctx.clearRect(0, 0, canvas.width, canvas.height); // brišemo platno // izris prve črte ctx.strokeStyle = "#ff0000"; ctx.beginPath(); // za začetek izrisa črte y1.splice(0, 1); // na mestu 0 v polju y1 brišemo eno vrednost y1[199] = potVrednost1; // novo vrednst pa dodamo na koncu polja for (var i=0; i<200; i++) { ctx.lineTo(x1[i], (100 - (y1[i] / 1023) * 100)); // izris vrednosti } ctx.stroke(); // za izris črte // izris druge črte ctx.strokeStyle = "#00ff00"; ctx.beginPath(); // za začetek izrisa črte y2.splice(0, 1); // na mestu 0 v polju y2 brišemo eno vrednost y2[199] = potVrednost2; // novo vrednst pa dodamo na koncu polja for (var i=0; i<200; i++) { ctx.lineTo(x2[i], (100 - (y2[i] / 1023) * 100)); // izris vrednosti } ctx.stroke(); // za izris črte // Graf izris ********************************************************** // izris legende ctx.strokeStyle = "#ff0000"; ctx.font = "11px Arial"; ctx.fillText("Želena", 70, 10); ctx.beginPath(); ctx.lineTo(50,6); ctx.lineTo(65,6); ctx.stroke(); ctx.strokeStyle = "#00ff00"; ctx.font = "11px Arial"; ctx.fillText("Dejanska", 140, 10); ctx.beginPath(); ctx.lineTo(120,6); ctx.lineTo(135,6); ctx.stroke(); log(value.želenaVrednost + "|" + value.dejanskaVrednost + "|" + (value.želenaVrednost-value.dejanskaVrednost) + "|" + (value.pwm).toFixed(0)); });function startKontrolniAlgoritem() { socket.emit("startKontrolniAlgoritem");}function stopKontrolniAlgoritem() { socket.emit("stopKontrolniAlgoritem");}function log(sporočilo) { var node=document.createElement("tr"); // we create the variable node as the a table row (tr) var textnode=document.createTextNode(števecIzpisanihVrstic + " | " + sporočilo); // we create element with the text adding the counter node.appendChild(textnode); // adding text to "node", i.e. table row divZaIzpis.insertBefore(node, divZaIzpis.childNodes[0]); // inserting into variable node if (števecIzpisanihVrstic > štVrsticPredPomikom-1) { // if the lines are more than limit -> start with scroll divZaIzpis.removeChild(divZaIzpis.childNodes[štVrsticPredPomikom]); // we remove the oldest printout } števecIzpisanihVrstic++; // increasing the number of printouts}</script></body></html>