2.2.21. Batch processing with PrusaSlicer
Todo
Batch processing with PrusaSlicer scripts.
Important
I am doing a massive update based on the recent name change from Slic3rPE to PrusaSlicer. Please bear with me while I update everything.
Note
The latest Alpha releases of PrusaSlicer do not support command-line processing as of this writing. Use the latest release version.
Note
These notes are based on my experiences with the Prusa i3 Mk3 and Artillery/Evnovo Sidewinder X1 printers. If you are using a different printer, please verify the hardware details are similar.
2.2.21.1. .ini scripts
1bed_shape = 0x0,250x0,250x210,0x210
2bridge_acceleration = 1000
3end_gcode = ; Last updated 20181007\nG4 ; wait\nG92 E0 ; prepare to retract\nG1 E-0.8 F2100; retract to avoid ooze\nM221 S100 ; reset extruder factor to 100%\nM900 K0 ; reset linear acceleration\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\n{if layer_z < max_print_height}G1 Z{z_offset+min(layer_z+60, max_print_height)}{endif} ; Move print head up\nG1 X0 Y200 ; present bed\nM84 ; disable motors\nM300 S100 P10 ; chirp
4gcode_flavor = marlin
5extruder_clearance_height = 20
6extruder_clearance_radius = 20
7extruder_colour = #FFFF00
8extruder_offset = 0x0
9extrusion_axis = E
10machine_max_acceleration_e = 5000,5000
11machine_max_acceleration_extruding = 1250,1250
12machine_max_acceleration_retracting = 1250,1250
13machine_max_acceleration_x = 1500,960
14machine_max_acceleration_y = 1500,960
15machine_max_acceleration_z = 1000,1000
16machine_max_feedrate_e = 120,120
17machine_max_feedrate_x = 200,100
18machine_max_feedrate_y = 200,100
19machine_max_feedrate_z = 12,12
20machine_max_jerk_e = 1.5,1.5
21machine_max_jerk_x = 8,8
22machine_max_jerk_y = 8,8
23machine_max_jerk_z = 0.4,0.4
24machine_min_extruding_rate = 0,0
25machine_min_travel_rate = 0,0
26max_volumetric_speed = 11.5
27max_print_height = 210
28output_filename_format = [input_filename_base].gcode
29printer_model = MK3
30;print_center = 125,105
31remaining_times = 1
32silent_mode = 1
33start_gcode = ; Last updated 20181018\nM115 U3.3.1 ; tell printer latest fw version\n; Set initial warmup temps\nM104 S140 ; set extruder no-ooze temp\nM140 S{max(first_layer_bed_temperature[0],60)} ; set bed PINDA warmup temp\n; Nozzle warmup routine\nM300 S40 P10 ; chirp\nG28 W ; home all without mesh bed level\nG0 X0 Y200 Z100.0 F10200 ; raise nozzle and present bed for cleaning\nM109 ; wait for extruder no-ooze warmup temp before mesh bed leveling, cool hot PINDA\n; PINDA warmup routine\nM300 S40 P10 ; chirp\nG0 X125 Y105 Z0.10 F10200; PINDA warming position\nM860 S35 ; wait for PINDA temp to stabilize\nM300 S40 P10 ; chirp\nG28 W ; home all without mesh bed level\nM140 S[first_layer_bed_temperature] ; set bed final temp\nG80 ; mesh bed leveling\n; Final warmup routine\nM104 S[first_layer_temperature] ; set extruder final temp\nM109 S[first_layer_temperature] ; wait for extruder final temp\nM190 S[first_layer_bed_temperature] ; wait for bed final temp\n; Prime line routine\nM300 S25 P10 ; chirp\nM83 ; extruder relative mode\nM900 K0; Disable LA for prime line\nG92 E0.0 ; reset extrusion distance\nG1 Y-3.0 F1000.0 ; go outside print area\nG1 E2 F1000 ; de-retract and push ooze\nG1 X20.0 E6 F1000.0 ; fat 20mm intro line @ 0.30\nG1 X60.0 E3.2 F1000.0 ; thin +40mm intro line @ 0.08\nG1 X100.0 E6 F1000.0 ; fat +40mm intro line @ 0.15\nG1 E-0.8 F2100; retract to avoid stringing\nG1 X99.0 E0 F1000.0 ; -1mm intro line @ 0.00\nG1 X110.0 E0 F1000.0 ; +10mm intro line @ 0.00\nG1 E0.5 F1500; de-retract\nG92 E0.0 ; reset extrusion distance\n; Final print adjustments\nM92 E282.54 ; adjust extrusion ratio\n;M221 S{if layer_height==0.05}100{else}95{endif}
34threads = 4
35use_relative_e_distances = 1
36use_volumetric_e = 0
37variable_layer_height = 1
1brim_width = 0
2external_perimeter_extrusion_width = 0
3extrusion_width = 0
4first_layer_extrusion_width = 0
5infill_extrusion_width = 0
6max_layer_height = 0.32
7min_layer_height = 0.1
8nozzle_diameter = 0.4
9perimeter_extrusion_width = 0
10perimeters = 3
11solid_infill_extrusion_width = 0
12support_material_extrusion_width = 0
13top_infill_extrusion_width = 0
1; filament characteristics
2filament_type = PLA
3filament_diameter = 1.715
4extrusion_multiplier = 0.98
5filament_max_volumetric_speed = 11.5
6z_offset = 0
7start_filament_gcode = "M900 K30"
8
9; temperatures
10bed_temperature = 55
11temperature = 200
12first_layer_bed_temperature = 60
13first_layer_temperature = 205
14
15; cooling
16max_fan_speed = 100
17min_fan_speed = 100
18disable_fan_first_layers = 1
19fan_always_on = 1
20fan_below_layer_time = 100
21bridge_fan_speed = 100
22cooling = 1
23
24; retraction
25retract_before_travel = 1
26retract_layer_change = 1
27retract_length = 0.8
28retract_lift = 0.6
29retract_lift_above = 0
30retract_lift_below = 209
31retract_restart_extra = 0
32retract_speed = 35
33deretract_speed = 25
34
35; bridges
36dont_support_bridges = 1
37bridge_flow_ratio = 1
38bridge_speed = 30
1notes = Normal
2;quality settings
3perimeters = 3
4external_perimeters_first = 0
5avoid_crossing_perimeters = 1
6external_fill_pattern = rectilinear
7extra_perimeters = 1
8infill_every_layers = 2
9only_retract_when_crossing_perimeters = 1
10ooze_prevention = 0
11overhangs = 1
12seam_position = aligned
13spiral_vase = 0
14variable_layer_height = 1
15xy_size_compensation = 0
16gcode_comments = 1
17
18; layer height
19layer_height = 0.2
20first_layer_height = 0.2
21bottom_solid_layers = 5
22top_solid_layers = 5
23
24; speeds
25perimeter_speed = 45
26external_perimeter_speed = 35
27small_perimeter_speed = 25
28first_layer_speed = 20
29gap_fill_speed = 40
30infill_speed = 200
31solid_infill_speed = 200
32min_print_speed = 15
33top_solid_infill_speed = 50
34travel_speed = 180
35
36; acceleration
37default_acceleration = 1000
38first_layer_acceleration = 1000
39infill_acceleration = 1250
40perimeter_acceleration = 800
41
42; print characteristics
43fill_angle = 45
44fill_density = 20%
45fill_pattern = grid
46infill_first = 0
47infill_only_where_needed = 0
48infill_overlap = 25%
49solid_infill_below_area = 0
50solid_infill_every_layers = 0
51solid_infill_extruder = 1
52solid_infill_extrusion_width = 0
53
54interface_shells = 0
55
56; skirt, brim & raft
57raft_layers = 0
58skirt_distance = 2
59skirt_height = 1
60skirts = 1
61min_skirt_length = 4
62
63; support
64support_material = 0
65support_material_angle = 0
66support_material_auto = 1
67support_material_buildplate_only = 0
68support_material_contact_distance = 0.25
69support_material_enforce_layers = 0
70support_material_extruder = 0
71support_material_extrusion_width = 0
72support_material_interface_contact_loops = 1
73support_material_interface_extruder = 0
74support_material_interface_layers = 1
75support_material_interface_spacing = 0.2
76support_material_interface_speed = 100%
77support_material_pattern = rectilinear
78support_material_spacing = 2
79support_material_speed = 50
80support_material_synchronize_layers = 0
81support_material_threshold = 45
82support_material_with_sheath = 0
83support_material_xy_spacing = 60%
84
2.2.21.2. Build scripts
1#!/bin/sh
2# Normal mode prints
3DIR_BASENAME="./output"
4find "./models/normal" -iname "*.stl" | while read MODEL
5do
6 echo "${MODEL}"
7 for NOZZLE in nozzles/*.ini; do
8 DIR_NOZZLE="$(basename -s .ini $NOZZLE)"
9 for FILAMENT in filaments/XT.ini; do
10 DIR_FILAMENT="$(basename -s .ini $FILAMENT)"
11 for SETTINGS in settings/settings_020_layers_normal.ini ; do
12 DIR_PATH="${DIR_BASENAME}/${DIR_FILAMENT}/${DIR_NOZZLE}"
13 mkdir -p "${DIR_PATH}"
14 run_prusaslicer \
15 --load printers/printer_mk3.ini \
16 --load $NOZZLE \
17 --load $FILAMENT \
18 --load $SETTINGS \
19 --post-process scripts/prusaslicer_massage.py \
20 --output "${DIR_PATH}" "${MODEL}"
21
22 done
23 done
24 done
25done
26
27# Vase mode prints
28find "./models/vase" -iname "*.stl" | while read MODEL
29do
30 echo "${MODEL}"
31 for NOZZLE in nozzles/*.ini; do
32 DIR_NOZZLE="$(basename -s .ini $NOZZLE)"
33 for FILAMENT in filaments/XT.ini; do
34 DIR_FILAMENT="$(basename -s .ini $FILAMENT)"
35 for SETTINGS in settings/settings_020_layers_vase.ini ; do
36 DIR_PATH="${DIR_BASENAME}/${DIR_FILAMENT}/${DIR_NOZZLE}"
37 echo "Output file is $DIR_BASENAME/${DIR_FILAMENT}/${DIR_NOZZLE}/${DIR_MODEL}"
38 mkdir -p "${DIR_PATH}"
39 run_prusaslicer \
40 --load printers/printer_mk3.ini \
41 --load $NOZZLE \
42 --load $FILAMENT \
43 --load $SETTINGS \
44 --post-process scripts/prusaslicer_massage.py \
45 --output "${DIR_PATH}" "$MODEL"
46
47 done
48 done
49 done
50done
51
52# Concentric fill prints
53find "./models/concentric" -iname "*.stl" | while read MODEL
54do
55 echo "${MODEL}"
56 for NOZZLE in nozzles/*.ini; do
57 DIR_NOZZLE="$(basename -s .ini $NOZZLE)"
58 for FILAMENT in filaments/XT.ini; do
59 DIR_FILAMENT="$(basename -s .ini $FILAMENT)"
60 for SETTINGS in settings/settings_020_layers_normal.ini ; do
61 DIR_PATH="${DIR_BASENAME}/${DIR_FILAMENT}/${DIR_NOZZLE}"
62 echo "Output file is $DIR_BASENAME/${DIR_FILAMENT}/${DIR_NOZZLE}/${DIR_MODEL}"
63 mkdir -p "${DIR_PATH}"
64 run_prusaslicer \
65 --load printers/printer_mk3.ini \
66 --load $NOZZLE \
67 --load $FILAMENT \
68 --load $SETTINGS \
69 --post-process scripts/prusaslicer_massage.py \
70 --output "${DIR_PATH}" "$MODEL" \
71 --external-fill-pattern concentric
72
73 done
74 done
75 done
76done
1#!/bin/sh
2/Applications/PrusaSlicer.app/Contents/MacOS/PrusaSlicer --no-gui --print-center 125,105 $*
3
1#!/usr/bin/python
2import sys
3import re
4import os
5
6parmEstimatedHours = ''
7parmEstimatedMinutes = ''
8parmEstimatedSeconds = ''
9parmNotes = ''
10
11sourceFile=sys.argv[1]
12
13# Read the ENTIRE g-code file into memory
14with open(sourceFile, "r") as f:
15 lines = f.readlines()
16
17 coordMinX = 9999.9
18 coordMaxX =0.0
19 coordMinY = 9999.9
20 coordMaxY = 0.0
21 currLine = 1
22 parsing = False
23
24for line in lines:
25 currLine += 1
26 parts = line.split(';', 1)
27 if len(parts) > 0:
28 # Parse command
29 command = parts[0].strip()
30 if len(parts) > 1:
31 # Parse comments
32 comment = parts[1].strip()
33
34 # Track extruder movement ranges
35 if not re.search(";", comment):
36 # Limit track to print movements, avoid start and end gcode blocks
37 if re.search("move to first skirt point", comment):
38 #if not parsing:
39 # print("Start extruder movement parsing at line %d with %s" % (currLine, comment))
40 parsing = True
41 if re.search("PURGING FINISHED", comment):
42 #print("Stop extruder movement parsing at line %d with %s" % (currLine, comment))
43 parsing = False
44 if parsing:
45 stringMatch = re.search ('^G[01].*X([0-9.]+)', command)
46 if stringMatch:
47 val = float(stringMatch.group(1))
48 # print("%s: X is %d" % (currLine, val))
49 if(val < coordMinX):
50 coordMinX = val
51 if(val > coordMaxX):
52 coordMaxX = val
53 stringMatch = re.search ('^G[01].*Y([0-9.]+)', command)
54 if stringMatch:
55 val = float(stringMatch.group(1))
56 if(val < coordMinY):
57 coordMinY = val
58 if(val > coordMaxY):
59 coordMaxY = val
60
61 # Include files
62 includeFile = re.search('#INCLUDE\s+(.*)', comment)
63 #if includeFile:
64 # outputFile.write(' -- Would include '+includeFile.group(1)+' stuff here')
65
66 # Parse estimated print time
67 stringMatch = re.search ('^notes = (.*)', comment)
68 if stringMatch:
69 parmNotes = stringMatch.group(1).strip()
70 stringMatch = re.search('estimated printing time \(normal mode\) =.* ([0-9]+)h.*', comment)
71 if stringMatch:
72 parmEstimatedHours = stringMatch.group(1)+'h'
73 stringMatch = re.search('estimated printing time \(normal mode\) =.* ([0-9]+)m.*', comment)
74 if stringMatch:
75 parmEstimatedMinutes = stringMatch.group(1)+'m'
76 stringMatch = re.search('estimated printing time \(normal mode\) =.* ([0-9]+)s.*', comment)
77 if stringMatch:
78 parmEstimatedSeconds = stringMatch.group(1)+'s'
79 # Parse print job parameters
80 stringMatch = re.search('filament_type = (.*)', comment)
81 if stringMatch:
82 parmFilamentType = stringMatch.group(1)
83 stringMatch = re.search('nozzle_diameter = (.*)', comment)
84 if stringMatch:
85 parmNozzleDiameter = stringMatch.group(1)
86 stringMatch = re.search('layer_height = (.*)', comment)
87 if stringMatch:
88 parmLayerHeight = stringMatch.group(1)
89 # Parse temperatures
90 stringMatch = re.search('bed_temperature = (.*)', comment)
91 if stringMatch:
92 parmBedTemperature = stringMatch.group(1)
93 stringMatch = re.search('first_layer_bed_temperature = (.*)', comment)
94 if stringMatch:
95 parm1stLayerBedTemperature = stringMatch.group(1)
96 stringMatch = re.search('temperature = (.*)', comment)
97 if stringMatch:
98 parmTemperature = stringMatch.group(1)
99 stringMatch = re.search('first_layer_temperature = (.*)', comment)
100 if stringMatch:
101 parm1stLayerTemperature = stringMatch.group(1)
102
103destFile = re.sub('\.gcode$','',sourceFile)
104if parmNotes:
105 destFile = destFile + ' ('+parmNotes+')'
106#destFile = destFile + ' S3r'
107if parmFilamentType:
108 destFile = destFile + ' '+parmFilamentType
109if parmLayerHeight:
110 destFile = destFile + ' '+parmLayerHeight
111if parmNozzleDiameter:
112 destFile = destFile + 'X'+parmNozzleDiameter
113if parm1stLayerTemperature:
114 destFile = destFile + ' '+parm1stLayerTemperature
115if parmTemperature:
116 destFile = destFile + '-'+parmTemperature
117if parm1stLayerBedTemperature:
118 destFile = destFile + ' '+parm1stLayerBedTemperature
119if parmBedTemperature:
120 destFile = destFile + '-'+parmBedTemperature
121if parmEstimatedHours or parmEstimatedMinutes or parmEstimatedSeconds:
122 destFile = destFile + ' '
123 if parmEstimatedHours:
124 destFile = destFile + parmEstimatedHours
125 if parmEstimatedMinutes:
126 destFile = destFile + parmEstimatedMinutes
127 if parmEstimatedSeconds:
128 destFile = destFile + parmEstimatedSeconds
129destFile = destFile + '.gcode'
130#print('Writing to %s' % re.sub('.*/','',destFile))
131
132with open(destFile, "w") as of:
133 of.write('; Minimum X = '+ str(coordMinX)+'\n')
134 of.write('; Maximum X = '+ str(coordMaxX)+'\n')
135 of.write('; Minimum Y = '+ str(coordMinY)+'\n')
136 of.write('; Maximum Y = '+ str(coordMaxY)+'\n')
137 for lIndex in xrange(len(lines)):
138 oline = lines[lIndex]
139 #if ("G0" in line or "G1" in line) and ("E" in line) :
140 # line = re.sub("E","B",line)
141 of.write(oline)
142
143of.close()
144f.close()
145
146os.remove(sourceFile)

Fig. 2.25 Batch build directory structure

Fig. 2.26 Batch output directory structure
See also
Contact and feedback
You can find me on the Prusa support forums or Reddit where I lurk in many of the 3D printing-related subreddits. I occasionally drop into the Official Prusa 3D discord server where I can be reached as bobstro (bobstro#9830). You can email me directly at projects@ttlexceeded.com.
Last updated 20190831