In this example the graphs of fuzzy rules will be added in order to better represent the fuzzy logic controller implementation. In the next figures the part of the GUI is shown, where different actual values are considered.
In this example socket.io library is used.
var http = require("http").createServer(handler); // on req - hand
var io = require("socket.io").listen(http); // socket library
var fs = require("fs"); // variable for file system for providing html
var firmata = require("firmata");
console.log("Starting the code");
var board = new firmata.Board("/dev/ttyACM0", function(){
console.log("Connecting to Arduino");
board.pinMode(0, board.MODES.ANALOG); // enable analog pin 0
board.pinMode(1, board.MODES.ANALOG); // enable analog pin 1
board.pinMode(2, board.MODES.OUTPUT); // direction of DC motor
board.pinMode(3, board.MODES.PWM); // PWM of motor
board.pinMode(4, board.MODES.OUTPUT); // direction of DC motor
});
function handler(req, res) {
fs.readFile(__dirname + "/example29.html",
function (err, data) {
if (err) {
res.writeHead(500, {"Content-Type": "text/plain"});
return res.end("Error loading html page.");
}
res.writeHead(200);
res.end(data);
})
}
var desiredValue = 0; // desired value var
var actualValue = 0; // actual value var
var Kp = 0.55; // proportional factor of PID controller
var Ki = 0.008; // integral factor of PID controller
var Kd = 0.15; // differential factor of PID controller
var factor = 0.3; // proportional factor that deterimes speed of res.
var pwm = 0; // set pwm as global variable
var pwmLimit = 254; // to limit value of the pwm that is sent to the motor
var err = 0; // error
var errSum = 0; // sum of errors as integral
var dErr = 0; // difference of error
var lastErr = 0; // to keep the value of previous error to estimate derivative
var controlAlgorithmStartedFlag = 0; // variable for indicating weather the Alg has benn sta.
var intervalCtrl; // var for setInterval in global scope
http.listen(8080); // server will listen on port 8080
var sendValueViaSocket = function(){}; // var for sending messages
var sendStaticMsgViaSocket = function(){}; // for sending static messages
board.on("ready", function(){
board.analogRead(0, function(value){
desiredValue = value; // continuous read of analog pin 0
});
board.analogRead(1, function(value){
actualValue = value; // continuous read of analog pin 1
});
io.sockets.on("connection", function(socket) {
socket.emit("messageToClient", "Srv connected, board OK");
socket.emit("staticMsgToClient", "Srv connected, board OK");
setInterval(sendValues, 40, socket); // on 40ms trigerr func. sendValues
socket.on("startControlAlgorithm", function(numberOfControlAlgorithm){
startControlAlgorithm(numberOfControlAlgorithm);
});
socket.on("stopControlAlgorithm", function(){
stopControlAlgorithm();
});
sendValueViaSocket = function (value) {
io.sockets.emit("messageToClient", value);
};
sendStaticMsgViaSocket = function(value) {
io.sockets.emit("staticMsgToClient", value);
};
}); // end of sockets.on connection
}); // end of board.on ready
////////////////////////////////////////////////fuzzy
{
var NFuzzyVars = 2;
var NFuzzyOutputs = 1;
var NFuzzySets = new Array(NFuzzyVars);
NFuzzySets[0] = 3;
NFuzzySets[1] = 3;
var FSvalues = new Array(NFuzzyVars);
for (var i=0;i!=NFuzzyVars;i++)
{
FSvalues[i] = new Array(NFuzzySets[i]);
for (var j=0;j!=NFuzzySets[i];j++)
{
FSvalues[i][j] = new Array(3);
}
}
var NRules = 3;
var RBase = new Array(NRules);
for (var i=0;i!=NRules;i++)
{
RBase[i] = new Array(NFuzzyVars);
}
var ValuesForFuzzy = new Array(NFuzzyVars);
ValuesForFuzzy[0] = 0;
ValuesForFuzzy[1] = 0;
var AlphaCut = new Array(NFuzzySets[0]);
var RN = 0;
RBase[RN][0] = 0; RBase[RN][1] = 0; RN++;
RBase[RN][0] = 1; RBase[RN][1] = 1; RN++;
RBase[RN][0] = 2; RBase[RN][1] = 2; RN++;
var FSpos1 = 125;
var FSpos2 = 25;
function resetFSvalues()
{
FSvalues[0][0][0] = -FSpos1;
FSvalues[0][0][1] = -FSpos1;
FSvalues[0][0][2] = 0;
FSvalues[0][1][0] = -FSpos1;
FSvalues[0][1][1] = 0;
FSvalues[0][1][2] = FSpos1;
FSvalues[0][2][0] = 0;
FSvalues[0][2][1] = FSpos1;
FSvalues[0][2][2] = FSpos1;
FSvalues[1][0][0] = -FSpos2;
FSvalues[1][0][1] = -FSpos2;
FSvalues[1][0][2] = 0;
FSvalues[1][1][0] = -FSpos2;
FSvalues[1][1][1] = 0;
FSvalues[1][1][2] = FSpos2;
FSvalues[1][2][0] = 0;
FSvalues[1][2][1] = FSpos2;
FSvalues[1][2][2] = FSpos2;
}
function getMRFromFSvalues(value,NumOfVar,NumOfSet)
{
if (NumOfSet == 0)
{
if (value < FSvalues[NumOfVar][NumOfSet][0])
{
return 1;
}
else if (value > FSvalues[NumOfVar][NumOfSet][2])
{
return 0;
}
else
{
return (FSvalues[NumOfVar][NumOfSet][2] - value) / (FSvalues[NumOfVar][NumOfSet][2] - FSvalues[NumOfVar][NumOfSet][1]);
}
}
else if (NumOfSet == NFuzzySets[NumOfVar] - 1)
{
if (value < FSvalues[NumOfVar][NumOfSet][0])
{
return 0;
}
else if (value > FSvalues[NumOfVar][NumOfSet][2])
{
return 1;
}
else if (value < FSvalues[NumOfVar][NumOfSet][1])
{
return (value - FSvalues[NumOfVar][NumOfSet][0]) / (FSvalues[NumOfVar][NumOfSet][1] - FSvalues[NumOfVar][NumOfSet][0]);
}
}
else
{
if (value < FSvalues[NumOfVar][NumOfSet][0])
{
return 0;
}
else if (value > FSvalues[NumOfVar][NumOfSet][2])
{
return 0;
}
else if (value < FSvalues[NumOfVar][NumOfSet][1])
{
return (value - FSvalues[NumOfVar][NumOfSet][0]) / (FSvalues[NumOfVar][NumOfSet][1] - FSvalues[NumOfVar][NumOfSet][0]);
}
else
{
return (FSvalues[NumOfVar][NumOfSet][2] - value) / (FSvalues[NumOfVar][NumOfSet][2] - FSvalues[NumOfVar][NumOfSet][1]);
}
}
}
function getDesiredValuesFuzzy()
{
resetFSvalues();
for (var j=0;j!=NFuzzySets[0];j++)
{
AlphaCut[j] = 0;
}
for (var i=0;i!=NRules;i++)
{
var tempMR = 0;
var tempMinMR = 1;
for (var CurrentVar = NFuzzyOutputs;CurrentVar!=NFuzzyVars;CurrentVar++)
{
tempMR = getMRFromFSvalues(ValuesForFuzzy[CurrentVar],CurrentVar,RBase[i][CurrentVar]);
if (tempMR < tempMinMR)
tempMinMR = tempMR;
}
for (var CurrentVar = 0;CurrentVar!=NFuzzyOutputs;CurrentVar++)
{
if (tempMinMR > AlphaCut[RBase[i][CurrentVar]])
AlphaCut[RBase[i][CurrentVar]] = tempMinMR;
}
}
for (var CurrentVar = 0;CurrentVar!=NFuzzyOutputs;CurrentVar++)
{
var FuzzyRange = FSvalues[CurrentVar][NFuzzySets[CurrentVar]-1][2] - FSvalues[CurrentVar][0][0];
console.log(FuzzyRange);
var NIntervals = 100;
var CoordinateMassSumm = 0;
var MassSumm = 0;
for (var i=0;i!=NIntervals;i++)
{
var TempCoordinate = FSvalues[CurrentVar][0][0] + FuzzyRange/NIntervals*i;
var TempMass1 = 0;
var TempMass2 = 0;
for (var j=0;j!=NFuzzySets[CurrentVar];j++)
{
TempMass2 = getMRFromFSvalues(TempCoordinate,CurrentVar,j);
if (TempMass2 > AlphaCut[j])
TempMass2 = AlphaCut[j];
if (TempMass2 > TempMass1)
TempMass1 = TempMass2;
}
MassSumm += TempMass1;
CoordinateMassSumm += TempCoordinate * TempMass1;
}
if (MassSumm != 0)
ValuesForFuzzy[CurrentVar] = CoordinateMassSumm / MassSumm;
if (ValuesForFuzzy[CurrentVar].isNaN)
ValuesForFuzzy[CurrentVar] = 0;
}
}
}
////////////////////////////////////////////////unfuzzy
function controlAlgorithm (parameters) {
if (parameters.ctrlAlgNo == 1) {
pwm = parameters.pCoeff*(desiredValue-actualValue);
if (pwm > pwmLimit) {pwm = pwmLimit}; // to limit pwm values
if (pwm < -pwmLimit) {pwm = -pwmLimit}; // to limit pwm values
if (pwm > 0) {board.digitalWrite(2,1); board.digitalWrite(4,0);}; // direction if > 0
if (pwm < 0) {board.digitalWrite(2,0); board.digitalWrite(4,1);}; // direction if < 0
board.analogWrite(3, Math.abs(pwm));
}
if (parameters.ctrlAlgNo == 2) {
err = desiredValue - actualValue; // error as difference between desired and actual val.
errSum += err; // sum of errors | like integral
dErr = err - lastErr; // difference of error
pwm = parameters.Kp1*err+parameters.Ki1*errSum+parameters.Kd1*dErr; // PID expression
lastErr = err; // save the value of error for next cycle to estimate the derivative
if (pwm > pwmLimit) {pwm = pwmLimit}; // to limit pwm values
if (pwm < -pwmLimit) {pwm = -pwmLimit}; // to limit pwm values
if (pwm > 0) {board.digitalWrite(2,1); board.digitalWrite(4,0);}; // direction if > 0
if (pwm < 0) {board.digitalWrite(2,0); board.digitalWrite(4,1);}; // direction if < 0
board.analogWrite(3, Math.abs(pwm));
}
if (parameters.ctrlAlgNo == 3) {
var errLast = err;
err = desiredValue - actualValue; // error as difference between desired and actual val.
errSum += err; // sum of errors | like integral
dErr = err - lastErr; // difference of error
if(errLast*err < 0)
errSum = 0;
if(errSum > 254/parameters.Ki2)
errSum = 254/parameters.Ki2;
if(errSum < -254/parameters.Ki2)
errSum = -254/parameters.Ki2;
pwm = parameters.Kp2*err+parameters.Ki2*errSum+parameters.Kd2*dErr; // PID expression
console.log(parameters.Kp2 + "|" + parameters.Ki2 + "|" + parameters.Kd2);
lastErr = err; // save the value of error for next cycle to estimate the derivative
if (pwm > pwmLimit) {pwm = pwmLimit}; // to limit pwm values
if (pwm < -pwmLimit) {pwm = -pwmLimit}; // to limit pwm values
if (pwm > 0) {board.digitalWrite(2,1); board.digitalWrite(4,0);}; // direction if > 0
if (pwm < 0) {board.digitalWrite(2,0); board.digitalWrite(4,1);}; // direction if < 0
board.analogWrite(3, Math.abs(pwm));
}
if (parameters.ctrlAlgNo == 4) {
ValuesForFuzzy[1] = desiredValue - actualValue;
FSpos1 = parameters.FSpos1;
FSpos2 = parameters.FSpos2;
console.log(parameters);
getDesiredValuesFuzzy();
pwm = ValuesForFuzzy[0];
err = desiredValue - actualValue; // error as difference between desired and actual val.
lastErr = err; // save the value of error for next cycle to estimate the derivative
if (pwm > pwmLimit) {pwm = pwmLimit}; // to limit pwm values
if (pwm < -pwmLimit) {pwm = -pwmLimit}; // to limit pwm values
if (pwm > 0) {board.digitalWrite(2,1); board.digitalWrite(4,0);}; // direction if > 0
if (pwm < 0) {board.digitalWrite(2,0); board.digitalWrite(4,1);}; // direction if < 0
board.analogWrite(3, Math.abs(pwm));
}
};
function startControlAlgorithm (parameters) {
if (controlAlgorithmStartedFlag == 0) {
controlAlgorithmStartedFlag = 1;
intervalCtrl = setInterval(function(){controlAlgorithm(parameters);}, 30); // call the alg. on 30ms
console.log("Control algorithm has been started.");
sendStaticMsgViaSocket("Control alg " + parameters.ctrlAlgNo + " started | " + json2txt(parameters));
}
};
function stopControlAlgorithm () {
clearInterval(intervalCtrl); // clear the interval of control algorihtm
board.analogWrite(3, 0);
err = 0; // error as difference between desired and actual val.
errSum = 0; // sum of errors | like integral
dErr = 0;
lastErr = 0; // difference
pwm = 0;
controlAlgorithmStartedFlag = 0;
console.log("Control algorithm has been stopped.");
sendStaticMsgViaSocket("Stopped.")
};
function sendValues (socket) {
socket.emit("clientReadValues",
{
"desiredValue": desiredValue,
"actualValue": actualValue,
"pwm": pwm,
"err": err,
"errSum": errSum,
"dErr": dErr,
"AlphaCut":AlphaCut,
"ValuesForFuzzy":ValuesForFuzzy
});
};
function json2txt(obj) // function to print out the json names and values
{
var txt = '';
var recurse = function(_obj) {
if ('object' != typeof(_obj)) {
txt += ' = ' + _obj + '\n';
}
else {
for (var key in _obj) {
if (_obj.hasOwnProperty(key)) {
txt += '.' + key;
recurse(_obj[key]);
}
}
}
};
recurse(obj);
return txt;
}
<!DOCTYPE html>
<meta charset = utf8>
<html>
<head>
<title>Example with potentiometer</title>
</head>
<body onload="load();">
<div>
<canvas id="canvas1" width ="200" height = "100" style="border: 1px dashed #00c3c3;"></canvas>
<canvas id="canvas4" width = "200" height = "100" style="border: 1px dashed #00c3c3;"></canvas>
<br>
<canvas id="canvas2" width ="200" height = "100" style="border: 1px dashed #00c3c3;"></canvas>
<canvas id="canvas5" width = "200" height = "100" style="border: 1px dashed #00c3c3;"></canvas>
<br>
<canvas id="canvas3" width = "200" height = "100" style="border: 1px dashed #00c3c3;"></canvas>
<canvas id="canvas6" width = "200" height = "100" style="border: 1px dashed #00c3c3;"></canvas>
<br>
</div>
<p></p>
pCoeff: <input id="pCoeff" value="0.1" size="5" />
<button id="buttonStartControlAlgorithm1" onClick="startControlAlgorithm1();">Start Ctrl Alg1</button>
<button id="buttonStopControlAlgorithm" onClick="stopControlAlgorithm();">Stop Ctrl Alg</button>
<p></p>
Kp: <input id="Kp1" value="0.15" size = "5" />
Ki: <input id="Ki1" value="0.0055" size = "5" />
Kd: <input id="Kd1" value="0.25" size = "5" />
<button id="buttonStartControlAlgorithm2" onClick="startControlAlgorithm2();">Start Ctrl Alg2</button>
<button id="buttonStopControlAlgorithm" onClick="stopControlAlgorithm();">Stop Ctrl Alg</button>
<p></p>
Kp: <input id="Kp2" value="0.5" size = "5" />
Ki: <input id="Ki2" value="0.008" size = "5" />
Kd: <input id="Kd2" value="0.35" size = "5" />
<button id="buttonStartControlAlgorithm3" onClick="startControlAlgorithm3();">Start Ctrl Alg3</button>
<button id="buttonStopControlAlgorithm" onClick="stopControlAlgorithm();">Stop Ctrl Alg</button>
<p></p>
FSpos1: <input id="FSpos1" value="125" size = "5" />
FSpos2: <input id="FSpos2" value="25" size = "5" />
<button id="buttonStartControlAlgorithm4" onClick="startControlAlgorithm4();">Start Ctrl Alg4</button>
<button id="buttonStopControlAlgorithm" onClick="stopControlAlgorithm();">Stop Ctrl Alg</button>
<div id="divForStaticPrint"> </div>
<p></p>
<div id="divForPrint"></div>
<br>
<script type="text/javascript" src="/socket.io/socket.io.js"></script>
<script type="text/javascript">
var potValue1 = 0; // value of the first potentiometer
var potValue2 = 0; // value of the second potentiometer
var x1 = new Array(); // array for x1
var y1 = new Array(); // array for y1
var x2 = new Array(); // array for x2
var y2 = new Array(); // array for y2
var x3 = new Array(); // array for x3 variable
var y3 = new Array(); // array for y3 variable
var canvas1;
var canvas2;
var ctx1;
var ctx2;
var pwm;
var FSpos1=document.getElementById("FSpos1").value;
var FSpos2=document.getElementById("FSpos2").value;
// variable for P part
var x4 = new Array(); // array for x4 variable
var y4 = new Array(); // array for y4 variable
var canvas4;
var ctx4;
// variable for I part
var x5 = new Array(); // array for x5 variable
var y5 = new Array(); // array for y5 variable
var canvas5;
var ctx5;
// variable for D part
var x6 = new Array(); // array for x6 variable
var y6 = new Array(); // array for y6 variable
var canvas6;
var ctx6;
function load() { // function that is started, when we open the page
canvas1 = document.getElementById("canvas1");
ctx1 = canvas1.getContext("2d");
canvas2 = document.getElementById("canvas2");
ctx2 = canvas2.getContext("2d");
// initialization for canvas3
canvas3 = document.getElementById("canvas3");
ctx3 = canvas3.getContext("2d");
// initialization for canvas4
canvas4 = document.getElementById("canvas4");
ctx4 = canvas4.getContext("2d");
// initialization for canvas5
canvas5 = document.getElementById("canvas5");
ctx5 = canvas5.getContext("2d");
// initialization for canvas6
canvas6 = document.getElementById("canvas6");
ctx6 = canvas6.getContext("2d");
// initialization of first graph
for (var i=0; i<200; i++) {
x1[i] = i; // for x values are 0, 1, 2, ...
y1[i] = 0; // for y values are 0
};
// initializaion of second graph
for (var i=0; i<200; i++) {
x2[i] = i; // x2 values are 0, 1, 2, ...
y2[i] = 0; // for y2 values are 0
};
// initialization of xy3 variables
for (var i=0; i<200; i++) {
x3[i] = i; // x values are 0, 1, 2, ...
y3[i] = 0; // for y values are 0
};
// initialize fourth graph arrays
for (var i=0; i<200; i++) {
x4[i] = i; // for x values are 0, 1, 2, ...
y4[i] = 0; // for y values are 0
};
// initialize fifth graph arrays
for (var i=0; i<200; i++) {
x5[i] = i; // for x values are 0, 1, 2, ...
y5[i] = 0; // for y values are 0
};
// initialize sixth graph arrays
for (var i=0; i<200; i++) {
x6[i] = i; // for x values are 0, 1, 2, ...
y6[i] = 0; // for y values are 0
};
};
var divForPrint = document.getElementById("divForPrint");
// var for printing messages
var numberOfLinesInLog = 20; // variable for the number of lines in log div
var counterOfLogs = 0; // variable for counting the logs
function log(msg) { // function to print messages to div with implemented scroll
var node=document.createElement("tr"); // we create variable node as tr (table row)
var textnode=document.createTextNode(counterOfLogs + " | " + msg); // create elem. with text
node.appendChild(textnode); // add to "node", i.e. table row
divForPrint.insertBefore(node, divForPrint.childNodes[0]); // insert into variable divForPrint -> document.getElementById("divForPrint");
if (counterOfLogs > numberOfLinesInLog-1) { // if there are more numbers as e.g. 10
divForPrint.removeChild(divForPrint.childNodes[numberOfLinesInLog]); // remove the oldest printout
}
counterOfLogs = counterOfLogs + 1; // increase the counter of logs
}
var socket = io.connect("192.168.254.149:8080"); // connect via socket
socket.on("messageToClient", function (msg){
log(msg); // add msg to div
});
socket.on("staticMsgToClient", function(msg) { // when we recive static message
document.getElementById("divForStaticPrint").innerHTML = "Status: " + msg; // we print to div
});
socket.on("clientReadValues", function(value) {
potValue1 = value.desiredValue;
potValue2 = value.actualValue;
pwm = parseInt((value.pwm).toFixed(0), 10);
// Draw graph No1 *****************************************
ctx1.lineWidth = "1";
ctx1.strokeStyle = "#ff0000";
ctx1.clearRect(0, 0, canvas1.width, canvas1.height); // clear the canvas
// add legend to graph
ctx1.font = "11px Arial";
ctx1.fillText("Desired", 70, 10);
ctx1.beginPath(); // beginning of the short line for the legend
ctx1.lineTo(50, 6);
ctx1.lineTo(65, 6);
ctx1.stroke();
ctx1.font = "11px Arial";
ctx1.fillText("Actual", 140, 10);
ctx1.strokeStyle = "#00ff00";
ctx1.beginPath(); // beginning of the short line for the legend
ctx1.lineTo(120, 6);
ctx1.lineTo(135, 6);
ctx1.stroke();
// add axis labels
ctx1.fillText("<-" + 0 + "|" + 200 + "->", 150, 100-5); // display no. of points on x-axis
// min on y-axis label
ctx1.fillText(1023,5,11);
ctx1.fillText(0,5,100-5);
ctx1.strokeStyle = "#ff0000";
ctx1.beginPath(); // to start drawing new line
y1.splice(0, 1); // on the position 0 in the field y1 we erase one value
y1[199] = potValue1; // new value is added at the end
for (var i=0; i<200; i++) {
ctx1.lineTo(x1[i], (100 - (y1[i] / 1023) * 100)); // 0,0 x,y coordinate is in upper left corner
};
ctx1.stroke(); // to draw the line
// End of draw graph No1 ***********************************
// Draw graph No2 *****************************************
ctx1.strokeStyle = "#00ff00"; // green line
ctx1.beginPath(); // to start drawing new line
y2.splice(0, 1); // on the position 0 in the field y2 we erase one value
y2[199] = potValue2; // new value is added at the end
for (var i=0; i<200; i++) {
ctx1.lineTo(x2[i], (100 - (y2[i] / 1023) * 100)); // 0,0 x,y coordinate is in upper left corner
};
ctx1.stroke(); // to draw the line
// End of draw graph No2 ***********************************
// Draw graph No3 on canvas2 *****************************************
ctx2.lineWidth = "1";
ctx2.clearRect(0, 0, canvas2.width, canvas2.height); // clear the canvas
// draw centerline at 0
ctx2.strokeStyle = "#add8e6";
ctx2.beginPath(); // draw centerline at 0
ctx2.lineTo(0, 50); // starting point
ctx2.lineTo(200, 50); // ending point
ctx2.stroke();
// add legend to graph
ctx2.font = "11px Arial";
ctx2.fillText("PWM", 70, 10);
ctx2.strokeStyle = "#0000ff";
ctx2.beginPath(); // beginning of the short line for the legend
ctx2.lineTo(50, 6);
ctx2.lineTo(65, 6);
ctx2.stroke();
ctx2.strokeStyle = "#0000ff";
ctx2.beginPath(); // to start drawing new line
y3.splice(0, 1); // on the position 0 in the field y we erase one value
y3[199] = pwm; // new value is added at the end
for (var i=0; i<200; i++) {
ctx2.lineTo(x3[i], (100 - (255 + y3[i]) / 510 * 100)); // 0,0 x,y coordinate is in upper left corner
};
ctx2.stroke(); // to draw the line
// add axis labels
ctx2.fillText("<-" + 0 + "|" + 200 + "->", 150, 100-5); // display no. of points on x-axis
// min on y-axis label
ctx2.fillText(255,5,11);
ctx2.fillText(-255,5,100-5);
// End of draw No3 on canvas2 ***********************************
// Draw canvas3 as X **********************************************
ctx3.clearRect(0, 0, canvas3.width, canvas3.height); // clear canvas only ONCE!
// draw X
ctx3.lineWidth = "1";
ctx3.strokeStyle = "#add8e6";
ctx3.beginPath(); // beginning of the line
ctx3.lineTo(10, 10); // starting point
ctx3.lineTo(190, 90); // ending point
ctx3.stroke(); // to put it on the graph
ctx3.beginPath(); // beginning of the line
ctx3.lineTo(10, 90); // starting point
ctx3.lineTo(190, 10); // ending point
ctx3.stroke(); // to put it on the graph
// Draw canvas3 END ************************************
// Draw canvas4 graph for P part **********************************************
ctx4.clearRect(0, 0, canvas4.width, canvas4.height); // clear canvas only ONCE!
var newvalue = 0;
var range = 35;
// draw line at coordinate 0
ctx4.lineWidth = "1";
ctx4.strokeStyle = "#000000"; // light red
ctx4.beginPath(); // beginning of the line
ctx4.lineTo(100, 0); // starting point
ctx4.lineTo(100, 100); // ending point
ctx4.stroke(); // to put it on the graph
ctx4.lineWidth = "1";
ctx4.strokeStyle = "#000000"; // light red
ctx4.beginPath(); // beginning of the line
ctx4.lineTo(0, 90); // starting point
ctx4.lineTo(200, 90); // ending point
ctx4.stroke(); // to put it on the graph
ctx4.lineWidth = "1";
ctx4.strokeStyle = "#000000"; // light red
ctx4.beginPath(); // beginning of the line
ctx4.lineTo(95, 10); // starting point
ctx4.lineTo(105, 10); // ending point
ctx4.stroke(); // to put it on the graph
ctx4.lineWidth = "1";
ctx4.strokeStyle = "#ff0000"; // light red
ctx4.beginPath(); // beginning of the line
ctx4.lineTo(100-FSpos2/range*100, 90); // starting point
ctx4.lineTo(100, 10); // ending point
ctx4.stroke(); // to put it on the graph
ctx4.lineWidth = "1";
ctx4.strokeStyle = "#ff0000"; // light red
ctx4.beginPath(); // beginning of the line
ctx4.lineTo(FSpos2/range*100+100, 90); // starting point
ctx4.lineTo(100, 10); // ending point
ctx4.stroke(); // to put it on the graph
ctx4.lineWidth = "1";
ctx4.strokeStyle = "#00ff00"; // light red
ctx4.beginPath(); // beginning of the line
ctx4.lineTo(100-FSpos2/range*100, 10); // starting point
ctx4.lineTo(100, 90); // ending point
ctx4.stroke(); // to put it on the graph
ctx4.lineWidth = "1";
ctx4.strokeStyle = "#00ff00"; // light red
ctx4.beginPath(); // beginning of the line
ctx4.lineTo(100-FSpos2/range*100, 10); // starting point
ctx4.lineTo(0, 10); // ending point
ctx4.stroke(); // to put it on the graph
ctx4.lineWidth = "1";
ctx4.strokeStyle = "#0000ff"; // light red
ctx4.beginPath(); // beginning of the line
ctx4.lineTo(FSpos2/range*100+100, 10); // starting point
ctx4.lineTo(100, 90); // ending point
ctx4.stroke(); // to put it on the graph
ctx4.lineWidth = "1";
ctx4.strokeStyle = "#0000ff"; // light red
ctx4.beginPath(); // beginning of the line
ctx4.lineTo(FSpos2/range*100+100, 10); // starting point
ctx4.lineTo(200, 10); // ending point
ctx4.stroke(); // to put it on the graph
var errvalue = value.err*range/FSpos2*2;
if(errvalue < -FSpos2/range*100/4)
{
ctx4.lineWidth = "1";
ctx4.strokeStyle = "#00ff00"; // light red
ctx4.beginPath(); // beginning of the line
ctx4.lineTo(100+errvalue, 90); // starting point
newvalue = 80/(FSpos2/range*100)*(errvalue+FSpos2/range*100)+10;
if(newvalue > 90)
newvalue = 90;
if(newvalue < 10)
newvalue = 10;
ctx4.lineTo(100+errvalue, newvalue); // ending point
ctx4.stroke(); // to put it on the graph
ctx4.lineWidth = "1";
ctx4.strokeStyle = "#ff0000"; // light red
ctx4.beginPath(); // beginning of the line
ctx4.lineTo(100+errvalue, 90); // starting point
newvalue = -80/(FSpos2/range*100)*(errvalue)+10;
if(errvalue > 0)
newvalue = 90;
if(newvalue > 90)
newvalue = 90;
if(newvalue < 10)
newvalue = 10;
ctx4.lineTo(100+errvalue, newvalue); // ending point
ctx4.stroke(); // to put it on the graph
}
else
{
ctx4.lineWidth = "1";
ctx4.strokeStyle = "#ff0000"; // light red
ctx4.beginPath(); // beginning of the line
ctx4.lineTo(100+errvalue, 90); // starting point
newvalue = -80/(FSpos2/range*100)*(errvalue)+10;
if(errvalue > 0)
newvalue = 90;
if(newvalue > 90)
newvalue = 90;
if(newvalue < 10)
newvalue = 10;
ctx4.lineTo(100+errvalue, newvalue); // ending point
ctx4.stroke(); // to put it on the graph
ctx4.lineWidth = "1";
ctx4.strokeStyle = "#00ff00"; // light red
ctx4.beginPath(); // beginning of the line
ctx4.lineTo(100+errvalue, 90); // starting point
newvalue = 80/(FSpos2/range*100)*(errvalue+FSpos2/range*100)+10;
if(newvalue > 90)
newvalue = 90;
if(newvalue < 10)
newvalue = 10;
ctx4.lineTo(100+errvalue, newvalue); // ending point
ctx4.stroke(); // to put it on the graph
}
if(errvalue > FSpos2/range*100/4)
{
ctx4.lineWidth = "1";
ctx4.strokeStyle = "#0000ff"; // light red
ctx4.beginPath(); // beginning of the line
ctx4.lineTo(100+errvalue, 90); // starting point
newvalue = -80/(FSpos2/range*100)*(errvalue-FSpos2/range*100)+10;
if(newvalue > 90)
newvalue = 90;
if(newvalue < 10)
newvalue = 10;
ctx4.lineTo(100+errvalue, newvalue); // ending point
ctx4.stroke(); // to put it on the graph
ctx4.lineWidth = "1";
ctx4.strokeStyle = "#ff0000"; // light red
ctx4.beginPath(); // beginning of the line
ctx4.lineTo(100+errvalue, 90); // starting point
newvalue = 80/(FSpos2/range*100)*(errvalue)+10;
if(errvalue < 0)
newvalue = 90;
if(newvalue > 90)
newvalue = 90;
if(newvalue < 10)
newvalue = 10;
ctx4.lineTo(100+errvalue, newvalue); // ending point
ctx4.stroke(); // to put it on the graph
}
else
{
ctx4.lineWidth = "1";
ctx4.strokeStyle = "#ff0000"; // light red
ctx4.beginPath(); // beginning of the line
ctx4.lineTo(100+errvalue, 90); // starting point
newvalue = 80/(FSpos2/range*100)*(errvalue)+10;
if(errvalue < 0)
newvalue = 90;
if(newvalue > 90)
newvalue = 90;
if(newvalue < 10)
newvalue = 10;
ctx4.lineTo(100+errvalue, newvalue); // ending point
ctx4.stroke(); // to put it on the graph
ctx4.lineWidth = "1";
ctx4.strokeStyle = "#0000ff"; // light red
ctx4.beginPath(); // beginning of the line
ctx4.lineTo(100+errvalue, 90); // starting point
newvalue = -80/(FSpos2/range*100)*(errvalue-FSpos2/range*100)+10;
if(newvalue > 90)
newvalue = 90;
if(newvalue < 10)
newvalue = 10;
ctx4.lineTo(100+errvalue, newvalue); // ending point
ctx4.stroke(); // to put it on the graph
}
ctx4.lineWidth = "1";
ctx4.strokeStyle = "#00ff00"; // light red
ctx4.beginPath(); // beginning of the line
newvalue = 80/(FSpos2/range*100)*(errvalue+FSpos2/range*100)+10;
if(newvalue > 90)
newvalue = 90;
if(newvalue < 10)
newvalue = 10;
ctx4.lineTo(100, newvalue); // starting point
ctx4.lineTo(100+errvalue, newvalue); // ending point
ctx4.stroke(); // to put it on the grap
ctx4.lineWidth = "1";
ctx4.strokeStyle = "#ff0000"; // light red
ctx4.beginPath(); // beginning of the line
newvalue = -80/(FSpos2/range*100)*(errvalue)+10;
if(errvalue > 0)
newvalue = 90;
if(newvalue > 90)
newvalue = 90;
if(newvalue < 10)
newvalue = 10;
ctx4.lineTo(100, newvalue); // starting point
ctx4.lineTo(100+errvalue, newvalue); // ending point
ctx4.stroke(); // to put it on the graph
ctx4.lineWidth = "1";
ctx4.strokeStyle = "#ff0000"; // light red
ctx4.beginPath(); // beginning of the line
newvalue = 80/(FSpos2/range*100)*(errvalue)+10;
if(errvalue < 0)
newvalue = 90;
if(newvalue > 90)
newvalue = 90;
if(newvalue < 10)
newvalue = 10;
ctx4.lineTo(100, newvalue); // starting point
ctx4.lineTo(100+errvalue, newvalue); // ending point
ctx4.stroke(); // to put it on the graph
ctx4.lineWidth = "1";
ctx4.strokeStyle = "#0000ff"; // light red
ctx4.beginPath(); // beginning of the line
newvalue = -80/(FSpos2/range*100)*(errvalue-FSpos2/range*100)+10;
if(newvalue > 90)
newvalue = 90;
if(newvalue < 10)
newvalue = 10;
ctx4.lineTo(100, newvalue); // starting point
ctx4.lineTo(100+errvalue, newvalue); // ending point
ctx4.stroke(); // to put it on the graph
ctx4.fillText(-range,5,85);
ctx4.fillText(range,180,85);
ctx4.fillStyle = "#00ff00";
ctx4.fillText(value.AlphaCut[0],5,38);
ctx4.fillStyle = "#ff0000";
ctx4.fillText(value.AlphaCut[1],5,50);
ctx4.fillStyle = "#0000ff";
ctx4.fillText(value.AlphaCut[2],5,62);
// draw P
/*ctx4.lineWidth = "1";
ctx4.strokeStyle = "#ff0000"; // set red color
ctx4.beginPath(); // to start drawing new line
y4.splice(0, 1); // on the position 0 in the field y3 we erase one value
y4[199] = value.err; // new value is added at the end
for (var i=0; i<200; i++) {
ctx4.lineTo(x4[i], (100 - (1024 + y4[i]) / 2048 * 100)); // 0,0 x,y coordinate is in upper left corner
};
ctx4.stroke(); // to draw the line*/
// END of draw canvas4 graph for P part **********************************************
// Draw canvas5 graph for I part **********************************************
ctx5.clearRect(0, 0, canvas4.width, canvas4.height); // clear canvas only ONCE!
newvalue = 0;
range = 254;
// draw line at coordinate 0
ctx5.lineWidth = "1";
ctx5.strokeStyle = "#000000"; // light red
ctx5.beginPath(); // beginning of the line
ctx5.lineTo(100, 0); // starting point
ctx5.lineTo(100, 100); // ending point
ctx5.stroke(); // to put it on the graph
ctx5.lineWidth = "1";
ctx5.strokeStyle = "#000000"; // light red
ctx5.beginPath(); // beginning of the line
ctx5.lineTo(0, 90); // starting point
ctx5.lineTo(200, 90); // ending point
ctx5.stroke(); // to put it on the graph
ctx5.lineWidth = "1";
ctx5.strokeStyle = "#000000"; // light red
ctx5.beginPath(); // beginning of the line
ctx5.lineTo(95, 10); // starting point
ctx5.lineTo(105, 10); // ending point
ctx5.stroke(); // to put it on the graph
ctx5.lineWidth = "1";
ctx5.strokeStyle = "#ff0000"; // light red
ctx5.beginPath(); // beginning of the line
ctx5.lineTo(100-FSpos1/range*100, 90); // starting point
ctx5.lineTo(100, 10); // ending point
ctx5.stroke(); // to put it on the graph
ctx5.lineWidth = "1";
ctx5.strokeStyle = "#ff0000"; // light red
ctx5.beginPath(); // beginning of the line
ctx5.lineTo(FSpos1/range*100+100, 90); // starting point
ctx5.lineTo(100, 10); // ending point
ctx5.stroke(); // to put it on the graph
ctx5.lineWidth = "1";
ctx5.strokeStyle = "#00ff00"; // light red
ctx5.beginPath(); // beginning of the line
ctx5.lineTo(100-FSpos1/range*100, 10); // starting point
ctx5.lineTo(100, 90); // ending point
ctx5.stroke(); // to put it on the graph
ctx5.lineWidth = "1";
ctx5.strokeStyle = "#00ff00"; // light red
ctx5.beginPath(); // beginning of the line
ctx5.lineTo(100-FSpos1/range*100, 10); // starting point
ctx5.lineTo(0, 10); // ending point
ctx5.stroke(); // to put it on the graph
ctx5.lineWidth = "1";
ctx5.strokeStyle = "#0000ff"; // light red
ctx5.beginPath(); // beginning of the line
ctx5.lineTo(FSpos1/range*100+100, 10); // starting point
ctx5.lineTo(100, 90); // ending point
ctx5.stroke(); // to put it on the graph
ctx5.lineWidth = "1";
ctx5.strokeStyle = "#0000ff"; // light red
ctx5.beginPath(); // beginning of the line
ctx5.lineTo(FSpos1/range*100+100, 10); // starting point
ctx5.lineTo(200, 10); // ending point
ctx5.stroke(); // to put it on the graph
ctx5.lineWidth = "1";
ctx5.strokeStyle = "#000000"; // light red
ctx5.beginPath(); // beginning of the line
ctx5.lineTo(100+FSpos1/range*100, 90); // starting point
ctx5.lineTo(100+FSpos1/range*100, 10); // starting point
ctx5.stroke(); // to put it on the graph
ctx5.lineWidth = "1";
ctx5.strokeStyle = "#000000"; // light red
ctx5.beginPath(); // beginning of the line
ctx5.lineTo(100-FSpos1/range*100, 90); // starting point
ctx5.lineTo(100-FSpos1/range*100, 10); // starting point
ctx5.stroke(); // to put it on the graph
ctx5.fillText(-range,5,85);
ctx5.fillText(range,180,85);
var cyclevalue = 0;
ctx5.lineWidth = "1";
ctx5.strokeStyle = "#00ff00"; // light red
for (var ii=-(100-FSpos1/range*100).toFixed()+2;ii<0;ii++)
{
ctx5.beginPath(); // beginning of the line
ctx5.lineTo(100+ii, 90); // starting point
newvalue = 80/(FSpos1/range*100)*(ii+FSpos1/range*100)+10;
if(newvalue > 90)
newvalue = 90;
if(newvalue < 10+80*(1-value.AlphaCut[0]))
newvalue = 10+80*(1-value.AlphaCut[0]);
ctx5.lineTo(100+ii, newvalue); // ending point
ctx5.stroke(); // to put it on the graph
}
ctx5.lineWidth = "1";
ctx5.strokeStyle = "#ff0000"; // light red
for (var ii=-(100-FSpos1/range*100).toFixed()+2;ii<0;ii++)
{
ctx5.beginPath(); // beginning of the line
ctx5.lineTo(100+ii, 90); // starting point
newvalue = -80/(FSpos1/range*100)*(ii)+10;
if(newvalue > 90)
newvalue = 90;
if(newvalue < 10+80*(1-value.AlphaCut[1]))
newvalue = 10+80*(1-value.AlphaCut[1]);
ctx5.lineTo(100+ii, newvalue); // ending point
ctx5.stroke(); // to put it on the graph
}
ctx5.lineWidth = "1";
ctx5.strokeStyle = "#ff0000"; // light red
for (var ii=0;ii<FSpos1/range*100;ii++)
{
ctx5.beginPath(); // beginning of the line
ctx5.lineTo(100+ii, 90); // starting point
newvalue = 80/(FSpos1/range*100)*(ii)+10;
if(newvalue > 90)
newvalue = 90;
if(newvalue < 10+80*(1-value.AlphaCut[1]))
newvalue = 10+80*(1-value.AlphaCut[1]);
ctx5.lineTo(100+ii, newvalue); // ending point
ctx5.stroke(); // to put it on the graph
}
ctx5.lineWidth = "1";
ctx5.strokeStyle = "#0000ff"; // light red
for (var ii=0;ii<FSpos1/range*100;ii++)
{
ctx5.beginPath(); // beginning of the line
ctx5.lineTo(100+ii, 90); // starting point
newvalue = -80/(FSpos1/range*100)*(ii-FSpos1/range*100)+10;
if(newvalue > 90)
newvalue = 90;
if(newvalue < 10+80*(1-value.AlphaCut[2]))
newvalue = 10+80*(1-value.AlphaCut[2]);
ctx5.lineTo(100+ii, newvalue); // ending point
ctx5.stroke(); // to put it on the graph
}
ctx5.lineWidth = "2";
ctx5.strokeStyle = "#000000"; // light red
ctx5.beginPath(); // beginning of the line
ctx5.lineTo(100+value.ValuesForFuzzy[0]/range*100, 90); // starting point
ctx5.lineTo(100+value.ValuesForFuzzy[0]/range*100, 85); // starting point
ctx5.stroke(); // to put it on the graph
// END of draw canvas5 graph for i part **********************************************
// Draw canvas6 graph for D part **********************************************
ctx6.clearRect(0, 0, canvas6.width, canvas6.height); // clear canvas only ONCE!
// draw line at coordinate 0
ctx6.lineWidth = "1";
ctx6.strokeStyle = "#add8e6"; // light green
ctx6.beginPath(); // beginning of the line
ctx6.lineTo(0, 50); // starting point
ctx6.lineTo(200, 50); // ending point
ctx6.stroke(); // to put it on the graph
// put on the legend
ctx6.font = "11px Arial";
ctx6.fillText("dError/dt",70,10);
ctx6.strokeStyle = "#00ff00";
ctx6.beginPath(); // beginning of legend line draw
ctx6.lineTo(50, 6);
ctx6.lineTo(65, 6);
ctx6.stroke(); // end of legend line draw
// draw I
ctx6.lineWidth = "1";
ctx6.strokeStyle = "#0000ff"; // set green color
ctx6.beginPath(); // to start drawing new line
y6.splice(0, 1); // on the position 0 in the field y3 we erase one value
y6[199] = value.dErr; // new value is added at the end
for (var i=0; i<200; i++) {
ctx6.lineTo(x6[i], (100 - (150 + y6[i]) / 300 * 100)); // 0,0 x,y coordinate is in upper left corner
};
ctx6.stroke(); // to draw the line
// add axis labels
ctx6.font = "10px Arial";
// x-axis label
ctx6.fillText("<-"+ 0 + "|" + 200 + "->", 155, 100-5); // display number of points on x-axis
// min on y-axis label:
//ctx6.textBaseline="top"; // to print font 5 px from top
ctx6.fillText(150,5,11); // values for y axis
ctx6.fillText(-150,5,100-5);
// END of draw canvas6 graph for D part **********************************************
log(value.desiredValue + "|" + value.actualValue + "|" + (value.desiredValue-value.actualValue) + "|" + (value.pwm).toFixed(0));
})
function startControlAlgorithm1() {
stopControlAlgorithm(); // just in case, if it is not started
pCoeff = document.getElementById("pCoeff").value; // read the value of coeff from input field
socket.emit("startControlAlgorithm", {"ctrlAlgNo": 1, "pCoeff": pCoeff}); // send value of coeff
}
function startControlAlgorithm2() {
stopControlAlgorithm(); // just in case, if it is not started
Kp1 = document.getElementById("Kp1").value; // read the value of coeff from input field
Ki1 = document.getElementById("Ki1").value; // read the value of coeff from input field
Kd1 = document.getElementById("Kd1").value; // read the value of coeff from input field
socket.emit("startControlAlgorithm", {"ctrlAlgNo": 2, "Kp1": Kp1, "Ki1": Ki1, "Kd1": Kd1}); // send value of coeff
}
function startControlAlgorithm3() {
stopControlAlgorithm(); // just in case, if it is not started
Kp2 = document.getElementById("Kp2").value; // read the value of coeff from input field
Ki2 = document.getElementById("Ki2").value; // read the value of coeff from input field
Kd2 = document.getElementById("Kd2").value; // read the value of coeff from input field
socket.emit("startControlAlgorithm", {"ctrlAlgNo": 3, "Kp2": Kp2, "Ki2": Ki2, "Kd2": Kd2}); // send value of coeff
}
function startControlAlgorithm4() {
stopControlAlgorithm(); // just in case, if it is not started
FSpos1 = document.getElementById("FSpos1").value; // read the value of coeff from input field
FSpos2 = document.getElementById("FSpos2").value; // read the value of coeff from input field
socket.emit("startControlAlgorithm", {"ctrlAlgNo": 4, "FSpos1": FSpos1, "FSpos2": FSpos2}); // send value of coeff
}
function stopControlAlgorithm() {
socket.emit("stopControlAlgorithm");
}
socket.on("disconnect", function(){
log("Disconnected from the server"); // we print status of disconn. to div
});
</script>
</body>
</html>