From a47c168a2256341123867b7a3d8c2b27ad616d6e Mon Sep 17 00:00:00 2001 From: ChK Date: Tue, 7 Apr 2026 09:30:46 +0200 Subject: [PATCH] nur wenn xyz genaendert, dann senden --- logs/gcode_commands.log | 3 + logs/pings.log | 3 + robot/GCode.js | 126 +++++++++------------------- robot/Robot.js | 93 ++++++++++++++------ robot/RobotMotorPosition.js | 8 ++ robot/TelnetSenderGRBL.js | 82 +++++++++--------- test/GCode.receiveGCode.G92.test.js | 33 +++++++- test/GCode.test.js | 36 +++++++- test/Robot.sendCommand.test.js | 4 +- test/Sender.Telnet.test.js | 11 +++ test/helpers/mockCmdReceiver.js | 10 +++ 11 files changed, 250 insertions(+), 159 deletions(-) diff --git a/logs/gcode_commands.log b/logs/gcode_commands.log index ef2c997..b98154c 100644 --- a/logs/gcode_commands.log +++ b/logs/gcode_commands.log @@ -2194,3 +2194,6 @@ 2026-04-04T21:04:06.238Z ::ffff:172.21.0.5: G91 G1 Y-5 F100 2026-04-05T03:31:21.526Z ::ffff:172.21.0.5: FShow 2026-04-05T03:32:57.698Z ::ffff:172.21.0.5: FShow +2026-04-06T06:05:17.310Z ::ffff:172.21.0.5: FShow +2026-04-06T06:05:21.815Z ::ffff:172.21.0.5: FShow +2026-04-06T06:05:47.347Z ::ffff:172.21.0.5: FShow diff --git a/logs/pings.log b/logs/pings.log index 26730e9..c4341f9 100644 --- a/logs/pings.log +++ b/logs/pings.log @@ -11175,3 +11175,6 @@ 2026-04-05T20:36:01.566Z ::ffff:172.21.0.5: Ping 2026-04-05T20:36:06.553Z ::ffff:172.21.0.5: Ping 2026-04-05T20:36:06.563Z ::ffff:172.21.0.5: Ping +2026-04-06T06:05:26.867Z ::ffff:172.21.0.5: Ping +2026-04-06T06:05:31.886Z ::ffff:172.21.0.5: Ping +2026-04-06T06:05:52.364Z ::ffff:172.21.0.5: Ping diff --git a/robot/GCode.js b/robot/GCode.js index 353744a..5821698 100755 --- a/robot/GCode.js +++ b/robot/GCode.js @@ -17,16 +17,9 @@ class GCode{ m = m.split(" "); if(m[0] == "M1"){ m.forEach((s) => { - if(s.includes("X")){ robot.xMotor += Number(s.substring(1, s.length));} - if(s.includes("x")){ robot.xMotor += Number(s.substring(1, s.length));} - - - if(s.includes("Y")){ robot.alpha += Number(s.substring(1, s.length));} - if(s.includes("y")){ robot.alpha += Number(s.substring(1, s.length));} - - - if(s.includes("Z")){ robot.beta += Number(s.substring(1, s.length));} - if(s.includes("z")){ robot.beta += Number(s.substring(1, s.length));} + if(s.toUpperCase().includes("X")){ robot.xMotor += Number(s.substring(1, s.length));} + if(s.toUpperCase().includes("Y")){ robot.alpha += Number(s.substring(1, s.length));} + if(s.toUpperCase().includes("Z")){ robot.beta += Number(s.substring(1, s.length));} }) } @@ -118,109 +111,68 @@ class GCode{ } else if(g[0] == "G1" && robot.moveRelative){ g.forEach((s) => { - if(s.includes("X")){ robot.x += Number(s.substring(1, s.length));} - if(s.includes("x")){ robot.x += Number(s.substring(1, s.length));} - if(s.includes("Y")){ robot.y += Number(s.substring(1, s.length));} - if(s.includes("y")){ robot.y += Number(s.substring(1, s.length));} - if(s.includes("Z")){ robot.z += Number(s.substring(1, s.length));} - if(s.includes("z")){ robot.z += Number(s.substring(1, s.length));} + if(s.toUpperCase().includes("X")){ robot.x += Number(s.substring(1, s.length)); robot.xMotorChanged = true;} + if(s.toUpperCase().includes("Y")){ robot.y += Number(s.substring(1, s.length)); robot.yMotorChanged = true;} + if(s.toUpperCase().includes("Z")){ robot.z += Number(s.substring(1, s.length)); robot.zMotorChanged = true;} - // abc in 2Pi-Angles - if(s.includes("A")){ robot.phi += Number(s.substring(1, s.length));} - if(s.includes("a")){ robot.phi += Number(s.substring(1, s.length));} - if(s.includes("B")){ robot.theta += Number(s.substring(1, s.length));} - if(s.includes("b")){ robot.theta += Number(s.substring(1, s.length));} - if(s.includes("C")){ robot.psi += Number(s.substring(1, s.length));} - if(s.includes("c")){ robot.psi += Number(s.substring(1, s.length));} - - if(s.includes("E")){ robot.e += Number(s.substring(1, s.length));} - if(s.includes("e")){ robot.e += Number(s.substring(1, s.length));} + if(s.toUpperCase().includes("A")){ robot.phi += Number(s.substring(1, s.length)); robot.aMotorChanged = true;} + if(s.toUpperCase().includes("B")){ robot.theta += Number(s.substring(1, s.length)); robot.bMotorChanged = true;} + if(s.toUpperCase().includes("C")){ robot.psi += Number(s.substring(1, s.length)); robot.cMotorChanged = true;} + if(s.toUpperCase().includes("E")){ robot.e += Number(s.substring(1, s.length)); robot.eMotorChanged = true;} }); } else if(g[0] == "M1" && robot.moveRelative){ calculateFromMotorCoordinates = true; g.forEach((s) => { - if(s.includes("X")){ robot.xMotor += Number(s.substring(1, s.length));} - if(s.includes("x")){ robot.xMotor += Number(s.substring(1, s.length));} - if(s.includes("Y")){ robot.alpha += Number(s.substring(1, s.length));} - if(s.includes("y")){ robot.alpha += Number(s.substring(1, s.length));} - if(s.includes("Z")){ robot.beta += Number(s.substring(1, s.length));} - if(s.includes("z")){ robot.beta += Number(s.substring(1, s.length));} + if(s.toUpperCase().includes("X")){ robot.xMotor += Number(s.substring(1, s.length)); robot.xMotorChanged = true;} + if(s.toUpperCase().includes("Y")){ robot.alpha += Number(s.substring(1, s.length)); robot.yMotorChanged = true;} + if(s.toUpperCase().includes("Z")){ robot.beta += Number(s.substring(1, s.length)); robot.zMotorChanged = true;} - - if(s.includes("A")){ robot.a += Number(s.substring(1, s.length));} - if(s.includes("a")){ robot.a += Number(s.substring(1, s.length));} - if(s.includes("B")){ robot.b += Number(s.substring(1, s.length));} - if(s.includes("b")){ robot.b += Number(s.substring(1, s.length));} - if(s.includes("C")){ robot.c += Number(s.substring(1, s.length));} - if(s.includes("c")){ robot.c += Number(s.substring(1, s.length));} - - if(s.includes("E")){ robot.e += Number(s.substring(1, s.length));} - if(s.includes("e")){ robot.e += Number(s.substring(1, s.length));} + if(s.toUpperCase().includes("A")){ robot.a += Number(s.substring(1, s.length)); robot.aMotorChanged = true;} + if(s.toUpperCase().includes("B")){ robot.b += Number(s.substring(1, s.length)); robot.bMotorChanged = true;} + if(s.toUpperCase().includes("C")){ robot.c += Number(s.substring(1, s.length)); robot.cMotorChanged = true;} + if(s.toUpperCase().includes("E")){ robot.e += Number(s.substring(1, s.length)); robot.eMotorChanged = true;} }); } // Absolute-Positioning else if(g[0] == "G1" && !robot.moveRelative){ g.forEach((s) => { - if(s.includes("X")){ robot.x = Number(s.substring(1, s.length));} - if(s.includes("x")){ robot.x = Number(s.substring(1, s.length));} - if(s.includes("Y")){ robot.y = Number(s.substring(1, s.length));} - if(s.includes("y")){ robot.y = Number(s.substring(1, s.length));} - if(s.includes("Z")){ robot.z = Number(s.substring(1, s.length));} - if(s.includes("z")){ robot.z = Number(s.substring(1, s.length));} + if(s.toUpperCase().includes("X")){ robot.x = Number(s.substring(1, s.length)); robot.xMotorChanged = true;} + if(s.toUpperCase().includes("Y")){ robot.y = Number(s.substring(1, s.length)); robot.yMotorChanged = true;} + if(s.toUpperCase().includes("Z")){ robot.z = Number(s.substring(1, s.length)); robot.zMotorChanged = true;} - if(s.includes("A")){ robot.phi = Number(s.substring(1, s.length));} - if(s.includes("a")){ robot.phi = Number(s.substring(1, s.length));} - if(s.includes("B")){ robot.theta = Number(s.substring(1, s.length));} - if(s.includes("b")){ robot.theta = Number(s.substring(1, s.length));} - if(s.includes("C")){ robot.psi = Number(s.substring(1, s.length));} - if(s.includes("c")){ robot.psi = Number(s.substring(1, s.length));} - - if(s.includes("E")){ robot.e = Number(s.substring(1, s.length));} - if(s.includes("e")){ robot.e = Number(s.substring(1, s.length));} + if(s.toUpperCase().includes("A")){ robot.phi = Number(s.substring(1, s.length)); robot.aMotorChanged = true;} + if(s.toUpperCase().includes("B")){ robot.theta = Number(s.substring(1, s.length)); robot.bMotorChanged = true;} + if(s.toUpperCase().includes("C")){ robot.psi = Number(s.substring(1, s.length)); robot.cMotorChanged = true;} + if(s.toUpperCase().includes("E")){ robot.e = Number(s.substring(1, s.length)); robot.eMotorChanged = true;} }); } else if(g[0] == "M1" && !robot.moveRelative){ calculateFromMotorCoordinates = true; g.forEach((s) => { - if(s.includes("X")){ robot.xMotor = Number(s.substring(1, s.length));} - if(s.includes("x")){ robot.xMotor = Number(s.substring(1, s.length));} - if(s.includes("Y")){ robot.alpha = Number(s.substring(1, s.length));} - if(s.includes("y")){ robot.alpha = Number(s.substring(1, s.length));} - if(s.includes("Z")){ robot.beta = Number(s.substring(1, s.length));} - if(s.includes("z")){ robot.beta = Number(s.substring(1, s.length));} + if(s.toUpperCase().includes("X")){ robot.xMotor = Number(s.substring(1, s.length)); robot.xMotorChanged = true;} + if(s.toUpperCase().includes("Y")){ robot.alpha = Number(s.substring(1, s.length)); robot.yMotorChanged = true;} + if(s.toUpperCase().includes("Z")){ robot.beta = Number(s.substring(1, s.length)); robot.zMotorChanged = true;} - if(s.includes("A")){ robot.a = Number(s.substring(1, s.length));} - if(s.includes("a")){ robot.a = Number(s.substring(1, s.length));} - if(s.includes("B")){ robot.b = Number(s.substring(1, s.length));} - if(s.includes("b")){ robot.b = Number(s.substring(1, s.length));} - if(s.includes("C")){ robot.c = Number(s.substring(1, s.length));} - if(s.includes("c")){ robot.c = Number(s.substring(1, s.length));} - - if(s.includes("E")){ robot.e = Number(s.substring(1, s.length));} - if(s.includes("e")){ robot.e = Number(s.substring(1, s.length));} + if(s.toUpperCase().includes("A")){ robot.a = Number(s.substring(1, s.length)); robot.aMotorChanged = true;} + if(s.toUpperCase().includes("B")){ robot.b = Number(s.substring(1, s.length)); robot.bMotorChanged = true;} + if(s.toUpperCase().includes("C")){ robot.c = Number(s.substring(1, s.length)); robot.cMotorChanged = true;} + if(s.toUpperCase().includes("E")){ robot.e = Number(s.substring(1, s.length)); robot.eMotorChanged = true;} }); + robot.calculatePositionFromMotorAngles(); } else if(g[0] == "M92"){ // G92 - Set Position --- M92 in Radiant robot.createMotorPosition(); g.forEach((s) => { - if(s.includes("X")){ robot.xMotor = Number(s.substring(1, s.length));} - if(s.includes("x")){ robot.xMotor = Number(s.substring(1, s.length));} - if(s.includes("Y")){ robot.alpha = Number(s.substring(1, s.length));} - if(s.includes("y")){ robot.alpha = Number(s.substring(1, s.length));} - if(s.includes("Z")){ robot.beta = Number(s.substring(1, s.length));} - if(s.includes("z")){ robot.beta = Number(s.substring(1, s.length));} + if(s.toUpperCase().includes("X")){ robot.xMotor = Number(s.substring(1, s.length)); robot.xMotorChanged = true;} + if(s.toUpperCase().includes("Y")){ robot.alpha = Number(s.substring(1, s.length)); robot.yMotorChanged = true;} + if(s.toUpperCase().includes("Z")){ robot.beta = Number(s.substring(1, s.length)); robot.zMotorChanged = true;} - if(s.includes("A")){ robot.a = Number(s.substring(1, s.length));} - if(s.includes("a")){ robot.a = Number(s.substring(1, s.length));} - if(s.includes("B")){ robot.b = Number(s.substring(1, s.length));} - if(s.includes("b")){ robot.b = Number(s.substring(1, s.length));} - if(s.includes("C")){ robot.c = Number(s.substring(1, s.length));} - if(s.includes("c")){ robot.c = Number(s.substring(1, s.length));} - - if(s.includes("E")){ robot.e = Number(s.substring(1, s.length));} - if(s.includes("e")){ robot.e = Number(s.substring(1, s.length));} + if(s.toUpperCase().includes("A")){ robot.a = Number(s.substring(1, s.length)); robot.aMotorChanged = true;} + if(s.toUpperCase().includes("B")){ robot.b = Number(s.substring(1, s.length)); robot.bMotorChanged = true;} + if(s.toUpperCase().includes("C")){ robot.c = Number(s.substring(1, s.length)); robot.cMotorChanged = true;} + if(s.toUpperCase().includes("E")){ robot.e = Number(s.substring(1, s.length)); robot.eMotorChanged = true;} }); robot.calculatePositionFromMotorAngles(); calculateNew = false; diff --git a/robot/Robot.js b/robot/Robot.js index d7d8782..be775e1 100755 --- a/robot/Robot.js +++ b/robot/Robot.js @@ -1,68 +1,116 @@ const MotorPosition = require('./RobotMotorPosition.js') -const telnetSender = require('./TelnetSenderGRBL.js') class Robot{ constructor(l1, l2, l3) { - this.speedX = 200; // mm/min - this.speedY = 200; + /** @type {number} Bewegungsgeschwindigkeit X-Achse in mm/min */ + this.speedX = 200; + /** @type {number} Bewegungsgeschwindigkeit Y-Achse in mm/min */ + this.speedY = 200; + /** @type {number} Bewegungsgeschwindigkeit Z-Achse in mm/min */ this.speedZ = 200; + /** @type {number} Zeitstempel des zuletzt gesendeten Kommandos */ this.lastCommandSend = 0; if(this.lastCommandSend == 0){ this.lastCommandSend = Date.now() }; + /** @type {boolean} Animation aktiviert */ this.doAnimate = false; - this.l1 = l1; // Oberarm - this.l2 = l2; // Unterarm - this.l3 = l3; // Hand-Länge + /** @type {number} Länge des Oberarms in mm */ + this.l1 = l1; + /** @type {number} Länge des Unterarms in mm */ + this.l2 = l2; + /** @type {number} Länge der Hand (Endeffector) in mm */ + this.l3 = l3; // Plan-Koordinaten - XYZ FingerSpitze + /** @type {number} X-Position der Fingerspitze in mm */ this.x = 0; + /** @type {number} Y-Position der Fingerspitze in mm */ this.y = 0; + /** @type {number} Z-Position der Fingerspitze in mm */ this.z = 0; - // Plan-Koordinaten - HandRichtung - this.phi = 0.0; // Euler-Winkel zwischen X-Achse - Laengengrad - this.theta = -Math.PI/2; // Euler-Winkel zwischen Z-Achse und P - Breitengrad - this.psi = 0.0; // Euler-Winkel: Drehung des Handgelenks abweichend vom Breitengrad + // Plan-Koordinaten - HandRichtung (Euler-Winkel) + /** @type {number} Phi - Euler-Winkel (Längengrad): Rotation um Z-Achse in rad */ + this.phi = 0.0; + /** @type {number} Theta - Euler-Winkel (Breitengrad): Neigungswinkel der Handachse in rad */ + this.theta = -Math.PI/2; + /** @type {number} Psi - Euler-Winkel: Zusätzliche Drehung des Handgelenks in rad */ + this.psi = 0.0; - this.e = 0.0 // Finger-Distance + /** @type {number} Finger-Abstands-Einstellung (Öffnungsweite) */ + this.e = 0.0; - // Zwischen-Ergebnisse: Hand Punkt (nur für Tests sind die Public) + // Zwischen-Ergebnisse: Handgelenk-Punkt (Koordinaten des Handgelenks, nur für Tests public) + /** @type {number} Handgelenk-Position X in mm (berechneter Zwischenwert) */ this.pX = 0.0; + /** @type {number} Handgelenk-Position Y in mm (berechneter Zwischenwert) */ this.pY = 0.0; + /** @type {number} Handgelenk-Position Z in mm (berechneter Zwischenwert) */ this.pZ = 0.0; // Motor-Koordinaten - Schulter, Ellebogen, Hand-Dreher + /** @type {number} X-Motor-Position (Schulterposition auf X-Schiene) in mm */ this.xMotor = 0; - this.alpha = 0; // =Y Motor - this.beta = 0; // =Z Motor = Winkel die der Unterarm unter der Y-Achse ist. + /** @type {number} Alpha - Y-Motor-Winkel (Schulterposition) in rad */ + this.alpha = 0; + /** @type {number} Beta - Z-Motor-Winkel (Unterarm-Neigung unter Y-Achse) in rad */ + this.beta = 0; - // Motor-Winkel fuer's Handgelenk - this.a = 0; // aMotor am Ellebogen - this.b = 0; // bMotor Handgelenk-Knicker - this.c = 0; // cMotor Hand-Dreher + this.xMotorChanged = false; + this.yMotorChanged = false; + this.zMotorChanged = false; - this.eMotor = 0; // eMotor Finger-Distanz + // Motor-Winkel für's Handgelenk + /** @type {number} a-Motor-Winkel: Rotation am Ellbogen in rad */ + this.a = 0; + /** @type {number} b-Motor-Winkel: Handgelenk-Knicker-Winkel in rad */ + this.b = 0; + /** @type {number} c-Motor-Winkel: Hand-Dreher-Rotation in rad */ + this.c = 0; + this.aMotorChanged = false; + this.bMotorChanged = false; + this.cMotorChanged = false; + this.eMotorChanged = false; + /** @type {number} e-Motor-Wert: Finger-Abstands-Motor-Position */ + this.eMotor = 0; + + /** @type {number} Zeitstempel des letzten verarbeiteten Kommandos */ this.oldCommandTime = Date.now(); + /** @type {Function[]} Array von Visualisierungs-Funktionen */ this.showFunctions = []; + /** @type {Object[]} Gespeicherte Roboterpositionen/Punkte */ this.savedPoints = []; + /** @type {number} Index des aktuell angesteuerten Punktes */ this.atPointNr = 0; - this.t = 0; // TimeStamp of this Point + /** @type {number} Zeitstempel des aktuellen Punktes in ms */ + this.t = 0; + /** @type {boolean} Relative oder absolute Bewegung (true = relativ) */ this.moveRelative = true; + /** @type {Object|null} Python-Sender-Instanz für GCode-Kommunikation */ this.pythonSender = null; + /** @type {Object[]} Array von Kommando-Empfängern */ this.cmdReceivers = []; } createMotorPosition(){ this.motorPosition = new MotorPosition(this.xMotor, this.alpha, this.beta, this.a, this.b, this.c, this.eMotor); + + this.motorPosition.xMotorChanged = this.xMotorChanged; + this.motorPosition.yMotorChanged = this.yMotorChanged; + this.motorPosition.zMotorChanged = this.zMotorChanged; + this.motorPosition.aMotorChanged = this.aMotorChanged; + this.motorPosition.bMotorChanged = this.bMotorChanged; + this.motorPosition.cMotorChanged = this.cMotorChanged; + this.motorPosition.eMotorChanged = this.eMotorChanged; } // Berechnet aus XYZ die Motor-Winkel für den GCode @@ -188,12 +236,7 @@ class Robot{ console.log("Robot.sendCommand: Motor-Pos: x=", this.motorPosition.x.toFixed(3), "yMotor=",this.motorPosition.y.toFixed(3), "zMotor=",this.motorPosition.z.toFixed(3), "aM=", this.motorPosition.a.toFixed(3), "bM=", this.motorPosition.b.toFixed(3), "cM=", this.motorPosition.c.toFixed(3), " e=", this.motorPosition.e.toFixed(3)); this.cmdReceivers.forEach(receiver => { - if(cmd == "G1"){ - receiver.moveTo(this.motorPositionOld, this.motorPosition); - } - else{ receiver.execCommand(cmd,this.motorPositionOld, this.motorPosition); - } }); } } diff --git a/robot/RobotMotorPosition.js b/robot/RobotMotorPosition.js index a1b9a2c..31a22e8 100755 --- a/robot/RobotMotorPosition.js +++ b/robot/RobotMotorPosition.js @@ -13,6 +13,14 @@ module.exports = class RobotMotorPosition{ this.e = e; // Finger open this.time = Date.now(); + + this.xMotorChanged = false; + this.yMotorChanged = false; + this.zMotorChanged = false; + this.aMotorChanged = false; + this.bMotorChanged = false; + this.cMotorChanged = false; + this.eMotorChanged = false; } } diff --git a/robot/TelnetSenderGRBL.js b/robot/TelnetSenderGRBL.js index 87fd8b3..f6e42fa 100755 --- a/robot/TelnetSenderGRBL.js +++ b/robot/TelnetSenderGRBL.js @@ -75,27 +75,27 @@ module.exports = class TelnetSenderGRBL{ var data = strCommand.toString("utf-8"); - if(this.xAxisGrbl == "x"){ + if(this.xAxisGrbl == "x" && mNew.xMotorChanged){ data += " x" + (mNew.x).toFixed(2).toString(); } - if(this.xAxisGrbl == "y"){ + if(this.xAxisGrbl == "y" && mNew.yMotorChanged){ data += " x" + (mNew.y * 180 / Math.PI).toFixed(2).toString(); } - if(this.xAxisGrbl == "z"){ + if(this.xAxisGrbl == "z" && mNew.zMotorChanged){ data += " x" + ((mNew.z * 180 / Math.PI) - (mNew.y * 180 / Math.PI) ).toFixed(2).toString(); } - if(this.xAxisGrbl == "a"){ + if(this.xAxisGrbl == "a" && mNew.aMotorChanged){ // 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"){ + if(this.xAxisGrbl == "b" && (mNew.bMotorChanged || mNew.cMotorChanged)){ 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(this.xAxisGrbl == "c" && (mNew.bMotorChanged || mNew.cMotorChanged || mNew.zMotorChanged)){ // 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"){ + if(this.xAxisGrbl == "e" && mNew.eMotorChanged){ //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 ; @@ -104,111 +104,109 @@ module.exports = class TelnetSenderGRBL{ - if(this.yAxisGrbl == "x"){ + if(this.yAxisGrbl == "x" && mNew.xMotorChanged){ data += " y" + (mNew.x ).toFixed(2).toString(); } - if(this.yAxisGrbl == "y"){ + if(this.yAxisGrbl == "y" && mNew.yMotorChanged){ data += " y" + (mNew.y * 180 / Math.PI).toFixed(2).toString(); } - if(this.yAxisGrbl == "z"){ + if(this.yAxisGrbl == "z" && mNew.zMotorChanged){ data += " y" + ((mNew.z * 180 / Math.PI) - (mNew.y * 180 / Math.PI) ).toFixed(2).toString(); } - if(this.yAxisGrbl == "a"){ + if(this.yAxisGrbl == "a" && mNew.aMotorChanged){ data += " y" + (mNew.a * 180 / Math.PI).toFixed(2).toString(); } - if(this.yAxisGrbl == "b"){ + if(this.yAxisGrbl == "b" && (mNew.bMotorChanged || mNew.cMotorChanged || mNew.zMotorChanged)){ 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(this.yAxisGrbl == "c" && (mNew.bMotorChanged || mNew.cMotorChanged || mNew.zMotorChanged)){ // 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"){ + if(this.yAxisGrbl == "e" && (mNew.eMotorChanged)){ data += " y" + (mNew.e * 180 / Math.PI).toFixed(2).toString(); } - if(this.zAxisGrbl == "x"){ + if(this.zAxisGrbl == "x" && mNew.xMotorChanged){ data += " z" + (mNew.x).toFixed(2).toString(); } - if(this.zAxisGrbl == "y"){ + if(this.zAxisGrbl == "y" && mNew.yMotorChanged){ data += " z" + (mNew.y * 180 / Math.PI).toFixed(2).toString(); } - if(this.zAxisGrbl == "z"){ + if(this.zAxisGrbl == "z" && mNew.zMotorChanged){ data += " z" + ((mNew.z * 180 / Math.PI) - (mNew.y * 180 / Math.PI) ).toFixed(2).toString(); } - if(this.zAxisGrbl == "a"){ + if(this.zAxisGrbl == "a" && mNew.aMotorChanged){ data += " z" + (mNew.a * 180 / Math.PI).toFixed(2).toString(); } - if(this.zAxisGrbl == "b"){ + if(this.zAxisGrbl == "b" && (mNew.bMotorChanged || mNew.cMotorChanged || mNew.zMotorChanged)){ // 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"){ + if(this.zAxisGrbl == "c" && (mNew.bMotorChanged || mNew.cMotorChanged || mNew.zMotorChanged)){ 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(this.zAxisGrbl == "e" && (mNew.eMotorChanged)){ data += " z" + (mNew.e * 180 / Math.PI).toFixed(2).toString(); } - if(this.aAxisGrbl == "x"){ + if(this.aAxisGrbl == "x" && mNew.xMotorChanged){ data += " a" + (mNew.y * 180 / Math.PI).toFixed(2).toString(); } - if(this.aAxisGrbl == "y"){ + if(this.aAxisGrbl == "y" && mNew.yMotorChanged){ data += " a" + (mNew.y * 180 / Math.PI).toFixed(2).toString(); } - if(this.aAxisGrbl == "z"){ + if(this.aAxisGrbl == "z" && mNew.zMotorChanged){ data += " a" + ((mNew.z * 180 / Math.PI) - (mNew.y * 180 / Math.PI) ).toFixed(2).toString(); } - if(this.aAxisGrbl == "a"){ + if(this.aAxisGrbl == "a" && mNew.aMotorChanged){ data += " a" + (mNew.a * 180 / Math.PI).toFixed(2).toString(); } - if(this.aAxisGrbl == "b"){ + if(this.aAxisGrbl == "b" && (mNew.bMotorChanged || mNew.cMotorChanged || mNew.zMotorChanged)){ 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(this.aAxisGrbl == "c" && (mNew.bMotorChanged || mNew.cMotorChanged || mNew.zMotorChanged)){ 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(this.aAxisGrbl == "e" && mNew.eMotorChanged){ // ToDo Mai 2024 data += " a" + (mNew.e * 180 / Math.PI).toFixed(2).toString(); } - - - - if(this.bAxisGrbl == "x"){ + if(this.bAxisGrbl == "x" && mNew.xMotorChanged){ data += " b" + (mNew.x).toFixed(2).toString(); } - if(this.bAxisGrbl == "y"){ + if(this.bAxisGrbl == "y" && mNew.yMotorChanged){ data += " b" + (mNew.y * 180 / Math.PI).toFixed(2).toString(); } - if(this.bAxisGrbl == "z"){ + if(this.bAxisGrbl == "z" && mNew.zMotorChanged){ data += " b" + ((mNew.z * 180 / Math.PI) - (mNew.y * 180 / Math.PI) ).toFixed(2).toString(); } - if(this.bAxisGrbl == "a"){ + if(this.bAxisGrbl == "a" && mNew.aMotorChanged){ data += " b" + (mNew.a * 180 / Math.PI).toFixed(2).toString(); } - if(this.bAxisGrbl == "b"){ + if(this.bAxisGrbl == "b" && (mNew.bMotorChanged || mNew.cMotorChanged || mNew.zMotorChanged)){ data += " b" + (mNew.b * 180 / Math.PI).toFixed(2).toString(); } - if(this.bAxisGrbl == "c"){ + if(this.bAxisGrbl == "c" && (mNew.bMotorChanged || mNew.cMotorChanged || mNew.zMotorChanged)){ 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(this.bAxisGrbl == "e" && mNew.eMotorChanged){ data += " b" + (mNew.e * 180 / Math.PI).toFixed(2).toString(); } - - if(strCommand == "G1"){ - data += " f"+(maxSpeedF.toFixed(2).toString()) - } if(this.tSocket && data.toString("utf-8").length > 3){ + + if(strCommand == "G1"){ + data += " f"+(maxSpeedF.toFixed(2).toString()) + } + if(!this.isTestMode){ console.log("" + this.urlGRBLstr + " gets the message: " + data.toString("utf-8"))} this.tSocket.write( data.toString("utf-8") + "\r\n"); } diff --git a/test/GCode.receiveGCode.G92.test.js b/test/GCode.receiveGCode.G92.test.js index 0bfe0fd..4f725ef 100755 --- a/test/GCode.receiveGCode.G92.test.js +++ b/test/GCode.receiveGCode.G92.test.js @@ -55,7 +55,7 @@ describe("Robot G92", () => { }); // G92 y2.8 z131.0 - test("ReadPosition -> G92()", () => { + test("ReadPosition -> G92() test ob nur bestimmte Achsen gesendet werden", () => { // === Instanz A: Vorwärts-Kinematik (XYZ -> Motorwinkel) === const L1 = 300; @@ -75,14 +75,43 @@ describe("Robot G92", () => { GCode.receiveGCode(robot,"M92 y0.049 z2.286"); - const strExpect1 = 'G92 x0.00 y2.81 z128.17\r\n'; + //const strExpect1 = 'G92 x0.00 y2.81 z128.17\r\n'; + const strExpect1 = 'G92 y2.81 z128.17\r\n'; // x soll eben nicht gesendet werden. const strExpect2 = 'G92 y2.81 z128.17\r\n'; allowedValues = [strExpect1, strExpect2]; expect(allowedValues).toContain(telnetSender1.tSocket.written); + expect(telnetSender2.tSocket.written.length).toBe(0); // kein GCode für Ellbow // ("Wenn nur G92 x3 gegeben wird, dann wird trotzdem auch y und z gesendet. schlecht." ); }); + // G92 y2.8 z131.0 + test("ReadPosition -> G92() test ob nur bestimmte Achsen gesendet werden", () => { + // === Instanz A: Vorwärts-Kinematik (XYZ -> Motorwinkel) === + const L1 = 300; + const L2 = 300; + const L3 = 20; + + const robot = new Robot(L1, L2, L3) + + var telnetSender1 = new TenetSender(urlGRBL = "test.test", maxSpeedF = 2300, xAxisGrbl = "x", yAxisGrbl = "y", zAxisGrbl = "z"); + var telnetSender2 = new TenetSender(urlGRBL = "test.test", maxSpeedF = 5000, xAxisGrbl = "a", yAxisGrbl = null, zAxisGrbl = null); + var telnetSender3 = new TenetSender(urlGRBL = "test.test", maxSpeedF = 5000, xAxisGrbl = "c", yAxisGrbl = "e", zAxisGrbl = "b"); + + robot.cmdReceivers.push(telnetSender1); + robot.cmdReceivers.push(telnetSender2); + robot.cmdReceivers.push(telnetSender3); + + + GCode.receiveGCode(robot,"M92 a0.20"); + + + expect(telnetSender1.tSocket.written.length).toBe(0); // kein GCode für XYZ + expect(telnetSender2.tSocket.written).toBe('G92 x11.46\r\n'); + expect(telnetSender3.tSocket.written.length).toBe(0); // kein GCode für XYZ + + // ("Wenn nur G92 x3 gegeben wird, dann wird trotzdem auch y und z gesendet. schlecht." ); + }); }); diff --git a/test/GCode.test.js b/test/GCode.test.js index 0ce2baf..21b8bdc 100755 --- a/test/GCode.test.js +++ b/test/GCode.test.js @@ -1,5 +1,6 @@ const GCode = require('../robot/GCode.js'); - +const Robot = require('../robot/Robot.js'); +var TenetSender = require('../robot/TelnetSenderGRBL.js') test('G91 ist ein GCode Command', () => { var x = GCode.containsCommand("G91") ; @@ -12,4 +13,37 @@ test('G28 ist ein GCode Command', () => { }); + beforeAll(() => { + jest.spyOn(console, 'log').mockImplementation(() => {}) + }) + + afterAll(() => { + jest.restoreAllMocks() + }) + + + test("ReadPosition -> G1", () => { + + const L1 = 300; + const L2 = 300; + const L3 = 20; + + const robot = new Robot(L1, L2, L3) + + var telnetSender1 = new TenetSender(urlGRBL = "test.test", maxSpeedF = 2300, xAxisGrbl = "x", yAxisGrbl = "y", zAxisGrbl = "z"); + var telnetSender2 = new TenetSender(urlGRBL = "test.test", maxSpeedF = 5000, xAxisGrbl = "a", yAxisGrbl = null, zAxisGrbl = null); + var telnetSender3 = new TenetSender(urlGRBL = "test.test", maxSpeedF = 5000, xAxisGrbl = "c", yAxisGrbl = "e", zAxisGrbl = "b"); + + robot.cmdReceivers.push(telnetSender1); + robot.cmdReceivers.push(telnetSender2); + robot.cmdReceivers.push(telnetSender3); + + + GCode.receiveGCode(robot,"G1 x120"); + + + expect(telnetSender1.tSocket.written).toContain('G1 x1') + }); + + diff --git a/test/Robot.sendCommand.test.js b/test/Robot.sendCommand.test.js index e1d813f..0564b1c 100644 --- a/test/Robot.sendCommand.test.js +++ b/test/Robot.sendCommand.test.js @@ -98,8 +98,8 @@ describe('Robot.sendCommand & cmdReceivers', () => { test('Receiver-Reihenfolge bleibt erhalten', () => { const order = [] - const r1 = { moveTo: () => order.push('r1') } - const r2 = { moveTo: () => order.push('r2') } + const r1 = { execCommand: () => order.push('r1') } + const r2 = { execCommand: () => order.push('r2') } robot.cmdReceivers.push(r1, r2) robot.sendCommand() diff --git a/test/Sender.Telnet.test.js b/test/Sender.Telnet.test.js index 6f4e7ac..3d8ad1c 100755 --- a/test/Sender.Telnet.test.js +++ b/test/Sender.Telnet.test.js @@ -19,6 +19,9 @@ describe("TelnetSenderGRBL.execCommand", () => { // Provide some sample motion data const mOld = { x: 0, y: 0, z: 0, a:0, b:0, c:0, e:0 }; // not used in your code const mNew = { x: 12.34, y: Math.PI/2, z: 0, a:0, b:0, c:0, e:0 }; + mNew.xMotorChanged = true; + mNew.yMotorChanged = true; + mNew.zMotorChanged = true; sender.execCommand("G1", mOld, mNew); @@ -44,6 +47,11 @@ describe("TelnetSenderGRBL.execCommand", () => { const mOld = { x: 0, y: 0, z: 0, a:Math.PI, b:0, c:0, e:0 }; // not used in your code const mNew = { x: 12.34, y: Math.PI/2, z: 0, a:Math.PI/8, b:0, c:0, e:0 }; + mNew.xMotorChanged = true; + mNew.yMotorChanged = true; + mNew.zMotorChanged = true; + mNew.aMotorChanged = true; + sender.execCommand("G1", mOld, mNew); // ✅ verify output @@ -66,6 +74,9 @@ describe("TelnetSenderGRBL.execCommand", () => { // Provide some sample motion data const mOld = { x: 0, y: 0, z: 0, a:0, b:0, c:0, e:0 }; // not used in your code const mNew = { x: 12.34, y: 1.0, z: 2.0, a:0, b:0, c:0, e:0 }; + mNew.xMotorChanged = true; + mNew.yMotorChanged = true; + mNew.zMotorChanged = true; sender.execCommand("G92", mOld, mNew); diff --git a/test/helpers/mockCmdReceiver.js b/test/helpers/mockCmdReceiver.js index 7fc2762..002b958 100644 --- a/test/helpers/mockCmdReceiver.js +++ b/test/helpers/mockCmdReceiver.js @@ -11,6 +11,16 @@ class MockCmdReceiver { }) } + execCommand(cmd, oldPos, newPos) { + this.calls.push({ + cmd, + oldPos, + newPos + }) + } + + + get callCount() { return this.calls.length }