Notifications
Clear all

Got rid of ringing/ghosting almost completely  

Page 1 / 3
  RSS
Hans2004
(@hans2004)
Active Member
Got rid of ringing/ghosting almost completely

I have written a simple python script that gets rid of ringing in prints. It works by parsing the gcode file and looking for perimeter movements that change direction of more than 60 degrees with respect to a previous movement. If that is the case, it will reduce the x and y jerk values of the printer to a low value by inserting a "M205 X2 Y2" command into the gcode file just before where the move starts, and restoring to a higher jerk value just before the first point where a smaller angle move has to be done.

Why does this work better than just having a low jerk value for the whole print: Because printing with very low jerk values messes up curvatures. It generates a wavy pattern all around curvatures.

It would be great to have such a feature built into Slic3r. I have tried to run the script as a post processing script in Slic3r prusa edition (1.38), but it refuses to run python scripts for some reason. Even when I run the script from a bash file and then use the bash file as a post processing script from Slic3r, the script does not run. A bash file that does not call a python script runs fine from Slic3r though.

If you want to try the script your self, it is simple:
- In print settings->output options, select Verbose G-Code. (The script needs this in order to detect perimeter moves)
- Now just call the script with the filename of your gcode file as the first and only argument. The script will then output a file with a .MOD.gcode extension that you can then load into your printer software. Your printer will now print with nearly all ghosting gone.

Below is a copy of the script. Sorry for bad coding standards. I am not a professional programmer and python is not my first programming language.

#!/usr/bin/python

from math import *
import sys

print sys.argv[1]

x0=0
y0=0
x1=0
y1=0
x2=0
y2=0
modFlag=0
angle=0
dvr=0
prevLine=""
prev2Line=""
lenfV=0
lentV=0
lastMod="NOANGLE"

filePath=sys.argv[1]
outputPath=filePath.rstrip("gcode")+"MOD.gcode"
fw=open(outputPath,"w")
with open(filePath) as fp:
line=fp.readline()
while line:
splitLine=line.split(";")
if len(splitLine)>1:
comment = splitLine[1].strip()
command=splitLine[0].strip()
command=command.split(" ")
if ("perimeter" in comment) or ("move to first" in comment) or ("move inwards" in comment):
modFlag=1
if command[0]=="G1":
if "X" in command[1] and len(command)>2:
x2=float(command[1].lstrip("X"))
y2=float(command[2].lstrip("Y"))
if (x0!=0):
fVx=x1-x0
fVy=y1-y0
tVx=x2-x1
tVy=y2-y1
lenfV=sqrt(fVx*fVx+fVy*fVy)
lentV=sqrt(tVx*tVx+tVy*tVy)
if lenfV!=0 and lentV!=0:
dvr=(fVx*tVx+fVy*tVy)/(sqrt(fVx*fVx+fVy*fVy)*sqrt(tVx*tVx+tVy*tVy))
if abs(1-dvr)<0.00000001: dvr=1 #This is to prevent a python roundoff error where the dvr value becomes greater than 1
#print command, comment, dvr
angle=degrees(acos(dvr))
x0=x1
y0=y1
x1=x2
y1=y2
if modFlag==1 and angle>45:
if lastMod!="ANGLE": fw.write("M205 X2 Y2\n")
lastMod="ANGLE"
print angle
elif lastMod=="ANGLE":
lastMod="NOANGLE"
fw.write("M205 X20 Y20\n")
fw.write(line)
#print comment, command, angle
prev2Line=prevLine
prevLine=line
modFlag=0
line=fp.readline()
angle=0
print outputPath

Posted : 25/09/2018 11:20 am
PJR
 PJR
(@pjr)
Antient Member Moderator
Re: Got rid of ringing/ghosting almost completely

You will also require a "G4 S0" before the M205.

Without the pause, the M205 will be actioned immediately upon receipt - before the preceeding "G" commands.

Peter

Please note: I do not have any affiliation with Prusa Research. Any advices given are offered in good faith. It is your responsibility to ensure that by following my advice you do not suffer or cause injury, damage…

Posted : 25/09/2018 11:44 am
Hans2004
(@hans2004)
Active Member
Topic starter answered:
Re: Got rid of ringing/ghosting almost completely

You will also require a "G4 S0" before the M205.

It works great now already. I will give it a try with the "G4 S0" and look for even more improvement. Thank you.

Posted : 25/09/2018 12:05 pm
Colin
(@colin-4)
Estimable Member
Re: Got rid of ringing/ghosting almost completely

Maybe you could open a ticket on Github to get something like this added to Slic3r PE?

Posted : 25/09/2018 1:26 pm
Hans2004
(@hans2004)
Active Member
Topic starter answered:
Re: Got rid of ringing/ghosting almost completely

You will also require a "G4 S0" before the M205.

I just tested that, and it made things slightly worse because then the printer dwells a fraction of a second for the command queue to be empty before continuing. Having read the source code for the Marlin firmware, it appears that nearly all commands, including the M205 command are sent to the planner. That means that the M205 will become effective at the right time, exactly before the next move that is written in the source code. This is confirmed in a thread on https://github.com/MarlinFirmware/Marlin/issues/2125 .

So, a G4 command or a M400 command does not have to be sent before the M205 command.

Here is an update of the script which mitigates another python rounding error that sometimes aborts the script:

#!/usr/bin/python

from math import *
import sys

print sys.argv[1]

x0=0
y0=0
x1=0
y1=0
x2=0
y2=0
modFlag=0
angle=0
dvr=0
prevLine=""
prev2Line=""
lenfV=0
lentV=0
lastMod="NOANGLE"

filePath=sys.argv[1]
outputPath=filePath.rstrip("gcode")+"MOD.gcode"
fw=open(outputPath,"w")
with open(filePath) as fp:
line=fp.readline()
while line:
splitLine=line.split(";")
if len(splitLine)>1:
comment = splitLine[1].strip()
command=splitLine[0].strip()
command=command.split(" ")
if ("perimeter" in comment) or ("move to first" in comment) or ("move inwards" in comment):
modFlag=1
if command[0]=="G1":
if "X" in command[1] and len(command)>2:
x2=float(command[1].lstrip("X"))
y2=float(command[2].lstrip("Y"))
if (x0!=0):
fVx=x1-x0
fVy=y1-y0
tVx=x2-x1
tVy=y2-y1
lenfV=sqrt(fVx*fVx+fVy*fVy)
lentV=sqrt(tVx*tVx+tVy*tVy)
if lenfV!=0 and lentV!=0:
dvr=(fVx*tVx+fVy*tVy)/(sqrt(fVx*fVx+fVy*fVy)*sqrt(tVx*tVx+tVy*tVy))
if abs(1-abs(dvr))<0.00000001: dvr=1 #This is to prevent a python roundoff error where the dvr value becomes greater than 1
#print command, comment, dvr
angle=degrees(acos(dvr))
x0=x1
y0=y1
x1=x2
y1=y2
if modFlag==1 and angle>45:
if lastMod!="ANGLE":
#fw.write("M400\n")
fw.write("M205 X2 Y2\n")
lastMod="ANGLE"
#print angle
elif lastMod=="ANGLE":
lastMod="NOANGLE"
#fw.write("M400\n")
fw.write("M205 X20 Y20\n")
fw.write(line)
#print comment, command, angle
prev2Line=prevLine
prevLine=line
modFlag=0
line=fp.readline()
angle=0
print outputPath

Posted : 25/09/2018 1:39 pm
Texy
 Texy
(@texy)
Reputable Member
Re: Got rid of ringing/ghosting almost completely

That really cool - can you post before and after print examples of the same model to show the improvement?
Texy

Posted : 25/09/2018 3:06 pm
PJR
 PJR
(@pjr)
Antient Member Moderator
Re: Got rid of ringing/ghosting almost completely


Having read the source code for the Marlin firmware, it appears that nearly all commands, including the M205 command are sent to the planner.

From my reading of the code that is not the case (but I am quite likely incorrect 🙁 )

From Marlin_main:

case 205: //M205 advanced settings: minimum travel speed S=while printing T=travel only, B=minimum segment time X= maximum xy jerk, Z=maximum Z jerk
{
if(code_seen('S')) minimumfeedrate = code_value();
if(code_seen('T')) mintravelfeedrate = code_value();
if(code_seen('B')) minsegmenttime = code_value() ;
if(code_seen('X')) max_jerk[X_AXIS] = max_jerk[Y_AXIS] = code_value();
if(code_seen('Y')) max_jerk[Y_AXIS] = code_value();
if(code_seen('Z')) max_jerk[Z_AXIS] = code_value();
if(code_seen('E')) max_jerk[E_AXIS] = code_value();
if (max_jerk[X_AXIS] > DEFAULT_XJERK) max_jerk[X_AXIS] = DEFAULT_XJERK;
if (max_jerk[Y_AXIS] > DEFAULT_YJERK) max_jerk[Y_AXIS] = DEFAULT_YJERK;
}
break;

Peter

Please note: I do not have any affiliation with Prusa Research. Any advices given are offered in good faith. It is your responsibility to ensure that by following my advice you do not suffer or cause injury, damage…

Posted : 25/09/2018 4:20 pm
Hans2004
(@hans2004)
Active Member
Topic starter answered:
Re: Got rid of ringing/ghosting almost completely

From my reading of the code that is not the case (but I am quite likely incorrect 🙁 )

What version of Marlin are you looking at? The one on github (1.19) shows the following code:

inline void gcode_M205() {
if (parser.seen('Q')) planner.min_segment_time_us = parser.value_ulong();
if (parser.seen('S')) planner.min_feedrate_mm_s = parser.value_linear_units();
if (parser.seen('T')) planner.min_travel_feedrate_mm_s = parser.value_linear_units();
#if ENABLED(JUNCTION_DEVIATION)
if (parser.seen('J')) {
const float junc_dev = parser.value_linear_units();
if (WITHIN(junc_dev, 0.01f, 0.3f)) {
planner.junction_deviation_mm = junc_dev;
planner.recalculate_max_e_jerk();
}
else {
SERIAL_ERROR_START();
SERIAL_ERRORLNPGM("?J out of range (0.01 to 0.3)");
}
}
#else
#if ENABLED(HANGPRINTER)
if (parser.seen('A')) planner.max_jerk[A_AXIS] = parser.value_linear_units();
if (parser.seen('B')) planner.max_jerk[B_AXIS] = parser.value_linear_units();
if (parser.seen('C')) planner.max_jerk[C_AXIS] = parser.value_linear_units();
if (parser.seen('D')) planner.max_jerk[D_AXIS] = parser.value_linear_units();
#else
if (parser.seen('X')) planner.max_jerk[X_AXIS] = parser.value_linear_units();
if (parser.seen('Y')) planner.max_jerk[Y_AXIS] = parser.value_linear_units();
if (parser.seen('Z')) {
planner.max_jerk[Z_AXIS] = parser.value_linear_units();
#if HAS_MESH
if (planner.max_jerk[Z_AXIS] <= 0.1f)
SERIAL_ECHOLNPGM("WARNING! Low Z Jerk may lead to unwanted pauses.");
#endif
}
#endif
if (parser.seen('E')) planner.max_jerk[E_AXIS] = parser.value_linear_units();
#endif
}

Posted : 25/09/2018 6:41 pm
PJR
 PJR
(@pjr)
Antient Member Moderator
Re: Got rid of ringing/ghosting almost completely


What version of Marlin are you looking at? The one on github (1.19) shows the following code:

Well, this is the Prusa Research forum, so I am looking at the Prusa Research Marlin branch version 3.4.0

Peter

Please note: I do not have any affiliation with Prusa Research. Any advices given are offered in good faith. It is your responsibility to ensure that by following my advice you do not suffer or cause injury, damage…

Posted : 25/09/2018 7:42 pm
Hans2004
(@hans2004)
Active Member
Topic starter answered:
Re: Got rid of ringing/ghosting almost completely

hans.d3 wrote: ↑
Sep 25, 2018 4:41 pm
What version of Marlin are you looking at? The one on github (1.19) shows the following code:

Well, this is the Prusa Research forum, so I am looking at the Prusa Research Marlin branch version 3.4.0

Peter

Ah, I see. I did not realize that there is a separate Marlin for the Prusa printers. I use the the latest main Marlin firmware on my RAPMS1.4 board (with my Prusa I3 box version printer). The reason I use the Prusa Slic3r is that it is just so much better than the original Slic3r, especially where support material is concerned.

So, if you are using the Prusa Marlin firmware: Yes, you will need the M400 command before the M205 command. It is already in my script. Just uncomment the two lines that contain #fw.write("M400\n"). You should still benefit from the ghosting being almost gone, but suffer slightly from the short dwell that happens after each M400 command in the gcode. It is a pity that the Prusa Marlin did not include the changes that were incorporated in the main Marlin around 2016 because not forwarding the M commands to the planner makes no sense whatsoever, except for a very few commands that need to be executed instantly such as an abort command.

Posted : 25/09/2018 10:03 pm
Hans2004
(@hans2004)
Active Member
Topic starter answered:
Re: Got rid of ringing/ghosting almost completely


That really cool - can you post before and after print examples of the same model to show the improvement?
Texy

Ok, I try now to add two pictures. If this post succeeds, you will see three Marvin statues in the pictures. The most left one is the one that was processed with my script. The middle one is with the standard jerk value of 20. The most right one is one where the jerk value is lowered to 2, but for the whole file.

You can clearly see some bad ghosting in the middle (unprocessed) one. And you can see some terrible vertical banding all around (but no ghosting) in the most-right (low jerk values) one. My script solves the banding issue by only applying a low jerk value where it is needed, and resetting it to a high one where it is not needed. Thus no ghosting and no banding.

All three were printed in PETG. I apologize that the most-right one was printed in a different colour PETG than the other two. But the banding shows up on all curved objects when jerk is low for the whole print, regardless of the material.

Posted : 25/09/2018 10:38 pm
toaf
 toaf
(@toaf)
Noble Member
Re: Got rid of ringing/ghosting almost completely

doesn't filament pick the worst possible time to run out?

I have a Prusa,therefore I research.

Posted : 26/09/2018 4:14 am
PJR
 PJR
(@pjr)
Antient Member Moderator
Re: Got rid of ringing/ghosting almost completely


It is a pity that the Prusa Marlin did not include the changes that were incorporated in the main Marlin around 2016 because not forwarding the M commands to the planner makes no sense whatsoever, except for a very few commands that need to be executed instantly such as an abort command.

How right you are! Until recently, there was also a requirement to include a pause immediately before a tool change, otherwise the tool number would just be a spurious character from a subsequent line of G-code 🙁

Peter

Please note: I do not have any affiliation with Prusa Research. Any advices given are offered in good faith. It is your responsibility to ensure that by following my advice you do not suffer or cause injury, damage…

Posted : 26/09/2018 9:54 am
PJR
 PJR
(@pjr)
Antient Member Moderator
Re: Got rid of ringing/ghosting almost completely


The middle one is with the standard jerk value of 20.

Currently for the Mk3, the XY Jerk value is set to 10.

Peter

Please note: I do not have any affiliation with Prusa Research. Any advices given are offered in good faith. It is your responsibility to ensure that by following my advice you do not suffer or cause injury, damage…

Posted : 26/09/2018 9:58 am
Hans2004
(@hans2004)
Active Member
Topic starter answered:
Re: Got rid of ringing/ghosting almost completely

Currently for the Mk3, the XY Jerk value is set to 10.

Peter

A value of 10 is not low enough to get rid of ghosting on my printer, but it is low enough to cause banding on curvatures. I tried that by printing hollow cylinders with a radius of 45mm. Ghosts could be seen at the layer change seems, and vertical bands could be seen all around the cylinders (though less noticeable than with lower jerk values). With jerk values above 20 I get really smooth curvatures without bands.

Posted : 26/09/2018 10:59 am
Hans2004
(@hans2004)
Active Member
Topic starter answered:
Re: Got rid of ringing/ghosting almost completely

On a side note, I am able now to call the script from the post processing scripts option in Slic3rPE. It turns out that the Appimage of Slic3r that I was using, somehow does not play well with python. I am now using the pre-compiled version, and it calls the script without issues. After clicking on "Export G-Code", two files are saved: The one that is generated by Slic3r and the one that has been modified by my script. So behavior is now just as if it is a built in feature of Slic3r. Really cool. I am so happy. It feels like I can squeeze some more years out of my (much modified) Prusa I3 box version now.

Posted : 26/09/2018 11:09 am
bobstro
(@bobstro)
Illustrious Member
Re: Got rid of ringing/ghosting almost completely


[...] Currently for the Mk3, the XY Jerk value is set to 10.
A fresh install of Slic3rPE 1.41.0 has X & Y jerk set to 8. They seem to be ratcheting the acceleration and jerk settings back a bit with each release.

My notes and disclaimers on 3D printing

and miscellaneous other tech projects
He is intelligent, but not experienced. His pattern indicates two dimensional thinking. -- Spock in Star Trek: The Wrath of Khan

Posted : 26/09/2018 11:12 am
PJR
 PJR
(@pjr)
Antient Member Moderator
Re: Got rid of ringing/ghosting almost completely


A fresh install of Slic3rPE 1.41.0 has X & Y jerk set to 8. They seem to be ratcheting the acceleration and jerk settings back a bit with each release.

Yes, I noticed that and have the same setting already in KISS. But the firmware setting is 10 😉

And yes, they are playing around with the settings quite often (example: E acceleration of 8000 is just way too high, but is thought to be "required" by the MMU - I use 1000 with the MMU for that setting).

Peter

Please note: I do not have any affiliation with Prusa Research. Any advices given are offered in good faith. It is your responsibility to ensure that by following my advice you do not suffer or cause injury, damage…

Posted : 26/09/2018 11:30 am
Texy
 Texy
(@texy)
Reputable Member
Re: Got rid of ringing/ghosting almost completely



That really cool - can you post before and after print examples of the same model to show the improvement?
Texy

Ok, I try now to add two pictures. If this post succeeds, you will see three Marvin statues in the pictures. The most left one is the one that was processed with my script. The middle one is with the standard jerk value of 20. The most right one is one where the jerk value is lowered to 2, but for the whole file.

You can clearly see some bad ghosting in the middle (unprocessed) one. And you can see some terrible vertical banding all around (but no ghosting) in the most-right (low jerk values) one. My script solves the banding issue by only applying a low jerk value where it is needed, and resetting it to a high one where it is not needed. Thus no ghosting and no banding.

All three were printed in PETG. I apologize that the most-right one was printed in a different colour PETG than the other two. But the banding shows up on all curved objects when jerk is low for the whole print, regardless of the material.

That is really impression - thanks for sharing.
Ian

Posted : 26/09/2018 2:31 pm
Hans2004
(@hans2004)
Active Member
Topic starter answered:
Re: Got rid of ringing/ghosting almost completely

I have made a new version. This time written in perl. Anyone should be able to use this version. Just copy and paste the code below into a text file, and name it: "deghost.pl"

If in Linux or Apple, make the file executable by typing: "chmod +x deghost.pl"

Then in Slic3r in Print Settings->Output Options, type the location and name of the script file in the Post-processing scripts box, and you are done. This also works with the appimage of Slic3r.

Here is the code below:
#!/usr/bin/perl

use strict;
use warnings;
use Math::Trig;

my $smallJerkSTR="M205 X2 Y2\n";
my $largeJerkSTR="M205 X20 Y20\n";

# Uncomment the next two lines for Prusa firmware.
#$smallJerkSTR="M400\n" . $smallJerkSTR;
#$largeJerkSTR="M400\n" . $largeJerkSTR;

#**************
#** Globals
#
********
my $fileName, my $outFile, my $fh, my $fw;
my $location; my $row; my @command;
my $x0; my $y0; my $x1; my$y1; my $x2; my $y2;
my $valid=0; my $isInside;
my @vecFrom; my @vecTo; my $lenFrom; my $lenTo; my $dvr; my $angle;
my $savedRow;
my $smallJerk=0; my $toPrint="";
my $jerkCTR=0;

#*********************************************************
#** Search in the gcode file for the next G1 X.. Y.. move
#
******************************************************
sub findNext {
my $notFound=0;
my $row;
my @command;
my $location=0;

while (!$notFound && !eof($fh) ) {
$location = tell $fh;
$row=<$fh>;
chomp $row;
@command=split(" ",$row);
if ($row ne "" && ($command[0]=~/G1/ && $command[1]=~/X/ && $command[2]=~/Y/)) {
$notFound=1;
seek $fh, $location, 0;
}
}
if (!eof($fh)) {
return 1;
} else {
return 0;
}
}

#**********************
#** Main program start
#
**********************
$fileName = $ARGV[0];
print "$fileName\n";

open($fh, '<:encoding(UTF-8)', $fileName)
or die "Could not open file '$fileName' $!";

if (index($fileName, "gcode") != -1) {
$outFile=substr($fileName,0,index($fileName,"gcode"));
}
$outFile.="PMOD.gcode";
open($fw, '>', $outFile) or die "Failed!!!";
print "$outFile\n";

# Loop through the file and insert the M205 commands where needed.
while ( !eof($fh) ) {
$row=<$fh>;
chomp $row;
$savedRow=$row;
@command=split(" ",$row);
$location = tell $fh;
$toPrint="";
$valid=0;
$isInside=0;

# Check if this is a valid G1 X.. Y.. move. If yes, store the coordinates
# and get the coordinates of the next two valid moves.
if ($row ne "" && ($command[0]=~/G1/ && $command[1]=~/X/ && $command[2]=~/Y/)) {
$valid=1;
chomp $row;
@command=split(" ", $row);
$x0=substr($command[1],1);
$y0=substr($command[2],1);
if ( $row =~ /perimeter/ || $row=~ m/first perimeter/ || $row=~ m/move inwards/ ) {
$isInside=1;
}
# Get the coordinates of the critical move and check if it is towards or inside from a perimeter.
if (findNext()) {
$row=<$fh>;
chomp $row;
@command=split(" ", $row);
$x1=substr($command[1],1);
$y1=substr($command[2],1);
if ( $row =~ /perimeter/ || $row=~ m/first perimeter/ || $row=~ m/move inwards/ ) {
$isInside=1;
}
} else {
$valid=0;
}
if (findNext()) {
$row=<$fh>;
chomp $row;
@command=split(" ", $row);
$x2=substr($command[1],1);
$y2=substr($command[2],1);
if ( $row =~ /perimeter/ || $row=~ m/first perimeter/ || $row=~ m/move inwards/ ) {
$isInside=1;
}
} else {
$valid=0;
}

# If the move is towards or inside a perimeter, check if the next move has an angle > 45 degrees.
# If that angle is > 45, then schedule a M205 command for small jerk.
# Otherwise schedule a command for large jerk. The $smallJerk variable is just
# there to prevent re-issuing the command when a small jerk value is already active.
if ($valid && $isInside) {
@vecFrom=($x1-$x0, $y1-$y0);
@vecTo =($x2-$x1, $y2-$y1);
$lenFrom=sqrt($vecFrom[0]**2+$vecFrom[1]**2);
$lenTo =sqrt($vecTo[0]**2+$vecTo[1]**2);
if ($lenFrom!=0 && $lenTo!=0) {
$dvr = ($vecFrom[0]*$vecTo[0]+$vecFrom[1]*$vecTo[1])/($lenFrom*$lenTo);
$angle = rad2deg(acos($dvr));
if ($angle>45 && !$smallJerk) {
$toPrint=$smallJerkSTR;
$smallJerk=1;
$jerkCTR=0;
}
if ($angle<45 && $smallJerk) {
$jerkCTR++;
#$toPrint=$largeJerkSTR;
#$smallJerk=0;
}
}
} else {
if ($smallJerk) {
$jerkCTR++;
#$toPrint=$largeJerkSTR;
#$smallJerk=0;
}
}
}

# JerkCTR counts the nomber of moves after leaving an area that requires slow moves.
# This allows time for the printer to stop ringing.
if ($jerkCTR>1) {
$toPrint=$largeJerkSTR;
$smallJerk=0;
$jerkCTR=0;
}
print $fw "$savedRow\n";
print $fw $toPrint;
seek $fh, $location, 0;

}

Posted : 29/09/2018 8:54 pm
Page 1 / 3
Share: