Parcourir la source

Cleaned up G-code parser. Fixed dwell command. Fixes #184.

Juan Pablo Caram il y a 9 ans
Parent
commit
d1442a4900
2 fichiers modifiés avec 32 ajouts et 62 suppressions
  1. 9 1
      FlatCAMObj.py
  2. 23 61
      camlib.py

+ 9 - 1
FlatCAMObj.py

@@ -1038,6 +1038,11 @@ class FlatCAMCNCjob(FlatCAMObj, CNCjob):
         self.export_gcode(filename, preamble=preamble, postamble=postamble)
         self.export_gcode(filename, preamble=preamble, postamble=postamble)
 
 
     def dwell_generator(self, lines):
     def dwell_generator(self, lines):
+        """
+        Inserts "G4 P..." instructions after spindle-start
+        instructions (M03 or M04).
+
+        """
 
 
         log.debug("dwell_generator()...")
         log.debug("dwell_generator()...")
 
 
@@ -1060,7 +1065,7 @@ class FlatCAMCNCjob(FlatCAMObj, CNCjob):
             # If start spindle, buffer a G4.
             # If start spindle, buffer a G4.
             if m3m4re.search(line):
             if m3m4re.search(line):
                 log.debug("Found M03/4")
                 log.debug("Found M03/4")
-                bufline = "G4 {}\n".format(self.options['dwelltime'])
+                bufline = "G4 P{}\n".format(self.options['dwelltime'])
 
 
             yield line
             yield line
 
 
@@ -1070,10 +1075,13 @@ class FlatCAMCNCjob(FlatCAMObj, CNCjob):
 
 
         lines = StringIO(self.gcode)
         lines = StringIO(self.gcode)
 
 
+        ## Post processing
+        # Dwell?
         if self.options['dwell']:
         if self.options['dwell']:
             log.debug("Will add G04!")
             log.debug("Will add G04!")
             lines = self.dwell_generator(lines)
             lines = self.dwell_generator(lines)
 
 
+        ## Write
         with open(filename, 'w') as f:
         with open(filename, 'w') as f:
             f.write(preamble + "\n")
             f.write(preamble + "\n")
 
 

+ 23 - 61
camlib.py

@@ -9,6 +9,7 @@
 #from scipy import optimize
 #from scipy import optimize
 #import traceback
 #import traceback
 
 
+from cStringIO import StringIO
 from numpy import arctan2, Inf, array, sqrt, pi, ceil, sin, cos, dot, float32, \
 from numpy import arctan2, Inf, array, sqrt, pi, ceil, sin, cos, dot, float32, \
     transpose
     transpose
 from numpy.linalg import solve, norm
 from numpy.linalg import solve, norm
@@ -3024,67 +3025,25 @@ class CNCjob(Geometry):
         self.gcode += "G00 X0Y0\n"
         self.gcode += "G00 X0Y0\n"
         self.gcode += "M05\n"  # Spindle stop
         self.gcode += "M05\n"  # Spindle stop
 
 
-    def pre_parse(self, gtext):
+    @staticmethod
+    def codes_split(gline):
         """
         """
-        Separates parts of the G-Code text into a list of dictionaries.
-        Used by ``self.gcode_parse()``.
+        Parses a line of G-Code such as "G01 X1234 Y987" into
+        a dictionary: {'G': 1.0, 'X': 1234.0, 'Y': 987.0}
 
 
-        :param gtext: A single string with g-code
+        :param gline: G-Code line string
+        :return: Dictionary with parsed line.
         """
         """
 
 
-        log.debug("pre_parse()")
-
-        # Units: G20-inches, G21-mm
-        units_re = re.compile(r'^G2([01])')
-
-        # TODO: This has to be re-done
-        gcmds = []
-        lines = gtext.split("\n")  # TODO: This is probably a lot of work!
-        for line in lines:
-            # Clean up
-            line = line.strip()
+        command = {}
 
 
-            # Remove comments
-            # NOTE: Limited to 1 bracket pair
-            op = line.find("(")
-            cl = line.find(")")
-            #if op > -1 and  cl > op:
-            if cl > op > -1:
-                #comment = line[op+1:cl]
-                line = line[:op] + line[(cl+1):]
-
-            # Units
-            match = units_re.match(line)
-            if match:
-                self.units = {'0': "IN", '1': "MM"}[match.group(1)]
-
-            # Parse GCode
-            # 0   4       12
-            # G01 X-0.007 Y-0.057
-            # --> codes_idx = [0, 4, 12]
-            codes = "NMGXYZIJFPST"
-            codes_idx = []
-            i = 0
-            for ch in line:
-                if ch in codes:
-                    codes_idx.append(i)
-                i += 1
-            n_codes = len(codes_idx)
-            if n_codes == 0:
-                continue
+        match = re.search(r'^\s*([A-Z])\s*([\+\-\.\d\s]+)', gline)
+        while match:
+            command[match.group(1)] = float(match.group(2).replace(" ", ""))
+            gline = gline[match.end():]
+            match = re.search(r'^\s*([A-Z])\s*([\+\-\.\d\s]+)', gline)
 
 
-            # Separate codes in line
-            parts = []
-            for p in range(n_codes - 1):
-                parts.append(line[codes_idx[p]:codes_idx[p+1]].strip())
-            parts.append(line[codes_idx[-1]:].strip())
-
-            # Separate codes from values
-            cmds = {}
-            for part in parts:
-                cmds[part[0]] = float(part[1:])
-            gcmds.append(cmds)
-        return gcmds
+        return command
 
 
     def gcode_parse(self):
     def gcode_parse(self):
         """
         """
@@ -3097,11 +3056,7 @@ class CNCjob(Geometry):
 
 
         # Results go here
         # Results go here
         geometry = []        
         geometry = []        
-        
-        # TODO: Merge into single parser?
-        gobjs = self.pre_parse(self.gcode)
 
 
-        log.debug("gcode_parse(): pre_parse() done.")
         # Last known instruction
         # Last known instruction
         current = {'X': 0.0, 'Y': 0.0, 'Z': 0.0, 'G': 0}
         current = {'X': 0.0, 'Y': 0.0, 'Z': 0.0, 'G': 0}
 
 
@@ -3110,7 +3065,14 @@ class CNCjob(Geometry):
         path = [(0, 0)]
         path = [(0, 0)]
 
 
         # Process every instruction
         # Process every instruction
-        for gobj in gobjs:
+        for line in StringIO(self.gcode):
+
+            gobj = self.codes_split(line)
+
+            ## Units
+            if 'G' in gobj and (gobj['G'] == 20.0 or gobj['G'] == 21.0):
+                self.units = {20.0: "IN", 21.0: "MM"}[gobj['G']]
+                continue
 
 
             ## Changing height
             ## Changing height
             if 'Z' in gobj:
             if 'Z' in gobj:
@@ -3154,7 +3116,7 @@ class CNCjob(Geometry):
                     center = [gobj['I'] + current['X'], gobj['J'] + current['Y']]
                     center = [gobj['I'] + current['X'], gobj['J'] + current['Y']]
                     radius = sqrt(gobj['I']**2 + gobj['J']**2)
                     radius = sqrt(gobj['I']**2 + gobj['J']**2)
                     start = arctan2(-gobj['J'], -gobj['I'])
                     start = arctan2(-gobj['J'], -gobj['I'])
-                    stop = arctan2(-center[1]+y, -center[0]+x)
+                    stop = arctan2(-center[1] + y, -center[0] + x)
                     path += arc(center, radius, start, stop,
                     path += arc(center, radius, start, stop,
                                 arcdir[current['G']],
                                 arcdir[current['G']],
                                 self.steps_per_circ)
                                 self.steps_per_circ)