Esempio n. 1
0
suppressedLines = 0
totLines = 0
totSuppressedLines = 0
suppressedCode = False
runGCode = True

totDistance = 0
totDistanceNew = 0

zfound = False
xfound = False
yfound = False

layerSize = 1

converter = GCodeConverter()

def isZMove():
  return zfound and not (xfound or yfound)

def isXYMove():
  return (xfound or yfound) and not zfound

def getVal(moveCode):
  return float(moveCode[1:])

def getDistance(move1, move2):
  return abs(getVal(move1) - getVal(move2))

for line in fileinput.input():
  line = converter.convert(line)
class GCodeAnalyzer():
    def __init__(self, calculateTravel=True):
        self.Reset()
        self.converter = GCodeConverter()
        self.calculateTravel = calculateTravel

    def Reset(self):
        self.x = 0
        self.y = 0
        self.z = 0
        self.e = 0
        self.emax = 0
        self.f = 1000  # standard feed rate
        self.fastf = 5000  # fast feed rate for g0 moves
        self.lastX = 0
        self.lastY = 0
        self.lastZ = 0
        self.lastE = 0
        self.xOffset = 0
        self.yOffset = 0
        self.zOffset = 0
        self.eOffset = 0
        self.lastZPrint = 0
        self.layerZ = 0
        self.relative = False
        self.eRelative = False
        self.homeX = 0
        self.homeY = 0
        self.homeZ = 0
        self.lastMovementGCode = None
        self.lastGCodeLine = ""
        self.metric = True

        # for G162: home to maximum
        self.axisMaxX = 150
        self.axisMaxY = 150
        self.axisMaxZ = 150

        # bounding box
        self.maxX = 0
        self.maxY = 0
        self.maxZ = 0
        self.minX = 0
        self.minY = 0
        self.minZ = 0

        self.hasHomeX = False
        self.hasHomeY = False
        self.hasHomeZ = False
        self.travel = 0
        self.time = 0  # time in minutes

        self.moveInMachineCoords = False

    # undo one movement gcode command (does not affect bouding box)
    def undo(self):
        #if self.lastMovementGCode is None: return
        self.x = self.lastX
        self.y = self.lastY
        self.z = self.lastZ
        self.e = self.lastE
        self.lastMovementGCode = None

    def Analyze(self, gcode):
        self.lastGCodeLine = gcode
        if gcode.find(";") >= 0:
            gcode = gcode[:gcode.find(";")]  # remove comments
        if gcode.find("(") >= 0:
            gcode = gcode[:gcode.find("(")]  # remove comments
        if gcode.find("$") >= 0:
            gcode = gcode[:gcode.find("$")]  # ignore configuration/jog commands

        tokens = ['']
        # convert multiple G commands on one line
        tokens.extend(re.split('([GM][^GM]+)', gcode, re.I))
        for line in tokens:
            if line.strip() != "":
                # print "Analyze ", line
                self.AnalyzeLine(self.converter.convert(line))  # handles grbl-style code

        self.moveInMachineCoords = False # this flag gets reset at the end of the gcode line

    def AnalyzeLine(self, gcode):
        self.lastMovementGCode = None  # by default, the move was not a g[0-3]; set it differently in case of actual movement gcode

        gcode = gcode.lstrip();
        if gcode.startswith("@"): return  # code is a host command

        code_g = findCode(gcode, "G")
        if '$H' in gcode:
            code_g = str(28) # this is a homing command equivalent to g28
        code_m = findCode(gcode, "M")
        # we have a g_code
        if code_g != None:
            if '.' in code_g: # codes like 38.2 were considered G0!
                code_g = safeFloat(code_g)
            else:
                code_g = safeInt(code_g)

            if (self.metric):
                metricConv = 1
            else:
                metricConv = 25.4

            # get movement codes
            if code_g == 0 or code_g == 1 or code_g == 2 or code_g == 3:
                self.lastX = self.x
                self.lastY = self.y
                self.lastZ = self.z
                self.lastE = self.e
                eChanged = False;
                code_f = findCode(gcode, "F")
                if code_f != None:
                    self.f = safeFloat(code_f) * metricConv

                code_x = findCode(gcode, "X")
                code_y = findCode(gcode, "Y")
                code_z = findCode(gcode, "Z")
                code_e = findCode(gcode, "E")

                if self.moveInMachineCoords: # convert the machine coords move to work coords
                    print "Move is in machine coords!"
                    if code_x is not None:
                        code_x = safeFloat(code_x) + self.xOffset

                    if code_y is not None:
                        code_y = safeFloat(code_y) + self.yOffset

                    if code_y is not None:
                        code_z = safeFloat(code_z) + self.zOffset


                code_i = findCode(gcode, "I")
                code_j = findCode(gcode, "J")

                self.lastMovementGCode = MovementGCode(code_g)
                self.lastMovementGCode.startX = self.lastX/metricConv
                self.lastMovementGCode.startY = self.lastY/metricConv
                self.lastMovementGCode.startZ = self.lastZ/metricConv
                self.lastMovementGCode.x = safeFloat(code_x or self.lastX/metricConv)
                self.lastMovementGCode.y = safeFloat(code_y or self.lastY/metricConv)
                self.lastMovementGCode.z = safeFloat(code_z or self.lastZ/metricConv)
                if code_g == 2 or code_g == 3:
                    self.lastMovementGCode.i = safeFloat(code_i)
                    self.lastMovementGCode.j = safeFloat(code_j)

                if code_e:
                    self.lastMovementGCode.e = safeFloat(code_e)

                if code_f:
                    self.lastMovementGCode.f = safeFloat(code_f)


                if self.relative:
                    if code_x != None: self.x += safeFloat(code_x) * metricConv
                    if code_y != None: self.y += safeFloat(code_y) * metricConv
                    if code_z != None: self.z += safeFloat(code_z) * metricConv
                    if code_e != None:
                        e = safeFloat(code_e) * metricConv
                        if e != 0:
                            eChanged = True
                            self.e += e
                else:
                    # absolute coordinates
                    if code_x != None: self.x =  safeFloat(code_x) * metricConv
                    if code_y != None: self.y =  safeFloat(code_y) * metricConv
                    if code_z != None: self.z =  safeFloat(code_z) * metricConv
                    if code_e != None:
                        e = safeFloat(code_e) * metricConv
                        if self.eRelative:
                            if e != 0:
                                eChanged = True
                                self.e += e
                        else:
                            # e is absolute. Is it changed?
                            if self.e != self.eOffset + e:
                                eChanged = True
                                self.e = self.eOffset + e
                # bbox calculation
                if self.x < self.minX: self.minX = self.x
                if self.y < self.minY: self.minY = self.y
                if self.z < self.minZ: self.minZ = self.z

                if self.x > self.maxX: self.maxX = self.x
                if self.y > self.maxY: self.maxY = self.y
                if self.z > self.maxZ: self.maxZ = self.z

                travel_len = 0
                travel_time = 0
                # calculate travelled distance. Quite time consuming, so only do it if needed.
                if self.calculateTravel:
                    if code_g == 0 or code_g == 1:
                        travel_len = euclidean_distance((self.lastX, self.lastY, self.lastZ), (self.x, self.y, self.z))
                        if code_g == 0:
                            travel_time = travel_len / self.fastf
                        else:
                            travel_time = travel_len / self.f
                    else:
                        # it's an arc: get the center
                        centerX = self.lastX + safeFloat(code_i) * metricConv
                        centerY = self.lastY + safeFloat(code_j) * metricConv
                        ccw = True if code_g == 3 else False  # g3 is counter clockwise arc
                        travel_len = arc_distance((centerX, centerY), (self.lastX, self.lastY), (self.x, self.y), ccw)
                        travel_time = travel_len / self.f

                self.travel += travel_len
                self.time += travel_time

                # Repetier has a bunch of limit-checking code here and time calculations: we are leaving them for now
            elif code_g == 20:
                self.metric = False
            elif code_g == 21:
                self.metric = True
            elif code_g == 28 or code_g == 161:
                self.lastX = self.x
                self.lastY = self.y
                self.lastZ = self.z
                self.lastE = self.e
                code_x = findCode(gcode, "X")
                code_y = findCode(gcode, "Y")
                code_z = findCode(gcode, "Z")
                code_e = findCode(gcode, "E")
                homeAll = False
                if code_x == None and code_y == None and code_z == None: homeAll = True
                if code_x != None or homeAll:
                    self.hasHomeX = True
                    self.xOffset = 0
                    self.x = self.homeX
                if code_y != None or homeAll:
                    self.hasHomeY = True
                    self.yOffset = 0
                    self.y = self.homeY
                if code_z != None or homeAll:
                    self.hasHomeZ = True
                    self.zOffset = 0
                    self.z = self.homeZ
                if code_e != None:
                    self.eOffset = 0
                    self.e = 0
            # elif code_g == 162:
            #     self.lastX = self.x
            #     self.lastY = self.y
            #     self.lastZ = self.z
            #     self.lastE = self.e
            #     code_x = findCode(gcode, "X")
            #     code_y = findCode(gcode, "Y")
            #     code_z = findCode(gcode, "Z")
            #     homeAll = False
            #     if code_x == None and code_y == None and code_z == None: homeAll = True
            #     if code_x != None or homeAll:
            #         self.hasHomeX = True
            #         self.xOffset = 0
            #         self.x = self.axisMaxX
            #     if code_y != None or homeAll:
            #         self.hasHomeY = True
            #         self.yOffset = 0
            #         self.y = self.axisMaxY
            #     if code_z != None or homeAll:
            #         self.hasHomeZ = True
            #         self.zOffset = 0
            #         self.z = self.axisMaxZ
            elif code_g == 53:
                self.moveInMachineCoords = True
            elif code_g == 90:
                self.relative = False
            elif code_g == 91:
                self.relative = True
            elif code_g == 92 or code_g == 10:
                code_x = findCode(gcode, "X")
                code_y = findCode(gcode, "Y")
                code_z = findCode(gcode, "Z")
                code_e = findCode(gcode, "E")

                current_machine_coords = self.getMachineXYZ()

                if code_x != None:
                    self.x = safeFloat(code_x) * metricConv

                if code_y != None:
                    self.y = safeFloat(code_y) * metricConv

                if code_z != None:
                    self.z = safeFloat(code_z) * metricConv

                if code_e != None:
                    self.e = safeFloat(code_e) * metricConv

                #redefine offsets x = machine_x + offset => offset = x - machine_x
                self.xOffset = self.x - current_machine_coords[0]
                self.yOffset = self.y - current_machine_coords[1]
                self.zOffset = self.z - current_machine_coords[2]



                # the following code is correct for 3D printers and Marlin. With Grbl, the position is factually redefined
                # if code_x != None:
                #   self.xOffset = self.x - safeFloat(code_x)
                #   self.x = self.xOffset
                # if code_y != None:
                #   self.yOffset = self.y - safeFloat(code_y)
                #   self.y = self.yOffset
                # if code_z != None:
                #   self.zOffset = self.z - safeFloat(code_z)
                #   self.z = self.zOffset
                # if code_e != None:
                #   self.eOffset = self.e - safeFloat(code_e)
                #   self.e = self.eOffset
        if code_m != None:
            code_m = safeInt(code_m)
            if code_m == 82:
                self.eRelative = False
            elif code_m == 83:
                self.eRelative = True

    #    self.print_status()

    def getMachineXYZ(self):
        return self.x - self.xOffset, self.y - self.yOffset, self.z - self.zOffset

    def getWorkXYZ(self):
        return self.x, self.y, self.z

    def syncStatusWithGrbl(self, grblMachineStatus, grblWorkStatus = None):
        if grblWorkStatus is None:
            # we only have one status report. Update the correct coordinates
            if grblMachineStatus['type'] == 'Work':
                self.x, self.y, self.z = grblWorkStatus['position']
            else:
                self.x = grblMachineStatus['position'][0] + self.xOffset
                self.y = grblMachineStatus['position'][1] + self.yOffset
                self.z = grblMachineStatus['position'][2] + self.zOffset
        else:
            self.x, self.y, self.z = grblWorkStatus['position']

            self.xOffset = grblWorkStatus['position'][0] - grblMachineStatus['position'][0]
            self.yOffset = grblWorkStatus['position'][1] - grblMachineStatus['position'][1]
            self.zOffset = grblWorkStatus['position'][2] - grblMachineStatus['position'][2]


    def getBoundingBox(self):
        return (self.minX, self.minY, self.minZ), (self.maxX, self.maxY, self.maxZ)

    def getPosition(self):
        return (self.x, self.y, self.z)

    def getTravelLen(self):
        return self.travel

    def getTravelTime(self):
        return self.time

    def print_status(self):
        attrs = vars(self)
        print '\n'.join("%s: %s" % item for item in attrs.items())

    # returns true if the last move intersected the x value
    def intersected(self, xValue):
        if self.lastMovementGCode is None: return False
        if (self.lastX <= xValue and self.x >= xValue) or (self.lastX >= xValue and self.x <= xValue): return True
        return False

    # returns -1 if the last movement was towards -x, +1 if it was towards +x, 0 otherwise
    def movementDirection(self):
        if self.lastMovementGCode is None: return 0
        if self.lastX < self.x: return 1
        if self.lastX > self.x: return -1
        return 0
 def __init__(self, calculateTravel=True):
     self.Reset()
     self.converter = GCodeConverter()
     self.calculateTravel = calculateTravel
Esempio n. 4
0
class GCodeAnalyzer():
    def __init__(self):
        self.Reset()
        self.converter = GCodeConverter()

    def Reset(self):
        self.x = 0
        self.y = 0
        self.z = 0
        self.e = 0
        self.emax = 0
        self.f = 1000  # standard feed rate
        self.fastf = 5000  # fast feed rate for g0 moves
        self.lastX = 0
        self.lastY = 0
        self.lastZ = 0
        self.lastE = 0
        self.xOffset = 0
        self.yOffset = 0
        self.zOffset = 0
        self.eOffset = 0
        self.lastZPrint = 0
        self.layerZ = 0
        self.relative = False
        self.eRelative = False
        self.homeX = 0
        self.homeY = 0
        self.homeZ = 0
        self.lastMovementGCode = None
        self.lastGCodeLine = ""

        # for G162: home to maximum
        self.axisMaxX = 150
        self.axisMaxY = 150
        self.axisMaxZ = 150

        # bounding box
        self.maxX = 0
        self.maxY = 0
        self.maxZ = 0
        self.minX = 0
        self.minY = 0
        self.minZ = 0

        self.hasHomeX = False
        self.hasHomeY = False
        self.hasHomeZ = False
        self.travel = 0
        self.time = 0  # time in minutes

    # undo one movement gcode command (does not affect bouding box)
    def undo(self):
        if self.lastMovementGCode is None: return
        self.x = self.lastX
        self.y = self.lastY
        self.z = self.lastZ
        self.e = self.lastE
        self.lastMovementGCode = None

    def Analyze(self, gcode):
        self.lastGCodeLine = gcode
        if gcode.find(";") >= 0:
            gcode = gcode[:gcode.find(";")]  # remove comments
        if gcode.find("(") >= 0:
            gcode = gcode[:gcode.find("(")]  # remove comments

        gcode = self.converter.convert(gcode)  # handles grbl-style code

        self.lastMovementGCode = None  # by default, the move was not a g[0-3]; set it differently in case of actual movement gcode

        gcode = gcode.lstrip()
        if gcode.startswith("@"): return  # code is a host command
        code_g = findCode(gcode, "G")
        code_m = findCode(gcode, "M")
        # we have a g_code
        if code_g != None:
            code_g = safeInt(code_g)

            #get movement codes
            if code_g == 0 or code_g == 1 or code_g == 2 or code_g == 3:
                self.lastX = self.x
                self.lastY = self.y
                self.lastZ = self.z
                self.lastE = self.e
                eChanged = False
                code_f = findCode(gcode, "F")
                if code_f != None:
                    self.f = safeFloat(code_f)

                code_x = findCode(gcode, "X")
                code_y = findCode(gcode, "Y")
                code_z = findCode(gcode, "Z")
                code_e = findCode(gcode, "E")
                self.lastMovementGCode = code_g

                if self.relative:
                    if code_x != None: self.x += safeFloat(code_x)
                    if code_y != None: self.y += safeFloat(code_y)
                    if code_z != None: self.z += safeFloat(code_z)
                    if code_e != None:
                        e = safeFloat(code_e)
                        if e != 0:
                            eChanged = True
                            self.e += e
                else:
                    #absolute coordinates
                    if code_x != None:
                        self.x = self.xOffset + safeFloat(code_x)
                    if code_y != None:
                        self.y = self.yOffset + safeFloat(code_y)
                    if code_z != None:
                        self.z = self.zOffset + safeFloat(code_z)
                    if code_e != None:
                        e = safeFloat(code_e)
                        if self.eRelative:
                            if e != 0:
                                eChanged = True
                                self.e += e
                        else:
                            # e is absolute. Is it changed?
                            if self.e != self.eOffset + e:
                                eChanged = True
                                self.e = self.eOffset + e
                #bbox calculation
                if self.x < self.minX: self.minX = self.x
                if self.y < self.minY: self.minY = self.y
                if self.z < self.minZ: self.minZ = self.z

                if self.x > self.maxX: self.maxX = self.x
                if self.y > self.maxY: self.maxY = self.y
                if self.z > self.maxZ: self.maxZ = self.z

                travel_len = 0
                travel_time = 0
                #calculate travelled distance
                if code_g == 0 or code_g == 1:
                    travel_len = euclidean_distance(
                        (self.lastX, self.lastY, self.lastZ),
                        (self.x, self.y, self.z))
                    if code_g == 0:
                        travel_time = travel_len / self.fastf
                    else:
                        travel_time = travel_len / self.f
                else:
                    # it's an arc: get the center
                    centerX = self.lastX + safeFloat(findCode(gcode, "I"))
                    centerY = self.lastY + safeFloat(findCode(gcode, "J"))
                    ccw = True if code_g == 3 else False  # g3 is counter clockwise arc
                    travel_len = arc_distance((centerX, centerY),
                                              (self.lastX, self.lastY),
                                              (self.x, self.y), ccw)
                    travel_time = travel_len / self.f

                self.travel += travel_len
                self.time += travel_time

                #Repetier has a bunch of limit-checking code here and time calculations: we are leaving them for now
            elif code_g == 28 or code_g == 161:
                self.lastX = self.x
                self.lastY = self.y
                self.lastZ = self.z
                self.lastE = self.e
                code_x = findCode(gcode, "X")
                code_y = findCode(gcode, "Y")
                code_z = findCode(gcode, "Z")
                code_e = findCode(gcode, "E")
                homeAll = False
                if code_x == None and code_y == None and code_z == None:
                    homeAll = True
                if code_x != None or homeAll:
                    self.hasHomeX = True
                    self.xOffset = 0
                    self.x = self.homeX
                if code_y != None or homeAll:
                    self.hasHomeY = True
                    self.yOffset = 0
                    self.y = self.homeY
                if code_z != None or homeAll:
                    self.hasHomeZ = True
                    self.zOffset = 0
                    self.z = self.homeZ
                if code_e != None:
                    self.eOffset = 0
                    self.e = 0
            elif code_g == 162:
                self.lastX = self.x
                self.lastY = self.y
                self.lastZ = self.z
                self.lastE = self.e
                code_x = findCode(gcode, "X")
                code_y = findCode(gcode, "Y")
                code_z = findCode(gcode, "Z")
                homeAll = False
                if code_x == None and code_y == None and code_z == None:
                    homeAll = True
                if code_x != None or homeAll:
                    self.hasHomeX = True
                    self.xOffset = 0
                    self.x = self.axisMaxX
                if code_y != None or homeAll:
                    self.hasHomeY = True
                    self.yOffset = 0
                    self.y = self.axisMaxY
                if code_z != None or homeAll:
                    self.hasHomeZ = True
                    self.zOffset = 0
                    self.z = self.axisMaxZ
            elif code_g == 90:
                self.relative = False
            elif code_g == 91:
                self.relative = True
            elif code_g == 92:
                code_x = findCode(gcode, "X")
                code_y = findCode(gcode, "Y")
                code_z = findCode(gcode, "Z")
                code_e = findCode(gcode, "E")
                if code_x != None:
                    self.xOffset = self.x - safeFloat(code_x)
                    self.x = self.xOffset
                if code_y != None:
                    self.yOffset = self.y - safeFloat(code_y)
                    self.y = self.yOffset
                if code_z != None:
                    self.zOffset = self.z - safeFloat(code_z)
                    self.z = self.zOffset
                if code_e != None:
                    self.eOffset = self.e - safeFloat(code_e)
                    self.e = self.eOffset
        if code_m != None:
            code_m = safeInt(code_m)
            if code_m == 82: self.eRelative = False
            elif code_m == 83: self.eRelative = True


#    self.print_status()

    def getBoundingBox(self):
        return (self.minX, self.minY, self.minZ), (self.maxX, self.maxY,
                                                   self.maxZ)

    def getPosition(self):
        return (self.x, self.y, self.z)

    def getTravelLen(self):
        return self.travel

    def getTravelTime(self):
        return self.time

    def print_status(self):
        attrs = vars(self)
        print '\n'.join("%s: %s" % item for item in attrs.items())

    # returns true if the last move intersected the x value
    def intersected(self, xValue):
        if self.lastMovementGCode is None: return False
        if (self.lastX <= xValue
                and self.x >= xValue) or (self.lastX >= xValue
                                          and self.x <= xValue):
            return True
        return False

    # returns -1 if the last movement was towards -x, +1 if it was towards +x, 0 otherwise
    def movementDirection(self):
        if self.lastMovementGCode is None: return 0
        if self.lastX < self.x: return 1
        if self.lastX > self.x: return -1
        return 0
Esempio n. 5
0
 def __init__(self):
     self.Reset()
     self.converter = GCodeConverter()
Esempio n. 6
0
suppressedLines = 0
totLines = 0
totSuppressedLines = 0
suppressedCode = False
runGCode = True

totDistance = 0
totDistanceNew = 0

zfound = False
xfound = False
yfound = False

layerSize = 1

converter = GCodeConverter()


def isZMove():
    return zfound and not (xfound or yfound)


def isXYMove():
    return (xfound or yfound) and not zfound


def getVal(moveCode):
    return float(moveCode[1:])


def getDistance(move1, move2):
Esempio n. 7
0
 def __init__(self):
   self.Reset()
   self.converter = GCodeConverter()
Esempio n. 8
0
class GCodeAnalyzer():
  def __init__(self):
    self.Reset()
    self.converter = GCodeConverter()
    
    
  def Reset(self):
    self.x = 0
    self.y = 0
    self.z = 0
    self.e = 0
    self.emax = 0
    self.f = 1000 # standard feed rate
    self.fastf = 5000 # fast feed rate for g0 moves
    self.lastX = 0
    self.lastY = 0
    self.lastZ = 0
    self.lastE = 0
    self.xOffset = 0
    self.yOffset = 0
    self.zOffset = 0
    self.eOffset = 0
    self.lastZPrint = 0
    self.layerZ = 0
    self.relative = False
    self.eRelative = False
    self.homeX = 0
    self.homeY = 0
    self.homeZ = 0
    self.lastMovementGCode = None
    self.lastGCodeLine = ""
    
    # for G162: home to maximum
    self.axisMaxX = 150
    self.axisMaxY = 150
    self.axisMaxZ = 150

    # bounding box
    self.maxX = 0
    self.maxY = 0
    self.maxZ = 0
    self.minX = 0
    self.minY = 0
    self.minZ = 0

    
    
    self.hasHomeX = False
    self.hasHomeY = False
    self.hasHomeZ = False
    self.travel = 0
    self.time = 0 # time in minutes
     
  # undo one movement gcode command (does not affect bouding box)
  def undo(self):
    if self.lastMovementGCode is None: return
    self.x = self.lastX
    self.y = self.lastY
    self.z = self.lastZ
    self.e = self.lastE
    self.lastMovementGCode = None
    
    
  def Analyze(self, gcode):
    self.lastGCodeLine = gcode
    if gcode.find(";") >= 0:
      gcode = gcode[:gcode.find(";")] # remove comments
    if gcode.find("(") >= 0:
      gcode = gcode[:gcode.find("(")] # remove comments
      
    gcode = self.converter.convert(gcode) # handles grbl-style code
    
    self.lastMovementGCode = None # by default, the move was not a g[0-3]; set it differently in case of actual movement gcode
    
    gcode = gcode.lstrip();
    if gcode.startswith("@"): return # code is a host command
    code_g = findCode(gcode, "G")
    code_m = findCode(gcode, "M")
    # we have a g_code
    if code_g != None:
      code_g = safeInt(code_g)
    
      #get movement codes
      if code_g == 0 or code_g == 1 or code_g == 2 or code_g == 3:
        self.lastX = self.x
        self.lastY = self.y
        self.lastZ = self.z
        self.lastE = self.e
        eChanged = False;
        code_f = findCode(gcode, "F")
        if code_f != None:
          self.f=safeFloat(code_f)
          
        code_x = findCode(gcode, "X")
        code_y = findCode(gcode, "Y")
        code_z = findCode(gcode, "Z")
        code_e = findCode(gcode, "E")
        self.lastMovementGCode = code_g

        if self.relative:
          if code_x != None: self.x += safeFloat(code_x)
          if code_y != None: self.y += safeFloat(code_y)
          if code_z != None: self.z += safeFloat(code_z)
          if code_e != None:
            e = safeFloat(code_e)
            if e != 0:
              eChanged = True
              self.e += e
        else:     
          #absolute coordinates
          if code_x != None: self.x = self.xOffset + safeFloat(code_x)
          if code_y != None: self.y = self.yOffset + safeFloat(code_y)
          if code_z != None: self.z = self.zOffset + safeFloat(code_z)
          if code_e != None:
            e = safeFloat(code_e)
            if self.eRelative:
              if e != 0:
                eChanged = True
                self.e += e
            else:
            # e is absolute. Is it changed?
              if self.e != self.eOffset + e:
                eChanged = True
                self.e = self.eOffset + e
        #bbox calculation
        if self.x < self.minX: self.minX = self.x
        if self.y < self.minY: self.minY = self.y
        if self.z < self.minZ: self.minZ = self.z
        
        if self.x > self.maxX: self.maxX = self.x
        if self.y > self.maxY: self.maxY = self.y
        if self.z > self.maxZ: self.maxZ = self.z
        
        travel_len = 0
        travel_time = 0
        #calculate travelled distance
        if code_g == 0 or code_g == 1:
          travel_len = euclidean_distance( (self.lastX, self.lastY, self.lastZ), (self.x, self.y, self.z) )
          if code_g == 0:
            travel_time = travel_len / self.fastf
          else:
            travel_time = travel_len / self.f
        else:
          # it's an arc: get the center
          centerX = self.lastX + safeFloat(findCode(gcode, "I"))
          centerY = self.lastY + safeFloat(findCode(gcode, "J"))
          ccw = True if code_g == 3 else False # g3 is counter clockwise arc
          travel_len = arc_distance( (centerX, centerY), (self.lastX, self.lastY), (self.x, self.y), ccw )
          travel_time = travel_len / self.f
          
        self.travel += travel_len
        self.time += travel_time
        
        #Repetier has a bunch of limit-checking code here and time calculations: we are leaving them for now
      elif code_g == 28 or code_g == 161:
        self.lastX = self.x
        self.lastY = self.y
        self.lastZ = self.z
        self.lastE = self.e
        code_x = findCode(gcode, "X")
        code_y = findCode(gcode, "Y")
        code_z = findCode(gcode, "Z")
        code_e = findCode(gcode, "E")
        homeAll = False
        if code_x == None and code_y == None and code_z == None: homeAll = True
        if code_x != None or homeAll:
          self.hasHomeX = True
          self.xOffset = 0
          self.x = self.homeX
        if code_y != None or homeAll:
          self.hasHomeY = True
          self.yOffset = 0
          self.y = self.homeY
        if code_z != None or homeAll:
          self.hasHomeZ = True
          self.zOffset = 0
          self.z = self.homeZ
        if code_e != None:
          self.eOffset = 0
          self.e = 0
      elif code_g == 162:
        self.lastX = self.x
        self.lastY = self.y
        self.lastZ = self.z
        self.lastE = self.e
        code_x = findCode(gcode, "X")
        code_y = findCode(gcode, "Y")
        code_z = findCode(gcode, "Z")
        homeAll = False
        if code_x == None and code_y == None and code_z == None: homeAll = True
        if code_x != None or homeAll:
          self.hasHomeX = True
          self.xOffset = 0
          self.x = self.axisMaxX
        if code_y != None or homeAll:
          self.hasHomeY = True
          self.yOffset = 0
          self.y = self.axisMaxY
        if code_z != None or homeAll:
          self.hasHomeZ = True
          self.zOffset = 0
          self.z = self.axisMaxZ
      elif code_g == 90: self.relative = False
      elif code_g == 91: self.relative = True
      elif code_g == 92:
        code_x = findCode(gcode, "X")
        code_y = findCode(gcode, "Y")
        code_z = findCode(gcode, "Z")
        code_e = findCode(gcode, "E")
        if code_x != None:
          self.xOffset = self.x - safeFloat(code_x)
          self.x = self.xOffset
        if code_y != None:
          self.yOffset = self.y - safeFloat(code_y)
          self.y = self.yOffset
        if code_z != None:
          self.zOffset = self.z - safeFloat(code_z)
          self.z = self.zOffset
        if code_e != None:
          self.eOffset = self.e - safeFloat(code_e)
          self.e = self.eOffset
    if code_m != None:
      code_m = safeInt(code_m)
      if code_m == 82: self.eRelative = False
      elif code_m == 83: self.eRelative = True
#    self.print_status()

  def getBoundingBox(self):
    return (self.minX, self.minY, self.minZ), (self.maxX, self.maxY, self.maxZ)
  
  def getPosition(self):
    return (self.x, self.y, self.z)
        
  def getTravelLen(self):
    return self.travel
  
  def getTravelTime(self):
    return self.time
  
  def print_status(self):
    attrs = vars(self)
    print '\n'.join("%s: %s" % item for item in attrs.items())
    
  # returns true if the last move intersected the x value
  def intersected(self, xValue):
    if self.lastMovementGCode is None: return False
    if (self.lastX <= xValue and self.x >= xValue) or (self.lastX >= xValue and self.x <= xValue): return True
    return False
  
  # returns -1 if the last movement was towards -x, +1 if it was towards +x, 0 otherwise
  def movementDirection(self):
    if self.lastMovementGCode is None: return 0
    if self.lastX < self.x: return 1
    if self.lastX > self.x: return -1
    return 0
Esempio n. 9
0
 def __init__(self, calculateTravel=True):
     self.Reset()
     self.converter = GCodeConverter()
     self.calculateTravel = calculateTravel
Esempio n. 10
0
class GCodeAnalyzer():
    def __init__(self, calculateTravel=True):
        self.Reset()
        self.converter = GCodeConverter()
        self.calculateTravel = calculateTravel

    def Reset(self):
        self.x = 0
        self.y = 0
        self.z = 0
        self.e = 0
        self.emax = 0
        self.f = 1000  # standard feed rate
        self.fastf = 5000  # fast feed rate for g0 moves
        self.lastX = 0
        self.lastY = 0
        self.lastZ = 0
        self.lastE = 0
        self.xOffset = 0
        self.yOffset = 0
        self.zOffset = 0
        self.eOffset = 0
        self.lastZPrint = 0
        self.layerZ = 0
        self.relative = False
        self.eRelative = False
        self.homeX = 0
        self.homeY = 0
        self.homeZ = 0
        self.lastMovementGCode = None
        self.lastGCodeLine = ""
        self.metric = True

        # for G162: home to maximum
        self.axisMaxX = 150
        self.axisMaxY = 150
        self.axisMaxZ = 150

        # bounding box
        self.maxX = 0
        self.maxY = 0
        self.maxZ = 0
        self.minX = 0
        self.minY = 0
        self.minZ = 0

        self.hasHomeX = False
        self.hasHomeY = False
        self.hasHomeZ = False
        self.travel = 0
        self.time = 0  # time in minutes

        self.moveInMachineCoords = False

    # undo one movement gcode command (does not affect bouding box)
    def undo(self):
        #if self.lastMovementGCode is None: return
        self.x = self.lastX
        self.y = self.lastY
        self.z = self.lastZ
        self.e = self.lastE
        self.lastMovementGCode = None

    def Analyze(self, gcode):
        self.lastGCodeLine = gcode
        if gcode.find(";") >= 0:
            gcode = gcode[:gcode.find(";")]  # remove comments
        if gcode.find("(") >= 0:
            gcode = gcode[:gcode.find("(")]  # remove comments
        if gcode.find("$") >= 0:
            gcode = gcode[:gcode.find(
                "$")]  # ignore configuration/jog commands

        tokens = ['']
        # convert multiple G commands on one line
        tokens.extend(re.split('([GM][^GM]+)', gcode, re.I))
        for line in tokens:
            if line.strip() != "":
                # print "Analyze ", line
                self.AnalyzeLine(
                    self.converter.convert(line))  # handles grbl-style code

        self.moveInMachineCoords = False  # this flag gets reset at the end of the gcode line

    def AnalyzeLine(self, gcode):
        self.lastMovementGCode = None  # by default, the move was not a g[0-3]; set it differently in case of actual movement gcode

        gcode = gcode.lstrip()
        if gcode.startswith("@"): return  # code is a host command

        code_g = findCode(gcode, "G")
        if '$H' in gcode:
            code_g = str(28)  # this is a homing command equivalent to g28
        code_m = findCode(gcode, "M")
        # we have a g_code
        if code_g != None:
            if '.' in code_g:  # codes like 38.2 were considered G0!
                code_g = safeFloat(code_g)
            else:
                code_g = safeInt(code_g)

            if (self.metric):
                metricConv = 1
            else:
                metricConv = 25.4

            # get movement codes
            if code_g == 0 or code_g == 1 or code_g == 2 or code_g == 3:
                self.lastX = self.x
                self.lastY = self.y
                self.lastZ = self.z
                self.lastE = self.e
                eChanged = False
                code_f = findCode(gcode, "F")
                if code_f != None:
                    self.f = safeFloat(code_f) * metricConv

                code_x = findCode(gcode, "X")
                code_y = findCode(gcode, "Y")
                code_z = findCode(gcode, "Z")
                code_e = findCode(gcode, "E")

                if self.moveInMachineCoords:  # convert the machine coords move to work coords
                    print "Move is in machine coords!"
                    if code_x is not None:
                        code_x = safeFloat(code_x) + self.xOffset

                    if code_y is not None:
                        code_y = safeFloat(code_y) + self.yOffset

                    if code_y is not None:
                        code_z = safeFloat(code_z) + self.zOffset

                code_i = findCode(gcode, "I")
                code_j = findCode(gcode, "J")

                self.lastMovementGCode = MovementGCode(code_g)
                self.lastMovementGCode.startX = self.lastX / metricConv
                self.lastMovementGCode.startY = self.lastY / metricConv
                self.lastMovementGCode.startZ = self.lastZ / metricConv
                self.lastMovementGCode.x = safeFloat(
                    code_x or self.lastX / metricConv)
                self.lastMovementGCode.y = safeFloat(
                    code_y or self.lastY / metricConv)
                self.lastMovementGCode.z = safeFloat(
                    code_z or self.lastZ / metricConv)
                if code_g == 2 or code_g == 3:
                    self.lastMovementGCode.i = safeFloat(code_i)
                    self.lastMovementGCode.j = safeFloat(code_j)

                if code_e:
                    self.lastMovementGCode.e = safeFloat(code_e)

                if code_f:
                    self.lastMovementGCode.f = safeFloat(code_f)

                if self.relative:
                    if code_x != None: self.x += safeFloat(code_x) * metricConv
                    if code_y != None: self.y += safeFloat(code_y) * metricConv
                    if code_z != None: self.z += safeFloat(code_z) * metricConv
                    if code_e != None:
                        e = safeFloat(code_e) * metricConv
                        if e != 0:
                            eChanged = True
                            self.e += e
                else:
                    # absolute coordinates
                    if code_x != None: self.x = safeFloat(code_x) * metricConv
                    if code_y != None: self.y = safeFloat(code_y) * metricConv
                    if code_z != None: self.z = safeFloat(code_z) * metricConv
                    if code_e != None:
                        e = safeFloat(code_e) * metricConv
                        if self.eRelative:
                            if e != 0:
                                eChanged = True
                                self.e += e
                        else:
                            # e is absolute. Is it changed?
                            if self.e != self.eOffset + e:
                                eChanged = True
                                self.e = self.eOffset + e
                # bbox calculation
                if self.x < self.minX: self.minX = self.x
                if self.y < self.minY: self.minY = self.y
                if self.z < self.minZ: self.minZ = self.z

                if self.x > self.maxX: self.maxX = self.x
                if self.y > self.maxY: self.maxY = self.y
                if self.z > self.maxZ: self.maxZ = self.z

                travel_len = 0
                travel_time = 0
                # calculate travelled distance. Quite time consuming, so only do it if needed.
                if self.calculateTravel:
                    if code_g == 0 or code_g == 1:
                        travel_len = euclidean_distance(
                            (self.lastX, self.lastY, self.lastZ),
                            (self.x, self.y, self.z))
                        if code_g == 0:
                            travel_time = travel_len / self.fastf
                        else:
                            travel_time = travel_len / self.f
                    else:
                        # it's an arc: get the center
                        centerX = self.lastX + safeFloat(code_i) * metricConv
                        centerY = self.lastY + safeFloat(code_j) * metricConv
                        ccw = True if code_g == 3 else False  # g3 is counter clockwise arc
                        travel_len = arc_distance((centerX, centerY),
                                                  (self.lastX, self.lastY),
                                                  (self.x, self.y), ccw)
                        travel_time = travel_len / self.f

                self.travel += travel_len
                self.time += travel_time

                # Repetier has a bunch of limit-checking code here and time calculations: we are leaving them for now
            elif code_g == 20:
                self.metric = False
            elif code_g == 21:
                self.metric = True
            elif code_g == 28 or code_g == 161:
                self.lastX = self.x
                self.lastY = self.y
                self.lastZ = self.z
                self.lastE = self.e
                code_x = findCode(gcode, "X")
                code_y = findCode(gcode, "Y")
                code_z = findCode(gcode, "Z")
                code_e = findCode(gcode, "E")
                homeAll = False
                if code_x == None and code_y == None and code_z == None:
                    homeAll = True
                if code_x != None or homeAll:
                    self.hasHomeX = True
                    self.xOffset = 0
                    self.x = self.homeX
                if code_y != None or homeAll:
                    self.hasHomeY = True
                    self.yOffset = 0
                    self.y = self.homeY
                if code_z != None or homeAll:
                    self.hasHomeZ = True
                    self.zOffset = 0
                    self.z = self.homeZ
                if code_e != None:
                    self.eOffset = 0
                    self.e = 0
            # elif code_g == 162:
            #     self.lastX = self.x
            #     self.lastY = self.y
            #     self.lastZ = self.z
            #     self.lastE = self.e
            #     code_x = findCode(gcode, "X")
            #     code_y = findCode(gcode, "Y")
            #     code_z = findCode(gcode, "Z")
            #     homeAll = False
            #     if code_x == None and code_y == None and code_z == None: homeAll = True
            #     if code_x != None or homeAll:
            #         self.hasHomeX = True
            #         self.xOffset = 0
            #         self.x = self.axisMaxX
            #     if code_y != None or homeAll:
            #         self.hasHomeY = True
            #         self.yOffset = 0
            #         self.y = self.axisMaxY
            #     if code_z != None or homeAll:
            #         self.hasHomeZ = True
            #         self.zOffset = 0
            #         self.z = self.axisMaxZ
            elif code_g == 53:
                self.moveInMachineCoords = True
            elif code_g == 90:
                self.relative = False
            elif code_g == 91:
                self.relative = True
            elif code_g == 92 or code_g == 10:
                code_x = findCode(gcode, "X")
                code_y = findCode(gcode, "Y")
                code_z = findCode(gcode, "Z")
                code_e = findCode(gcode, "E")

                current_machine_coords = self.getMachineXYZ()

                if code_x != None:
                    self.x = safeFloat(code_x) * metricConv

                if code_y != None:
                    self.y = safeFloat(code_y) * metricConv

                if code_z != None:
                    self.z = safeFloat(code_z) * metricConv

                if code_e != None:
                    self.e = safeFloat(code_e) * metricConv

                #redefine offsets x = machine_x + offset => offset = x - machine_x
                self.xOffset = self.x - current_machine_coords[0]
                self.yOffset = self.y - current_machine_coords[1]
                self.zOffset = self.z - current_machine_coords[2]

                # the following code is correct for 3D printers and Marlin. With Grbl, the position is factually redefined
                # if code_x != None:
                #   self.xOffset = self.x - safeFloat(code_x)
                #   self.x = self.xOffset
                # if code_y != None:
                #   self.yOffset = self.y - safeFloat(code_y)
                #   self.y = self.yOffset
                # if code_z != None:
                #   self.zOffset = self.z - safeFloat(code_z)
                #   self.z = self.zOffset
                # if code_e != None:
                #   self.eOffset = self.e - safeFloat(code_e)
                #   self.e = self.eOffset
        if code_m != None:
            code_m = safeInt(code_m)
            if code_m == 82:
                self.eRelative = False
            elif code_m == 83:
                self.eRelative = True

    #    self.print_status()

    def getMachineXYZ(self):
        return self.x - self.xOffset, self.y - self.yOffset, self.z - self.zOffset

    def getWorkXYZ(self):
        return self.x, self.y, self.z

    def syncStatusWithGrbl(self, grblMachineStatus, grblWorkStatus=None):
        if grblWorkStatus is None:
            # we only have one status report. Update the correct coordinates
            if grblMachineStatus['type'] == 'Work':
                self.x, self.y, self.z = grblWorkStatus['position']
            else:
                self.x = grblMachineStatus['position'][0] + self.xOffset
                self.y = grblMachineStatus['position'][1] + self.yOffset
                self.z = grblMachineStatus['position'][2] + self.zOffset
        else:
            self.x, self.y, self.z = grblWorkStatus['position']

            self.xOffset = grblWorkStatus['position'][0] - grblMachineStatus[
                'position'][0]
            self.yOffset = grblWorkStatus['position'][1] - grblMachineStatus[
                'position'][1]
            self.zOffset = grblWorkStatus['position'][2] - grblMachineStatus[
                'position'][2]

    def getBoundingBox(self):
        return (self.minX, self.minY, self.minZ), (self.maxX, self.maxY,
                                                   self.maxZ)

    def getPosition(self):
        return (self.x, self.y, self.z)

    def getTravelLen(self):
        return self.travel

    def getTravelTime(self):
        return self.time

    def print_status(self):
        attrs = vars(self)
        print '\n'.join("%s: %s" % item for item in attrs.items())

    # returns true if the last move intersected the x value
    def intersected(self, xValue):
        if self.lastMovementGCode is None: return False
        if (self.lastX <= xValue
                and self.x >= xValue) or (self.lastX >= xValue
                                          and self.x <= xValue):
            return True
        return False

    # returns -1 if the last movement was towards -x, +1 if it was towards +x, 0 otherwise
    def movementDirection(self):
        if self.lastMovementGCode is None: return 0
        if self.lastX < self.x: return 1
        if self.lastX > self.x: return -1
        return 0