# Implementation of the module {gcode}. # Last edited on 2021-02-19 14:44:35 by jstolfi import path import move import rn import sys from math import sqrt, sin, cos, pi, inf, nan def write(wr, oph, islice, parms): write_file_preamble(wr, islice, parms) write_slice_preamble(wr, islice, parms) write_moves(wr, oph, parms) write_slice_postamble(wr, islice, parms) write_file_postamble(wr, parms) def write_file_preamble(wr, islice, parms): # Writes the commands preparing for a multi-slice frabrication. # # Sets units in mm and absolute coordinates, except the filament # which is set to relative. Sends the head and platform # to the home position and sets the {X,Y} origins there. # # Turns the print cooling fan off. Sets the nozzle temperature from # {parms} and waits for it to be reached. # # Extrudes some filament in order to prime the nozzle, then retracts it # by 2mm. wr.write("M104 S%.0f ; set temperature, no wait" % parms['temperature']) wr.write("M107 ; print cooling fan off\n") wr.write("G21 ; set units to millimeters\n") wr.write("G28 ; move to home position\n") wr.write("G92 X0 Y0 E0 ; set coordinate origin\n") wr.write("G90 ; use absolute coordinates\n") wr.write("M83 ; use relative coordinates for the filament\n") wr.write("M109 S%.0f ; wait for temperature" % parms['temperature']) # Extrude 20 mm of filament at 100 mm/min without moving, to prime the nozzle: wr.write("G1 E20.0 F100.0 ; extrude\n") wr.write("G1 E-2.00000 F24000 ; retract filament\n") wr.write("\n") wr.flush() def write_slice_preamble(wr, islice, parms): # Writes the initial commands that prepare the printer to fabricate # the slice number {islice}. # # Positions the nozzle at the the proper {Z} height, computed from the # slice number (0 = bottom) and the slice thickness from {parms}. # # Does not change the {X,Y} coordinates. Assumes that the filament has # been retracted by 2 mm and leaves it in that position. wr.write("(begin layer %d)\n" % islice) # Move nozzle up to proper height: zslice = parms['slice_thickness'] * (islice + 1) # Z cordinate of slice ??? zspeed = parms['job_z_speed']*60 # Max Z travel speed ??? wr.write("G1 Z%.3f F%.0f ; move to layer's Z\n" % (zslice, zspeed)) wr.write("\n") def write_slice_postamble(wr, islice, parms): # Writes the G-code to finalize the current slice. # # Assumes that the filament is retracted by 2 mm and leaves it there. # Leaves the {X,Y,Z} coordinates unchanged. wr.write("(end layer %d)\n" % islice) wr.write("\n") wr.write("\n") wr.flush() def write_file_postamble(wr, parms): # Writes the G-code to finalize the file. # # Assumes that the filament is retracted by 2 mm and leaves it there. # Moves the nozzle and platform to the home position and turns heating # and fan off. wr.write("M107 ; print cooling fan off\n") wr.write("M104 S0 ; nozzle heater off\n") wr.write("G28 ; home all axes\n") wr.flush() def write_moves(wr, oph, parms): # Writes the G-code to execute the moves (traces or jumps) # of the path {oph}. # # Assumes that the nozzle is at some arbitrary {X,Y} coordinates and at # the correct {Z} to extrude the layer, with the filament retracted by # 2mm. At the end, the filament will be retracted by 2 mm. fatn = False # True if filament is at the nozzle, false if it is retracted by 2 mm. p = path.pini(oph) # Jump to initial point of path. write_jump(wr, p, parms) pant = p for k in range(path.nelems(oph)): # wr.write("(Move %d)\n" % k) omvk = path.elem(oph, k) p = move.pini(omvk) q = move.pfin(omvk) assert p == pant, "discontinuous path" if move.is_jump(omvk): if fatn: wr.write("G1 E-2 F2400\n") write_jump(wr, q, parms) fatn = False else: if not fatn: wr.write("G1 E2 F2400\n") write_trace(wr, p, q, parms) fatn = True pant = q # Make sure that the filament is retracted at the end: if fatn: wr.write("G1 E-2.00000 F24000 ; retracts 2mm of material\n") def write_jump(wr, q, parms): # Writes the G-code to move from the current position to point {q} # without extruding. Assumes that the filament is retracted by 2mm. jspeed = parms['job_jump_speed'] * 60 # Cruise speed of nozzle during jumps. wr.write("G0 E0 X%.6f Y%.6f F%d\n" % (q[0], q[1], jspeed)) def write_trace(wr, p, q, parms): # Writes the G-code to extrude a trace from {p} (assumed to be the current position) # to point {q}. Assumes that the filament is at the nozzle, and leaves it # so at the end. tspeed = parms['job_filling_speed'] * 60 # Cruise speed of nozzle while extruding. tfeed = compute_feed_length(p, q, parms) wr.write("G1 X%.6f Y%.6f E%.3f F%d\n" % (q[0], q[1], tfeed, tspeed)) def compute_feed_length(p, q, parms): dpq = rn.dist(p, q) wdt = parms['solid_raster_width'] # Spacing of traces in solid fill. thk = parms['slice_thickness'] # Thickness of slice. # Compute area {tarea} of cross-section of extruded material, assuming that it is # a rectangle with height {thk} and width {wdt-thk} with semicircles # of radius {thk/2} on each side: tarea = thk * wdt volume = dpq*tarea # Volume of material needed # Compute area of cross-section of filament: fdiam = parms['filament_diameter'] farea = pi*fdiam*fdiam/4 # Length of filament flength = volume/farea return flength