def __init__(self): if(platform.system() == 'Linux'): self.serial = serial.Serial ("/dev/ttyAMA0", self.BAUDRATE, timeout=1) # open the serial "/dev/ttyAMA0" self.svg2plt = SVG2PLT() self.plt = PLT() self.home()
class Cutter: # PLT and SVG plt = None svg = None # CONSTANTS MAX_X = 10000 # maximum distance on the X axis MAX_Y = 10000 # maximum distance on the Y axis BAUDRATE = 57600 # baudrate for the serial port comms # The current location of the head on the x, y axis current_x = 0 current_y = 0 step_size = 100 # the number of positions to move with user control passes = 1 # the number of times to cut the shape scale = 1.0 # Up speed - speed that the machine moves while up # us <1-40> up_speed = 40 # Down speed - speed that the machine moves while down # ds <1-40> down_speed = 40 # Plunge speed - speed at which the tool is lowered # ps <1-40> plunge_speed = 40 # Lift speed - speed at which the tool is raised # ls <1-40> lift_speed = 40 # Depth - default tool depth while down # dp <1-670> cutting_depth = 300 # Up lift - Lift tool by an extra amount while up (for special cases) # ul <0-300> up_lift = 0 # Up/down state - Value is 1 if up, 0 if down # returned: up=<0/1>; up = None # Tool - Value is 0 for left tool or 1 for right tool # tool <0/1> # returned: tool=<0/1>; current_tool = 0 serial = None # CONSTRUCTOR def __init__(self): if (platform.system() == 'Linux'): self.serial = False #self.serial = serial.Serial ("/dev/ttyAMA0", self.BAUDRATE, timeout=1) # open the serial "/dev/ttyAMA0" self.svg2plt = SVG2PLT() self.plt = PLT() self.home() def __del__(self): if (platform.system() == 'Linux' and self.serial != False): self.serial.close() # home the cutter location def home(self): self.current_x = 0 self.current_y = 0 self.move(self.current_x, self.current_y) # change a setting variable def change_setting(self, setting, value): setattr(self, setting, float(value)) print(setting + ":" + value) # load a file def load_file(self, filename='./static/svg/pattern.svg'): self.svg2plt.load_file(filename) self.svg2plt.parse() self.plt = self.svg2plt.plt # TODO: i'm not completely happy with this idea self.plt.reset_settings() output = self.display_dimensions() return (json.dumps(output)) # send the PLT to the cutter def cut(self): self.plt.scale = self.scale output = self.plt.build() print(output) for line in output: response = self.send(line) def move_direction(self, direction): if (direction == 'N'): self.move((self.step_size * -1), 0) elif (direction == 'S'): self.move(self.step_size, 0) elif (direction == 'E'): self.move(0, (self.step_size * -1)) elif (direction == 'W'): self.move(0, self.step_size) def move(self, x, y): next_x = self.current_x + x next_y = self.current_y + y if (next_x < 0): next_x = 0 elif (next_x > self.MAX_X): next_x = self.MAX_X if (next_y < 0): next_y = 0 elif (next_y > self.MAX_Y): next_y = self.MAX_Y command = Coord('U', next_x, next_y) response = self.send(str(command)) if (response): self.current_x = next_x self.current_y = next_y self.plt.x_offset = self.current_x # TODO: I'm not sure this is the right place to do this. self.plt.y_offset = self.current_y # send a string to the serial port and read the response def send(self, command): if (platform.system() == 'Linux' and self.serial != False): response = self.serial.write(command.encode('utf-8')) else: response = 1 return (response) def display_dimensions(self): if (self.plt.display_units == "mm"): output = { "width": format(self.plt.display_width * 25.4, '.1f'), "height": format(self.plt.display_height * 25.4, '.1f'), "units": self.plt.display_units } else: output = { "width": self.plt.display_width, "height": self.plt.display_height, "units": self.plt.display_units } return (json.dumps(output))
class Cutter: # PLT and SVG plt = None svg = None # CONSTANTS MAX_X = 10000 # maximum distance on the X axis MAX_Y = 10000 # maximum distance on the Y axis BAUDRATE = 57600 # baudrate for the serial port comms # The current location of the head on the x, y axis current_x = 0 current_y = 0 step_size = 100 # the number of positions to move with user control passes = 1 # the number of times to cut the shape scale = 1.0 # Up speed - speed that the machine moves while up # us <1-40> up_speed = 40 # Down speed - speed that the machine moves while down # ds <1-40> down_speed = 40 # Plunge speed - speed at which the tool is lowered # ps <1-40> plunge_speed = 40 # Lift speed - speed at which the tool is raised # ls <1-40> lift_speed = 40 # Depth - default tool depth while down # dp <1-670> cutting_depth = 300 # Up lift - Lift tool by an extra amount while up (for special cases) # ul <0-300> up_lift = 0 # Up/down state - Value is 1 if up, 0 if down # returned: up=<0/1>; up = None # Tool - Value is 0 for left tool or 1 for right tool # tool <0/1> # returned: tool=<0/1>; current_tool = 0 serial = None # CONSTRUCTOR def __init__(self): if(platform.system() == 'Linux'): self.serial = serial.Serial ("/dev/ttyAMA0", self.BAUDRATE, timeout=1) # open the serial "/dev/ttyAMA0" self.svg2plt = SVG2PLT() self.plt = PLT() self.home() def __del__(self): if(platform.system() == 'Linux'): self.serial.close() # home the cutter location def home(self): self.current_x = 0 self.current_y = 0 self.move(self.current_x, self.current_y) # change a setting variable def change_setting(self, setting, value): setattr(self, setting, float(value)) print(setting+":"+value) # load a file def load_file(self, filename='./static/svg/pattern.svg'): self.svg2plt.load_file(filename) self.svg2plt.parse() self.plt = self.svg2plt.plt # TODO: i'm not completely happy with this idea self.plt.reset_settings() output = self.display_dimensions() return(json.dumps(output)) # send the PLT to the cutter def cut(self): self.plt.scale = self.scale output = self.plt.build() print(output) for line in output: response = self.send(line) def move_direction(self, direction): if(direction=='N'): self.move((self.step_size*-1), 0) elif(direction=='S'): self.move(self.step_size, 0) elif(direction=='E'): self.move(0, (self.step_size*-1)) elif(direction=='W'): self.move(0, self.step_size) def move(self, x, y): next_x = self.current_x + x next_y = self.current_y + y if(next_x<0): next_x = 0 elif(next_x>self.MAX_X): next_x = self.MAX_X if(next_y<0): next_y = 0 elif(next_y>self.MAX_Y): next_y = self.MAX_Y command = Coord('U', next_x, next_y) response = self.send(str(command)) if(response): self.current_x = next_x; self.current_y = next_y; self.plt.x_offset = self.current_x # TODO: I'm not sure this is the right place to do this. self.plt.y_offset = self.current_y # send a string to the serial port and read the response def send(self, command): if(platform.system() == 'Linux'): response = self.serial.write(command.encode('utf-8')) else: response = 1 return(response) def display_dimensions(self): if(self.plt.display_units == "mm"): output = {"width":format(self.plt.display_width*25.4, '.1f'),"height":format(self.plt.display_height*25.4, '.1f'),"units":self.plt.display_units} else: output = {"width":self.plt.display_width,"height":self.plt.display_height,"units":self.plt.display_units} return(json.dumps(output))
class SVG2PLT: # the PLT object for operations and export plt = None # SVG path objects paths = None delimiter = 'z' # path delimiter (mM -> zZ) divisions = 30.0 # the number of point divisions on an element overcut = 0.2 # how much to overcut the next shape (TODO: units for now as percentage. could be a percentage of the line, could be mm?) def __init__(self): self.paths = [] self.plt = PLT() # open a file with name 'filename', extract the path elements def load_file(self, filename): #read the svg doc as a DOM to extract the XML <path> element doc = xml.dom.minidom.parse(filename) # determine the ratio of each pixel to real world units svg = doc.getElementsByTagName('svg')[0] #get the units for this file height = svg.getAttribute('height') width = svg.getAttribute('width') if(height.find("in")!=-1): self.display_units = "in" elif(height.find("mm")!=-1): self.display_units = "mm" elif(height.find("cm")!=-1): self.display_units = "cm" elif(height.find("px")!=-1): self.display_units = "px" height = height.replace(self.display_units, "") width = width.replace(self.display_units, "") viewbox = svg.getAttribute('viewBox').rsplit(" ") self.unit = (float(width)/float(viewbox[2]) + float(height)/float(viewbox[3]))/2 self.plt.display_units = self.display_units # extract the path elements path_strings = [path.getAttribute('d') for path in doc.getElementsByTagName('path')] # iterate over each path that is found for path_string in path_strings: # break up each path shape into the individual lines (mM -> zZ) lines = re.split('z|Z', path_string) for line in lines: if(len(line)>2): line += self.delimiter item = parse_path(line) # convert the string to a path using svg.path library self.paths.append(item) # load the file def parse(self): for path in self.paths: self.parse_path(path) if(path.closed==True): self.parse_overcut(path) self.plt.calc_bounding_box() # parse a path def parse_path(self, path): first = True for item in path: self.parse_item(item, first) if(first): first = False; # parse an item (line, cubic, quadratic bezier) def parse_item(self, item, first): for i in range(0, int(self.divisions)): loc = i/self.divisions point = item.point(loc) if(first and i==0): self.plt.add_coord('U', point.real, point.imag) self.plt.add_coord('D', point.real, point.imag) # parse a the first item in a path for overcut (line, cubic, quadratic bezier) def parse_overcut(self, path): item = path[0] for i in range(0, int(self.divisions*self.overcut)): loc = i/self.divisions point = item.point(loc) self.plt.add_coord('D', point.real, point.imag)
def __init__(self): self.paths = [] self.plt = PLT()