const net = require("net"); const { resolve } = require("path"); const { TelnetSocket } = require("telnet-stream"); module.exports = class TelnetSenderGRBL{ /* urlGRBL: URL für den GCode Empfänger (MicroController, GRBL) * xAxisGrbl: Welche Achse soll ausgelesen werden? Welche Achse ist die GRBL-X-Achse * yAxisGrbl: ... * zAxisGrbl: ... */ constructor(urlGRBL = "grblesp.local", maxSpeedF = 5000, xAxisGrbl = "x", yAxisGrbl = "y", zAxisGrbl = "z", aAxisGrbl = null, bAxisGrbl = null, cAxisGrbl = null, eAxisGrbl = null){ var socket = null; this.tSocket = null; this.receiver = null; this.urlGRBLstr = urlGRBL; this.xAxisGrbl = xAxisGrbl; this.yAxisGrbl = yAxisGrbl; this.zAxisGrbl = zAxisGrbl; this.aAxisGrbl = aAxisGrbl; this.bAxisGrbl = bAxisGrbl; this.cAxisGrbl = cAxisGrbl; this.eAxisGrbl = eAxisGrbl; this.maxSpeedF = maxSpeedF; // Speichere für Backward-Kompatibilität if (urlGRBL === "test.test") { this.tSocket = { written: "", write(txt){ this.written = txt; } }; this.isTestMode = true; return; } new Promise((resolve, reject) => { socket = net.createConnection({port: 23, host: urlGRBL},() => { resolve(socket); }) .on('error', reject); }).then( connection => { connection.on('data', data => {}); }, error => { console.log("Telnet Connection Error on " + urlGRBL + ": " + error.toString()); this.tSocket = null; }); if(socket != null){ this.tSocket = new TelnetSocket(socket); this.tSocket.on("close", function () { console.log("Telnet Closed " + urlGRBL); this.tSocket = null; }); } console.log("🤖 TelnetSenderGRBL initialized: " + urlGRBL); } moveTo(mOld, mNew){ this.execCommand("G1", mOld, mNew) } execCommand(strCommand = "G1", mOld, mNew ){ // The Hand-Turn is not 1:1 to the Hand-Lift ° var factorTurnLift = 1.2; // The Hand-Open is not 1:1 to the Hand-Turn var factorOpenTurn = 1.92; // Hand-Open in mm var handOpenInMM = 1.0 var data = strCommand.toString("utf-8"); if(this.xAxisGrbl == "x" && mNew.xMotorChanged && Number.isFinite(mNew.x)){ data += " x" + (mNew.x).toFixed(2).toString(); } if(this.xAxisGrbl == "y" && mNew.yMotorChanged && Number.isFinite(mNew.y)){ data += " x" + (mNew.y * 180 / Math.PI).toFixed(2).toString(); } if(this.xAxisGrbl == "z" && mNew.zMotorChanged && Number.isFinite(mNew.z) && Number.isFinite(mNew.y)){ data += " x" + ((mNew.z * 180 / Math.PI) - (mNew.y * 180 / Math.PI) ).toFixed(2).toString(); } if(this.xAxisGrbl == "a" && mNew.aMotorChanged && Number.isFinite(mNew.a)){ // This is the case for the Ellbow, when the Motor is connected to the X-Port of the FluidNC data += " x" + (mNew.a * 180 / Math.PI).toFixed(2).toString(); } if(this.xAxisGrbl == "b" && (mNew.bMotorChanged || mNew.cMotorChanged) && Number.isFinite(mNew.b) && Number.isFinite(mNew.z) && Number.isFinite(mNew.y)){ data += " x" + (mNew.b * 180 / Math.PI+(mNew.z * 180 / Math.PI) - (mNew.y * 180 / Math.PI)).toFixed(2).toString(); } if(this.xAxisGrbl == "c" && (mNew.bMotorChanged || mNew.cMotorChanged || mNew.zMotorChanged) && Number.isFinite(mNew.b) && Number.isFinite(mNew.c)){ // Runs correctly, substracts the "b" axis, uses the "c" axis to send to the x-Motor wich is in this case the hand-twist data += " x" + ((-1)*mNew.b * 180 / Math.PI + (mNew.c * 180 / Math.PI) ).toFixed(2).toString(); } if(this.xAxisGrbl == "e" && mNew.eMotorChanged && Number.isFinite(mNew.b) && Number.isFinite(mNew.c) && Number.isFinite(mNew.e)){ //This is the case for the Hand, when the Open-Close Motor is connected to the X-Port of FluidNC var handUpDown = mNew.b * 180 * factorTurnLift / Math.PI ; var handTurn = mNew.c*180/Math.PI ; data += " x" + ((-1.0*(-1.0*(handUpDown) + handTurn) + mNew.e*handOpenInMM)).toFixed(2).toString(); } if(this.yAxisGrbl == "x" && mNew.xMotorChanged && Number.isFinite(mNew.x)){ data += " y" + (mNew.x ).toFixed(2).toString(); } if(this.yAxisGrbl == "y" && mNew.yMotorChanged && Number.isFinite(mNew.y)){ data += " y" + (mNew.y * 180 / Math.PI).toFixed(2).toString(); } if(this.yAxisGrbl == "z" && mNew.zMotorChanged && Number.isFinite(mNew.z) && Number.isFinite(mNew.y)){ data += " y" + ((mNew.z * 180 / Math.PI) - (mNew.y * 180 / Math.PI) ).toFixed(2).toString(); } if(this.yAxisGrbl == "a" && mNew.aMotorChanged && Number.isFinite(mNew.a)){ data += " y" + (mNew.a * 180 / Math.PI).toFixed(2).toString(); } if(this.yAxisGrbl == "b" && (mNew.bMotorChanged || mNew.cMotorChanged || mNew.zMotorChanged) && Number.isFinite(mNew.b) && Number.isFinite(mNew.z) && Number.isFinite(mNew.y)){ data += " y" + (mNew.b * 180 / Math.PI+(mNew.z * 180 / Math.PI) - (mNew.y * 180 / Math.PI)).toFixed(2).toString(); } if(this.yAxisGrbl == "c" && (mNew.bMotorChanged || mNew.cMotorChanged || mNew.zMotorChanged) && Number.isFinite(mNew.b) && Number.isFinite(mNew.c)){ // This is the case if the hand-rotation-turner is connected to the FluidNC-Y var handUpDown = (mNew.b * 180 / Math.PI ) * factorTurnLift; var handTurn = ( mNew.c*180/Math.PI ) ; data += " y" + (-1.0*(handUpDown) + handTurn).toFixed(2).toString(); } if(this.yAxisGrbl == "e" && (mNew.eMotorChanged) && Number.isFinite(mNew.e)){ data += " y" + (mNew.e * 180 / Math.PI).toFixed(2).toString(); } if(this.zAxisGrbl == "x" && mNew.xMotorChanged && Number.isFinite(mNew.x)){ data += " z" + (mNew.x).toFixed(2).toString(); } if(this.zAxisGrbl == "y" && mNew.yMotorChanged && Number.isFinite(mNew.y)){ data += " z" + (mNew.y * 180 / Math.PI).toFixed(2).toString(); } if(this.zAxisGrbl == "z" && mNew.zMotorChanged && Number.isFinite(mNew.z) && Number.isFinite(mNew.y)){ data += " z" + ((mNew.z * 180 / Math.PI) - (mNew.y * 180 / Math.PI) ).toFixed(2).toString(); } if(this.zAxisGrbl == "a" && mNew.aMotorChanged && Number.isFinite(mNew.a)){ data += " z" + (mNew.a * 180 / Math.PI).toFixed(2).toString(); } if(this.zAxisGrbl == "b" && (mNew.bMotorChanged || mNew.cMotorChanged || mNew.zMotorChanged) && Number.isFinite(mNew.b)){ // This is the case of the Hand, when the Up-Down-Motor is connected to the FluidNC-Z data += " z" + ( mNew.b * 180 / Math.PI ).toFixed(2).toString(); } if(this.zAxisGrbl == "c" && (mNew.bMotorChanged || mNew.cMotorChanged || mNew.zMotorChanged) && Number.isFinite(mNew.c) && Number.isFinite(mNew.b) && Number.isFinite(mNew.z) && Number.isFinite(mNew.y)){ data += " z" + (mNew.c * 180 / Math.PI + (mNew.b * 180 / Math.PI) + (mNew.z * 180 / Math.PI) - (mNew.y * 180 / Math.PI)).toFixed(2).toString(); } if(this.zAxisGrbl == "e" && (mNew.eMotorChanged) && Number.isFinite(mNew.e)){ data += " z" + (mNew.e * 180 / Math.PI).toFixed(2).toString(); } if(this.aAxisGrbl == "x" && mNew.xMotorChanged && Number.isFinite(mNew.y)){ data += " a" + (mNew.y * 180 / Math.PI).toFixed(2).toString(); } if(this.aAxisGrbl == "y" && mNew.yMotorChanged && Number.isFinite(mNew.y)){ data += " a" + (mNew.y * 180 / Math.PI).toFixed(2).toString(); } if(this.aAxisGrbl == "z" && mNew.zMotorChanged && Number.isFinite(mNew.z) && Number.isFinite(mNew.y)){ data += " a" + ((mNew.z * 180 / Math.PI) - (mNew.y * 180 / Math.PI) ).toFixed(2).toString(); } if(this.aAxisGrbl == "a" && mNew.aMotorChanged && Number.isFinite(mNew.a)){ data += " a" + (mNew.a * 180 / Math.PI).toFixed(2).toString(); } if(this.aAxisGrbl == "b" && (mNew.bMotorChanged || mNew.cMotorChanged || mNew.zMotorChanged) && Number.isFinite(mNew.b) && Number.isFinite(mNew.z) && Number.isFinite(mNew.y)){ data += " a" + (mNew.b * 180 / Math.PI+(mNew.z * 180 / Math.PI) - (mNew.y * 180 / Math.PI)).toFixed(2).toString(); } if(this.aAxisGrbl == "c" && (mNew.bMotorChanged || mNew.cMotorChanged || mNew.zMotorChanged) && Number.isFinite(mNew.c) && Number.isFinite(mNew.b) && Number.isFinite(mNew.z) && Number.isFinite(mNew.y)){ data += " a" + (mNew.c * 180 / Math.PI + (mNew.b * 180 / Math.PI) + (mNew.z * 180 / Math.PI) - (mNew.y * 180 / Math.PI)).toFixed(2).toString(); } if(this.aAxisGrbl == "e" && mNew.eMotorChanged && Number.isFinite(mNew.e)){ // ToDo Mai 2024 data += " a" + (mNew.e * 180 / Math.PI).toFixed(2).toString(); } if(this.bAxisGrbl == "x" && mNew.xMotorChanged && Number.isFinite(mNew.x)){ data += " b" + (mNew.x).toFixed(2).toString(); } if(this.bAxisGrbl == "y" && mNew.yMotorChanged && Number.isFinite(mNew.y)){ data += " b" + (mNew.y * 180 / Math.PI).toFixed(2).toString(); } if(this.bAxisGrbl == "z" && mNew.zMotorChanged && Number.isFinite(mNew.z) && Number.isFinite(mNew.y)){ data += " b" + ((mNew.z * 180 / Math.PI) - (mNew.y * 180 / Math.PI) ).toFixed(2).toString(); } if(this.bAxisGrbl == "a" && mNew.aMotorChanged && Number.isFinite(mNew.a)){ data += " b" + (mNew.a * 180 / Math.PI).toFixed(2).toString(); } if(this.bAxisGrbl == "b" && (mNew.bMotorChanged || mNew.cMotorChanged || mNew.zMotorChanged) && Number.isFinite(mNew.b)){ data += " b" + (mNew.b * 180 / Math.PI).toFixed(2).toString(); } if(this.bAxisGrbl == "c" && (mNew.bMotorChanged || mNew.cMotorChanged || mNew.zMotorChanged) && Number.isFinite(mNew.c) && Number.isFinite(mNew.b) && Number.isFinite(mNew.z) && Number.isFinite(mNew.y)){ data += " b" + (mNew.c * 180 / Math.PI + (mNew.b * 180 / Math.PI) + (mNew.z * 180 / Math.PI) - (mNew.y * 180 / Math.PI)).toFixed(2).toString(); } if(this.bAxisGrbl == "e" && mNew.eMotorChanged && Number.isFinite(mNew.e)){ data += " b" + (mNew.e * 180 / Math.PI).toFixed(2).toString(); } if(this.tSocket && data.length > 3){ if(strCommand == "G1" && mNew){ const DEFAULT_FEEDRATE = process.env.ROBOT_DEFAULT_FEEDRATE ? Number(process.env.ROBOT_DEFAULT_FEEDRATE) : this.maxSpeedF; const feedrate = mNew.feedrate !== undefined ? mNew.feedrate : DEFAULT_FEEDRATE; data += " f"+(feedrate.toFixed(2).toString()) // ToDo: Aus motorSpeed mit einzelnenen Werten muss noch die feedrate berechnet werden. // hier bin ich unsicher, ob das nicht in den Sender rein sollte, da es eventuell // abhngig vom FluidNC und dessen speed interpretation ist. } if(data.indexOf("G90") == -1){ data = "G90 " + data; } console.log("Driver send to 🤖 " + this.urlGRBLstr + " the message: " + data) this.tSocket.write( data + "\r\n"); } } }