How to determine filament extruded?

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.

Can someone point me in the right direction?

Thanks,
Scott

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:

G1 X123.891 Y87.419 E-0.09241
G1 X123.689 Y86.591 E-0.19668
G1 X124.271 Y86.587 E-0.13434
G1 X124.245 Y85.130 E-0.33657
G1 E-0.04000 F2100.00000
G1 Z0.800 F10800.000
G1 X125.647 Y78.831
G1 Z0.200
G1 E0.80000 F2100.00000

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.

Scott

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.

1 Like