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 stanja
Omogoč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 -> handler
var 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 8080
var želenaVrednost = 0; // želeno vrednost postavimo na 0
var dejanskaVrednost = 0; // dejansko vrednost postavimo na 0
var faktor =0.1; // faktor, ki določa hitrost doseganja želenega stanja
var pwm = 0;
var kontrolniAlgoritemVključen = 0; // spremenljivka, ki določa ali je ctrl. alg. vključen
var intervalCtrl; // spremenljivka za setInterval v globalnem prostoru
console.log("Zagon sistema"); // izpis sporočila o zagonu
board.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 x1
var y1 = new Array(); // polje za spremenljivko y1
var x2 = new Array(); // polje za spremenljivko x2
var y2 = new Array(); // polje za spremenljivko y2
var canvas;
var ctx;
var potVrednost1; // vrednost prvega potenciometra
var potVrednost2; // vrednost drugega potenciometra
var 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>