G92 > send-to-ESP

This commit is contained in:
ChK
2026-04-06 05:24:41 +02:00
parent 3e874e70c9
commit 3d33ecd747
12 changed files with 3337 additions and 20 deletions

16
.vscode/launch.json vendored
View File

@@ -11,6 +11,22 @@
"remoteRoot": "/usr/src/app", "remoteRoot": "/usr/src/app",
"restart": true, "restart": true,
"timeout": 10000 "timeout": 10000
},
{
"name": "Debug npm test",
"type": "node",
"request": "launch",
"runtimeExecutable": "npm",
"runtimeArgs": ["run", "test"],
"console": "integratedTerminal"
},
{
"name": "Debug current test file",
"type": "node",
"request": "launch",
"program": "${workspaceFolder}/node_modules/jest/bin/jest.js",
"args": ["--runInBand", "${file}"],
"console": "integratedTerminal"
} }
] ]
} }

View File

@@ -2192,3 +2192,5 @@
2026-04-04T21:04:06.177Z ::ffff:172.21.0.5: G91 G1 Y-5 F100 2026-04-04T21:04:06.177Z ::ffff:172.21.0.5: G91 G1 Y-5 F100
2026-04-04T21:04:06.206Z ::ffff:172.21.0.5: G91 G1 Y-5 F100 2026-04-04T21:04:06.206Z ::ffff:172.21.0.5: G91 G1 Y-5 F100
2026-04-04T21:04:06.238Z ::ffff:172.21.0.5: G91 G1 Y-5 F100 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

File diff suppressed because it is too large Load Diff

113
public/allApps.css Normal file
View File

@@ -0,0 +1,113 @@
/* =========================================================
allApps.css — Gemeinsames UI-Fundament für alle Robot-Apps
(layout-neutral)
========================================================= */
/* ---------- Design Tokens ---------- */
:root {
--bg: #0b1c2d;
--panel: #132c44;
--border: #0e1822;
--text: #e0e6ed;
--muted: #9aa6b2;
--accent: #a4bbd4;
--radius: 8px;
--gap: 16px;
--border-subtle: rgba(255,255,255,0.08);
}
/* ---------- Reset & Base ---------- */
* {
box-sizing: border-box;
}
html, body {
min-height: 100%;
}
body {
margin: 16px;
font-family: system-ui, -apple-system, BlinkMacSystemFont,
"Segoe UI", Roboto, Inter, Arial, sans-serif;
background: linear-gradient(
to bottom,
#dddddd -20%,
var(--bg) 130%
);
color: var(--text);
font-size: 14px;
}
/* ---------- Headings ---------- */
h1 {
margin: 0 0 16px;
font-size: 20px;
color: var(--accent);
}
h2 {
margin: 0;
font-size: 15px;
color: var(--accent);
}
/* ---------- Sections Container ---------- */
/* Grid-Spalten werden von der jeweiligen App definiert */
.sections {
display: grid;
gap: var(--gap);
}
/* ---------- Section Card ---------- */
.section {
background: var(--panel);
border: 1px solid var(--border);
border-radius: var(--radius);
padding: 22px 20px;
}
/* Semantische Breitenklassen (wirken nur,
wenn die App ein entsprechendes Grid definiert) */
.section.full {}
.section.half {}
.section.quarter {}
.section.eighth {}
/* ---------- Section Header / Collapse ---------- */
.section > h2 {
cursor: pointer;
display: flex;
justify-content: space-between;
align-items: center;
user-select: none;
}
/* Collapse Arrow */
.section > h2::after {
content: "▼";
font-size: 12px;
transition: transform 0.2s ease;
}
/* Collapsed state */
.section.collapsed > h2::after {
transform: rotate(-90deg);
}
/* Hide content when collapsed */
.section.collapsed > :not(h2) {
display: none;
}
/* ---------- Generic Lists ---------- */
.section ul {
margin: 10px 0 0;
padding: 0;
list-style: none;
}
.section li {
padding: 4px 0;
border-bottom: 1px solid var(--border-subtle);
}

View File

@@ -5,25 +5,26 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Robot Driver Info</title> <title>Robot Driver Info</title>
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+Math&display=swap" rel="stylesheet"> <link href="https://fonts.googleapis.com/css2?family=Noto+Sans+Math&display=swap" rel="stylesheet">
<link rel="stylesheet" href="allApps.css">
<link rel="stylesheet" href="style.css"> <link rel="stylesheet" href="style.css">
</head> </head>
<body> <body>
<h1>Robot Driver Status</h1> <!--<h1>Robot Driver Status</h1>-->
<div class="sections"> <div class="sections">
<div id="status" class="section half" data-id="clients"> <div id="status" class="section half" data-id="clients">
<h2>Verbundene WebClients</h2> <h2>WebClients</h2>
<ul id="clients"></ul> <ul id="clients"></ul>
</div> </div>
<div id="senders" class="section half" data-id="senders"> <div id="senders" class="section half" data-id="senders">
<h2>Verbundene FluidNC-Controller</h2> <h2>FluidNC-Controller</h2>
<ul id="senderList"></ul> <ul id="senderList"></ul>
</div> </div>
<div id="driverState" class="section half" data-id="driver"> <div id="driverState" class="section half" data-id="driver">
<h2>Zustand Driver</h2> <h2>Position Driver</h2>
<ul class="state-grid"> <ul class="state-grid">
<li><span>X</span><span id="state-x"></span></li> <li><span>X</span><span id="state-x"></span></li>
<li><span>Y</span><span id="state-y"></span></li> <li><span>Y</span><span id="state-y"></span></li>
@@ -40,7 +41,7 @@
<div id="motorState" class="section half" data-id="motors"> <div id="motorState" class="section half" data-id="motors">
<h2>Zustand Motoren</h2> <h2>Postion Motoren</h2>
<ul class="state-grid"> <ul class="state-grid">
<li><span>X</span><span id="motor-x"></span></li> <li><span>X</span><span id="motor-x"></span></li>
<li><span>Y</span><span id="motor-y"></span></li> <li><span>Y</span><span id="motor-y"></span></li>
@@ -57,12 +58,12 @@
<div id="commands" class="section" data-id="commands"> <div id="commands" class="section" data-id="commands">
<h2>Letzte Commands</h2> <h2>Commands</h2>
<ul id="commandList"></ul> <ul id="commandList"></ul>
</div> </div>
<div id="pings" class="section" data-id="pings"> <div id="pings" class="section" data-id="pings">
<h2>Letzte Ping Nachrichten</h2> <h2>Ping Messages</h2>
<ul id="pingList"></ul> <ul id="pingList"></ul>
</div> </div>
</div> </div>

View File

@@ -1,9 +1,9 @@
:root { :root {
--bg: #0b1c2d; --bg: #0b1c2d;
--panel: #132c44; --panel: #132c44;
--border: #1e3b58; --border: #0e1822;
--text: #e0e6ed; --text: #e0e6ed;
--accent: #6fb3ff; --accent: #a4bbd4;
} }
* { * {

View File

@@ -202,7 +202,8 @@ class GCode{
if(s.includes("e")){ robot.e = Number(s.substring(1, s.length));} if(s.includes("e")){ robot.e = Number(s.substring(1, s.length));}
}); });
} }
else if(g[0] == "G92"){ // G92 - Set Position else if(g[0] == "M92"){ // G92 - Set Position --- M92 in Radiant
robot.createMotorPosition();
g.forEach((s) => { 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("x")){ robot.xMotor = Number(s.substring(1, s.length));} if(s.includes("x")){ robot.xMotor = Number(s.substring(1, s.length));}
@@ -226,6 +227,7 @@ class GCode{
// ToDo: Send Command to update Position of Robot, because G92 should // ToDo: Send Command to update Position of Robot, because G92 should
// set the current Position to the given Coordinates without moving the Robot. // set the current Position to the given Coordinates without moving the Robot.
robot.sendCommand("G92");
} }
if(calculateNew && !calculateFromMotorCoordinates){ if(calculateNew && !calculateFromMotorCoordinates){

View File

@@ -180,7 +180,7 @@ class Robot{
while(this.theta < -Math.PI){this.theta += 2*Math.PI} while(this.theta < -Math.PI){this.theta += 2*Math.PI}
} }
sendCommand(){ sendCommand(cmd="G1"){
if(this.motorPosition == null){this.createMotorPosition() } if(this.motorPosition == null){this.createMotorPosition() }
this.motorPositionOld = this.motorPosition; this.motorPositionOld = this.motorPosition;
this.createMotorPosition() this.createMotorPosition()
@@ -188,7 +188,12 @@ 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)); 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 => { this.cmdReceivers.forEach(receiver => {
if(cmd == "G1"){
receiver.moveTo(this.motorPositionOld, this.motorPosition); receiver.moveTo(this.motorPositionOld, this.motorPosition);
}
else{
receiver.execCommand(cmd,this.motorPositionOld, this.motorPosition);
}
}); });
} }
} }

View File

@@ -204,8 +204,9 @@ module.exports = class TelnetSenderGRBL{
data += " b" + (mNew.e * 180 / Math.PI).toFixed(2).toString(); data += " b" + (mNew.e * 180 / Math.PI).toFixed(2).toString();
} }
if(strCommand == "G1"){
data += " f"+(maxSpeedF.toFixed(2).toString()) data += " f"+(maxSpeedF.toFixed(2).toString())
}
if(this.tSocket && data.toString("utf-8").length > 3){ if(this.tSocket && data.toString("utf-8").length > 3){
if(!this.isTestMode){ console.log("" + this.urlGRBLstr + " gets the message: " + data.toString("utf-8"))} if(!this.isTestMode){ console.log("" + this.urlGRBLstr + " gets the message: " + data.toString("utf-8"))}

View File

@@ -187,6 +187,15 @@ const infoServer = https.createServer(httpsOptions, (req, res) => {
res.writeHead(200, {'Content-Type': 'text/css'}); res.writeHead(200, {'Content-Type': 'text/css'});
res.end(data); res.end(data);
} }
}); } else if (req.url === '/allApps.css') {
fs.readFile('./public/allApps.css', (err, data) => {
if (err) {
res.writeHead(404);
res.end('Not found');
} else {
res.writeHead(200, {'Content-Type': 'text/css'});
res.end(data);
}
}); });
} else if (req.url === '/api/status') { } else if (req.url === '/api/status') {
const status = { const status = {
@@ -196,8 +205,8 @@ const infoServer = https.createServer(httpsOptions, (req, res) => {
{name: 'Elbow', status: telnetSender2?.tSocket ? 'connected' : 'disconnected'}, {name: 'Elbow', status: telnetSender2?.tSocket ? 'connected' : 'disconnected'},
{name: 'Hand', status: telnetSender3?.tSocket ? 'connected' : 'disconnected'} {name: 'Hand', status: telnetSender3?.tSocket ? 'connected' : 'disconnected'}
], ],
lastCommands: getLastLines('./logs/gcode_commands.log', 10), lastCommands: getLastLines('./logs/gcode_commands.log', 15),
lastPings: getLastLines('./logs/pings.log', 10) lastPings: getLastLines('./logs/pings.log', 15)
}; };
res.writeHead(200, {'Content-Type': 'application/json'}); res.writeHead(200, {'Content-Type': 'application/json'});
res.end(JSON.stringify(status)); res.end(JSON.stringify(status));

View File

@@ -1,9 +1,18 @@
// __tests__/Robot.inverseKinematics.test.js // __tests__/Robot.inverseKinematics.test.js
const Robot = require('../robot/Robot.js'); const Robot = require('../robot/Robot.js');
const GCode = require('../robot/GCode.js'); const GCode = require('../robot/GCode.js');
var TenetSender = require('../robot/TelnetSenderGRBL.js')
describe("Robot G92", () => { describe("Robot G92", () => {
beforeAll(() => {
jest.spyOn(console, 'log').mockImplementation(() => {})
})
afterAll(() => {
jest.restoreAllMocks()
})
test("ReadPosition -> calculatePositionFromMotorAngles()", () => { test("ReadPosition -> calculatePositionFromMotorAngles()", () => {
// === Instanz A: Vorwärts-Kinematik (XYZ -> Motorwinkel) === // === Instanz A: Vorwärts-Kinematik (XYZ -> Motorwinkel) ===
@@ -26,7 +35,7 @@ describe("Robot G92", () => {
A.calculateAngles3D(); A.calculateAngles3D();
var strGCode = `G92 X${A.xMotor} Y${A.alpha} Z${A.beta} A${A.a} B${A.b} C${A.c}` var strGCode = `M92 X${A.xMotor} Y${A.alpha} Z${A.beta} A${A.a} B${A.b} C${A.c}`
const T = new Robot(L1, L2, L3) const T = new Robot(L1, L2, L3)
@@ -44,5 +53,36 @@ describe("Robot G92", () => {
}); });
// G92 y2.8 z131.0
test("ReadPosition -> G92()", () => {
// === 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 y0.049 z2.286");
const strExpect1 = 'G92 x0.00 y2.81 z128.17\r\n';
const strExpect2 = 'G92 y2.81 z128.17\r\n';
allowedValues = [strExpect1, strExpect2];
expect(allowedValues).toContain(telnetSender1.tSocket.written);
// ("Wenn nur G92 x3 gegeben wird, dann wird trotzdem auch y und z gesendet. schlecht." );
});
}); });

View File

@@ -70,7 +70,7 @@ describe("TelnetSenderGRBL.execCommand", () => {
sender.execCommand("G92", mOld, mNew); sender.execCommand("G92", mOld, mNew);
// ✅ verify output // ✅ verify output
expect(sender.tSocket.written).toBe("G92 x12.34 y57.30 z57.30 f2300.00\r\n"); expect(sender.tSocket.written).toBe("G92 x12.34 y57.30 z57.30\r\n");
}); });
}); });