Add diagonal Z hop post processor page

This commit is contained in:
teachingtechYT
2023-01-20 16:32:20 +11:00
parent 2f75b52997
commit 3b3c29ee79
5 changed files with 208 additions and 3 deletions

95
diagonalZhop.html Normal file
View File

@ -0,0 +1,95 @@
<!DOCTYPE html>
<html>
<head>
<script src="js/loadscripts.js"></script>
</head>
<body onload="loadAllFormData()">
<div id="menu"></div>
<div id="header"></div>
<div>
<div class="exp">
<h5>Aim:</h5>
<p>To provide a compromise between no Z hop, which reduces stringing but has a higher chance of the nozzle knocking the model loose, and Z hop, which does the opposite.</p>
<h5>When required:</h5>
<p>This is currently experimental, and may not be needed in many cases. If you have a print that keeps disloging from nozzle contact, this may be worth a try.</p>
<h5>Tools:</h5>
<p>Your own sliced gcode and the post processor on on this page.</p>
<button class="zoom" onclick="$('html, body').animate({scrollTop: ($('#zh').offset().top-200)},500);">Scroll to post processor</button>
</div>
<p>This page allows you to paste in your existing sliced gcode and have it convert it to diagonal Z hop. It is a simple conversion and has been tested thoroughly, but still use it with caution.</p>
<p>This concept is covered in detail in the following video:</p>
<iframe width="480" height="360" src="https://www.youtube.com/embed/OAXi_apvgl4" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
<h2>Diagonal Z hop is an experiment</h2>
<p>This is the result of a 'what if' thought when printing a tricky model. It may turn out to be useful, useless, or perhaps need alteration to be more effective. The post processing script on this page has limitations that actual slicing software does not. Proper implementation in a slicer might be more effective. Please try it out and post your feedback in the comments of the video above.</p>
<p>If this concept does have merit, I am very happy for it to be implemented into any and every slicer that wants it. If the process helps people, I gladly release it to the public domain.</p>
<h2>Traditional retraction, travel and Z hop</h2>
<p>Retraction is when filament is pulled away from the hot end to reduce pressure. This will usually be done before a travel move. A travel move is a movement made by the printer where no filament is extruded. At the end of the travel move, the extruder will usually unretract to get nozzle pressure back to normal, and then continue printing. Without retraction, prints tend to suffer from stringing, where filament leaks during travel moves and creates fine strings of filament connecting surfaces that should be isolated:</p>
<a href="#" data-featherlight="img/stringing.jpg"><img loading="lazy" class="thumb" src="img/stringing.jpg"></a>
<p></p>
<p>Z hop is an option your slicer can employ either side of a travel move. After retraction, the nozzle will lift up vertically, followed by the travel move, then move vertically downwards to return to the correct height, before unretracting and resuming printing.</p>
<p>Z hop gives the nozzle additional clearance over the model, which can prevent the nozzle from crashing into the model and knocking it loose. This can ensure success on a tricky model where parts with steep overhangs may curl up on the tip into the path of the nozzle. However, Z hop is compromised because it generally introduces fine stringing. It improves reliability at the expense of print quality.</p>
<h2>Aim of diagonal Z hop</h2>
<p>Rather than have Z hop be a three part movement (up, travel horizontally then down), diagonal Z hop breaks a travel move into two sections.</p>
<ul>
<li>In the traditional version, the first move is half way horizontally while also travelling vertically up, and the second completes the horizontal travel move whilst coming vertically back down to printing height.</li>
<li>In the alternate version, the first move travels diagonally up to above the next extrusion point, before dropping vertically downwards.</li>
</ul>
<p>It is hoped that the sequence is faster than standard Z hop, reduces stringing, whilst still offering additional clearance over delicate models to prevent collisions.</p>
<p>The following diagrams best illustrate the movment path for each of these options:</p>
<a href="#" data-featherlight="img/dhz-comparison-banner.jpg"><img loading="lazy" class="thumb" src="img/dhz-comparison-banner.jpg"></a>
<div id="zh">
<h6>Diagonal Z hop Post Processor</h6>
<form name="diagZhop" id="diagZhop" onsubmit="return false;">
<p>The following form will convert your existing gcode to have diagonal Z hop. Slice a model of your choice in your own slicer with the following considerations:</p>
<ul>
<li>Traditional retraction as opposed to firmware retraction.</li>
<li>Z hop should be turned OFF. Slice with a normal travel move only.</li>
<li>Absolute movements <i>G90</i> vs relative movements <i>G91</i>. This is the default for most slicers.</li>
</ul>
<p>Firmware and slicer flavour should not matter. As long as the slicer outputs <i>G0</i>/<i>G1</i> commands for movements, this post processor should work.</p>
<p>Please consider that like using standard Z hop, your Z axis will be a lot more active during printing. If you already experience any problems with binding, any form of Z hop will make it worse.</p>
<h4>Existing gcode</h4>
<p>You may attach a file and have this page automatically extract its contents to the input box, or paste the gcode into the input box yourself.</p>
<p><input type="file" id="uploadedFile" name="uploadedFile"><input type="button" name="convertFile" onclick="convertGcode()" value="Convert attached file"></p>
<p>Or paste your existing gcode into the box below:</p>
<textarea name="tradGcode"></textarea>
<h4>Parameters</h4>
<p>
<label>Diagonal Z hop height (mm):</label>
<input type="number" name="diagZheight" value="0.2" min="0" max="10" step="0.1">
<label>Minimum travel length to convert to diagonal Z hop (mm):</label>
<input type="number" name="minLength" value="2.0" min="0" max="100" step="0.1">
</p>
<a href="#" data-featherlight="img/dzh-selection-banner.jpg"><img loading="lazy" class="thumb" src="img/dzh-selection-banner.jpg"></a>
<p style="margin-left:20px;" class="firmwareSelector">Version:
<input name="version" id="trad" value="trad" checked="" type="radio">
<label for="trad">Traditional</label>
<input name="version" id="alt" value="alt" type="radio">
<label for="alt">Alternate</label>
</p>
<p><input type="button" onclick="diagonalZhop();" value="Process Gcode"></p>
<h4>Output gcode</h4>
<textarea id="diagZHopOutput" name="diagZhopGcode"></textarea>
<p><input type="button" value="Copy to Clipboard" onclick="copyToClipboard('diagZHopOutput')"></p>
<p><label for="diagZFilename">Filename:</label><input type="text" name="diagZFilename" value="diagZhop"> .gcode</p>
<p><input type="button" onclick="downloadFile(document.diagZhop.diagZFilename.value+'.gcode', document.diagZhop.diagZhopGcode.value);" value="Download Gcode"></p>
<div class="warning">
<h2>Warning - Read carefully!</h2>
<p>Every attempt has been made to ensure this is safe but ultimately there always is risk in running modified gcode from the internet. Preview the gcode in your slicer or <a href="http://zupfe.velor.ca" target="_blank">Zupfe GCode Viewer</a> and <span style="color:red; font-weight: bolder;">print at your own risk.</span></p>
<p>Only print this gcode when you are present, alert and capable of stopping the printer in case of emergency.</p>
<p>Validation has been built into the forms to only allow sensible min and max values, however this is not foolproof.</p>
</div>
</form>
</div>
</div>
<div id="up"></div>
<div id="footer"></div>
</body>
<script>
var pageName = "Diagonal Z Hop";
var pageTitle = "Diagonal Z Hop Post Processor";
</script>
<script src="js/dynamic.js"></script>
<html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 143 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

View File

@ -1,5 +1,5 @@
var pages = ["Home", "Calibration", "Troubleshooting", "Upgrade Guides", "Review Policy", "Sponsors", "Contact"]
var urls = ["index.html", "calibration.html", "troubleshooting.html", "upgrades.html", "reviewpolicy.html", "sponsors.html", "contact.html"]
var pages = ["Home", "Calibration", "Troubleshooting", "Upgrade Guides", "Diagonal Z Hop", "Review Policy", "Sponsors", "Contact"]
var urls = ["index.html", "calibration.html", "troubleshooting.html", "upgrades.html", "diagonalZhop.html", "reviewpolicy.html", "sponsors.html", "contact.html"]
var menu = '<img src="img/ttwhite.png" />';
var tab;
for(var i = 0; i < pages.length; i++){
@ -26,7 +26,6 @@ $( "#up" ).bind( "click", function() {
$('html, body').animate({scrollTop: '0px'}, 500);
});
var footer = `
<p style="text-align: center;">This page is fully <a href="https://github.com/teachingtechYT/teachingtechYT.github.io" target="_blank">open source</a>. If you find a bug or have a feature request, please post in the <a href="https://github.com/teachingtechYT/teachingtechYT.github.io/issues" target="_blank">issues</a> section. Make sure to read the <a href="https://github.com/teachingtechYT/teachingtechYT.github.io/issues/323" target="_blank">pinned readme</a>.</p>
<p style="text-align: center;">This page was created using:</p>

View File

@ -709,6 +709,117 @@ function processGcode(formName) {
downloadFile(description+'.gcode', gcode);
}
function convertGcode() {
var file = document.getElementById("uploadedFile").files[0];
console.log("1");
if(file) { // A file has been atached with the file input
if(file.name.search(".gcode") == -1){
console.log("2a: Non .gcode file.");
alert("Please select a gcode file only");
return;
}
var reader = new FileReader();
reader.readAsText(file, "UTF-8");
reader.onload = function (evt) {
console.log("2b: Converting uploaded file.");
document.diagZhop.tradGcode.value = evt.target.result; // set gcode variables to file contents
console.log("3");
}
reader.onerror = function (evt) {
alert("Error reading file"); // warn user if file not suitable
console.log("2c: Error reading file.");
}
} else {
console.log("2d: Nothing to convert");
alert("No file attached.");
}
}
function copyToClipboard(div) {
var copyText = document.getElementById(div);
copyText.select();
copyText.setSelectionRange(0, 99999); // For mobile devices
navigator.clipboard.writeText(copyText.value);
}
function diagonalZhop() {
document.diagZhop.diagZhopGcode.value = "";
var hop = parseFloat(document.diagZhop.diagZheight.value); // Collect user specific vertical height
var minLength = parseFloat(document.diagZhop.minLength.value) // Collect user specified minimum travel length
var version = document.diagZhop.version.value; // Collect user specified version input
var oldX, oldY, nextX, nextY, halfX, halfY, oldZ, halfZ, oldF, travelLength, startedExtrusion, gType;
var regexpX = /X-?[0-9\.]+/; // Regex to search for X coordinates
var regexpY = /Y-?[0-9\.]+/; // Regex to search for Y coordinates
var regexpZ = /Z-?[0-9\.]+/; // Regex to search for Z coordinates
var regexpF = /F[0-9\.]+/;// Regex to search for F feedrate
var gcode = document.diagZhop.tradGcode.value; // Collect user input gcode
if(gcode == ""){ // No file attached or input into text field
alert("Please enter gcode into the text box.");
return;
}
var gcodeArray = gcode.split(/\n/g); // Split gcode line by line into an array
gcodeArray.forEach(function(index, item){ // For each line..
if((gcodeArray[item].search("G0") == 0) || (gcodeArray[item].search("G1") == 0)){ // Check if G0/G1 present
if(gcodeArray[item].search(/Z/) > -1){ // Search for change of Z height / layer change
oldZ = parseFloat(gcodeArray[item].match(regexpZ)[0].substring(1)); // Store current Z height
} else if((gcodeArray[item].search("X") > -1) && (gcodeArray[item].search("Y") > -1)){ // Both X and Y positions present - travel or print move
if(gcodeArray[item].search("E") > -1){ // Search for E = extrusion move
startedExtrusion = true; // Mark that actual printing has started
oldX = parseFloat(gcodeArray[item].match(regexpX)[0].substring(1)); // Store current X position
oldY = parseFloat(gcodeArray[item].match(regexpY)[0].substring(1)); // Store current Y position
} else { // No extrusion - travel move
if(startedExtrusion){ // Only progress if printing has actually started
gType = gcodeArray[item].substring(0,2); // Capture either 'G0' or 'G1' to reuse
nextX = parseFloat(gcodeArray[item].match(regexpX)[0].substring(1)); // Store X coordinate for end of travel move
nextY = parseFloat(gcodeArray[item].match(regexpY)[0].substring(1)); // Store Y coordinate for end of travel move
travelLength = parseFloat(Math.sqrt(Math.pow(nextX-oldX, 2) + Math.pow(nextY-oldY, 2))); // Calculate length of travel move using Pythagoras' theorem
if(travelLength > minLength){ // Check if travel meets length requirement, create diagonal Z hop if it does
if(gcodeArray[item].search("F") > -1){ // Store feedrate for travel move if it is present
oldF = parseFloat(gcodeArray[item].match(regexpF)[0].substring(1)).toFixed(4);
} else {
oldF = -1; // If no F parameter, mark as -1
}
if(version == "trad"){
halfX = (oldX + nextX) / 2; // Calculate half way point for X travel
halfY = (oldY + nextY) / 2; // Calculate half way point for Y travel
}
oldX = parseFloat(gcodeArray[item].match(regexpX)[0].substring(1)); // Store X position in case of multiple travel moves in a row
oldY = parseFloat(gcodeArray[item].match(regexpY)[0].substring(1)); // Store Y position in case of multiple travel moves in a row
halfZ = parseFloat(oldZ + hop).toFixed(4); // Calculate temporary z height for peak of diagonal travel
if(version == "trad"){ // Create movements for a diagonal Z hop halfway between points
var newLine = gType+" X"+parseFloat(halfX).toFixed(4)+" Y"+parseFloat(halfY).toFixed(4)+" Z"+halfZ; // Create new G0/G1 travel move to the halfway point
if(oldF != -1){ // Check if a feedrate was stored or bogus -1 value
newLine += " F"+oldF; // Add F feedrate to the line if possible
}
newLine += " ; Diagonal Z hop part 1\n"; // Add comment
gcodeArray[item] = newLine+gcodeArray[item]+" Z"+oldZ+" ; Diagonal Z hop part 2"; // Add new travel move plus old travel together, adding Z height to the end of the old travel move.
} else { // Create movements for a diagonal Z hop above the destination, then lower down
gcodeArray[item] += " Z"+halfZ+" ; Diagonal Z hop part 1\n";
gcodeArray[item] += gType+" Z"+oldZ+" ; Diagonal Z hop part 2";
}
} else { // If the travel length was too short, add comment only
gcodeArray[item] += " ; Travel move of "+travelLength+" below user threshold of "+minLength+" mm";
}
}
}
}
}
});
gcode = gcodeArray.join("\n"); // Join all of the individuallines back together
var header = "; Experimental diagonal Z hop post processor from: https://teachingtechyt.github.io/diagonalZhop.html\n"; // Add URL
header += "; Diagonal Z hop height: "+hop+" mm\n"; // Add user input
header += "; Miniumum travel length: "+minLength+" mm\n" // Add user input
header += "; Version: "; // Add user input
if(version == "trad"){
header += "Traditional (diagonal move up to half way point)\n";
} else {
header += "Alternate (diagonal move to above finishing point)\n";
}
gcode = header+gcode; // Append string to the start of the start of the gcode
document.diagZhop.diagZhopGcode.value = gcode; // Insert post processed gcode into the output box
}
function outputSettings(formName) {
var fileName;
var string = "Settings for ";