I'm writing a plugin and trying to figure out how much filament is extruded during a print. My first naive attempt was to watch for the PositionUpdate event and look at the e position. However, this seems to be a number that continuously oscillates between 0 and -1.
I track extrusions on the python side with a little class that is based on the gcode parser from filaswitch. Just check the command queue with a hook, if it is an extrusion move, make sure it is positive (not a retraction) and add them up.
#stolen directly from filaswitch
class Gcode_parser:
MOVE_RE = re.compile("^G0\s+|^G1\s+")
X_COORD_RE = re.compile(".*\s+X([-]*\d+\.*\d*)")
Y_COORD_RE = re.compile(".*\s+Y([-]*\d+\.*\d*)")
E_COORD_RE = re.compile(".*\s+E([-]*\d+\.*\d*)")
Z_COORD_RE = re.compile(".*\s+Z([-]*\d+\.*\d*)")
SPEED_VAL_RE = re.compile(".*\s+F(\d+\.*\d*)")
def __init__(self):
self.last_match = None
def is_extrusion_move(self, line):
"""
Match given line against extrusion move regex
:param line: g-code line
:return: None or tuple with X, Y and E positions
"""
self.last_match = None
m = self.parse_move_args(line)
if m and (m[0] is not None or m[1] is not None) and m[3] is not None and m[3] != 0:
self.last_match = m
return self.last_match
def parse_move_args(self, line):
self.last_match = None
m = self.MOVE_RE.match(line)
if m:
x = None
y = None
z = None
e = None
speed = None
m = self.X_COORD_RE.match(line)
if m:
x = float(m.groups()[0])
m = self.Y_COORD_RE.match(line)
if m:
y = float(m.groups()[0])
m = self.Z_COORD_RE.match(line)
if m:
z = float(m.groups()[0])
m = self.E_COORD_RE.match(line)
if m:
e = float(m.groups()[0])
m = self.SPEED_VAL_RE.match(line)
if m:
speed = float(m.groups()[0])
return x, y, z, e, speed
Thanks. One question -- If I throw away the retractions, then won't I end up overcounting the amount of filament extruded? Doesn't each retraction need to be balanced by a corresponding move in the positive direction, before we get back to the point where filament will be extruded again?
ETA: Hmm, looking at some gcode, I think I understand what you're saying:
Your code is only considering movements that have X or Y, and E. So you're missing that final E0.80000 that undid all of those previous negative E moves. So you have to throw away the negative moves.
Would it work out the same then to count all E moves, including negative ones and ones where X | Y didn't change? Seems a little simpler for my purpose.
Of course, you can do exactly that. The parse_move_args method could be used. For my purposes, I only want to get extrusion moves (to get a bounding box for an object).
Here's a handy alternative to Paukstelis's parse args code above:
assuming cmd contains the full command line (as received on sent_gcode for example):
CmdDict = dict ((x,float(y)) for d,x,y in (re.split('([A-Z])', i) for i in cmd.upper().split()))
if "E" in CmdDict:
e = CmdDict["E"]
e now contains the extruded length, and the CmdDict contains all the single letter commands and their associated values. Requires import re somewhere up higher in the code.