Some notes on Post-Processing Scripts with PrusaSlicer (and MacOS)

3 minute read

Post-Processing scripts are a powerful way to modify the Gcode PrusaSlicer outputs to tweak some settings or add new features without compiling the full slicer. In short, before exporting the Gcode file, PrusaSlicer will send it through a script, that can be any language your computer supports.

My intention to make a script was to add a Monoprice-specific time-estimate to the Gcode, so it gets displayed correctly. However, this didn’t work out for reasons elaborated later…

Warning: those are just my experiences, I am not an expert in Python, so my vocabulary and methods might not be correct.

Thanks to the Voron #gchat members (Rev) for answering some of my questions!

Saving the script in directories with spaces

Error code: 127 Output: /bin/bash: /Users/matteo/Library/Application: No such file or directory

PrusaSlicer doesn’t like to have spaces in the path to the script, so you need to add \ before the space to have it access the script.

/Users/matteo/Library/Application Support/PrusaSlicer/post-processing/time-left.py

should be:

/Users/matteo/Library/Application\ Support/PrusaSlicer/post-processing/time-left.py

The path to the script can be specified in the “Print Settings” under “Output Options”. Thanks grg!

Allow the file to be executed

If you receive a 126 error code, it might be possible that PrusaSlicer isn’t allowed to execute the script. Changing the permissions for that script solved this problem for me:

chmod 755 /Users/matteo/Library/Application\ Support/PrusaSlicer/post-processing/time-left.py

Thanks no_help_forthcoming!

Older Versions of Python

Okay, this one might be obvious to some coders, but I included it anyways: if you downloaded some random script from the internet, it’s possible that it was written for a different version of Python. For example, Bob's BumpFan script doesn’t specify a version of Python, so PrusaSlicer threw an error.

By “porting” the script to my version of Python, I was able to run the script.

Specifying the version: #!/usr/bin/python3

Changing some function names: xrange(len(lines)) becomes range(len(lines))

Using environment variables

Environment variables are basically just some settings that PrusaSlicer provides to the scrip so it can adjust the Gcode.

os.environ.get("SLIC3R_Fill_density") will convert to the infill percentage you set while slicing the part. You simply need to take the value that PrusaSlicer shows when you hover over the parameter in the user interface, capitalise the first letter and add SLIC3R_, that’s it!

More information: Prusa and nylas

It’s important that you check that the parameter you need is available before you commit to coding your script, for example the estimated print time is not transfered unfortunately.

Examples

  1. Bob's BumpFan script searches for M106 commands and modifies these to have the fan start spinning before the full cooling power is needed:
  2. Jeremy Reeder's script corrects for thermistor differences between printer if you have a print farm.
  3. johnnyruz's MMU Temp Fix changes the heating behaviour to be used with MMUs.
  4. My own example: This script is very heavily based on the examples from above, and is not tested extensively. So take a lot of care while using this, I am not liable for it. It looks for a command to replace, and takes the infill percentage to add to it. Also, it contains a “note” about the script. It should only serve as an inspiration, do not actually use this please. It might be more efficient to make the changes in a new file, so longer Gcode-files don’t crash the computer.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
#!/usr/bin/python3
import re, sys, os

script_filename = sys.argv[0]
gcode_filename = sys.argv[1]

with open(gcode_filename, 'r') as gcode_file:
	gcode = gcode_file.readlines()
	gcode_file.close()

with open(gcode_filename, 'w') as gcode_file:
	gcode_file.write('; post-processed by ' + script_filename + ' to do something\n')
	for original_gcode_line in gcode:
		gcode_line = original_gcode_line
		for group in re.findall('Command to be replaced', original_gcode_line):
			yourVariable = os.environ.get("SLIC3R_Fill_density")
			gcode_line = re.sub('Command to be replaced', 'New command' + str(yourVariable), original_gcode_line)
		gcode_file.write(gcode_line)
	gcode_file.close()