MrDraw/printer_webui/util/gcodeInterpreter.py
Gina Häußge a85ea69fb0 Established settings mechanism
Allows reading and writing default serial port and baudrate (this also is available via the web interface) and setting the host and port on which the server should listen. Might allow persisting more options in the future.

The configuration file is stored in ~/.printerwebui/config.ini under Linux, in %APPDATA%/PrinterWebUI/config.ini under Windows and should be stored in ~/Library/Application Support/config.ini under MacOS X

Closes #1
2013-01-01 21:04:00 +01:00

284 lines
8 KiB
Python

from __future__ import absolute_import
import sys
import math
import re
import os
from printer_webui.util import util3d
preferences = {
"extruder_offset_x1": -22.0,
"extruder_offset_y1": 0.0,
"extruder_offset_x2": 0.0,
"extruder_offset_y2": 0.0,
"extruder_offset_x3": 0.0,
"extruder_offset_y3": 0.0,
}
def getPreference(key, default=None):
if preferences.has_key(key):
return preferences[key]
else:
return default
class gcodePath(object):
def __init__(self, newType, pathType, layerThickness, startPoint):
self.type = newType
self.pathType = pathType
self.layerThickness = layerThickness
self.list = [startPoint]
class gcode(object):
def __init__(self):
self.regMatch = {}
self.layerList = []
self.extrusionAmount = 0
self.totalMoveTimeMinute = 0
self.progressCallback = None
def load(self, filename):
if os.path.isfile(filename):
self._fileSize = os.stat(filename).st_size
gcodeFile = open(filename, 'r')
self._load(gcodeFile)
gcodeFile.close()
def loadList(self, l):
self._load(l)
def _load(self, gcodeFile):
filePos = 0
pos = util3d.Vector3()
posOffset = util3d.Vector3()
currentE = 0.0
totalExtrusion = 0.0
maxExtrusion = 0.0
currentExtruder = 0
extrudeAmountMultiply = 1.0
totalMoveTimeMinute = 0.0
scale = 1.0
posAbs = True
feedRate = 3600
layerThickness = 0.1
pathType = 'CUSTOM';
startCodeDone = False
currentLayer = []
currentPath = gcodePath('move', pathType, layerThickness, pos.copy())
currentPath.list[0].e = totalExtrusion
currentPath.list[0].extrudeAmountMultiply = extrudeAmountMultiply
currentLayer.append(currentPath)
for line in gcodeFile:
if type(line) is tuple:
line = line[0]
if self.progressCallback != None:
if isinstance(gcodeFile, (file)):
self.progressCallback(float(filePos) / float(self._fileSize))
elif isinstance(gcodeFile, (list)):
self.progressCallback(float(filePos) / float(len(gcodeFile)))
filePos += 1
#Parse Cura_SF comments
if line.startswith(';TYPE:'):
pathType = line[6:].strip()
if pathType != "CUSTOM":
startCodeDone = True
if ';' in line:
#Slic3r GCode comment parser
comment = line[line.find(';')+1:].strip()
if comment == 'fill':
pathType = 'FILL'
elif comment == 'perimeter':
pathType = 'WALL-INNER'
elif comment == 'skirt':
pathType = 'SKIRT'
if comment.startswith('LAYER:'):
self.layerList.append(currentLayer)
currentLayer = []
if pathType != "CUSTOM":
startCodeDone = True
line = line[0:line.find(';')]
T = self.getCodeInt(line, 'T')
if T is not None:
if currentExtruder > 0:
posOffset.x -= getPreference('extruder_offset_x%d' % (currentExtruder), 0.0)
posOffset.y -= getPreference('extruder_offset_y%d' % (currentExtruder), 0.0)
currentExtruder = T
if currentExtruder > 0:
posOffset.x += getPreference('extruder_offset_x%d' % (currentExtruder), 0.0)
posOffset.y += getPreference('extruder_offset_y%d' % (currentExtruder), 0.0)
G = self.getCodeInt(line, 'G')
if G is not None:
if G == 0 or G == 1: #Move
x = self.getCodeFloat(line, 'X')
y = self.getCodeFloat(line, 'Y')
z = self.getCodeFloat(line, 'Z')
e = self.getCodeFloat(line, 'E')
f = self.getCodeFloat(line, 'F')
oldPos = pos.copy()
if x is not None:
if posAbs:
pos.x = x * scale + posOffset.x
else:
pos.x += x * scale
if y is not None:
if posAbs:
pos.y = y * scale + posOffset.y
else:
pos.y += y * scale
if z is not None:
if posAbs:
pos.z = z * scale + posOffset.z
else:
pos.z += z * scale
if f is not None:
feedRate = f
if x is not None or y is not None or z is not None:
totalMoveTimeMinute += (oldPos - pos).vsize() / feedRate
moveType = 'move'
if e is not None:
if posAbs:
if e > currentE:
moveType = 'extrude'
if e < currentE:
moveType = 'retract'
else:
if e > 0:
moveType = 'extrude'
if e < 0:
moveType = 'retract'
totalExtrusion += e - currentE
currentE = e
if totalExtrusion > maxExtrusion:
maxExtrusion = totalExtrusion
if moveType == 'move' and oldPos.z != pos.z:
if oldPos.z > pos.z and abs(oldPos.z - pos.z) > 5.0 and pos.z < 1.0:
oldPos.z = 0.0
layerThickness = abs(oldPos.z - pos.z)
if currentPath.type != moveType or currentPath.pathType != pathType:
currentPath = gcodePath(moveType, pathType, layerThickness, currentPath.list[-1])
currentLayer.append(currentPath)
newPos = pos.copy()
newPos.e = totalExtrusion
newPos.extrudeAmountMultiply = extrudeAmountMultiply
currentPath.list.append(newPos)
elif G == 4: #Delay
S = self.getCodeFloat(line, 'S')
if S is not None:
totalMoveTimeMinute += S / 60
P = self.getCodeFloat(line, 'P')
if P is not None:
totalMoveTimeMinute += P / 60 / 1000
elif G == 20: #Units are inches
scale = 25.4
elif G == 21: #Units are mm
scale = 1.0
elif G == 28: #Home
x = self.getCodeFloat(line, 'X')
y = self.getCodeFloat(line, 'Y')
z = self.getCodeFloat(line, 'Z')
if x is None and y is None and z is None:
pos = util3d.Vector3()
else:
if x is not None:
pos.x = 0.0
if y is not None:
pos.y = 0.0
if z is not None:
pos.z = 0.0
elif G == 90: #Absolute position
posAbs = True
elif G == 91: #Relative position
posAbs = False
elif G == 92:
x = self.getCodeFloat(line, 'X')
y = self.getCodeFloat(line, 'Y')
z = self.getCodeFloat(line, 'Z')
e = self.getCodeFloat(line, 'E')
if e is not None:
currentE = e
if x is not None:
posOffset.x = pos.x - x
if y is not None:
posOffset.y = pos.y - y
if z is not None:
posOffset.z = pos.z - z
else:
print "Unknown G code:" + str(G)
else:
M = self.getCodeInt(line, 'M')
if M is not None:
if M == 1: #Message with possible wait (ignored)
pass
elif M == 80: #Enable power supply
pass
elif M == 81: #Suicide/disable power supply
pass
elif M == 84: #Disable step drivers
pass
elif M == 92: #Set steps per unit
pass
elif M == 101: #Enable extruder
pass
elif M == 103: #Disable extruder
pass
elif M == 104: #Set temperature, no wait
pass
elif M == 105: #Get temperature
pass
elif M == 106: #Enable fan
pass
elif M == 107: #Disable fan
pass
elif M == 108: #Extruder RPM (these should not be in the final GCode, but they are)
pass
elif M == 109: #Set temperature, wait
pass
elif M == 110: #Reset N counter
pass
elif M == 113: #Extruder PWM (these should not be in the final GCode, but they are)
pass
elif M == 140: #Set bed temperature
pass
elif M == 190: #Set bed temperature & wait
pass
elif M == 221: #Extrude amount multiplier
s = self.getCodeFloat(line, 'S')
if s != None:
extrudeAmountMultiply = s / 100.0
else:
print "Unknown M code:" + str(M)
self.layerList.append(currentLayer)
self.extrusionAmount = maxExtrusion
self.totalMoveTimeMinute = totalMoveTimeMinute
#print "Extruded a total of: %d mm of filament" % (self.extrusionAmount)
#print "Estimated print duration: %.2f minutes" % (self.totalMoveTimeMinute)
def getCodeInt(self, line, code):
if code not in self.regMatch:
self.regMatch[code] = re.compile(code + '([^\s]+)')
m = self.regMatch[code].search(line)
if m == None:
return None
try:
return int(m.group(1))
except:
return None
def getCodeFloat(self, line, code):
if code not in self.regMatch:
self.regMatch[code] = re.compile(code + '([^\s]+)')
m = self.regMatch[code].search(line)
if m == None:
return None
try:
return float(m.group(1))
except:
return None
if __name__ == '__main__':
for filename in sys.argv[1:]:
gcode().load(filename)