示例#1
0
class StateMachinePygcode(StateMachineBase):
    """ State Machine reflecting the state of a pygcode virtual machine.
        https://github.com/fragmuffin/pygcode/wiki/Interpreting-gcode """
    def __init__(self, on_update_callback: Callable[[str, Any], None]) -> None:
        super().__init__(on_update_callback)
        self._virtual_cnc = Machine()

    def update(self) -> None:
        """ Populate this state machine values from self._virtual_cnc. """
        self._parse_modal()
        self.machine_pos = self._virtual_cnc.pos.values
        self.feed_rate = self._virtual_cnc.mode.feed_rate.word.value

    def _parse_modal(self) -> None:
        """ Update current modal group values. """
        for modal in self._virtual_cnc.mode.gcodes:
            modal_bytes = str(modal).encode('utf-8')
            if modal_bytes in self.MODAL_COMMANDS:
                modal_group = self.MODAL_COMMANDS[modal_bytes]
                self.gcode_modal[modal_group] = modal_bytes
            elif chr(modal_bytes[0]).encode('utf-8') in self.MODAL_COMMANDS:
                modal_group = self.MODAL_COMMANDS[chr(
                    modal_bytes[0]).encode('utf-8')]
                self.gcode_modal[modal_group] = modal_bytes
            else:
                print("TODO: ", modal)
        # print(self.gcode_modal)

    def proces_gcode(self, gcode_block: Block) -> None:
        """ Have the pygcode VM parse incoming gcode. """
        self._virtual_cnc.process_block(gcode_block)
示例#2
0
def list(args, gcodes, clearance_height):
  m = Machine()
  print("The line numbers where a cut is possible are:")
  for gcode in gcodes:
    m.process_gcodes(gcode['gcode'])
    if clearance_height == m.pos._value['Z']:
      print("  {:7} at {:6.2f}% in {}".format(gcode["line_no"], gcode["line_no"]*100/gcodes[-1]["line_no"],m.pos))
示例#3
0
 def readGcode(self, filepath):
     m = Machine()
     with open(filepath, 'r') as fh:
         for line_text in fh.readlines():
             self.traj.append((m.pos.values['X'], m.pos.values['Y']))
             line = Line(line_text)
             m.process_block(line.block)
示例#4
0
    def __init__(self, gcode):

        self.gcode = gcode
        # gcode stored in plain text or whatever

        self.all_positions = []
        # list of every xyz position the gcode contains, including 'strokes' and 'seeks'. without separating strokes and
        # seeks, the order of the self.all_positions cannot be changed

        self.machine = Machine()
        # Virtual machine that will simulate running the gcode and extract coordinates

        self.cities = []
        # in TSP parlance, each uninterrupted line to be drawn on the paper is considered a city
        # unlike usual TSP, our cities must have a different start and end rather than being a single point
        # therefore each city is a list coordinates.

        self.cities_lite = []
        # in order to find the best tour we only need the start and end points of each city.
        # we will need the whole city only when we come to output new gcode one day.
        # so to keep it lite we strip all the in between coordinates plus the z values
        # also format the data as a simple array for numpy reasons
        # format is [startX, startY, endX, endY]

        self.seek_threshold = self.guess_seek_threshold()
        print('seek threshold is', self.seek_threshold)
        # if the Z position of the pen is above this value, we will assume it's a seek (flight), not a stroke (city)

        # self.original_tour = [x for x in range(len(self.cities_lite))]
        # in TSP parlance the tour is the order in which we visit the cities, ie the whole thing we want to find
        # we keep the original order of strokes for reference

        self.parse()
示例#5
0
def getClearanceHeight(gcodes):
  m = Machine()  
  last = m.pos
  clearance_height = m.pos._value['Z']
  for gcode in gcodes:
    m.process_gcodes(gcode['gcode'])
    if clearance_height < m.pos._value['Z']: clearance_height = m.pos._value['Z']
  return clearance_height
示例#6
0
 def __init__(self):
     self.state_pos = {
         'state': IDLE,
         'mpos': [0.000, 0.000, 0.000],
         'wpos': [0.000, 0.000, 0.000],
         'plan buf': 0,
         'rx buf': 0
     }
     self.mach = Machine()
示例#7
0
def get_positions(data):
    t1 = dt.now()
    machine = Machine()
    positions = []
    last = []
    for i in data.split('\n'):
        line = Line(i)
        block = line.block.gcodes
        for g in block:
            machine.process_gcodes(g)
            keys = []
            for key in machine.pos.values.keys():

                keys.append(machine.pos.values[key])
            #positions.append(keys)
            position = machine.pos.values
            if position != last:
                positions.append(position)
            last = position
    timer(t1, "processing gcode")


    return positions
示例#8
0
def cut(args, gcodes, clearance_height):
  non_motion = []
  
  # Select where to cut
  m = Machine()
  last = m.pos
  checkpoint = {'gcode': None, 'pos': m.pos, 'mode': m.mode.distance}
  for idx, gcode in enumerate(gcodes):
    m.process_gcodes(gcode['gcode'])
    if gcode["line_no"] > args.line:
      break
    if m.pos == last: non_motion.append(gcode)
    last = m.pos
    if clearance_height == m.pos._value['Z']:
      checkpoint = {'idx': idx, 'gcode': gcode, 'pos': m.pos, 'mode': m.mode.distance}
      
  #print("Checkpoint at {}".format(checkpoint))
  
  # If the user wants to cut before the first clearance height, do nothing
  if checkpoint['gcode'] is None:
    print("The provided line is not a valid one, use list subcommand for more info. Exiting")
    return
    
  # Dump the non motion commands first
  for gcode in non_motion:
   # if not isinstance(gcode['gcode'], GCodeFeedRate):  # Ignore feedrates please
      print(FORMAT.format(str(gcode['gcode']), str(gcode['line_no']), gcode['gcode'].__class__.__name__), file=args.output)
   
  # Insert the travel until the checkpoint position
  gcode = GCodeAbsoluteDistanceMode()
  print(FORMAT.format(str(gcode), "Cut comp.", gcode.__class__.__name__), file=args.output)
  gcode = GCodeRapidMove(Z=clearance_height)
  print(FORMAT.format(str(gcode), "Cut comp.", gcode.__class__.__name__), file=args.output)
  gcode = GCodeRapidMove(X=checkpoint['pos']._value['X'], Y=checkpoint['pos']._value['Y'], Z=checkpoint['pos']._value['Z'])
  print(FORMAT.format(str(gcode), "Cut comp.", gcode.__class__.__name__), file=args.output)
  gcode = checkpoint['mode']
  print(FORMAT.format(str(gcode), "Cut comp.", gcode.__class__.__name__), file=args.output)
  print(CHECKPOINT_TAG, file=args.output)
      
  # Dump the rest of the codes from the original file (to preserve formatting)
  try: 
    args.input.seek(gcodes[checkpoint['idx']+1]['offset'])
    for line in args.input:
      print(line, file=args.output, end="")
  except: pass
  
  if args.verify:
    s = Machine()
    t = Machine()
    
    # Run input gcodes until the selected
    for gcode in gcodes[:checkpoint['idx']+1]:
      s.process_gcodes(gcode['gcode'])
    
    # Run output gcodes until checkpoint
    args.output.seek(0)
    line = args.output.readline()
    while line:
      if CHECKPOINT_TAG in line:
        break
      for gcode in Line(line).block.gcodes:
        t.process_gcodes(gcode)
      line = args.output.readline()

    args.input.seek(gcodes[checkpoint['idx']+1]['offset'])
    sline = args.output.readline()
    tline = args.input.readline()
    while sline and tline:
      for gcode in Line(sline).block.gcodes: s.process_gcodes(gcode)
      for gcode in Line(tline).block.gcodes: t.process_gcodes(gcode)
      if s.pos!=t.pos:
        print("\nOutput gcode not verified (source: {}, target: {})".format(s.pos, t.pos))
        return
      sline = args.output.readline()
      tline = args.input.readline()
        
    print("\nOutput gcode verified")
示例#9
0
class parse_gcode(object):

    def __init__(self, gcode):

        self.gcode = gcode
        # gcode stored in plain text or whatever

        self.all_positions = []
        # list of every xyz position the gcode contains, including 'strokes' and 'seeks'. without separating strokes and
        # seeks, the order of the self.all_positions cannot be changed

        self.machine = Machine()
        # Virtual machine that will simulate running the gcode and extract coordinates

        self.cities = []
        # in TSP parlance, each uninterrupted line to be drawn on the paper is considered a city
        # unlike usual TSP, our cities must have a different start and end rather than being a single point
        # therefore each city is a list coordinates.

        self.cities_lite = []
        # in order to find the best tour we only need the start and end points of each city.
        # we will need the whole city only when we come to output new gcode one day.
        # so to keep it lite we strip all the in between coordinates plus the z values
        # also format the data as a simple array for numpy reasons
        # format is [startX, startY, endX, endY]

        self.seek_threshold = self.guess_seek_threshold()
        print('seek threshold is', self.seek_threshold)
        # if the Z position of the pen is above this value, we will assume it's a seek (flight), not a stroke (city)

        # self.original_tour = [x for x in range(len(self.cities_lite))]
        # in TSP parlance the tour is the order in which we visit the cities, ie the whole thing we want to find
        # we keep the original order of strokes for reference

        self.parse()

    def parse(self):
        # use the machine to populate the all_positions variable with xyz coordinates
        t1 = dt.now()

        previous_position = []

        for i in self.gcode.split('\n'):
            line = Line(i)
            block = line.block.gcodes
            for g in block:
                self.machine.process_gcodes(g)
                keys = []
                for key in self.machine.pos.values.keys():
                    keys.append(self.machine.pos.values[key])
                this_position = self.machine.pos.values
                if this_position != previous_position:
                    self.all_positions.append(this_position)

                previous_position = this_position
        timer(t1, 'parsing')
        self.get_cities()
        return self.all_positions

    def guess_seek_threshold(self):

        minZ = 0
        maxZ = 0
        for i in self.all_positions:
            if "Z" in i.keys():
                minZ = min(minZ, i["Z"])
                maxZ = max(maxZ, i["Z"])
        return (minZ + maxZ) / 2

    def get_cities(self):

        this_city = []

        for x, this_position in enumerate(self.all_positions):
            if x == 0:
                pass
                # current_pos = self.all_positions[0]
                #
                # if current_pos['Z'] <= self.seek_threshold:
                #     this_city.append(this_position)
            else:
                if this_position['Z'] <= self.seek_threshold:
                    this_city.append(this_position)
                else:
                    if this_city:
                        self.cities.append(this_city)
                        this_city = []

        self.cities_lite = [[i[0]['X'], i[0]['Y'], i[-1]['X'], i[-1]['Y']] for i in self.cities]

        return self.cities
示例#10
0
 def __init__(self, on_update_callback: Callable[[str, Any], None]) -> None:
     super().__init__(on_update_callback)
     self._virtual_cnc = Machine()
示例#11
0
# requires PyGCode: pip3 install pygcode

from pygcode import GCodeRapidMove, GCodeLinearMove
from pygcode import Machine, Line, split_gcodes
m = Machine()
coordinates = []
pairs = []
with open('triangle.gcode', 'r') as fh:
    for line_text in fh.readlines():
        line = Line(line_text)
        line.block.gcodes  # list of gcodes
        if line.block.gcodes:  # not a blank line
            (befores, (g, ),
             afters) = split_gcodes(line.block.gcodes,
                                    (GCodeRapidMove, GCodeLinearMove))
            if g.X is not None:
                pairs = [g.X - 150, g.Y]
                coordinates.append(pairs)
print("Number of points:", len(coordinates))
print(coordinates)
with open('triangle.json', 'w') as fh:
    fh.write(repr(coordinates))

i = 0
for line in coordinates:
    print("G1", "X", coordinates[i][0], "Y", coordinates[i][1], "F2.0")
    i = i + 1
示例#12
0
from pygcode import Line
from pygcode import Machine, GCodeRapidMove
import re
import sys

m = Machine()
min_x = 0
max_x = 0
min_y = 0
max_y = 0
min_z = 0
max_z = 0


with open(sys.argv[1], 'r') as fh:
    for line_text in fh.readlines():
        ma = re.match(r'^M8.*$', line_text)
        if (ma):
            continue
        ma = re.match(r'^S.*$', line_text)
        if (ma):
            continue
        ma = re.search(r'\sG50\s', line_text)
        if (ma):
            line_text = re.sub(r'\sG50\s', '', line_text)
        line = Line(line_text)
        m.process_block(line.block)
        if (m.pos.X < min_x):
            min_x = m.pos.X
        if (m.pos.X > max_x):
            max_x = m.pos.X