improved gcode handling

This commit is contained in:
casperlamboo 2015-06-09 11:08:06 +02:00
parent 38bf3c74f3
commit 17bd8f4f25
7 changed files with 205 additions and 88 deletions

View File

@ -37,7 +37,7 @@ function init () {
var loader = new THREE.STLLoader(); var loader = new THREE.STLLoader();
loader.load("models/dom.stl", function (geometry) { loader.load("models/dom.stl", function (geometry) {
var geometry = new THREE.BoxGeometry(10, 10, 10, 1, 1, 1); //var geometry = new THREE.BoxGeometry(10, 10, 10, 1, 1, 1);
//var geometry = new THREE.SphereGeometry(10, 20, 10); //var geometry = new THREE.SphereGeometry(10, 20, 10);
//var geometry = new THREE.TorusGeometry(20, 10, 30, 30); //var geometry = new THREE.TorusGeometry(20, 10, 30, 30);
/* /*

View File

@ -9,12 +9,32 @@
D3D.GCode = function () { D3D.GCode = function () {
"use strict"; "use strict";
this.current = {};
this.extruder = 0.0; this.extruder = 0.0;
this.bottom = true; this.bottom = true;
this.isRetracted = false; this.isRetracted = false;
this.isFanOn = false;
this.gcode = []; this.gcode = [];
this.nozzlePosition = new THREE.Vector2(0, 0); this.nozzlePosition = new THREE.Vector2(0, 0);
}; };
D3D.GCode.prototype.addGCode = function (command) {
"use strict";
var str = [];
for (var i in command) {
if (this.current[i] !== command[i] || i === "G") {
str.push(i + command[i]);
this.current[i] = command[i];
}
}
str = str.join(" ");
if (str.length > 0) {
this.gcode.push(str);
}
};
D3D.GCode.prototype.setSettings = function (printer) { D3D.GCode.prototype.setSettings = function (printer) {
"use strict"; "use strict";
@ -22,10 +42,33 @@ D3D.GCode.prototype.setSettings = function (printer) {
return this; return this;
}; };
D3D.GCode.prototype.turnOnFan = function () { D3D.GCode.prototype.turnFanOn = function (fanSpeed) {
"use strict"; "use strict";
this.gcode.push("M106"); this.isFanOn = true;
var gcode = {
"M": 106
};
if (fanSpeed !== undefined) {
gcode["S"] = fanSpeed;
}
this.addGCode(gcode);
return this;
};
D3D.GCode.prototype.turnFanOff = function () {
"use strict";
this.isFanOn = false;
this.addGCode({
"M": 107
});
return this;
}; };
D3D.GCode.prototype.moveTo = function (extrude, x, y, layer) { D3D.GCode.prototype.moveTo = function (extrude, x, y, layer) {
"use strict"; "use strict";
@ -58,30 +101,27 @@ D3D.GCode.prototype.moveTo = function (extrude, x, y, layer) {
var filamentSurfaceArea = Math.pow((filamentThickness/2), 2) * Math.PI; var filamentSurfaceArea = Math.pow((filamentThickness/2), 2) * Math.PI;
this.extruder += lineLength * nozzleDiameter * layerHeight / filamentSurfaceArea * flowRate; this.extruder += lineLength * nozzleDiameter * layerHeight / filamentSurfaceArea * flowRate;
this.gcode.push( this.addGCode({
"G1" + "G": 1,
" X" + x.toFixed(3) + "X": x.toFixed(3), "Y": y.toFixed(3), "Z": z.toFixed(3),
" Y" + y.toFixed(3) + "F": speed.toFixed(3),
((z !== this.lastZ) ? (" Z" + z.toFixed(3)) : "") + "E": this.extruder.toFixed(3)
((speed !== this.lastSpeed) ? (" F" + speed.toFixed(3)) : "") + });
" E" + this.extruder.toFixed(3)
);
} }
else { else {
var speed = travelSpeed * 60; var speed = travelSpeed * 60;
this.gcode.push( this.addGCode.({
"G0" + "G": 0,
" X" + x.toFixed(3) + " Y" + y.toFixed(3) + " Z" + z + "X": x.toFixed(3), "Y": y.toFixed(3), "Z": z.toFixed(3),
" F" + speed.toFixed(3) "F": speed.toFixed(3)
); });
} }
this.lastSpeed = speed;
this.lastZ = z;
this.nozzlePosition = new THREE.Vector2(x, y); this.nozzlePosition = new THREE.Vector2(x, y);
return this;
}; };
D3D.GCode.prototype.unRetract = function () { D3D.GCode.prototype.unRetract = function () {
"use strict"; "use strict";
@ -96,12 +136,14 @@ D3D.GCode.prototype.unRetract = function () {
var speed = retractionSpeed * 60; var speed = retractionSpeed * 60;
if (this.extruder > retractionMinDistance && retractionEnabled) { if (this.extruder > retractionMinDistance && retractionEnabled) {
this.gcode.push( this.addGCode({
"G0" + "G": 0,
" E" + this.extruder.toFixed(3) + "E": this.extruder.toFixed(3),
" F" + (speed * 60).toFixed(3) "F": speed.toFixed(3)
); });
} }
return this;
}; };
D3D.GCode.prototype.retract = function () { D3D.GCode.prototype.retract = function () {
"use strict"; "use strict";
@ -116,16 +158,16 @@ D3D.GCode.prototype.retract = function () {
var speed = retractionSpeed * 60; var speed = retractionSpeed * 60;
if (this.extruder > retractionMinDistance && retractionEnabled) { if (this.extruder > retractionMinDistance && retractionEnabled) {
this.gcode.push( this.addGCode({
"G0" + "G": 0,
" E" + (this.extruder - retractionAmount).toFixed(3) + "E": (this.extruder - retractionAmount).toFixed(3),
" F" + speed.toFixed(3) "F": speed.toFixed(3)
); });
} }
this.lastSpeed = speed; return this;
}; };
D3D.GCode.prototype.getFinal = function () { D3D.GCode.prototype.getGCode = function () {
"use strict"; "use strict";
return this.settings.getStartCode().concat(this.gcode, this.settings.getEndCode()); return this.settings.getStartCode().concat(this.gcode, this.settings.getEndCode());

View File

@ -24,26 +24,23 @@ D3D.Slicer.prototype.setMesh = function (geometry, matrix) {
geometry = new THREE.Geometry().fromBufferGeometry(geometry); geometry = new THREE.Geometry().fromBufferGeometry(geometry);
} }
//remove duplicate vertices; //apply mesh matrix on geometry;
geometry.applyMatrix(matrix);
geometry.mergeVertices();
geometry.computeFaceNormals();
geometry.computeBoundingBox();
/* /*
for (var i = 0; i < geometry.vertices.length; i ++) { for (var i = 0; i < geometry.faces.length; i ++) {
var vertexA = geometry.vertices[i]; var face = geometry.faces[i];
var normal = face.normal;
for (var j = i + 1; j < geometry.vertices.length; j ++) { if (normal.x === 0 && normal.y === 0 && normal.z === 0) {
var vertexB = geometry.vertices[j]; geometry.faces.splice(i, 1);
i --;
if (vertexA.equals(vertexB)) {
geometry.vertices[j] = vertexA;
}
} }
} }
*/ */
geometry.mergeVertices();
//apply mesh matrix on geometry;
geometry.applyMatrix(matrix);
geometry.computeFaceNormals();
geometry.computeBoundingBox();
this.geometry = geometry; this.geometry = geometry;
@ -77,9 +74,7 @@ D3D.Slicer.prototype.createLines = function () {
var self = this; var self = this;
function addLine (a, b) { function addLine (a, b) {
var index = lineLookup[b + "_" + a];
//think lookup can only be b_a, a_b is only possible when face is flipped
var index = lineLookup[b + "_" + a] || lineLookup[a + "_" + b];
if (index === undefined) { if (index === undefined) {
index = self.lines.length; index = self.lines.length;
@ -123,6 +118,7 @@ D3D.Slicer.prototype.createLines = function () {
}; };
D3D.Slicer.prototype.slice = function (layerHeight, height) { D3D.Slicer.prototype.slice = function (layerHeight, height) {
"use strict"; "use strict";
var numLayers = height / layerHeight;
var layersIntersections = []; var layersIntersections = [];
@ -133,7 +129,7 @@ D3D.Slicer.prototype.slice = function (layerHeight, height) {
var max = Math.floor(Math.max(line.start.y, line.end.y) / layerHeight); var max = Math.floor(Math.max(line.start.y, line.end.y) / layerHeight);
for (var layerIndex = min; layerIndex <= max; layerIndex ++) { for (var layerIndex = min; layerIndex <= max; layerIndex ++) {
if (layerIndex >= 0 && layerIndex < height / layerHeight) { if (layerIndex >= 0 && layerIndex < numLayers) {
if (layersIntersections[layerIndex] === undefined) { if (layersIntersections[layerIndex] === undefined) {
layersIntersections[layerIndex] = []; layersIntersections[layerIndex] = [];
} }
@ -151,6 +147,7 @@ D3D.Slicer.prototype.slice = function (layerHeight, height) {
var y = layer * layerHeight; var y = layer * layerHeight;
var intersections = []; var intersections = [];
var log = [];
for (var i = 0; i < layerIntersections.length; i ++) { for (var i = 0; i < layerIntersections.length; i ++) {
var index = layerIntersections[i]; var index = layerIntersections[i];
var line = this.lines[index].line; var line = this.lines[index].line;
@ -164,8 +161,14 @@ D3D.Slicer.prototype.slice = function (layerHeight, height) {
var x = line.end.x * alpha + line.start.x * (1 - alpha); var x = line.end.x * alpha + line.start.x * (1 - alpha);
var z = line.end.z * alpha + line.start.z * (1 - alpha); var z = line.end.z * alpha + line.start.z * (1 - alpha);
} }
intersections[index] = new THREE.Vector2(z, x); intersections[index] = new THREE.Vector2(z, x);
log.push({x: z, y: x, index: index, connects: this.lines[index].connects});
} }
/*if (layer === 10) {
console.log(JSON.stringify(log));
breakCode();
}*/
var done = []; var done = [];
var slice = []; var slice = [];
@ -179,24 +182,33 @@ D3D.Slicer.prototype.slice = function (layerHeight, height) {
var intersection = intersections[index]; var intersection = intersections[index];
shape.push({X: intersection.x, Y: intersection.y}); shape.push({X: intersection.x, Y: intersection.y});
done.push(index);
var connects = this.lines[index].connects; var connects = this.lines[index].connects;
var faceNormals = this.lines[index].normals; var faceNormals = this.lines[index].normals;
for (var j = 0; j < connects.length; j ++) { for (var j = 0; j < connects.length; j ++) {
index = connects[j]; index = connects[j];
if (intersections[index] && done.indexOf(index) === -1) { if (intersections[index] !== undefined && done.indexOf(index) === -1) {
done.push(index);
var a = new THREE.Vector2(intersection.x, intersection.y); var a = new THREE.Vector2(intersection.x, intersection.y);
var b = intersections[index]; var b = intersections[index];
var normal = a.sub(b).normal().normalize();
var faceNormal = faceNormals[Math.floor(j/2)];
if (normal.dot(faceNormal) > 0) { if (a.distanceTo(b) === 0) {
break; connects = connects.concat(this.lines[index].connects);
faceNormals = faceNormals.concat(this.lines[index].normals);
index = -1;
} }
else { else {
index = -1; var normal = a.sub(b).normal().normalize();
var faceNormal = faceNormals[Math.floor(j/2)];
if (normal.dot(faceNormal) >= 0) {
//if (true) {
break;
}
else {
index = -1;
}
} }
} }
else { else {
@ -234,6 +246,7 @@ D3D.Slicer.prototype.slice = function (layerHeight, height) {
} }
} }
var layerParts = []; var layerParts = [];
for (var i = 0; i < slice.length; i ++) { for (var i = 0; i < slice.length; i ++) {
@ -265,7 +278,6 @@ D3D.Slicer.prototype.slice = function (layerHeight, height) {
this.progress.sliceLayer = layer; this.progress.sliceLayer = layer;
this.updateProgress(); this.updateProgress();
} }
return slices; return slices;
}; };
D3D.Slicer.prototype.slicesToData = function (slices, printer) { D3D.Slicer.prototype.slicesToData = function (slices, printer) {
@ -405,7 +417,7 @@ D3D.Slicer.prototype.getFillTemplate = function (bounds, size, even, uneven) {
return paths; return paths;
}; };
/* /*
D3D.Slicer.prototype.dataToGcode = function (data, printer) { D3D.Slicer.prototype.dataToGCode = function (data, printer) {
"use strict"; "use strict";
var layerHeight = printer.config["printer.layerHeight"]; var layerHeight = printer.config["printer.layerHeight"];
@ -423,7 +435,7 @@ D3D.Slicer.prototype.dataToGcode = function (data, printer) {
var retractionMinDistance = printer.config["printer.retraction.minDistance"]; var retractionMinDistance = printer.config["printer.retraction.minDistance"];
var retractionAmount = printer.config["printer.retraction.amount"]; var retractionAmount = printer.config["printer.retraction.amount"];
function sliceToGcode (path) { function sliceToGCode (path) {
var gcode = []; var gcode = [];
for (var i = 0; i < path.length; i ++) { for (var i = 0; i < path.length; i ++) {
@ -507,9 +519,9 @@ D3D.Slicer.prototype.dataToGcode = function (data, printer) {
for (var i = 0; i < slice.length; i ++) { for (var i = 0; i < slice.length; i ++) {
var layerPart = slice[i]; var layerPart = slice[i];
gcode = gcode.concat(sliceToGcode(layerPart.outerLayer)); gcode = gcode.concat(sliceToGCode(layerPart.outerLayer));
gcode = gcode.concat(sliceToGcode(layerPart.insets)); gcode = gcode.concat(sliceToGCode(layerPart.insets));
gcode = gcode.concat(sliceToGcode(layerPart.fill)); gcode = gcode.concat(sliceToGCode(layerPart.fill));
} }
this.progress.gcodeLayer = layer; this.progress.gcodeLayer = layer;
@ -521,12 +533,12 @@ D3D.Slicer.prototype.dataToGcode = function (data, printer) {
return gcode; return gcode;
}; };
*/ */
D3D.Slicer.prototype.dataToGcode = function (data, printer) { D3D.Slicer.prototype.dataToGCode = function (data, printer) {
"use strict"; "use strict";
var gcode = new D3D.GCode().setSettings(printer); var gcode = new D3D.GCode().setSettings(printer);
function sliceToGcode (path, retract, unRetract) { function sliceToGCode (path, retract, unRetract) {
for (var i = 0; i < path.length; i ++) { for (var i = 0; i < path.length; i ++) {
var shape = path[i]; var shape = path[i];
@ -557,25 +569,25 @@ D3D.Slicer.prototype.dataToGcode = function (data, printer) {
var slice = data[layer]; var slice = data[layer];
if (layer === 1) { if (layer === 1) {
gcode.turnOnFan(); gcode.turnFanOn();
gcode.bottom = false; gcode.bottom = false;
} }
for (var i = 0; i < slice.length; i ++) { for (var i = 0; i < slice.length; i ++) {
var layerPart = slice[i]; var layerPart = slice[i];
sliceToGcode(layerPart.outerLayer, false, true); sliceToGCode(layerPart.outerLayer, false, true);
sliceToGcode(layerPart.insets, false, false); sliceToGCode(layerPart.insets, false, false);
sliceToGcode(layerPart.fill, true, false); sliceToGCode(layerPart.fill, true, false);
} }
this.progress.gcodeLayer = layer; this.progress.gcodeLayer = layer;
this.updateProgress(); this.updateProgress();
} }
return gcode.getFinal(); return gcode.getGCode();
}; };
D3D.Slicer.prototype.getGcode = function (printer) { D3D.Slicer.prototype.getGCode = function (printer) {
"use strict"; "use strict";
var layerHeight = printer.config["printer.layerHeight"]; var layerHeight = printer.config["printer.layerHeight"];
@ -597,7 +609,7 @@ D3D.Slicer.prototype.getGcode = function (printer) {
console.log("Data: " + (end - start) + "ms"); console.log("Data: " + (end - start) + "ms");
start = new Date().getTime(); start = new Date().getTime();
var gcode = this.dataToGcode(data, printer); var gcode = this.dataToGCode(data, printer);
end = new Date().getTime(); end = new Date().getTime();
console.log("Gcode: " + (end - start) + "ms"); console.log("Gcode: " + (end - start) + "ms");

View File

@ -7,6 +7,7 @@ D3D.SlicerWorker = function () {
this.worker.addEventListener('message', function (event) { this.worker.addEventListener('message', function (event) {
switch (event.data['cmd']) { switch (event.data['cmd']) {
case 'PROGRESS': case 'PROGRESS':
if (scope.onprogress !== undefined) { if (scope.onprogress !== undefined) {
var progress = event.data['progress']; var progress = event.data['progress'];

View File

@ -1,7 +1,7 @@
/****************************************************** /******************************************************
* *
* Utils * Utils
* requires jQuery, Three.js * dependices Three.js
* *
******************************************************/ ******************************************************/
@ -14,6 +14,37 @@ var D3D = {
function sendAPI (url, data, callback) { function sendAPI (url, data, callback) {
"use strict"; "use strict";
/*
var form = new FormData();
for (var i in data) {
form.append(i, JSON.stringify(data[i]));
}
var request = new XMLHttpRequest();
request.open('POST', url, true);
request.send(data);
request.onreadystatechange = function () {
if (request.readyState === 4 && request.status === 200) {
var response = JSON.parse(request.responseText);
if (response.status === "success") {
if (callback !== undefined) {
callback(response.data);
}
}
else {
console.warn(response.msg);
}
}
else {
console.log(request);
console.warn("Failed connecting to " + url);
//sendAPI(url, data, callback);
}
};
*/
$.ajax({ $.ajax({
url: url, url: url,
type: "POST", type: "POST",
@ -38,7 +69,30 @@ function sendAPI (url, data, callback) {
function getAPI (url, callback) { function getAPI (url, callback) {
"use strict"; "use strict";
/*
var request = new XMLHttpRequest();
request.open('GET', url, true);
request.send();
request.onreadystatechange = function () {
if (request.readyState === 4 && request.status === 200) {
var response = JSON.parse(request.responseText);
if (response.status === "success") {
if (callback !== undefined) {
callback(response.data);
}
}
else {
console.warn(response.msg);
}
}
else {
console.warn("Failed connecting to " + url);
sendAPI(url, callback);
}
};*/
$.ajax({ $.ajax({
url: url, url: url,
dataType: "json", dataType: "json",
@ -57,6 +111,7 @@ function getAPI (url, callback) {
console.warn("Failed connecting to " + url); console.warn("Failed connecting to " + url);
getAPI(url, callback); getAPI(url, callback);
}); });
} }
function loadSettings (url, callback) { function loadSettings (url, callback) {

View File

@ -16,7 +16,6 @@ slicer.onProgress = function (progress) {
"progress": progress "progress": progress
}); });
//console.log(progress);
}; };
self.addEventListener("message", function (event) { self.addEventListener("message", function (event) {
@ -42,7 +41,7 @@ self.addEventListener("message", function (event) {
break; break;
case "SLICE": case "SLICE":
var gcode = slicer.getGcode(printer); var gcode = slicer.getGCode(printer);
self.postMessage({ self.postMessage({
"cmd": "GCODE", "cmd": "GCODE",

View File

@ -16,7 +16,7 @@ canvas {border: 1px solid black;}
#progress {height: 20px; width: 200px; border: 1px solid black; overflow: hidden;} #progress {height: 20px; width: 200px; border: 1px solid black; overflow: hidden;}
#progress_bar {height: 20px; background-color: lightblue; width: 0%;} #progress_bar {height: 20px; background-color: lightblue; width: 0%;}
.block {border: 1px solid black; width: 400px; height: 400px; display: inline-block;} .block {border: 1px solid black; width: 400px; height: 400px; display: inline-block;}
#start_print {display: none;} #start_print, #download {display: none;}
</style> </style>
</head> </head>
<body> <body>
@ -33,8 +33,9 @@ canvas {border: 1px solid black;}
<p>Total Lines: <span id='total_lines'></span></p> <p>Total Lines: <span id='total_lines'></span></p>
<p>Batches To Send: <span id='print_batches'></span></p> <p>Batches To Send: <span id='print_batches'></span></p>
<div id='progress'><div id='progress_bar'></div></div> <div id='progress'><div id='progress_bar'></div></div>
<button id="start_print">Start Print</button>
<button id="stop_print">Stop Print</button> <button id="stop_print">Stop Print</button>
<button id="start_print">Start Print</button>
<button id="download">Download Gcode</button>
</div> </div>
<script> <script>
@ -48,10 +49,7 @@ function init () {
var localIp = location.hash.substring(1); var localIp = location.hash.substring(1);
doodleBox = new D3D.Box(localIp); doodleBox = new D3D.Box(localIp);
printer = new D3D.Printer().updateConfig(USER_SETTINGS).updateConfig(PRINTER_SETTINGS['ultimaker2go']);
doodleBox.onupdate = function (data) { doodleBox.onupdate = function (data) {
document.getElementById('state').innerHTML = data.state; document.getElementById('state').innerHTML = data.state;
document.getElementById('bed_temp').innerHTML = data.bed; document.getElementById('bed_temp').innerHTML = data.bed;
document.getElementById('bed_target_temp').innerHTML = data.bed_target; document.getElementById('bed_target_temp').innerHTML = data.bed_target;
@ -63,6 +61,8 @@ function init () {
document.getElementById('print_batches').innerHTML = doodleBox.printBatches.length; document.getElementById('print_batches').innerHTML = doodleBox.printBatches.length;
}; };
printer = new D3D.Printer().updateConfig(USER_SETTINGS).updateConfig(PRINTER_SETTINGS['ultimaker2go']);
document.getElementById('stop_print').onclick = function () { document.getElementById('stop_print').onclick = function () {
doodleBox.stopPrint(printer); doodleBox.stopPrint(printer);
}; };
@ -77,22 +77,30 @@ function init () {
}; };
slicer.onfinish = function (_gcode) { slicer.onfinish = function (_gcode) {
gcode = _gcode; gcode = _gcode;
var button = document.getElementById('start_print'); var startPrintButton = document.getElementById('start_print');
button.style.display = 'initial'; var downloadButton = document.getElementById('download');
button.onclick = function () {
startPrintButton.style.display = 'initial';
startPrintButton.onclick = function () {
doodleBox.print(gcode); doodleBox.print(gcode);
}; };
downloadButton.style.display = 'initial';
downloadButton.onclick = function () {
downloadFile("gcode.gcode", gcode.join('\n'));
};
}; };
var loader = new THREE.STLLoader(); var loader = new THREE.STLLoader();
loader.load('models/pokemon/pikachu.stl', function (geometry) { loader.load('models/dom.stl', function (geometry) {
var geometry = new THREE.TorusGeometry(20, 10, 30, 30).clone(); //var geometry = new THREE.TorusGeometry(20, 10, 30, 30).clone();
var material = new THREE.MeshPhongMaterial({color: 0x00ff00, wireframe: false}); var material = new THREE.MeshPhongMaterial({color: 0x00ff00, wireframe: false});
//var material = new THREE.MeshBasicMaterial({color: 0x000000, wireframe: true});
var mesh = new THREE.Mesh(geometry, material); var mesh = new THREE.Mesh(geometry, material);
mesh.rotation.x = -Math.PI/2; mesh.rotation.x = -Math.PI/2;
mesh.scale.x = mesh.scale.y = mesh.scale.z = 0.5; mesh.scale.x = mesh.scale.y = mesh.scale.z = 1;
mesh.position.y = -0.1; mesh.position.y = -0.1;
mesh.position.x = 60; mesh.position.x = 60;
mesh.position.z = 60; mesh.position.z = 60;