Merge branch 'main' of http://thinkcentre.local:3000/ChK/appRobotControlScara
This commit is contained in:
11
jest.config.js
Normal file
11
jest.config.js
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
module.exports = {
|
||||||
|
testEnvironment: 'node',
|
||||||
|
testMatch: ['**/test/**/*.test.js'],
|
||||||
|
collectCoverageFrom: [
|
||||||
|
'server/**/*.js',
|
||||||
|
'!server/config/**'
|
||||||
|
],
|
||||||
|
verbose: true,
|
||||||
|
// Ignoriere console.log Warnings nach Tests
|
||||||
|
setupFilesAfterEnv: ['<rootDir>/test/setup.js']
|
||||||
|
};
|
||||||
4060
package-lock.json
generated
4060
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -3,7 +3,8 @@
|
|||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"main": "server/server.js",
|
"main": "server/server.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "node server/server.js"
|
"start": "node server/server.js",
|
||||||
|
"test": "jest"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"express": "^4.22.1",
|
"express": "^4.22.1",
|
||||||
@@ -18,5 +19,8 @@
|
|||||||
"keywords": [],
|
"keywords": [],
|
||||||
"author": "",
|
"author": "",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"type": "commonjs"
|
"type": "commonjs",
|
||||||
|
"devDependencies": {
|
||||||
|
"jest": "^30.3.0"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,12 @@ class FluidNCClient extends EventEmitter {
|
|||||||
});
|
});
|
||||||
|
|
||||||
this.ws.on("message", (msg) => {
|
this.ws.on("message", (msg) => {
|
||||||
|
// console.log("[FluidNC] Received from FluidNC:", msg.toString());
|
||||||
|
// ExampleMessgae: <Idle|MPos:0.000,0.000,0.000|FS:0,0|Pn:P|WCO:0.000,0.000,-70.000>
|
||||||
|
// <Idle|MPos:0.000,0.000,0.000|FS:0,0|Pn:P>
|
||||||
|
if (!msg.toString().includes("<Idle|MPos:") && msg.toString() != "ok") {
|
||||||
|
console.log("[FluidNC] Received from FluidNC:", msg.toString());
|
||||||
|
}
|
||||||
this.emit("message", msg.toString());
|
this.emit("message", msg.toString());
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -36,6 +42,14 @@ class FluidNCClient extends EventEmitter {
|
|||||||
this.ws.on("error", (err) => {
|
this.ws.on("error", (err) => {
|
||||||
console.log("[FluidNC] WS Error:", err.message);
|
console.log("[FluidNC] WS Error:", err.message);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.ws.on("unexpected-response", (req, res) => {
|
||||||
|
console.log("[FluidNC] WS Unexpected Response:", res.statusCode, res.statusMessage);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.ws.on("disconnect", () => {
|
||||||
|
console.log("[FluidNC] WS Disconnected");
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
sendLine(cmd) {
|
sendLine(cmd) {
|
||||||
@@ -48,8 +62,13 @@ class FluidNCClient extends EventEmitter {
|
|||||||
this.sendLine("?");
|
this.sendLine("?");
|
||||||
}
|
}
|
||||||
|
|
||||||
jog(axis, value) {
|
jog(relative, axis, value) {
|
||||||
const cmd = `$J=G91 ${axis}${value} F2000`;
|
// $J= um den Befehl als Jog zu kennzeichnen
|
||||||
|
// G91 für relative Bewegungen (G90 für absolute)
|
||||||
|
// G1 Linearbewegung
|
||||||
|
//const cmd = relative? `$J=G91 G1 ${axis}${value} F2000\r\n`: `$J=G90 G1 ${axis}${value} F2000\r\n`;
|
||||||
|
const cmd = relative? `G91 G1 ${axis}${value} F2000\r\n`: `G90 G1 ${axis}${value} F2000\r\n`;
|
||||||
|
console.log("[FluidNC] Jog Command:", cmd);
|
||||||
this.sendLine(cmd);
|
this.sendLine(cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ wss.on("connection", (ws) => {
|
|||||||
|
|
||||||
console.log("Message from WSS: " + msg);
|
console.log("Message from WSS: " + msg);
|
||||||
if (data.type === "jog") {
|
if (data.type === "jog") {
|
||||||
fluid.jog(data.axis, data.value);
|
fluid.jog(data.relative, data.axis, data.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.type === "gcode") {
|
if (data.type === "gcode") {
|
||||||
@@ -66,10 +66,10 @@ fluid.onMessage((msg) => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Status polling ("?" every 50ms)
|
// Status polling ("?" every 1000ms)
|
||||||
setInterval(() => {
|
setInterval(() => {
|
||||||
fluid.requestStatus();
|
fluid.requestStatus();
|
||||||
}, 50);
|
}, 3000);
|
||||||
|
|
||||||
server.listen(config.server.port, () => {
|
server.listen(config.server.port, () => {
|
||||||
console.log("[Server] Running at:");
|
console.log("[Server] Running at:");
|
||||||
|
|||||||
68
test/helpers/TestFluidNCClient.js
Normal file
68
test/helpers/TestFluidNCClient.js
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
const WebSocket = require("ws");
|
||||||
|
const EventEmitter = require("events");
|
||||||
|
|
||||||
|
class TestFluidNCClient extends EventEmitter {
|
||||||
|
constructor(cfg) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.host = cfg.host;
|
||||||
|
this.port = cfg.port || 81;
|
||||||
|
|
||||||
|
this.ws = null;
|
||||||
|
this.connect();
|
||||||
|
}
|
||||||
|
|
||||||
|
connect() {
|
||||||
|
const url = `ws://${this.host}:${this.port}`;
|
||||||
|
|
||||||
|
this.ws = new WebSocket(url);
|
||||||
|
|
||||||
|
this.ws.on("open", () => {
|
||||||
|
console.log("[TestFluidNC] Connected (WS)");
|
||||||
|
});
|
||||||
|
|
||||||
|
this.ws.on("message", (msg) => {
|
||||||
|
this.emit("message", msg.toString());
|
||||||
|
});
|
||||||
|
|
||||||
|
this.ws.on("close", () => {
|
||||||
|
console.log("[TestFluidNC] Disconnected");
|
||||||
|
});
|
||||||
|
|
||||||
|
this.ws.on("error", (err) => {
|
||||||
|
console.log("[TestFluidNC] WS Error:", err.message);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
sendLine(cmd) {
|
||||||
|
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
|
||||||
|
this.ws.send(cmd + "\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
requestStatus() {
|
||||||
|
this.sendLine("?");
|
||||||
|
}
|
||||||
|
|
||||||
|
jog(relative, axis, value) {
|
||||||
|
const cmd = relative? `$J=G91 G1 ${axis}${value} F2000\r\n`: `$J=G90 G1 ${axis}${value} F2000\r\n`;
|
||||||
|
this.sendLine(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
sendGcode(cmd) {
|
||||||
|
this.sendLine(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
onMessage(fn) {
|
||||||
|
this.on("message", fn);
|
||||||
|
}
|
||||||
|
|
||||||
|
close() {
|
||||||
|
if (this.ws) {
|
||||||
|
this.ws.close();
|
||||||
|
this.ws = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = TestFluidNCClient;
|
||||||
146
test/helpers/mockFluidNC.js
Normal file
146
test/helpers/mockFluidNC.js
Normal file
@@ -0,0 +1,146 @@
|
|||||||
|
const WebSocket = require("ws");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mock FluidNC WebSocket Server für Tests
|
||||||
|
* Ermöglicht es, FluidNCClient in Tests gegen einen echten WS-Server zu testen
|
||||||
|
*/
|
||||||
|
class MockFluidNC {
|
||||||
|
constructor(host = "localhost", port = 9000) {
|
||||||
|
this.host = host;
|
||||||
|
this.port = port;
|
||||||
|
this.server = null;
|
||||||
|
this.clients = [];
|
||||||
|
this.messageHandlers = [];
|
||||||
|
this.receivedCommands = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Startet den Mock-Server
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
|
start() {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
this.server = new WebSocket.Server({ host: this.host, port: this.port }, () => {
|
||||||
|
console.log(`[MockFluidNC] Server started on ws://${this.host}:${this.port}`);
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.server.on("connection", (ws) => {
|
||||||
|
console.log("[MockFluidNC] Client connected");
|
||||||
|
this.clients.push(ws);
|
||||||
|
|
||||||
|
ws.on("message", (msg) => {
|
||||||
|
const msgStr = msg.toString().trim();
|
||||||
|
console.log(`[MockFluidNC] Received: ${msgStr}`);
|
||||||
|
|
||||||
|
// Befehl zur Historie hinzufügen
|
||||||
|
this.receivedCommands.push(msgStr);
|
||||||
|
|
||||||
|
// Handler aufrufen, die registriert wurden
|
||||||
|
this.messageHandlers.forEach(handler => handler(msgStr));
|
||||||
|
|
||||||
|
// Automatische Responses für spezielle Befehle
|
||||||
|
this._handleCommand(msgStr, ws);
|
||||||
|
});
|
||||||
|
|
||||||
|
ws.on("close", () => {
|
||||||
|
console.log("[MockFluidNC] Client disconnected");
|
||||||
|
this.clients = this.clients.filter(c => c !== ws);
|
||||||
|
});
|
||||||
|
|
||||||
|
ws.on("error", (err) => {
|
||||||
|
console.log("[MockFluidNC] Client error:", err.message);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
this.server.on("error", reject);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stoppt den Mock-Server
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
|
stop() {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
if (this.server) {
|
||||||
|
// Alle Clients disconnecten
|
||||||
|
this.clients.forEach(client => {
|
||||||
|
if (client.readyState === WebSocket.OPEN) {
|
||||||
|
client.close();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.clients = [];
|
||||||
|
|
||||||
|
this.server.close(() => {
|
||||||
|
console.log("[MockFluidNC] Server stopped");
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
resolve();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sendet eine Nachricht an alle verbundenen Clients
|
||||||
|
* @param {string} msg
|
||||||
|
*/
|
||||||
|
broadcast(msg) {
|
||||||
|
this.clients.forEach(client => {
|
||||||
|
if (client.readyState === WebSocket.OPEN) {
|
||||||
|
client.send(msg);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registriert einen Handler, der bei jeder empfangenen Nachricht aufgerufen wird
|
||||||
|
* @param {Function} handler - (msg: string) => void
|
||||||
|
*/
|
||||||
|
onMessage(handler) {
|
||||||
|
this.messageHandlers.push(handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Behandelt spezielle G-Code Befehle mit Auto-Responses
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_handleCommand(cmd, ws) {
|
||||||
|
if (cmd === "?") {
|
||||||
|
// Status request - sende eine Status-Antwort
|
||||||
|
ws.send("<Idle|MPos:0.000,0.000,0.000|FS:0,0>\n");
|
||||||
|
} else if (cmd.startsWith("$J=")) {
|
||||||
|
// Jog command - sende OK
|
||||||
|
ws.send("ok\n");
|
||||||
|
} else if (cmd.includes("G1") || cmd.includes("G0")) {
|
||||||
|
// G-Code command - sende OK
|
||||||
|
ws.send("ok\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gibt die Anzahl verbundener Clients zurück
|
||||||
|
*/
|
||||||
|
getConnectedClientCount() {
|
||||||
|
return this.clients.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gibt alle empfangenen Befehle zurück und leert die Liste
|
||||||
|
*/
|
||||||
|
getReceivedCommands() {
|
||||||
|
const commands = [...this.receivedCommands];
|
||||||
|
this.receivedCommands = [];
|
||||||
|
return commands;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gibt den letzten empfangenen Befehl zurück
|
||||||
|
*/
|
||||||
|
getLastReceivedCommand() {
|
||||||
|
return this.receivedCommands[this.receivedCommands.length - 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = MockFluidNC;
|
||||||
91
test/mockFluidNC.test.js
Normal file
91
test/mockFluidNC.test.js
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
const MockFluidNC = require("./helpers/mockFluidNC");
|
||||||
|
const TestFluidNCClient = require("./helpers/TestFluidNCClient");
|
||||||
|
|
||||||
|
describe("FluidNCClient with MockFluidNC", () => {
|
||||||
|
let mock;
|
||||||
|
let client;
|
||||||
|
|
||||||
|
beforeAll(async () => {
|
||||||
|
// Mock-Server starten
|
||||||
|
mock = new MockFluidNC("localhost", 9003);
|
||||||
|
await mock.start();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterAll(async () => {
|
||||||
|
// Mock-Server stoppen - das stoppt alle Verbindungen
|
||||||
|
await mock.stop();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
// Neuen Test-Client für jeden Test erstellen
|
||||||
|
client = new TestFluidNCClient({
|
||||||
|
host: "localhost",
|
||||||
|
port: 9003
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
// Client sauber schließen
|
||||||
|
if (client) {
|
||||||
|
client.close();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test("sollte sich mit Mock-Server verbinden", async () => {
|
||||||
|
// Warten bis verbunden
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 300));
|
||||||
|
expect(mock.getConnectedClientCount()).toBeGreaterThan(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("sollte Status Request senden", async () => {
|
||||||
|
// Warten bis verbunden
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 300));
|
||||||
|
|
||||||
|
const messagePromise = new Promise((resolve) => {
|
||||||
|
client.onMessage((msg) => {
|
||||||
|
resolve(msg);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
client.requestStatus();
|
||||||
|
|
||||||
|
const response = await messagePromise;
|
||||||
|
expect(response).toContain("Idle");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("sollte Jog Command verarbeiten", async () => {
|
||||||
|
// Warten bis verbunden
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 300));
|
||||||
|
|
||||||
|
const messagePromise = new Promise((resolve) => {
|
||||||
|
client.onMessage((msg) => {
|
||||||
|
resolve(msg);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
client.jog(true, "X", 10);
|
||||||
|
|
||||||
|
const response = await messagePromise;
|
||||||
|
expect(response.trim()).toBe("ok");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("sollte G-Code Command verarbeiten", async () => {
|
||||||
|
// Warten bis verbunden
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 300));
|
||||||
|
|
||||||
|
const messagePromise = new Promise((resolve) => {
|
||||||
|
client.onMessage((msg) => {
|
||||||
|
resolve(msg);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
client.sendGcode("G0 X10 Y20");
|
||||||
|
|
||||||
|
const response = await messagePromise;
|
||||||
|
expect(response.trim()).toBe("ok");
|
||||||
|
|
||||||
|
// Zusätzlich prüfen, dass der korrekte Befehl empfangen wurde
|
||||||
|
const receivedCommands = mock.getReceivedCommands();
|
||||||
|
expect(receivedCommands).toContain("G0 X10 Y20");
|
||||||
|
});
|
||||||
|
}, 10000);
|
||||||
13
test/setup.js
Normal file
13
test/setup.js
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
// Jest Setup für alle Tests
|
||||||
|
const originalConsoleLog = console.log;
|
||||||
|
|
||||||
|
// Mock console.log um Warnings nach Tests zu vermeiden
|
||||||
|
beforeAll(() => {
|
||||||
|
console.log = jest.fn();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterAll(async () => {
|
||||||
|
console.log = originalConsoleLog;
|
||||||
|
// Warten bis alle async Operationen fertig sind
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 200));
|
||||||
|
});
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
<html lang="de">
|
<html lang="de">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<title>2D Robot Control</title>
|
<title>FluidNC Robot Control</title>
|
||||||
<style>
|
<style>
|
||||||
body {
|
body {
|
||||||
background: #234;
|
background: #234;
|
||||||
@@ -91,6 +91,7 @@
|
|||||||
|
|
||||||
<div id="posBox">
|
<div id="posBox">
|
||||||
<div>X: <span id="posX">0.000</span></div>
|
<div>X: <span id="posX">0.000</span></div>
|
||||||
|
<div>Y: <span id="posY">0.000</span></div>
|
||||||
<div>Z: <span id="posZ">0.000</span></div>
|
<div>Z: <span id="posZ">0.000</span></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -103,6 +104,12 @@
|
|||||||
<button onclick="jog('X', 1)">X +1</button>
|
<button onclick="jog('X', 1)">X +1</button>
|
||||||
<button onclick="jog('X', 10)">X +10</button>
|
<button onclick="jog('X', 10)">X +10</button>
|
||||||
|
|
||||||
|
<button onclick="jog('Y', -10)">Y -10</button>
|
||||||
|
<button onclick="jog('Y', -1)">Y -1</button>
|
||||||
|
<button class="noMouseHover"></button>
|
||||||
|
<button onclick="jog('Y', 1)">Y +1</button>
|
||||||
|
<button onclick="jog('Y', 10)">Y +10</button>
|
||||||
|
|
||||||
<button onclick="jog('Z', -10)">Z -10</button>
|
<button onclick="jog('Z', -10)">Z -10</button>
|
||||||
<button onclick="jog('Z', -1)">Z -1</button>
|
<button onclick="jog('Z', -1)">Z -1</button>
|
||||||
<button class="noMouseHover"></button>
|
<button class="noMouseHover"></button>
|
||||||
@@ -168,6 +175,7 @@
|
|||||||
ws.send(JSON.stringify({
|
ws.send(JSON.stringify({
|
||||||
type: "jog",
|
type: "jog",
|
||||||
axis: axis,
|
axis: axis,
|
||||||
|
relative: true,
|
||||||
value: value
|
value: value
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
@@ -180,8 +188,8 @@
|
|||||||
// 1) Versuche WPos direkt zu lesen
|
// 1) Versuche WPos direkt zu lesen
|
||||||
const wposMatch = line.match(/WPos:([^|>]+)/);
|
const wposMatch = line.match(/WPos:([^|>]+)/);
|
||||||
if (wposMatch) {
|
if (wposMatch) {
|
||||||
const [x, , z] = wposMatch[1].split(",").map(Number);
|
const [x, y, z] = wposMatch[1].split(",").map(Number);
|
||||||
updateXZ(x, z);
|
updateXZ(x, y, z);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -194,16 +202,19 @@
|
|||||||
const wco = wcoMatch[1].split(",").map(Number);
|
const wco = wcoMatch[1].split(",").map(Number);
|
||||||
|
|
||||||
const x = (mpos[0] ?? 0) - (wco[0] ?? 0);
|
const x = (mpos[0] ?? 0) - (wco[0] ?? 0);
|
||||||
|
const y = (mpos[1] ?? 0) - (wco[1] ?? 0);
|
||||||
const z = (mpos[2] ?? 0) - (wco[2] ?? 0);
|
const z = (mpos[2] ?? 0) - (wco[2] ?? 0);
|
||||||
|
|
||||||
updateXZ(x, z);
|
updateXZ(x, y, z);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateXZ(x, z) {
|
function updateXZ(x, y, z) {
|
||||||
const elX = document.getElementById("posX");
|
const elX = document.getElementById("posX");
|
||||||
|
const elY = document.getElementById("posY");
|
||||||
const elZ = document.getElementById("posZ");
|
const elZ = document.getElementById("posZ");
|
||||||
if (elX) elX.textContent = Number.isFinite(x) ? x.toFixed(3) : "—";
|
if (elX) elX.textContent = Number.isFinite(x) ? x.toFixed(3) : "—";
|
||||||
|
if (elY) elY.textContent = Number.isFinite(y) ? y.toFixed(3) : "—";
|
||||||
if (elZ) elZ.textContent = Number.isFinite(z) ? z.toFixed(3) : "—";
|
if (elZ) elZ.textContent = Number.isFinite(z) ? z.toFixed(3) : "—";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -226,7 +237,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function setZero() {
|
function setZero() {
|
||||||
sendGcode("G92 X0 Z0");
|
sendGcode("G92 X0 Y0 Z0");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user