Punkt 2 implementieren GitHub CoPilot
This commit is contained in:
19
robot/SenderInterface.js
Normal file
19
robot/SenderInterface.js
Normal file
@@ -0,0 +1,19 @@
|
||||
class SenderInterface {
|
||||
async connect() {
|
||||
throw new Error('connect() must be implemented by sender classes');
|
||||
}
|
||||
|
||||
send(command) {
|
||||
throw new Error('send() must be implemented by sender classes');
|
||||
}
|
||||
|
||||
getStatus() {
|
||||
throw new Error('getStatus() must be implemented by sender classes');
|
||||
}
|
||||
|
||||
disconnect() {
|
||||
throw new Error('disconnect() must be implemented by sender classes');
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = SenderInterface;
|
||||
@@ -1,20 +1,25 @@
|
||||
const net = require("net");
|
||||
const { resolve } = require("path");
|
||||
const { TelnetSocket } = require("telnet-stream");
|
||||
const SenderInterface = require("./SenderInterface");
|
||||
|
||||
|
||||
|
||||
module.exports = class TelnetSenderGRBL{
|
||||
module.exports = class TelnetSenderGRBL extends SenderInterface {
|
||||
|
||||
/* 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;
|
||||
constructor(urlGRBL = "grblesp.local", maxSpeedF = 5000, xAxisGrbl = "x", yAxisGrbl = "y", zAxisGrbl = "z", aAxisGrbl = null, bAxisGrbl = null, cAxisGrbl = null, eAxisGrbl = null, options = {}){
|
||||
super();
|
||||
|
||||
this.tSocket = null;
|
||||
this.receiver = null;
|
||||
this.connectPromise = null;
|
||||
this.connectResolver = null;
|
||||
this.connectRejecter = null;
|
||||
this.state = 'disconnected';
|
||||
this.error = null;
|
||||
|
||||
this.urlGRBLstr = urlGRBL;
|
||||
this.xAxisGrbl = xAxisGrbl;
|
||||
@@ -26,40 +31,206 @@ module.exports = class TelnetSenderGRBL{
|
||||
this.eAxisGrbl = eAxisGrbl;
|
||||
|
||||
this.maxSpeedF = maxSpeedF; // Speichere für Backward-Kompatibilität
|
||||
|
||||
|
||||
|
||||
this.netModule = options.netModule || net;
|
||||
this.TelnetSocketClass = options.TelnetSocketClass || TelnetSocket;
|
||||
this.setTimeoutFn = options.setTimeoutFn || setTimeout;
|
||||
this.clearTimeoutFn = options.clearTimeoutFn || clearTimeout;
|
||||
this.reconnectDelay = Number.isFinite(options.reconnectDelay) ? options.reconnectDelay : 1000;
|
||||
this.maxReconnectDelay = Number.isFinite(options.maxReconnectDelay) ? options.maxReconnectDelay : 30000;
|
||||
this.reconnectAttempt = 0;
|
||||
this.reconnectTimer = null;
|
||||
this.shouldReconnect = true;
|
||||
this.autoConnect = options.autoConnect !== false;
|
||||
this.isTestMode = false;
|
||||
|
||||
if (urlGRBL === "test.test") {
|
||||
this.tSocket = { written: "", write(txt){ this.written = txt; } };
|
||||
this.isTestMode = true;
|
||||
this.state = 'connected';
|
||||
this.shouldReconnect = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.autoConnect) {
|
||||
this.connect();
|
||||
console.log("🤖 TelnetSenderGRBL initialized: " + urlGRBL);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
});
|
||||
async connect() {
|
||||
if (this.isTestMode) {
|
||||
this.state = 'connected';
|
||||
return Promise.resolve(this);
|
||||
}
|
||||
|
||||
console.log("🤖 TelnetSenderGRBL initialized: " + urlGRBL);
|
||||
if (this.state === 'connected' && this.tSocket) {
|
||||
return Promise.resolve(this);
|
||||
}
|
||||
|
||||
if (this.connectPromise) {
|
||||
return this.connectPromise;
|
||||
}
|
||||
|
||||
if (this.reconnectTimer) {
|
||||
this.clearTimeoutFn(this.reconnectTimer);
|
||||
this.reconnectTimer = null;
|
||||
}
|
||||
|
||||
this.state = 'connecting';
|
||||
this.error = null;
|
||||
this.shouldReconnect = true;
|
||||
|
||||
this.connectPromise = new Promise((resolve, reject) => {
|
||||
this.connectResolver = resolve;
|
||||
this.connectRejecter = reject;
|
||||
this.tryConnect();
|
||||
});
|
||||
|
||||
return this.connectPromise;
|
||||
}
|
||||
|
||||
|
||||
tryConnect() {
|
||||
if (!this.shouldReconnect) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.state = 'connecting';
|
||||
this.error = null;
|
||||
|
||||
const socket = this.netModule.createConnection({ port: 23, host: this.urlGRBLstr });
|
||||
|
||||
socket.on('connect', () => {
|
||||
if (!this.shouldReconnect) {
|
||||
if (typeof socket.end === 'function') {
|
||||
socket.end();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
this.tSocket = new this.TelnetSocketClass(socket);
|
||||
this.tSocket.on('close', () => {
|
||||
console.log("Telnet Closed " + this.urlGRBLstr);
|
||||
this.tSocket = null;
|
||||
if (this.shouldReconnect) {
|
||||
this.state = 'reconnecting';
|
||||
this.scheduleReconnect();
|
||||
} else {
|
||||
this.state = 'disconnected';
|
||||
}
|
||||
});
|
||||
|
||||
socket.on('data', () => {});
|
||||
this.state = 'connected';
|
||||
this.error = null;
|
||||
this.reconnectAttempt = 0;
|
||||
if (this.connectResolver) {
|
||||
this.connectResolver(this);
|
||||
this.connectResolver = null;
|
||||
this.connectRejecter = null;
|
||||
}
|
||||
this.connectPromise = null;
|
||||
});
|
||||
|
||||
socket.on('error', (error) => {
|
||||
console.log("Telnet Connection Error on " + this.urlGRBLstr + ": " + error.toString());
|
||||
this.tSocket = null;
|
||||
this.error = error.message || String(error);
|
||||
this.connectPromise = this.connectPromise || null;
|
||||
if (this.shouldReconnect) {
|
||||
this.state = 'reconnecting';
|
||||
this.scheduleReconnect();
|
||||
} else {
|
||||
this.state = 'disconnected';
|
||||
if (this.connectRejecter) {
|
||||
this.connectRejecter(error);
|
||||
this.connectResolver = null;
|
||||
this.connectRejecter = null;
|
||||
this.connectPromise = null;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
scheduleReconnect() {
|
||||
if (!this.shouldReconnect || this.reconnectTimer) {
|
||||
return;
|
||||
}
|
||||
|
||||
const delay = Math.min(this.reconnectDelay * 2 ** this.reconnectAttempt, this.maxReconnectDelay);
|
||||
this.reconnectAttempt += 1;
|
||||
console.log(`Telnet reconnect attempt ${this.reconnectAttempt} in ${delay}ms for ${this.urlGRBLstr}`);
|
||||
|
||||
this.reconnectTimer = this.setTimeoutFn(() => {
|
||||
this.reconnectTimer = null;
|
||||
this.tryConnect();
|
||||
}, delay);
|
||||
}
|
||||
|
||||
send(command) {
|
||||
if (!this.tSocket || typeof this.tSocket.write !== 'function') {
|
||||
return false;
|
||||
}
|
||||
|
||||
const payload = typeof command === 'string' ? command : String(command);
|
||||
if (!payload || payload.length === 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
this.tSocket.write(payload + "\r\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
getStatus() {
|
||||
return {
|
||||
state: this.state,
|
||||
url: this.urlGRBLstr,
|
||||
error: this.error,
|
||||
isTestMode: !!this.isTestMode,
|
||||
reconnectAttempt: this.reconnectAttempt,
|
||||
reconnectTimer: !!this.reconnectTimer
|
||||
};
|
||||
}
|
||||
|
||||
disconnect() {
|
||||
if (this.isTestMode) {
|
||||
this.tSocket = null;
|
||||
this.state = 'disconnected';
|
||||
this.shouldReconnect = false;
|
||||
if (this.reconnectTimer) {
|
||||
this.clearTimeoutFn(this.reconnectTimer);
|
||||
this.reconnectTimer = null;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
this.shouldReconnect = false;
|
||||
if (this.reconnectTimer) {
|
||||
this.clearTimeoutFn(this.reconnectTimer);
|
||||
this.reconnectTimer = null;
|
||||
}
|
||||
|
||||
if (this.connectPromise && this.connectRejecter) {
|
||||
this.connectRejecter(new Error('disconnect'));
|
||||
this.connectPromise = null;
|
||||
this.connectResolver = null;
|
||||
this.connectRejecter = null;
|
||||
}
|
||||
|
||||
if (this.tSocket && typeof this.tSocket.end === 'function') {
|
||||
this.tSocket.end();
|
||||
}
|
||||
|
||||
if (this.tSocket && typeof this.tSocket.destroy === 'function') {
|
||||
this.tSocket.destroy();
|
||||
}
|
||||
|
||||
this.tSocket = null;
|
||||
this.state = 'disconnected';
|
||||
this.connectPromise = null;
|
||||
this.error = null;
|
||||
}
|
||||
|
||||
moveTo(mOld, mNew){
|
||||
this.execCommand("G1", mOld, mNew)
|
||||
}
|
||||
|
||||
@@ -1,347 +1,398 @@
|
||||
const net = require("net");
|
||||
const { resolve } = require("path");
|
||||
const FluidNCClient = require("./fluidnc/FluidNCClient");
|
||||
|
||||
|
||||
|
||||
|
||||
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.maxSpeedF = maxSpeedF;
|
||||
this.xAxisGrbl = xAxisGrbl;
|
||||
this.yAxisGrbl = yAxisGrbl;
|
||||
this.zAxisGrbl = zAxisGrbl;
|
||||
this.aAxisGrbl = aAxisGrbl;
|
||||
this.bAxisGrbl = bAxisGrbl;
|
||||
this.cAxisGrbl = cAxisGrbl;
|
||||
this.eAxisGrbl = eAxisGrbl;
|
||||
|
||||
if (urlGRBL === "test.test") {
|
||||
this.tSocket = { written: "", write(txt){ this.written = txt; } };
|
||||
this.isTestMode = true;
|
||||
return;
|
||||
}
|
||||
|
||||
var fluidConfig = { host: urlGRBL, port: 80, reconnectDelay: 30000}
|
||||
|
||||
// Create FluidNC WebSocket client
|
||||
const fluid = new FluidNCClient(fluidConfig);
|
||||
}
|
||||
|
||||
|
||||
|
||||
moveTo(mOld, mNew){
|
||||
this.execCommand("G1", mOld, mNew)
|
||||
}
|
||||
|
||||
execCommand(strCommand = "G1", mOld, mNew){
|
||||
|
||||
var data = strCommand.toString("utf-8");
|
||||
|
||||
// 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
|
||||
|
||||
|
||||
|
||||
if(this.xAxisGrbl == "x"){
|
||||
if(Number.isFinite(mNew.x)){
|
||||
data += " x" + (mNew.x).toFixed(2).toString();
|
||||
} else {
|
||||
console.log("Non-finite value for mNew.x in execCommand");
|
||||
}
|
||||
}
|
||||
if(this.xAxisGrbl == "y"){
|
||||
if(Number.isFinite(mNew.y)){
|
||||
data += " x" + (mNew.y * 180 / Math.PI).toFixed(2).toString();
|
||||
} else {
|
||||
console.log("Non-finite value for mNew.y in execCommand");
|
||||
}
|
||||
}
|
||||
if(this.xAxisGrbl == "z"){
|
||||
if(Number.isFinite(mNew.z) && Number.isFinite(mNew.y)){
|
||||
data += " x" + ((mNew.z * 180 / Math.PI) - (mNew.y * 180 / Math.PI) ).toFixed(2).toString();
|
||||
} else {
|
||||
console.log("Non-finite value for mNew.z or mNew.y in execCommand");
|
||||
}
|
||||
}
|
||||
if(this.xAxisGrbl == "a"){
|
||||
if(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();
|
||||
} else {
|
||||
console.log("Non-finite value for mNew.a in execCommand");
|
||||
}
|
||||
}
|
||||
if(this.xAxisGrbl == "b"){
|
||||
if(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();
|
||||
} else {
|
||||
console.log("Non-finite value for mNew.b, mNew.z or mNew.y in execCommand");
|
||||
}
|
||||
}
|
||||
if(this.xAxisGrbl == "c"){
|
||||
if(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();
|
||||
} else {
|
||||
console.log("Non-finite value for mNew.b or mNew.c in execCommand");
|
||||
}
|
||||
}
|
||||
if(this.xAxisGrbl == "e"){
|
||||
if(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();
|
||||
} else {
|
||||
console.log("Non-finite value for mNew.b, mNew.c or mNew.e in execCommand");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
if(this.yAxisGrbl == "x"){
|
||||
if(Number.isFinite(mNew.x)){
|
||||
data += " y" + (mNew.x ).toFixed(2).toString();
|
||||
} else {
|
||||
console.log("Non-finite value for mNew.x in execCommand");
|
||||
}
|
||||
}
|
||||
if(this.yAxisGrbl == "y"){
|
||||
if(Number.isFinite(mNew.y)){
|
||||
data += " y" + (mNew.y * 180 / Math.PI).toFixed(2).toString();
|
||||
} else {
|
||||
console.log("Non-finite value for mNew.y in execCommand");
|
||||
}
|
||||
}
|
||||
if(this.yAxisGrbl == "z"){
|
||||
if(Number.isFinite(mNew.z) && Number.isFinite(mNew.y)){
|
||||
data += " y" + ((mNew.z * 180 / Math.PI) - (mNew.y * 180 / Math.PI) ).toFixed(2).toString();
|
||||
} else {
|
||||
console.log("Non-finite value for mNew.z or mNew.y in execCommand");
|
||||
}
|
||||
}
|
||||
if(this.yAxisGrbl == "a"){
|
||||
if(Number.isFinite(mNew.a)){
|
||||
data += " y" + (mNew.a * 180 / Math.PI).toFixed(2).toString();
|
||||
} else {
|
||||
console.log("Non-finite value for mNew.a in execCommand");
|
||||
}
|
||||
}
|
||||
if(this.yAxisGrbl == "b"){
|
||||
if(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();
|
||||
} else {
|
||||
console.log("Non-finite value for mNew.b, mNew.z or mNew.y in execCommand");
|
||||
}
|
||||
}
|
||||
if(this.yAxisGrbl == "c"){
|
||||
if(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();
|
||||
} else {
|
||||
console.log("Non-finite value for mNew.b or mNew.c in execCommand");
|
||||
}
|
||||
}
|
||||
if(this.yAxisGrbl == "e"){
|
||||
if(Number.isFinite(mNew.e)){
|
||||
data += " y" + (mNew.e * 180 / Math.PI).toFixed(2).toString();
|
||||
} else {
|
||||
console.log("Non-finite value for mNew.e in execCommand");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(this.zAxisGrbl == "x"){
|
||||
if(Number.isFinite(mNew.x)){
|
||||
data += " z" + (mNew.x).toFixed(2).toString();
|
||||
} else {
|
||||
console.log("Non-finite value for mNew.x in execCommand");
|
||||
}
|
||||
}
|
||||
if(this.zAxisGrbl == "y"){
|
||||
if(Number.isFinite(mNew.y)){
|
||||
data += " z" + (mNew.y * 180 / Math.PI).toFixed(2).toString();
|
||||
} else {
|
||||
console.log("Non-finite value for mNew.y in execCommand");
|
||||
}
|
||||
}
|
||||
if(this.zAxisGrbl == "z"){
|
||||
if(Number.isFinite(mNew.z) && Number.isFinite(mNew.y)){
|
||||
data += " z" + ((mNew.z * 180 / Math.PI) - (mNew.y * 180 / Math.PI) ).toFixed(2).toString();
|
||||
} else {
|
||||
console.log("Non-finite value for mNew.z or mNew.y in execCommand");
|
||||
}
|
||||
}
|
||||
if(this.zAxisGrbl == "a"){
|
||||
if(Number.isFinite(mNew.a)){
|
||||
data += " z" + (mNew.a * 180 / Math.PI).toFixed(2).toString();
|
||||
} else {
|
||||
console.log("Non-finite value for mNew.a in execCommand");
|
||||
}
|
||||
}
|
||||
if(this.zAxisGrbl == "b"){
|
||||
if(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();
|
||||
} else {
|
||||
console.log("Non-finite value for mNew.b in execCommand");
|
||||
}
|
||||
}
|
||||
if(this.zAxisGrbl == "c"){
|
||||
if(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();
|
||||
} else {
|
||||
console.log("Non-finite value for mNew.c, mNew.b, mNew.z or mNew.y in execCommand");
|
||||
}
|
||||
}
|
||||
if(this.zAxisGrbl == "e"){
|
||||
if(Number.isFinite(mNew.e)){
|
||||
|
||||
data += " z" + (mNew.e * 180 / Math.PI).toFixed(2).toString();
|
||||
} else {
|
||||
console.log("Non-finite value for mNew.e in execCommand");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
if(this.aAxisGrbl == "x"){
|
||||
if(Number.isFinite(mNew.y)){
|
||||
data += " a" + (mNew.y * 180 / Math.PI).toFixed(2).toString();
|
||||
} else {
|
||||
console.log("Non-finite value for mNew.y in execCommand");
|
||||
}
|
||||
}
|
||||
if(this.aAxisGrbl == "y"){
|
||||
if(Number.isFinite(mNew.y)){
|
||||
data += " a" + (mNew.y * 180 / Math.PI).toFixed(2).toString();
|
||||
} else {
|
||||
console.log("Non-finite value for mNew.y in execCommand");
|
||||
}
|
||||
}
|
||||
if(this.aAxisGrbl == "z"){
|
||||
if(Number.isFinite(mNew.z) && Number.isFinite(mNew.y)){
|
||||
data += " a" + ((mNew.z * 180 / Math.PI) - (mNew.y * 180 / Math.PI) ).toFixed(2).toString();
|
||||
} else {
|
||||
console.log("Non-finite value for mNew.z or mNew.y in execCommand");
|
||||
}
|
||||
}
|
||||
if(this.aAxisGrbl == "a"){
|
||||
if(Number.isFinite(mNew.a)){
|
||||
data += " a" + (mNew.a * 180 / Math.PI).toFixed(2).toString();
|
||||
} else {
|
||||
console.log("Non-finite value for mNew.a in execCommand");
|
||||
}
|
||||
}
|
||||
if(this.aAxisGrbl == "b"){
|
||||
if(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();
|
||||
} else {
|
||||
console.log("Non-finite value for mNew.b, mNew.z or mNew.y in execCommand");
|
||||
}
|
||||
}
|
||||
if(this.aAxisGrbl == "c"){
|
||||
if(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();
|
||||
} else {
|
||||
console.log("Non-finite value for mNew.c, mNew.b, mNew.z or mNew.y in execCommand");
|
||||
}
|
||||
}
|
||||
if(this.aAxisGrbl == "e"){
|
||||
if(Number.isFinite(mNew.e)){
|
||||
// ToDo Mai 2024
|
||||
data += " a" + (mNew.e * 180 / Math.PI).toFixed(2).toString();
|
||||
} else {
|
||||
console.log("Non-finite value for mNew.e in execCommand");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
if(this.bAxisGrbl == "x"){
|
||||
if(Number.isFinite(mNew.x)){
|
||||
data += " b" + (mNew.x).toFixed(2).toString();
|
||||
} else {
|
||||
console.log("Non-finite value for mNew.x in execCommand");
|
||||
}
|
||||
}
|
||||
if(this.bAxisGrbl == "y"){
|
||||
if(Number.isFinite(mNew.y)){
|
||||
data += " b" + (mNew.y * 180 / Math.PI).toFixed(2).toString();
|
||||
} else {
|
||||
console.log("Non-finite value for mNew.y in execCommand");
|
||||
}
|
||||
}
|
||||
if(this.bAxisGrbl == "z"){
|
||||
if(Number.isFinite(mNew.z) && Number.isFinite(mNew.y)){
|
||||
data += " b" + ((mNew.z * 180 / Math.PI) - (mNew.y * 180 / Math.PI) ).toFixed(2).toString();
|
||||
} else {
|
||||
console.log("Non-finite value for mNew.z or mNew.y in execCommand");
|
||||
}
|
||||
}
|
||||
if(this.bAxisGrbl == "a"){
|
||||
if(Number.isFinite(mNew.a)){
|
||||
data += " b" + (mNew.a * 180 / Math.PI).toFixed(2).toString();
|
||||
} else {
|
||||
console.log("Non-finite value for mNew.a in execCommand");
|
||||
}
|
||||
}
|
||||
if(this.bAxisGrbl == "b"){
|
||||
if(Number.isFinite(mNew.b)){
|
||||
data += " b" + (mNew.b * 180 / Math.PI).toFixed(2).toString();
|
||||
} else {
|
||||
console.log("Non-finite value for mNew.b in execCommand");
|
||||
}
|
||||
}
|
||||
if(this.bAxisGrbl == "c"){
|
||||
if(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();
|
||||
} else {
|
||||
console.log("Non-finite value for mNew.c, mNew.b, mNew.z or mNew.y in execCommand");
|
||||
}
|
||||
}
|
||||
if(this.bAxisGrbl == "e"){
|
||||
if(Number.isFinite(mNew.e)){
|
||||
data += " b" + (mNew.e * 180 / Math.PI).toFixed(2).toString();
|
||||
} else {
|
||||
console.log("Non-finite value for mNew.e in execCommand");
|
||||
}
|
||||
}
|
||||
|
||||
data += " f"+(this.maxSpeedF.toFixed(2).toString())
|
||||
|
||||
|
||||
if(this.tSocket && data.length > 3){
|
||||
// Ensure that the command starts with G90 (absolute positioning) if it's not already included
|
||||
if(data.indexOf("G90") == -1){
|
||||
data = "G90 " + data;
|
||||
}
|
||||
|
||||
console.log("Driver send to 🤖 " + this.urlGRBLstr + " the message: " + data)
|
||||
|
||||
this.tSocket.write( data + "\r\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
const WebSocket = require('ws');
|
||||
const SenderInterface = require('./SenderInterface');
|
||||
|
||||
module.exports = class WSSenderGrbl extends SenderInterface {
|
||||
|
||||
constructor(urlGRBL = "grblesp.local", maxSpeedF = 5000, xAxisGrbl = "x", yAxisGrbl = "y", zAxisGrbl = "z", aAxisGrbl = null, bAxisGrbl = null, cAxisGrbl = null, eAxisGrbl = null, options = {}) {
|
||||
super();
|
||||
|
||||
this.ws = null;
|
||||
this.state = 'disconnected';
|
||||
this.error = null;
|
||||
this.isTestMode = false;
|
||||
this.shouldReconnect = true;
|
||||
this.reconnectTimer = null;
|
||||
this.connectPromise = null;
|
||||
this.connectResolver = null;
|
||||
this.connectRejecter = null;
|
||||
this.reconnectAttempt = 0;
|
||||
|
||||
this.urlGRBLstr = urlGRBL;
|
||||
this.maxSpeedF = maxSpeedF;
|
||||
this.xAxisGrbl = xAxisGrbl;
|
||||
this.yAxisGrbl = yAxisGrbl;
|
||||
this.zAxisGrbl = zAxisGrbl;
|
||||
this.aAxisGrbl = aAxisGrbl;
|
||||
this.bAxisGrbl = bAxisGrbl;
|
||||
this.cAxisGrbl = cAxisGrbl;
|
||||
this.eAxisGrbl = eAxisGrbl;
|
||||
|
||||
this.WebSocketClass = options.WebSocketClass || WebSocket;
|
||||
this.setTimeoutFn = options.setTimeoutFn || setTimeout;
|
||||
this.clearTimeoutFn = options.clearTimeoutFn || clearTimeout;
|
||||
this.reconnectDelay = Number.isFinite(options.reconnectDelay) ? options.reconnectDelay : 2000;
|
||||
this.maxReconnectDelay = Number.isFinite(options.maxReconnectDelay) ? options.maxReconnectDelay : 30000;
|
||||
this.wsPort = options.wsPort || 81;
|
||||
this.autoConnect = options.autoConnect !== false;
|
||||
|
||||
if (urlGRBL === "test.test") {
|
||||
this.isTestMode = true;
|
||||
this.state = 'connected';
|
||||
this.shouldReconnect = false;
|
||||
this.ws = { readyState: 1, written: "", send(txt) { this.written = txt; }, close() {} };
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.autoConnect) {
|
||||
this.connect();
|
||||
console.log("🤖 WSSenderGrbl initialized: " + urlGRBL);
|
||||
}
|
||||
}
|
||||
|
||||
async connect() {
|
||||
if (this.isTestMode) {
|
||||
this.state = 'connected';
|
||||
return Promise.resolve(this);
|
||||
}
|
||||
|
||||
if (this.state === 'connected' && this.ws && this.ws.readyState === 1) {
|
||||
return Promise.resolve(this);
|
||||
}
|
||||
|
||||
if (this.connectPromise) {
|
||||
return this.connectPromise;
|
||||
}
|
||||
|
||||
if (this.reconnectTimer) {
|
||||
this.clearTimeoutFn(this.reconnectTimer);
|
||||
this.reconnectTimer = null;
|
||||
}
|
||||
|
||||
this.state = 'connecting';
|
||||
this.error = null;
|
||||
this.shouldReconnect = true;
|
||||
|
||||
this.connectPromise = new Promise((resolve, reject) => {
|
||||
this.connectResolver = resolve;
|
||||
this.connectRejecter = reject;
|
||||
this._tryConnect();
|
||||
});
|
||||
|
||||
return this.connectPromise;
|
||||
}
|
||||
|
||||
_tryConnect() {
|
||||
if (!this.shouldReconnect) return;
|
||||
|
||||
this.state = 'connecting';
|
||||
this.error = null;
|
||||
|
||||
const url = `ws://${this.urlGRBLstr}:${this.wsPort}`;
|
||||
const ws = new this.WebSocketClass(url);
|
||||
|
||||
ws.on('open', () => {
|
||||
if (!this.shouldReconnect) {
|
||||
ws.close();
|
||||
return;
|
||||
}
|
||||
this.ws = ws;
|
||||
this.state = 'connected';
|
||||
this.error = null;
|
||||
this.reconnectAttempt = 0;
|
||||
if (this.connectResolver) {
|
||||
this.connectResolver(this);
|
||||
this.connectResolver = null;
|
||||
this.connectRejecter = null;
|
||||
}
|
||||
this.connectPromise = null;
|
||||
});
|
||||
|
||||
ws.on('close', () => {
|
||||
console.log("WS Closed " + this.urlGRBLstr);
|
||||
this.ws = null;
|
||||
if (this.shouldReconnect) {
|
||||
this.state = 'reconnecting';
|
||||
this._scheduleReconnect();
|
||||
} else {
|
||||
this.state = 'disconnected';
|
||||
}
|
||||
});
|
||||
|
||||
ws.on('error', (err) => {
|
||||
console.log("WS Connection Error on " + this.urlGRBLstr + ": " + err.message);
|
||||
this.error = err.message || String(err);
|
||||
if (!this.shouldReconnect) {
|
||||
this.state = 'disconnected';
|
||||
if (this.connectRejecter) {
|
||||
this.connectRejecter(err);
|
||||
this.connectResolver = null;
|
||||
this.connectRejecter = null;
|
||||
this.connectPromise = null;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
_scheduleReconnect() {
|
||||
if (!this.shouldReconnect || this.reconnectTimer) return;
|
||||
|
||||
const delay = Math.min(this.reconnectDelay * 2 ** this.reconnectAttempt, this.maxReconnectDelay);
|
||||
this.reconnectAttempt += 1;
|
||||
console.log(`WS reconnect attempt ${this.reconnectAttempt} in ${delay}ms for ${this.urlGRBLstr}`);
|
||||
|
||||
this.reconnectTimer = this.setTimeoutFn(() => {
|
||||
this.reconnectTimer = null;
|
||||
this._tryConnect();
|
||||
}, delay);
|
||||
}
|
||||
|
||||
send(command) {
|
||||
if (!this.ws || this.ws.readyState !== 1) return false;
|
||||
const payload = typeof command === 'string' ? command : String(command);
|
||||
if (!payload) return false;
|
||||
this.ws.send(payload + "\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
getStatus() {
|
||||
return {
|
||||
state: this.state,
|
||||
url: this.urlGRBLstr,
|
||||
error: this.error,
|
||||
isTestMode: !!this.isTestMode,
|
||||
reconnectAttempt: this.reconnectAttempt,
|
||||
reconnectTimer: !!this.reconnectTimer
|
||||
};
|
||||
}
|
||||
|
||||
disconnect() {
|
||||
this.shouldReconnect = false;
|
||||
|
||||
if (this.reconnectTimer) {
|
||||
this.clearTimeoutFn(this.reconnectTimer);
|
||||
this.reconnectTimer = null;
|
||||
}
|
||||
|
||||
if (this.connectPromise && this.connectRejecter) {
|
||||
this.connectRejecter(new Error('disconnect'));
|
||||
this.connectPromise = null;
|
||||
this.connectResolver = null;
|
||||
this.connectRejecter = null;
|
||||
}
|
||||
|
||||
if (this.ws && this.ws.readyState !== 3) {
|
||||
this.ws.close();
|
||||
}
|
||||
|
||||
this.ws = null;
|
||||
this.state = 'disconnected';
|
||||
this.error = null;
|
||||
}
|
||||
|
||||
moveTo(mOld, mNew) {
|
||||
this.execCommand("G1", mOld, mNew);
|
||||
}
|
||||
|
||||
execCommand(strCommand = "G1", mOld, mNew) {
|
||||
|
||||
var factorTurnLift = 1.2;
|
||||
var factorOpenTurn = 1.92;
|
||||
var handOpenInMM = 1.0;
|
||||
|
||||
var data = strCommand.toString("utf-8");
|
||||
|
||||
if (this.xAxisGrbl == "x") {
|
||||
if (Number.isFinite(mNew.x)) {
|
||||
data += " x" + (mNew.x).toFixed(2).toString();
|
||||
}
|
||||
}
|
||||
if (this.xAxisGrbl == "y") {
|
||||
if (Number.isFinite(mNew.y)) {
|
||||
data += " x" + (mNew.y * 180 / Math.PI).toFixed(2).toString();
|
||||
}
|
||||
}
|
||||
if (this.xAxisGrbl == "z") {
|
||||
if (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") {
|
||||
if (Number.isFinite(mNew.a)) {
|
||||
data += " x" + (mNew.a * 180 / Math.PI).toFixed(2).toString();
|
||||
}
|
||||
}
|
||||
if (this.xAxisGrbl == "b") {
|
||||
if (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") {
|
||||
if (Number.isFinite(mNew.b) && Number.isFinite(mNew.c)) {
|
||||
data += " x" + ((-1) * mNew.b * 180 / Math.PI + (mNew.c * 180 / Math.PI)).toFixed(2).toString();
|
||||
}
|
||||
}
|
||||
if (this.xAxisGrbl == "e") {
|
||||
if (Number.isFinite(mNew.b) && Number.isFinite(mNew.c) && Number.isFinite(mNew.e)) {
|
||||
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") {
|
||||
if (Number.isFinite(mNew.x)) {
|
||||
data += " y" + (mNew.x).toFixed(2).toString();
|
||||
}
|
||||
}
|
||||
if (this.yAxisGrbl == "y") {
|
||||
if (Number.isFinite(mNew.y)) {
|
||||
data += " y" + (mNew.y * 180 / Math.PI).toFixed(2).toString();
|
||||
}
|
||||
}
|
||||
if (this.yAxisGrbl == "z") {
|
||||
if (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") {
|
||||
if (Number.isFinite(mNew.a)) {
|
||||
data += " y" + (mNew.a * 180 / Math.PI).toFixed(2).toString();
|
||||
}
|
||||
}
|
||||
if (this.yAxisGrbl == "b") {
|
||||
if (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") {
|
||||
if (Number.isFinite(mNew.b) && Number.isFinite(mNew.c)) {
|
||||
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") {
|
||||
if (Number.isFinite(mNew.e)) {
|
||||
data += " y" + (mNew.e * 180 / Math.PI).toFixed(2).toString();
|
||||
}
|
||||
}
|
||||
|
||||
if (this.zAxisGrbl == "x") {
|
||||
if (Number.isFinite(mNew.x)) {
|
||||
data += " z" + (mNew.x).toFixed(2).toString();
|
||||
}
|
||||
}
|
||||
if (this.zAxisGrbl == "y") {
|
||||
if (Number.isFinite(mNew.y)) {
|
||||
data += " z" + (mNew.y * 180 / Math.PI).toFixed(2).toString();
|
||||
}
|
||||
}
|
||||
if (this.zAxisGrbl == "z") {
|
||||
if (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") {
|
||||
if (Number.isFinite(mNew.a)) {
|
||||
data += " z" + (mNew.a * 180 / Math.PI).toFixed(2).toString();
|
||||
}
|
||||
}
|
||||
if (this.zAxisGrbl == "b") {
|
||||
if (Number.isFinite(mNew.b)) {
|
||||
data += " z" + (mNew.b * 180 / Math.PI).toFixed(2).toString();
|
||||
}
|
||||
}
|
||||
if (this.zAxisGrbl == "c") {
|
||||
if (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") {
|
||||
if (Number.isFinite(mNew.e)) {
|
||||
data += " z" + (mNew.e * 180 / Math.PI).toFixed(2).toString();
|
||||
}
|
||||
}
|
||||
|
||||
if (this.aAxisGrbl == "x") {
|
||||
if (Number.isFinite(mNew.y)) {
|
||||
data += " a" + (mNew.y * 180 / Math.PI).toFixed(2).toString();
|
||||
}
|
||||
}
|
||||
if (this.aAxisGrbl == "y") {
|
||||
if (Number.isFinite(mNew.y)) {
|
||||
data += " a" + (mNew.y * 180 / Math.PI).toFixed(2).toString();
|
||||
}
|
||||
}
|
||||
if (this.aAxisGrbl == "z") {
|
||||
if (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") {
|
||||
if (Number.isFinite(mNew.a)) {
|
||||
data += " a" + (mNew.a * 180 / Math.PI).toFixed(2).toString();
|
||||
}
|
||||
}
|
||||
if (this.aAxisGrbl == "b") {
|
||||
if (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") {
|
||||
if (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") {
|
||||
if (Number.isFinite(mNew.e)) {
|
||||
data += " a" + (mNew.e * 180 / Math.PI).toFixed(2).toString();
|
||||
}
|
||||
}
|
||||
|
||||
if (this.bAxisGrbl == "x") {
|
||||
if (Number.isFinite(mNew.x)) {
|
||||
data += " b" + (mNew.x).toFixed(2).toString();
|
||||
}
|
||||
}
|
||||
if (this.bAxisGrbl == "y") {
|
||||
if (Number.isFinite(mNew.y)) {
|
||||
data += " b" + (mNew.y * 180 / Math.PI).toFixed(2).toString();
|
||||
}
|
||||
}
|
||||
if (this.bAxisGrbl == "z") {
|
||||
if (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") {
|
||||
if (Number.isFinite(mNew.a)) {
|
||||
data += " b" + (mNew.a * 180 / Math.PI).toFixed(2).toString();
|
||||
}
|
||||
}
|
||||
if (this.bAxisGrbl == "b") {
|
||||
if (Number.isFinite(mNew.b)) {
|
||||
data += " b" + (mNew.b * 180 / Math.PI).toFixed(2).toString();
|
||||
}
|
||||
}
|
||||
if (this.bAxisGrbl == "c") {
|
||||
if (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") {
|
||||
if (Number.isFinite(mNew.e)) {
|
||||
data += " b" + (mNew.e * 180 / Math.PI).toFixed(2).toString();
|
||||
}
|
||||
}
|
||||
|
||||
data += " f" + (this.maxSpeedF.toFixed(2).toString());
|
||||
|
||||
if (data.length > 3) {
|
||||
if (data.indexOf("G90") == -1) {
|
||||
data = "G90 " + data;
|
||||
}
|
||||
console.log("Driver send to 🤖 " + this.urlGRBLstr + " the message: " + data);
|
||||
this.send(data);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user