Beispiel #1
0
    def test_weird_comments(self):
        gcode = GCode()
        gcode.load_file("gc_weird_comments.gcode")

        # check correct number of commands
        self.assertEqual(len(gcode._lines), 6)

        g_lines = 0
        for i in range(6):
            if gcode._lines[i].has_word("G"):
                g_lines += 1

                # check correct command recognition
                self.assertTrue(gcode._lines[i].get_word("G"), 1)

                # check if parameters were found
                self.assertEqual(gcode._lines[i].has_word("X"), True)
                self.assertEqual(gcode._lines[i].has_word("Y"), True)
                self.assertEqual(gcode._lines[i].has_word("E"), True)

                # check if values were found
                self.assertEqual(gcode._lines[i].get_word("X"), 50)
                self.assertEqual(gcode._lines[i].get_word("Y"), 50)
                self.assertEqual(gcode._lines[i].get_word("E"), 50.75)

            # check validity
            self.assertEqual(gcode._lines[i].is_valid(), True)

        self.assertEqual(g_lines, 4)

        for i in range(5):
            # check if a comment was found (last line has none there fore only range(5))
            self.assertNotEqual(gcode._lines[i].comment, None)
Beispiel #2
0
    def __init__(self, controller):
        super(Slic3rEngineRunner, self).__init__()
        self.is_running = True
        self.controller = controller

        self.gcode = GCode(self.controller.app_config.tmp_place + 'out.gcode',
                           self.controller, None, None)

        system_platform = platform.system()
        if system_platform in ['Linux']:
            self.slicer_place = ['/home/tibor/dev/Slic3r/bin/slic3r']
            #self.slicer_place = './tools/Slic3r-Lite/slic3r'
        elif system_platform in ['Darwin']:
            self.slicer_place = [
                self.controller.app_config.local_path +
                "tools/Slic3r-Lite/Slic3r.app/Contents/MacOS/Slic3r"
            ]
        elif system_platform in ['Windows']:
            self.slicer_place = ['tools\\Slic3r-Lite\\slic3r-noconsole.exe']
        else:
            self.slicer_place = ['slic3r']

        #print(self.slicer_place)

        self.step_max = 9
        self.step = 0
Beispiel #3
0
    def test_g01_equal_g1(self):
        gcode = GCode()
        gcode.load_file("gc_g1_equals_g01.gcode")

        self.assertEqual(len(gcode._lines), 3)  # three commands should be loaded

        for i in range(3):
            self.assertEqual(gcode._lines[i].get_word("G"), 1)
Beispiel #4
0
def load_text2(z):
    s = 0.3
    t1 = GCode.from_file('text/Home is where.nc').depth(G0Z, z)
    t2 = GCode.from_file('text/your stop is.nc').depth(G0Z, z)
    t1 = t1.scale(s, s)
    t2 = t2.scale(s, s)
    t1 = t1.move(3, 2.75, 0.5, 0.5)
    t2 = t2.move(3, 2.25, 0.5, 0.5)
    return t1 + t2
Beispiel #5
0
    def test_multi_int(self):
        gcode = GCode()
        gcode.load_file("gc_multi_int.gcode")

        # check correct number of commands
        self.assertEqual(len(gcode._lines), 12)

        cnt = 0
        for i in range(len(gcode._lines)):
            if gcode._lines[i].is_comment_only():
                cnt += 1

        self.assertEqual(cnt, 2)  # two lines should contain only a comment

        # check correct command recognition
        self.assertEqual(gcode._lines[1].get_word("G"), 1)
        self.assertEqual(gcode._lines[2].get_word("G"), 0)
        self.assertEqual(gcode._lines[3].get_word("G"), 10)
        self.assertEqual(gcode._lines[4].get_word("G"), 16)
        self.assertEqual(gcode._lines[5].get_word("G"), 1)
        self.assertEqual(gcode._lines[6].get_word("G"), 1)
        self.assertEqual(gcode._lines[7].get_word("G"), 1)

        self.assertEqual(gcode._lines[9].get_word("G"), 0)
        self.assertEqual(gcode._lines[10].get_word("G"), 1)
        self.assertEqual(gcode._lines[11].get_word("G"), 17)

        for i in range(1, 8):  # batch check for lines 1 to 7
            # check if parameters were found
            self.assertEqual(gcode._lines[i].has_word("X"), True)
            self.assertEqual(gcode._lines[i].has_word("Y"), True)

            # check if values were found
            self.assertEqual(gcode._lines[i].get_word("X"), 500)
            self.assertEqual(gcode._lines[i].get_word("Y"), 400)

            # check validity
            self.assertEqual(gcode._lines[i].is_valid(), True)

        for i in range(1,4):
            # check if comment was found by checking for "Test comment"
            self.assertEqual("Test comment" in gcode._lines[i].comment, True)

        ###################################
        # check the last three lines extra
        #
        # weird but valid line formatting (NIST example)
        self.assertEquals(gcode._lines[9].get_word("X"), 0.1234)
        self.assertEquals(gcode._lines[9].get_word("Y"), 7)

        # negative signs
        self.assertEqual(gcode._lines[10].get_word("X"), -5)
        self.assertEqual(gcode._lines[10].get_word("Y"), -0.17)

        # this is the no-hex-check
        self.assertEqual(gcode._lines[11].get_word("X"), 500)
        self.assertEqual(gcode._lines[11].get_word("Y"), 0)
Beispiel #6
0
def load_text1(z):
    s = 0.3
    t1 = GCode.from_file('text/TransLoc.nc').depth(G0Z, z)
    t2 = GCode.from_file('text/OnDemand.nc').depth(G0Z, z)
    t1 = t1.scale(s, s)
    t2 = t2.scale(s, s)
    t1 = t1.move(3 - 0.125, 6.75, 1, 0.5)
    t2 = t2.move(3 + 0.125, 6.75, 0, 0.5)
    return t1 + t2
    def load_data(self, filename):
        # initalizes a virtual machine from the gcode in the file given
        # all path data for this gcode is calculated; this is a cpu intensive task!
        self.gcode = GCode()
        self.gcode.load_file(filename)
        self.machine = Machine(self.gcode, self.profilecon)
        self.machine.create_path()

        # set the layer sliders maximum to represent the given amount of layers and enable the slider
        self.layerSlider.setMaximum(len(self.machine.layers) - 1)
        self.layerSlider.setEnabled(True)
Beispiel #8
0
	def run_file(self, fname):
		print("Currently not supported. Use the web interface!")
		return
		g = GCode(self.cfg, fname)
		g.set_zero_extruder(self.zero_extruder)
		m = Move(self.cfg, g, self.printer)
		self.preheat()
		self.sc = StepperCluster(self.audiodev, self.dim, self.cfg, m)
		self.sc.set_speed_scale(self.speed_scale)
		self.sc.set_max_feedrate(self.limit)
		self.scd = StepperClusterDispatcher(self.sc, self)
Beispiel #9
0
def create_piece(piece, mirror):
    bit_diameter = 0.125
    corner_radius = 0.1875
    groove_depth = 0.0625
    cells = [cell(x, y) for x, y in piece]
    mp = cascaded_union(cells).buffer(-corner_radius).buffer(corner_radius)
    g = GCode()
    for p in cells:
        g += GCode.from_geometry(p, G0Z, -groove_depth)
    g += GCode.from_geometry(mp.buffer(bit_diameter / 2), G0Z, -0.4, bit_diameter + 0.2, 3.5)
    if mirror:
        g = g.scale(-1, 1)
    g = g.origin()
    return g
Beispiel #10
0
def main():
    g0z = 0.2
    g1z = -0.01
    w = 32
    h = 6
    g = GCode()
    for i, (name, au, radius) in enumerate(PLANETS):
        p = (au + 0.25) / (PLANETS[-1][1] + 1)
        x = w * p
        t = GCode.from_file('text/%s.nc' % name)
        t = t.depth(0.2, -0.01)
        t = t.rotate(90).scale(0.2, 0.2)
        t = t.move(x, 0.75, 0.5, 0.5)
        _, ty1, _, ty2 = t.bounds
        g += t
        if i > 0:
            r = 1.2 * radius / 71492.68
            y1 = h / 2 - r
            y2 = h / 2 + r
            g += GCode(['G0 X%f Y%f' % (x, y1), 'G3 X%f Y%f I%f J%f' % (x, y2, 0, r), 'G3 X%f Y%f I%f J%f' % (x, y1, 0, -r)])
            g += GCode.from_points([(x, 0), (x, ty1 - 0.1)], g0z, g1z)
            g += GCode.from_points([(x, ty2 + 0.1), (x, y1-0.1)], g0z, g1z)
            g += GCode.from_points([(x, y2+0.1), (x, h)], g0z, g1z)
        else:
            g += GCode.from_points([(x, 0), (x, ty1 - 0.1)], g0z, g1z)
            g += GCode.from_points([(x, ty2 + 0.1), (x, h)], g0z, g1z)
    im = g.render(0, 0, 32, 6, 96)
    im.write_to_png('planets.png')
Beispiel #11
0
def generate_text(name, x, y, scale, angle):
    g = GCode.from_file('text/%s.nc' % name)
    g = g.depth(G0Z, G1Z_TEXT)
    g = g.scale(scale, scale)
    g = g.rotate(angle)
    g = g.move(x, y, 0.5, 0.5)
    return g
Beispiel #12
0
def coaster(style, side, corner_radius, circle_diameter, circle_depth, depth, bit):
    n = 120
    points = filled_circle(circle_diameter / 2.0 - bit / 2.0, n, bit / 4.0)
    g = GCode.from_points(points, G0Z, -circle_depth)
    if style == 1:
        points = rounded_square(side + bit, corner_radius)
    elif style == 2:
        points = circle(side / 2.0, n)
    elif style == 3:
        points = rounded_polygon(6, side / 2.0, corner_radius)
    elif style == 4:
        points = wavy_circle(side / 2.0, 360, 0.2, 7)
    else:
        raise Exception('invalid style')
    g += GCode.from_points(points, G0Z, -depth).multipass(G0Z, -depth, bit)
    return g.origin()
Beispiel #13
0
def parse(code, ifile, dump, ofile, stats, noopt):
    if not ifile and not code:
        print("Need either file or code")
        return -1

    if ifile:
        code = ifile.read()
    else:
        code = '\n'.join(code.split(';'))

    codes = parse_and_optimize(code, noopt)

    absolute = GStatement(GCode('G', 90))
    codes.insert(0, absolute)

    if stats:
        print(generate_stats(codes), file=sys.stderr)

    s = []
    for statement in codes:
        s.append(str(statement))

    if ofile:
        ofile.write('\n'.join(s))
    if dump:
        print('\n'.join(s), )
Beispiel #14
0
def load_letter(letter):
    if letter.isdigit():
        letter = 'NUM' + letter
    wkt = getattr(foam, letter)
    polygon = loads(wkt)
    g = GCode.from_geometry(polygon, 0.2, -0.1875)
    g = g.scale(6, 6).move(3, 4, 0.5, 0.5)
    return g
Beispiel #15
0
def load_marker(z):
    sx, sy = W / 600, H / 800
    s = min(sx, sy)
    polygon = loads(WKT)
    polygon = scale(polygon, s, s)
    polygon = polygon.buffer(0.125)
    g = GCode.from_geometry(polygon, G0Z, z)
    g = g.move(3, 4, 0.5, 0.5)
    return g
Beispiel #16
0
def create_mounts():
    a = 116.56505
    p = create_mount(5, 3.5, 1, 0.125, a)
    g = GCode.from_geometry(p, G0Z, -0.1)
    g1 = g.move(3, 0.25, 0.5, 0)
    g2 = g.origin().rotate(180).move(3, 5.5, 0.5, 1)
    g = g1 + g2
    g = g.depth(G0Z, -0.2) + g.depth(G0Z, -0.4) + g.depth(G0Z, -0.6)
    g = HEADER + g + FOOTER
    g.save('mounts.nc')
    im = g.render(0, 0, 6, 8, 96)
    im.write_to_png('mounts.png')
Beispiel #17
0
def create_supports():
    n = 18
    a = 116.56505
    p = create_support(1, 0.125, a)
    g = GCode.from_geometry(p, G0Z, -0.1)
    g = g.origin()
    g = pack_gcodes([g] * n, 6, 8, 0.125)[0]
    g = g.depth(G0Z, -0.2) + g.depth(G0Z, -0.4) + g.depth(G0Z, -0.6)
    g = HEADER + g + FOOTER
    g.save('supports.nc')
    im = g.render(0, 0, 6, 8, 96)
    im.write_to_png('supports.png')
Beispiel #18
0
    def GCodeInfo(self, gcodeFile):
        gcode = GCode(open(gcodeFile, "rU"))
        xdims = (gcode.xmin, gcode.xmax, gcode.width)
        ydims = (gcode.ymin, gcode.ymax, gcode.depth)
        zdims = (gcode.zmin, gcode.zmax, gcode.height)

        filamenUse = gcode.filament_length
        layersN =  gcode.layers_count
        estimateTime =  gcode.estimate_duration()[1]

        gridData = [
            ['GCode', gcodeFile],
            ['Dimensions X', ("Min %0.02f - Max %0.02f (%0.02f)" % xdims)],
            ['Dimensions Y', ("Min %0.02f - Max %0.02f (%0.02f)" % ydims)],
            ['Dimensions Z', ("Min %0.02f - Max %0.02f (%0.02f)" % zdims)],
            ['Filament used', ("%0.02f mm - %0.02f cm" % (filamenUse, filamenUse/100))],
            ['Number of layers', (" %d" % layersN)],
            ['Estimated duration: ', ("%s" % estimateTime)]
        ]

        return gridData
Beispiel #19
0
    def test_single_int(self):
        gcode = GCode()
        gcode.load_file("gc_single_int.gcode")

        # check if only one command
        self.assertEqual(len(gcode._lines), 1)

        # check command recognized correctly
        self.assertTrue(gcode._lines[0].has_word("G"))
        self.assertEqual(gcode._lines[0].get_word("G"), 5)

        # check parameters recognized correctly and upper/lowercase compatibility
        self.assertEqual(gcode._lines[0].has_word("X"), True)
        self.assertEqual(gcode._lines[0].has_word("x"), True)
        self.assertEqual(gcode._lines[0].has_word("Y"), True)
        self.assertEqual(gcode._lines[0].has_word("y"), True)

        self.assertEqual(gcode._lines[0].get_word("X"), 500)
        self.assertEqual(gcode._lines[0].get_word("Y"), 400)

        # check validity
        self.assertEqual(gcode._lines[0].is_valid(), True)
Beispiel #20
0
 def __init__(self, cfg):
     self.cfg = cfg
     self.webui = None
     self.gcode_queue = queue.Queue(100)
     self.gcode_file = None
     self.idling = True
     self.pause = False
     self.ev_buffer = asyncio.Event()
     self.pid = {}
     self.setpoint = {}
     self.setpoint_fail_time = {}
     self.tolerance = 3
     self.current_status = None
     self.heater_enable_mcodes = True
     self.heater_disable_eof = True
     self.ignore_endstop = False
     self.prepare_endswitches()
     self.machine_ready = False
     self.move = Move(self.cfg, self)
     self.gcode = GCode(self.cfg)
     dim = self.cfg.settings["num_motors"]
     audiodev = self.cfg.settings["sound_device"]
     self.current_e = 0
     self.extruder_safety_timeout = 300  # FIXME
     self.extruder_safety_time = time.time() + self.extruder_safety_timeout
     for n in ["ext", "bed"]:
         name = n.upper()
         o = GPOutput("heater_" + name)
         s = ScaledSensor(self.cfg, name)
         t = Thermistor100k(s)
         self.pid[n] = PidController(t, o, 0.3, 0.004, 0.5)
         self.launch_pid(n, 20)
     self.loop = asyncio.get_event_loop()
     self.sc = StepperCluster(audiodev, dim, self.cfg, self.esw)
     self.sc.connect_cmd_buffer(self.move.get_output_buffer())
     self.loop.add_writer(self.sc.fileno(), self.handle_sc_write)
     asyncio. async (self.gcode_processor())
     asyncio. async (self.coro_check_machine())
Beispiel #21
0
def create_s():
    c1 = create_circle(0, 1.03, 1, 20, 270-15)
    c2 = create_circle(0, -1.03, 1, 200, 450-15)
    s = LineString(c1 + list(reversed(c2)))
    s = s.buffer(0.4)
    g = GCode.from_geometry(s, 0, 0)
    g = g.scale_to_fit(6, 8)
    g = g.move(3, 4, 0.5, 0.5)
    g1 = g.depth(0.2, -0.3)
    g2 = g.depth(0.2, -0.6)
    g = HEADER + g1 + g2 + FOOTER
    g.save('sophia.nc')
    im = g.render(0, 0, 6, 8, 96)
    im.write_to_png('sophia.png')
Beispiel #22
0
def main():
    tw, th = 6, 8
    w, h = 24-2, 24-2
    p = 0
    shapes = load_shapes()
    shapes.append(circle(R))
    shapes.append(circle(R * 1.05))
    mp = MultiLineString(shapes)
    mp = fit_shape(mp, w, h, p)
    g = GCode.from_geometry(mp, G0Z, G1Z)
    im = g.render(0, 0, w, h, 96)
    im.write_to_png('hemi.png')
    for i in range(4):
        for j in range(3):
            print i, j
            tile = create_tile(i, j, tw, th)
            tmp = intersection(mp, tile)
            g = GCode.from_geometry(tmp, G0Z, G1Z)
            g = g.translate(-i * tw, -j * th)
            g = HEADER + g + FOOTER
            im = g.render(0, 0, tw, th, 96)
            im.write_to_png('hemi-tiles/%d.%d.png' % (j, i))
            g.save('hemi-tiles/%d.%d.nc' % (j, i))
Beispiel #23
0
def create_face(dihedral, sides, length, depth, iterations):
    angle = radians((180 - dihedral) / 2)
    hyp = 1 / cos(angle) * depth
    max_offset = sin(angle) * hyp
    points = []
    for i in range(iterations):
        p = i / float(iterations - 1)
        offset = sin(angle) * p * hyp
        z = -cos(angle) * p * hyp
        p = create_points(sides, length, offset - max_offset)
        p = [(x, y, z) for x, y in p]
        points.extend(p)
    lines = []
    lines.append('G0 Z%f' % G0Z)
    lines.append('G0 X%f Y%f' % points[0][:2])
    for point in points:
        lines.append('G1 X%f Y%f Z%f' % point)
    lines.append('G0 Z%f' % G0Z)
    g = GCode(lines)
    g = g.origin()
    g = HEADER + g + FOOTER
    g.save('polyhedra.nc')
    im = g.render(0, 0, 6, 8, 96)
    im.write_to_png('polyhedra.png')
Beispiel #24
0
def generate_county(shape, name, text):
    result = []
    polygons = get_polygons(shape, SCALE)
    max_polygon = max(polygons, key=attrgetter('area'))
    for i, polygon in enumerate(polygons):
        g = GCode.from_geometry(polygon, G0Z, G1Z_BEVEL)
        if text and polygon == max_polygon:
            x, y = polygon.centroid.coords[0]
            dx, dy = TEXT_OFFSETS.get(name, (0, 0))
            scale = TEXT_SIZES.get(name, TEXT_SIZE)
            angle = TEXT_ANGLES.get(name, 0)
            g += generate_text(name, x + dx, y + dy, scale, angle)
        g = g.origin()
        g.name = ('%s %d' % (name, i)) if i else name
        result.append(g)
    return result
Beispiel #25
0
def main2():
    bit = 0.0625
    s = 1.82748538
    for letter in 'MEGAN':
        p = load_letter(letter)
        p = scale(p, s, s)
        p = p.buffer(bit / 2)
        g = GCode.from_geometry(p, G0Z, -bit)
        g = g.origin()
        depths = [-bit, -bit*2, -bit*3, -bit*4]
        gs = [g.depth(G0Z, d) for d in depths]
        g = reduce(operator.add, gs)
        g = HEADER + g + FOOTER
        im = g.render(0, 0, 6, 8, 96)
        im.write_to_png('megan-%s.png' % letter)
        g.save('megan-%s.nc' % letter)
Beispiel #26
0
def create_shape(sides, length):
    p = create_points(sides, length)
    g = GCode()
    g += GCode.from_points(p, G0Z, -0.24)
    # g += GCode.from_points(p, G0Z, -0.4)
    # g += GCode.from_points(p, G0Z, -0.5)
    # g = g.rotate_and_scale_to_fit(6.5, 8)
    # g = g.rotate(180)
    g = g + g.translate(0, 4)
    g = g.origin()
    g = HEADER + g + FOOTER
    g.save('solids.nc')
    im = g.render(0, 0, 6.5, 8, 96)
    im.write_to_png('solids.png')
Beispiel #27
0
def main():
    bit = 0.125
    r = 0.21875
    d = 0.09375
    steps = 16
    cells = [
        cell(0, 0),
        cell(1, 0),
        cell(1, 1),
        cell(2, 1),
        cell(3, 1),
    ]
    mp = cascaded_union(cells).buffer(-bit).buffer(bit)
    g = GCode()
    for p in cells:
        g += GCode.from_geometry(p, G0Z, -d)
    # for p in cells:
    #     g += GCode.from_geometry(p, G0Z, -bit)
    for step in range(steps):
        p = step / (steps - 1.0)
        a = radians(p * 90)
        x = sin(a) * r
        b = x + bit / 2 - r
        z = r - (r * r - x * x) ** 0.5
        print '%.3f, %.3f, %.3f, %.3f' % (p, x, b, z)
        g += GCode.from_geometry(mp.buffer(b), G0Z, -z)
    # g += GCode.from_geometry(mp.buffer(bit / 2), G0Z, -0.4)
    # g += GCode.from_geometry(mp.buffer(bit / 2), G0Z, -0.7)
    # g += GCode.from_geometry(mp.buffer(bit / 2), G0Z, -0.6, bit + 0.1, 3)
    g += GCode.from_geometry(mp.buffer(bit / 2), G0Z, -0.4, bit + 0.2, 3.5)
    g = g.scale(-1, 1)
    g = g.origin().translate(0, 0.5)
    g = HEADER + g + FOOTER
    p = 0#0.5
    im = g.render(-p, -p, 6 + p, 6 + p, 96*4)
    im.write_to_png('blokus.png')
    g.save('blokus.nc')
Beispiel #28
0
def best_scale(width, height):
    result = None
    shapes = load_county_shapes('37')
    for county in COUNTIES:
        shape = shapes[county.name]
        polygons = get_polygons(shape, 1)
        for polygon in polygons:
            sizes = []
            g = GCode.from_geometry(polygon, 0, 0)
            for angle in range(0, 180, 5):
                w, h = g.rotate(angle).size
                size = min(width / w, height / h)
                sizes.append((size, angle))
            size = max(sizes)
            print county.name, size
            if result is None or size < result:
                result = size
    print result
    return result
Beispiel #29
0
def main():
    # 8x3
    i, j = 5, 1
    tw, th = 6, 8
    w, h = 48-2, 24-2
    p = 0
    shapes = load_shapes()
    mp = MultiPolygon(shapes)
    mp = fit_shape(mp, w, h, p)
    for i in range(7):
        for j in range(3):
            print i, j
            tile = create_tile(i, j, tw, th)
            tmp = intersection(mp, tile)
            g = GCode.from_geometry(tmp, G0Z, G1Z)
            g = g.translate(-i * tw, -j * th)
            g = HEADER + g + FOOTER
            im = g.render(0, 0, tw, th, 96)
            im.write_to_png('usa-tiles/%d.%d.png' % (j, i))
            g.save('usa-tiles/%d.%d.nc' % (j, i))
Beispiel #30
0
def training_batches(min_sequence=64, max_sequence=2048):
    filenames = ['./data/Killer_Queen_Jojo_Skull_Redo.stl']
    gcodes = [
        g.normalize_moves().relative_moves() for f in filenames
        for g in GCode.stl_to_gcode(f)
    ]
    datas = list(map(gcode_to_numpy, gcodes))
    del gcodes

    def _():
        for data in datas:
            nlines = data.shape[0]
            i = 0
            while nlines > min_sequence:
                upper = min(max_sequence or nlines, nlines) - 1
                seqlen = random.randint(min_sequence, upper)
                yield (data[i:i + seqlen], data[i + seqlen])
                nlines -= seqlen + 1
                i += seqlen + 1

    return _
Beispiel #31
0
    def __init__(self, controller):
        super(Slic3rEngineRunner, self).__init__()
        self.is_running = True
        self.controller = controller

        self.gcode = GCode(self.controller.app_config.tmp_place + 'out.gcode', self.controller, None, None)

        system_platform = platform.system()
        if system_platform in ['Linux']:
            self.slicer_place = [self.controller.app_config.local_path + "tools/Slic3r-Lite/bin/slic3r"]
        elif system_platform in ['Darwin']:
            self.slicer_place = [self.controller.app_config.local_path + "tools/Slic3r-Lite/Slic3r.app/Contents/MacOS/Slic3r"]
        elif system_platform in ['Windows']:
            self.slicer_place = ['tools\\Slic3r-Lite\\slic3r-noconsole.exe']
        else:
            self.slicer_place = ['slic3r']

        #print(self.slicer_place)

        self.step_max = 9
        self.step = 0
Beispiel #32
0
def main():
    bit = 0.25
    mp = load_letters('MEGAN')
    mp = mp.buffer(-bit / 2)
    mps = []
    while not mp.is_empty:
        mps.append(mp)
        mp = mp.buffer(-bit / 2)
    g = GCode()
    for mp in mps:
        g += GCode.from_geometry(mp, G0Z, -0.21875 * 1.0)
    g = g.rotate(90).origin().translate(2, 0)
    g = HEADER + g + FOOTER
    im = g.render(0, 0, 6, 8, 96)
    im.write_to_png('megan.png')
    g.save('megan.nc')
Beispiel #33
0
def main():
    counties = load_polygons(COUNTY_SHAPEFILE)
    state = load_polygons(STATE_SHAPEFILE)
    for y in range(4):
        for x in range(14):
            tile = create_tile(x, y, 6, 8)
            county_shapes = intersection(counties, tile)
            state_shapes = intersection(state, tile, -0.25)
            if not county_shapes and not state_shapes:
                continue
            print x, y, len(county_shapes), len(state_shapes)
            g = GCode()
            for shape in county_shapes:
                g += GCode.from_geometry(shape, G0Z, G1Z_COUNTY)
            for shape in state_shapes:
                g += GCode.from_geometry(shape, G0Z, G1Z_STATE1)
            for shape in state_shapes:
                g += GCode.from_geometry(shape, G0Z, G1Z_STATE2)
            g = g.translate(-tile.bounds[0], -tile.bounds[1])
            g = HEADER + g + FOOTER
            g.save('tiles/%02d.%02d.nc' % (y, x))
            p = 0.1
            surface = g.render(0 - p, 0 - p, 6 + p, 8 + p, 96)
            surface.write_to_png('tiles/%02d.%02d.png' % (y, x))
Beispiel #34
0
	def __init__(self, cfg):
		self.cfg = cfg
		self.webui = None
		self.gcode_queue = queue.Queue(100)
		self.gcode_file = None
		self.idling = True
		self.pause = False
		self.ev_buffer = asyncio.Event()
		self.pid = {}
		self.setpoint = {}
		self.setpoint_fail_time = {}
		self.tolerance = 3
		self.current_status = None
		self.heater_enable_mcodes = True
		self.heater_disable_eof = True
		self.ignore_endstop = False
		self.prepare_endswitches()
		self.machine_ready = False
		self.move = Move(self.cfg, self)
		self.gcode = GCode(self.cfg)
		dim = self.cfg.settings["num_motors"]
		audiodev = self.cfg.settings["sound_device"]
		self.current_e = 0
		self.extruder_safety_timeout = 300 # FIXME
		self.extruder_safety_time = time.time() + self.extruder_safety_timeout
		for n in ["ext", "bed"]:
			name = n.upper()
			o = GPOutput("heater_" + name)
			s = ScaledSensor(self.cfg, name)
			t = Thermistor100k(s)
			self.pid[n] = PidController(t, o, 0.3, 0.004, 0.5)
			self.launch_pid(n, 20)
		self.loop = asyncio.get_event_loop()
		self.sc = StepperCluster(audiodev, dim, self.cfg, self.esw)
		self.sc.connect_cmd_buffer(self.move.get_output_buffer())
		self.loop.add_writer(self.sc.fileno(), self.handle_sc_write)
		asyncio.async(self.gcode_processor())
		asyncio.async(self.coro_check_machine())
Beispiel #35
0
def main():
    sep = GCode.from_points([(3, 0), (3, 8)], 0.2, -0.05)

    t1 = GCode.from_file('text/Planet Earth.nc')
    t2 = GCode.from_file('text/Lambert Azimuthal Equal-Area.nc')
    t3 = GCode.from_file('text/0 N 110 W.nc')
    t4 = GCode.from_file('text/Michael Fogleman.nc')
    t5 = GCode.from_file('text/July 2015.nc')

    t1 = t1.scale(1.25, 1.25)
    t2 = t2.scale(0.55, 0.55)
    t3 = t3.scale(0.55, 0.55)

    t1 = t1.move(0, 0, 0.5, 0.5).depth(0.2, -0.07)
    t2 = t2.move(0, 0, 0.5, 0.5).depth(0.2, -0.03)
    t3 = t3.move(0, 0, 0.5, 0.5).depth(0.2, -0.03)
    t4 = t4.move(0, 0, 0.5, 0.5).depth(0.2, -0.05)
    t5 = t5.move(0, 0, 0.5, 0.5).depth(0.2, -0.05)

    t1 = t1.translate(0, 6.5)
    t2 = t2.translate(0, 5)
    t3 = t3.translate(0, 4)
    t4 = t4.translate(0, 2)
    t5 = t5.translate(0, 0)

    t = t1 + t2 + t3
    b = t4 + t5
    s = 2.0 / 3.0
    t = t.scale(s, s)
    b = b.scale(s, s)
    t = t.rotate(90)
    b = b.rotate(90)
    t = t.move(1.5, 4, 0.5, 0.5)
    b = b.move(4.5, 4, 0.5, 0.5)
    t = t + b
    t = t + sep
    t = HEADER + t + FOOTER
    p = 0.25
    im = t.render(0-p, 0-p, 6+p, 8+p, 96)
    im.write_to_png('engrave.png')
    t.save('engrave.nc')
Beispiel #36
0
def create_shape(sides, length):
    bit = 0.125
    size = 0.25
    offset = bit / 5
    data = [
        [0] * 5,
        # [1] * 5,
        # [0, 1, 0, 0, 1],
        # [1, 0, 1, 1, 0],
    ]
    # gs = GCode()
    for index, directions in enumerate(data):
        p = create_points(sides, length)
        # p = add_notches(p, size, offset, directions)
        # p = LineString(p).buffer(bit / 2).exterior.coords
        g = GCode()
        g += GCode.from_points(p, G0Z, -0.15)
        g += GCode.from_points(p, G0Z, -0.275)
        # g = g.move(3, 0, 0.5, 0)
        # gs += g
        g = HEADER + g + FOOTER
        g.save('solids%d.nc' % index)
        im = g.render(0, 0, 6, 8, 96)
        im.write_to_png('solids%d.png' % index)
Beispiel #37
0
import logging
import re
from extruder import Extruder
from gcode import GCode
from layer import FirstLayer, ACT_INFILL, ACT_PASS, ACT_SWITCH, Layer

import utils
from gcode_file import SLICER_SIMPLIFY3D, GCodeFile
from settings import Settings

gcode = GCode()
log = logging.getLogger("S3DSlicer")


class Simplify3dGCodeFile(GCodeFile):

    slicer_type = SLICER_SIMPLIFY3D

    LAYER_START_RE = re.compile(b".*layer (\d+), Z = (\d+\.*\d*)")
    VERSION_RE = re.compile(b".*Version (\d)\.(\d)\.(\d)")

    def __init__(self, logger, settings: Settings):
        super().__init__(logger, settings)
        self.extruder_name = []
        self.extruder_tool = []
        self.extruder_diameter = []
        self.extruder_multiplier = []
        self.extruder_use_retract = []
        self.extruder_retract_dist = []
        self.extruder_retract_speed = []
        self.extruder_zhop = []
Beispiel #38
0
def send(code, ifile, device, baudrate, measure, yes, noopt, stats, zero):
    if not ifile and not code:
        print("Need either file or code")
        return -1

    if ifile:
        code = ifile.read()
    else:
        code = '\n'.join(code.split(';'))

    codes = parse_and_optimize(code, noopt)

    absolute = GStatement(GCode('G', 90))
    spindle_start = GStatement(GCode('M', 3))
    codes.insert(0, absolute)
    codes.insert(0, spindle_start)

    if measure == 'metric':
        adjust = GCode('G', 21)
    else:
        adjust = GCode('G', 20)

    codes.insert(0, GStatement(adjust))

    if zero:
        zero = GStatement(GCode('G', 0), GCode('Z', 0), GCode('X', 0),
                          GCode('Y', 0))
        codes.append(zero)

    codes.append(GStatement(GCode('M', 5)))

    if stats:
        print(generate_stats(codes), file=sys.stderr)

    if not yes:
        print()
        x = None
        while x != 'y':
            x = raw_input('Start? (y/n) ')
            if x == 'n':
                print('Aborting')
                return -1

    cnc = CNC(device, baudrate)
    cnc.add_codes(*codes)

    cnc.onprogress, cnc.oncomplete = make_progressbar(len(cnc), 'Buffer: ')
    cnc.onalarm = lambda x: print('\nalarm: %s, %s' % (x, cnc.cur))
    cnc.onerror = lambda x: print('\nerror: %s, %s' % (x, cnc.cur))

    try:
        cnc.connect()
        cnc.send_queue()
    except KeyboardInterrupt:
        print()
        print('Interrupted')
        print('Raising position alarm')
        cnc.halt()
        return -1

    return 0
Beispiel #39
0
    def setupUi(self):
        self.setObjectName(_fromUtf8("MainWindow"))
        self.resize(603, 600)
        self.centralwidget = QtGui.QWidget(self)
        self.centralwidget.setObjectName(_fromUtf8("centralwidget"))
        self.horizontalLayout = QtGui.QHBoxLayout(self.centralwidget)
        self.horizontalLayout.setMargin(5)
        self.horizontalLayout.setObjectName(_fromUtf8("horizontalLayout"))
        self.textEdit = QtGui.QTextEdit(self.centralwidget)
        self.textEdit.setReadOnly(True)
        sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding)
        sizePolicy.setHorizontalStretch(1)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.textEdit.sizePolicy().hasHeightForWidth())
        self.textEdit.setSizePolicy(sizePolicy)
        self.textEdit.setObjectName(_fromUtf8("textEdit"))
        self.horizontalLayout.addWidget(self.textEdit)
        self.widget = GLWidget(self.centralwidget)
        sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Preferred)
        sizePolicy.setHorizontalStretch(1)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.widget.sizePolicy().hasHeightForWidth())
        self.widget.setSizePolicy(sizePolicy)
        self.widget.setObjectName(_fromUtf8("widget"))
        self.horizontalLayout.addWidget(self.widget)
        spacerItem = QtGui.QSpacerItem(40, 20, QtGui.QSizePolicy.Ignored, QtGui.QSizePolicy.Minimum)
        self.horizontalLayout.addItem(spacerItem)
        self.setCentralWidget(self.centralwidget)
        self.menubar = QtGui.QMenuBar(self)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 603, 21))
        self.menubar.setObjectName(_fromUtf8("menubar"))
        self.setMenuBar(self.menubar)

        self.menu_File = QtGui.QMenu(self.menubar)
        self.menu_File.setObjectName(_fromUtf8("menu_File"))
        self.menuTool = QtGui.QMenu(self.menubar)
        self.menuTool.setObjectName(_fromUtf8("menuTool"))
        self.menuPort = QtGui.QMenu(self.menubar)
        self.menuPort.setObjectName(_fromUtf8("menuPort"))
        self.menuBaud = QtGui.QMenu(self.menubar)
        self.menuBaud.setObjectName(_fromUtf8("menuBaud"))
        self.menuTool.addMenu(self.menuPort)
        self.menuTool.addMenu(self.menuBaud)
        self.menuHelp = QtGui.QMenu(self.menubar)
        self.menuHelp.setObjectName(_fromUtf8("menuHelp"))

        self.statusbar = QtGui.QStatusBar(self)
        self.statusbar.setObjectName(_fromUtf8("statusbar"))
        self.setStatusBar(self.statusbar)
        self.action_Open = QtGui.QAction(QtGui.QIcon('open.png'), "&Open...", self)
        self.action_Open.setObjectName(_fromUtf8("action_Open"))
        self.action_Open.triggered.connect(self.openFile)
        self.action_Quit = QtGui.QAction(self)
        self.action_Quit.setObjectName(_fromUtf8("action_Quit"))
        self.action_Quit.triggered.connect(self.quitapp)
        self.actionAbout = QtGui.QAction(self)
        self.actionAbout.setObjectName(_fromUtf8("actionAbout"))
        self.menu_File.addAction(self.action_Open)
        self.menu_File.addSeparator()
        self.menu_File.addAction(self.action_Quit)
        self.menuHelp.addAction(self.actionAbout)
        self.menubar.addAction(self.menu_File.menuAction())
        self.menubar.addAction(self.menuTool.menuAction())
        self.menubar.addAction(self.menuHelp.menuAction())
        self.startAction = QtGui.QAction(QtGui.QIcon('play.png'), "Start", self)
        self.stopAction = QtGui.QAction(QtGui.QIcon('stop.png'), "Stop", self)
        self.rePort = QtGui.QAction("Refresh", self)
        self.rePort.triggered.connect(self.getPorts)
        self.serialCon = QtGui.QAction(QtGui.QIcon('connection.png'), "Connect", self)
        self.serialCon.triggered.connect(self.toggleConnection)
        self.toolbar = self.addToolBar("Toolbar")
        self.toolbar.addAction(self.action_Open)
        self.toolbar.addSeparator()
        self.toolbar.addAction(self.serialCon)
        self.toolbar.addAction(self.startAction)
        self.toolbar.addAction(self.stopAction)

        self.gcode = GCode()
        self.getPorts()
        self.setBaudrates()
        self.setBaudrate()

        self.setEnablePrintPanel(False)

        self.retranslateUi()
        QtCore.QMetaObject.connectSlotsByName(self)
Beispiel #40
0
 def setUp(self):
     self.test_object = GCode()
Beispiel #41
0
class Printer(object):
	def __init__(self, cfg):
		self.cfg = cfg
		self.webui = None
		self.gcode_queue = queue.Queue(100)
		self.gcode_file = None
		self.idling = True
		self.pause = False
		self.ev_buffer = asyncio.Event()
		self.pid = {}
		self.setpoint = {}
		self.setpoint_fail_time = {}
		self.tolerance = 3
		self.current_status = None
		self.heater_enable_mcodes = True
		self.heater_disable_eof = True
		self.ignore_endstop = False
		self.prepare_endswitches()
		self.machine_ready = False
		self.move = Move(self.cfg, self)
		self.gcode = GCode(self.cfg)
		dim = self.cfg.settings["num_motors"]
		audiodev = self.cfg.settings["sound_device"]
		self.current_e = 0
		self.extruder_safety_timeout = 300 # FIXME
		self.extruder_safety_time = time.time() + self.extruder_safety_timeout
		for n in ["ext", "bed"]:
			name = n.upper()
			o = GPOutput("heater_" + name)
			s = ScaledSensor(self.cfg, name)
			t = Thermistor100k(s)
			self.pid[n] = PidController(t, o, 0.3, 0.004, 0.5)
			self.launch_pid(n, 20)
		self.loop = asyncio.get_event_loop()
		self.sc = StepperCluster(audiodev, dim, self.cfg, self.esw)
		self.sc.connect_cmd_buffer(self.move.get_output_buffer())
		self.loop.add_writer(self.sc.fileno(), self.handle_sc_write)
		asyncio.async(self.gcode_processor())
		asyncio.async(self.coro_check_machine())

	def add_webui(self, webui):
		self.webui = webui

	def launch_pid(self, name, sp):
		self.pid[name].spawn()
		self.set_setpoint(name, sp)

	def shutdown(self):
		self.loop.stop()
		for name in self.pid:
			self.pid[name].set_setpoint(0)
			self.pid[name].shutdown()
		if self.sc is not None:
			self.sc.zero_output()
			self.sc.zero_output()
			self.sc.zero_output()
			self.sc.zero_output()
			self.sc.close()

	def set_setpoint(self, name, sp, report=True):
		if sp and sp < 10:
			sp = 10
		elif name == "ext" and sp > 280:
			sp = 280
		elif name == "bed" and sp > 120:
			sp = 120
		print("Set", name, "temperature:", sp, "deg. C")
		self.setpoint[name] = sp
		self.setpoint_fail_time[name] = 0
		self.pid[name].set_setpoint(sp)
		if report and self.webui:
			self.webui.queue_setpoint(name, sp)

	def set_zoffset(self, zoff):
		print("PRINTER: Set Z-offset:", zoff)
		self.gcode.set_zoffset(zoff)

	def get_temperature(self, name):
		return self.pid[name].get_input()

	def check_setpoint_immediate(self, name):
		temp = self.get_temperature(name)
		sp = self.setpoint[name]
		dt = abs(temp - sp)
		if sp < 30: # Heater off = ok
			dt = 0
		ok = (dt < self.tolerance)
		return ok

	def check_setpoint(self, name):
		ok = self.check_setpoint_immediate(name)
		if ok:
			self.setpoint_fail_time[name] = 0
		elif not self.setpoint_fail_time[name]:
			self.setpoint_fail_time[name] = time.time() + 10
		return (ok or time.time() < self.setpoint_fail_time[name])

	def check_setpoints(self):
		return self.check_setpoint("ext") and self.check_setpoint("bed")

	@asyncio.coroutine
	def coro_check_machine(self):
		self.tolerance = 3
		wasok = True
		while True:
			res = self.check_setpoints()
			if res: # Hysteresis
				self.tolerance = 10
			else:
				self.tolerance = 3
			if not res and wasok:
				print("Printer not ready")
			elif res and not wasok:
				print("Printer ready")
			wasok = res
			self.machine_ready = res
			self.update_status()
			yield from asyncio.sleep(2.0)

	def set_position_mm(self, x, y, z, e):
		if self.webui:
			self.webui.queue_move(x, y, z, e)
		if e != self.current_e:
			self.current_e = e
			self.extruder_safety_time = time.time() + self.extruder_safety_timeout

	def printer_handler(self):
		ti = time.time()
		if self.extruder_safety_time < ti and "ext" in self.pid and \
				self.setpoint["ext"] > 150:
			print("Extruder safety timeout hit. Lowering setpoint!")
			self.pid["ext"].set_setpoint(self.setpoint["ext"] - 50)

	@asyncio.coroutine
	def print_file(self, fname):
		if self.gcode_file is not None:
			return False
		print("Starting print:", fname)
		self.gcode_file = AIOFileReader(fname)
		asyncio.sleep(0)
		return True

	@asyncio.coroutine
	def wait_for_setpoints(self):
		while True:
			if self.check_setpoint_immediate("ext") and self.check_setpoint_immediate("bed"):
				break
			yield from asyncio.sleep(2)

	@asyncio.coroutine
	def start_auto(self, sp_ext, en_ext, sp_bed, en_bed, fname):
		if self.gcode_file is not None:
			return False
		if en_bed:
			# Heat up bed first
			self.set_setpoint("bed", sp_bed)
			while True:
				t_bed = self.get_temperature("bed")
				if t_bed > (sp_bed - 10):
					break
				yield from asyncio.sleep(5)
		if en_ext:
			# Bed near ok, so start hotend
			self.set_setpoint("ext", sp_ext)
			while True:
				t_ext = self.get_temperature("ext")
				if t_ext > (sp_ext - 10):
					break
				yield from asyncio.sleep(5)
		# Temperatures high enough to start homing
		self.reset()
		yield from self.execute_gcode("G28 X0 Y0")
		yield from self.wait_for_setpoints()
		yield from self.execute_gcode("G28 Z0")
		yield from self.print_file(fname)

	@asyncio.coroutine
	def execute_gcode(self, cmd):
		try:
			self.gcode_queue.put_nowait(cmd)
		except queue.Full:
			return False
		yield from asyncio.sleep(0)
		return True

	def _read_gcode(self):
		try:
			ret = self.gcode_queue.get_nowait()
		except queue.Empty:
			ret = ""
		return ret

	@asyncio.coroutine
	def _queue_move(self, obj):
		if self.move.buffer_ready():
			self.move.process_command(obj)
			yield from asyncio.sleep(0)
		else:
			self.ev_buffer.clear()
			yield from self.ev_buffer.wait()
			self.move.process_command(obj)

	@asyncio.coroutine
	def gcode_processor(self):
		idle = True
		while True:
			if (self.gcode_file is None or self.pause) and self.gcode_queue.empty():
				if not idle:
					yield from self._queue_move({"command":"eof"})
					idle = True
				yield from asyncio.sleep(0.2)
				continue
			if self.gcode_file and not self.pause:
				if not self.machine_ready:
					yield from asyncio.sleep(0.2)
					continue
				l = self.gcode_file.readline()
				if l is None: # End of file
					self.gcode_file = None
					if self.heater_disable_eof:
						self.set_setpoint("ext", 0)
						self.set_setpoint("bed", 0)
					yield from self._queue_move({"command":"eof"})
					self.move.reset()
					continue
			else:
				l = self._read_gcode()
			if len(l) == 0: # File reader stalled
				yield from self._queue_move({"command":"eof"})
				self.move.reset()
				continue
			obj = self.gcode.process_line(l)
			if obj is None:
				continue
			# print("PRINTER GCODE:", repr(obj))
			cmd = obj["command"]
			if cmd == "setpoint":
				if self.heater_enable_mcodes:
					self.set_setpoint(obj["type"], obj["value"])
					if obj["wait"]:
						yield from self.wait_for_setpoints()
			elif cmd == "log":
				self.webui.queue_log(obj['type'], obj['value'])
			else:
				yield from self._queue_move(obj)
				idle = False
				self.set_idle(False)

	def _heater_status(self, name):
		ok = self.check_setpoint(name)
		sp = self.setpoint[name]
		temp = self.get_temperature(name)
		if sp == 0:
			return "off"
		if ok:
			return "ok"
		if sp > temp:
			return "low"
		if sp < temp:
			return "high"

	def update_status(self, force=False):
		if self.idling:
			motors = "idle"
		elif self.gcode_file is not None:
			motors = "processing"
		else:
			motors = "moving"
		ext = self._heater_status("ext")
		bed = self._heater_status("bed")
		status = (motors, ext, bed)
		if self.webui is None:
			return
		if self.current_status == status:
			return
		self.current_status = status
		self.webui.queue_status(*status)

	def set_idle(self, idle):
		if idle != self.idling:
			self.idling = idle
			self.update_status()

	def handle_sc_write(self):
		if not self.idling:
			ret = self.sc.pull_cmd_buffer()
			if ret == 1:
				self.set_idle(True)
			if self.move.buffer_ready() and not self.ev_buffer.is_set():
				# print("PRINTER: cond notify")
				self.ev_buffer.set()
		else:
			self.sc.zero_output()

	def set_pause(self, pause):
		self.pause = pause
		print("Set pause:", repr(pause))

	@asyncio.coroutine
	def stop(self):
		print("Stopping...")
		self.abort()
		yield from self.execute_gcode("G91")
		yield from self.execute_gcode("G1 Z5 F5000")
		yield from self.execute_gcode("G90")

	def abort(self):
		print("Aborting...")
		if self.gcode_file:
			self.gcode_file.close()
			self.gcode_file = None
		while not self.gcode_queue.empty():
			self.gcode_queue.get_nowait()
		self.sc.cancel_destination()
		self.sc.flush_queue()
		# We may have interrupted a move. Make sure we know where we are...
		scpos = self.sc.get_position()
		gpos = self.move.reverse_transform(scpos)
		self.gcode.set_position(gpos)
		self.set_setpoint("ext", 0)
		self.set_setpoint("bed", 0)

	def reset(self):
		self.gcode.reset()
		self.sc.set_position([0, 0, 0, 0])
		self.move.reset()
		self.set_position_mm(0, 0, 0, 0)

	def set_heater_enable_mcodes(self, value):
		self.heater_enable_mcodes = value

	def set_heater_disable_eof(self, value):
		self.heater_disable_eof = value

	def set_ignore_endstop(self, value):
		if self.ignore_endstop != value:
			self.ignore_endstop = value
			if value:
				self.disable_endswitches()
			else:
				self.enable_endswitches()

	def disable_endswitches(self):
		for e in self.esw:
			e.disable_exceptions()

	def enable_endswitches(self):
		for e in self.esw:
			e.enable_exceptions()

	def prepare_endswitches(self):
		self.esw = []
		for axis in ["X", "Y", "Z"]:
			eswname = "endstop_" + axis
			self.esw.append(AsyncGPInput(eswname, self))

	def gpio_event(self, name, val):
		print("GPIO Event from", name, "value:", val)
		self.sc.stop()
		self.sc.cancel_destination()
		self.sc.restart()

	def run(self):
		self.loop.run_forever()
Beispiel #42
0
from gcode import GCode




gcode = GCode(49,19)
gcode.init_file()
gcode.build_file()

lines = gcode.get_gcode()
print('++++++++++++++++++++++++')
print('lines ----->', len(lines))
# print(lines.len)
Beispiel #43
0
class TestGcode(unittest.TestCase):
    def setUp(self):
        self.test_object = GCode()

    def tearDown(self):
        pass

    def test_is_extruder_move(self):
        self.assertEqual(
            (-2.5, 1500), self.test_object.is_extruder_move(b"G1 E-2.5 F1500")
        )
        self.assertEqual((-2.5, None), self.test_object.is_extruder_move(b"G1 E-2.5"))
        self.assertEqual(
            (-3.0, 4800), self.test_object.is_extruder_move(b"G1 E-3.00000 F4800.00000")
        )
        self.assertEqual(
            (-3.0, 4800), self.test_object.is_extruder_move(b"G1 F4800.00000 E-3.00000")
        )
        self.assertEqual(
            (-2.6162, 1200), self.test_object.is_extruder_move(b"G1 F1200 E-2.6162")
        )
        self.assertEqual(
            None,
            self.test_object.is_extruder_move(b"G1 F4800.00000 E-3.00000 X0 Y0 Z0"),
        )
        self.assertEqual((2.0, 2700), self.test_object.is_extruder_move(b"G1 F2700 E2"))

    def test_read_gcode_line(self):
        self.assertEqual(
            (b"G1 E5 F1500  ", b" juu"),
            self.test_object.read_gcode_line(b"G1 E5 F1500  ; juu"),
        )
        self.assertEqual((None, b" juu"), self.test_object.read_gcode_line(b"; juu"))
        self.assertEqual(
            (None, b" juu ; joo"), self.test_object.read_gcode_line(b"; juu ; joo")
        )
        self.assertEqual(
            (b"G1 E-3.00000 F4800.00000", None),
            self.test_object.read_gcode_line(b"G1 E-3.00000 F4800.00000"),
        )


    def test_format_to_string(self):
        self.assertEqual(
            b"G1 X1 Y1 Z1 E1 F1000; test",
            self.test_object.format_to_string(b"G1 X1 Y1 Z1 E1 F1000", b" test"),
        )
        self.assertEqual(
            b"G1 X1 Y1 Z1 E1 F1000",
            self.test_object.format_to_string(b"G1 X1 Y1 Z1 E1 F1000", None),
        )
        self.assertEqual(b"; test", self.test_object.format_to_string(None, b" test"))

    def test_is_tool_change(self):
        self.assertEqual(0, self.test_object.is_tool_change(b"T0"))
        self.assertEqual(1, self.test_object.is_tool_change(b"T1"))
        self.assertEqual(1, self.test_object.is_tool_change(b"T1  ; tool 1"))

    def test_is_z_move(self):
        self.assertEqual((5.5, 1500), self.test_object.is_z_move(b"G1 Z5.500 F1500"))
        self.assertEqual((5.5, None), self.test_object.is_z_move(b"G1 Z5.500"))
        self.assertEqual(
            None, self.test_object.is_z_move(b"G1 X67.626 Y63.341 Z0.25 E0 F900")
        )
        self.assertEqual((0.5, None), self.test_object.is_z_move(b"G1 Z.5"))

    def test_is_extrusion_move(self):
        self.assertEqual(
            (80.349, 81.849, None, -2.5, None),
            self.test_object.is_extrusion_move(b"G1 X80.349 Y81.849 E-2.5000"),
        )
        self.assertEqual(
            None, self.test_object.is_extrusion_move(b"G1 X80.349 Y81.849 E0")
        )
        self.assertEqual(
            (80.349, 81.849, None, 5, 2000),
            self.test_object.is_extrusion_move(b"G1 X80.349 Y81.849 E5 F2000"),
        )
        self.assertEqual(
            (45.488, 56.304, 0.225, 1, 9000),
            self.test_object.is_extrusion_move(b"G1 X45.488 Y56.304 Z0.225 E1 F9000"),
        )

    def test_is_head_move(self):
        self.assertEqual(
            (65.82, 76.532, 5.7, 1500),
            self.test_object.is_head_move(b"G1 X65.82 Y76.532 Z5.7 E0 F1500"),
        )
        self.assertEqual(
            (65.82, 76.532, None, 1500),
            self.test_object.is_head_move(b"G1 X65.82 Y76.532 F1500"),
        )
        self.assertEqual(
            (None, 76.532, None, 1500),
            self.test_object.is_head_move(b"G1 Y76.532 F1500"),
        )
        self.assertEqual(
            (65.82, None, None, 1500), self.test_object.is_head_move(b"G1 X65.82 F1500")
        )
        self.assertEqual(
            (65.82, 76.532, None, 1500),
            self.test_object.is_head_move(b"G1 F1500 X65.82 Y76.532"),
        )
        self.assertEqual(
            (0.0, 10.0, 0.5, 5400.0),
            self.test_object.is_head_move(b"G0 F5400 X0.00 Y10 Z0.5"),
        )
        self.assertEqual(
            (45.488, 56.304, 0.225, 9000),
            self.test_object.is_head_move(b"G1 X45.488 Y56.304 Z0.225 E0 F9000"),
        )

    def test_is_lin_advance(self):
        self.assertEqual(100, self.test_object.is_lin_advance(b"M900 K100"))
        self.assertEqual(0, self.test_object.is_lin_advance(b"M900 K0"))
        self.assertEqual(None, self.test_object.is_lin_advance(b"M900 Ko"))
        self.assertEqual(0.2, self.test_object.is_lin_advance(b"M900 K0.2"))

    def test_gen_lin_advance(self):
        self.assertEqual(b"M900 K100", self.test_object.gen_lin_advance(100))
        self.assertEqual(b"M900 K0.2", self.test_object.gen_lin_advance(0.2))

    def test_is_pressure_advance(self):
        self.assertEqual(
            (b"0", 0.3), self.test_object.is_pressure_advance(b"M572 D0 S0.3")
        )
        self.assertEqual(
            (b"0:1", 0.3), self.test_object.is_pressure_advance(b"M572 D0:1 S0.3")
        )
        self.assertEqual(
            (b"0:1:2", 0.3), self.test_object.is_pressure_advance(b"M572 D0:1:2 S0.3")
        )
        self.assertEqual(
            None, self.test_object.is_pressure_advance(b"M572 D0:1:a S0.3")
        )

    def test_gen_direction_move(self):
        ret = self.test_object.gen_direction_move(E, 40, 3000, 0.1)
        expected = [b"G1 X40.000 Y0 F3000"]
        for r in ret:
            self.assertEqual(expected[0], r)

    def test_gen_direction_move_with_e(self):
        e = extruder.Extruder(0)
        e.coasting = 0.2
        e.extrusion_width = 0.4

        ret = self.test_object.gen_direction_move(W, 40, 3000, 0.2, e)
        expected = [b"G1 X-40.000 Y0 E1.3304 F3000"]
        for r in ret:
            self.assertEqual(expected[0], r)

        ret = self.test_object.gen_direction_move(S, 40, 3000, 0.1, e, last_line=True)
        expected = [b"G1 X0 Y-39.800 E0.6619 F3000", b"G1 X0 Y-0.200 F3000"]
        for r in ret:
            self.assertEqual(expected[0], r)
            expected.pop(0)

    def test_get_coordinates(self):

        self.assertEqual(
            (6.123233995736766e-16, 10.0), self.test_object._get_coordinates(N, 10)
        )
        self.assertEqual(
            (7.0710678118654755, 7.071067811865475),
            self.test_object._get_coordinates(NE, 10),
        )
        self.assertEqual((10.0, 0.0), self.test_object._get_coordinates(E, 10))
        self.assertEqual(
            (7.071067811865474, -7.071067811865477),
            self.test_object._get_coordinates(SE, 10),
        )
        self.assertEqual(
            (-1.8369701987210296e-15, -10.0), self.test_object._get_coordinates(S, 10)
        )
        self.assertEqual(
            (-7.071067811865477, -7.071067811865475),
            self.test_object._get_coordinates(SW, 10),
        )
        self.assertEqual(
            (-10.0, 1.2246467991473533e-15), self.test_object._get_coordinates(W, 10)
        )
        self.assertEqual(
            (-7.071067811865475, 7.0710678118654755),
            self.test_object._get_coordinates(NW, 10),
        )
        self.assertEqual(
            (8.660254037844387, 4.999999999999999),
            self.test_object._get_coordinates(30, 10),
        )
        self.assertEqual(
            (1.7364817766693041, 9.84807753012208),
            self.test_object._get_coordinates(80, 10),
        )
        self.assertEqual(
            (-1.736481776669303, 9.84807753012208),
            self.test_object._get_coordinates(100, 10),
        )
        self.assertEqual(
            (-9.396926207859085, -3.4202014332566866),
            self.test_object._get_coordinates(200, 10),
        )
        self.assertEqual(
            (9.702957262759965, -2.4192189559966786),
            self.test_object._get_coordinates(346, 10),
        )

    def test_get_coordinates_by_offsets(self):
        self.assertEqual(
            (11.0, 25.0), self.test_object.get_coordinates_by_offsets(0, 10, 10, 1, 15)
        )
        self.assertEqual(
            (10.738061598597138, 25.015167833783153),
            self.test_object.get_coordinates_by_offsets(1, 10, 10, 1, 15),
        )
        self.assertEqual(
            (6.999999999999998, 25.0),
            self.test_object.get_coordinates_by_offsets(0, 10, 10, -3, 15),
        )
        self.assertEqual(
            (4.440854075959419, 24.25117176218233),
            self.test_object.get_coordinates_by_offsets(10, 10, 10, -3, 15),
        )
        self.assertEqual(
            (11.795967328357486, 11.33210410834607),
            self.test_object.get_coordinates_by_offsets(10, 10, 10, 2, 1),
        )
        self.assertEqual(
            (6.408065343285028, 7.335791783307863),
            self.test_object.get_coordinates_by_offsets(10, 10, 10, -4, -2),
        )
        self.assertEqual(
            (8.724977204643308, 5.713472632617306),
            self.test_object.get_coordinates_by_offsets(10, 10, 10, -2, -4),
        )
        self.assertEqual(
            (12.664208216692137, 6.408065343285028),
            self.test_object.get_coordinates_by_offsets(10, 10, 10, 2, -4),
        )

    def test_is_temp_nowait(self):
        self.assertEqual((255,), self.test_object.is_temp_nowait(b"M104 S255"))
        self.assertEqual(
            (255, 0), self.test_object.is_temp_nowait_tool(b"M104 S255  T0")
        )

    def test_is_temp_wait(self):
        self.assertEqual((255,), self.test_object.is_temp_wait(b"M109 S255"))
        self.assertEqual((255, 0), self.test_object.is_temp_wait_tool(b"M109 S255 T0"))

    def test_is_fan_speed(self):
        self.assertEqual(255, self.test_object.is_fan_speed(b"M106 S255"))

    def test_opposite_dir(self):
        self.assertEqual(180, self.test_object.opposite_dir(E))
        self.assertEqual(0, self.test_object.opposite_dir(W))
        self.assertEqual(90, self.test_object.opposite_dir(S))
        self.assertEqual(270, self.test_object.opposite_dir(N))

        self.assertEqual(90, self.test_object.opposite_dir(E + 270))
        self.assertEqual(270, self.test_object.opposite_dir(W + 270))
        self.assertEqual(360, self.test_object.opposite_dir(S + 270))
        self.assertEqual(180, self.test_object.opposite_dir(N + 270))

    def test_rotate(self):
        self.assertEqual(90, self.test_object.rotate(W, 270))
Beispiel #44
0
class Printer(object):
    def __init__(self, cfg):
        self.cfg = cfg
        self.webui = None
        self.gcode_queue = queue.Queue(100)
        self.gcode_file = None
        self.idling = True
        self.pause = False
        self.ev_buffer = asyncio.Event()
        self.pid = {}
        self.setpoint = {}
        self.setpoint_fail_time = {}
        self.tolerance = 3
        self.current_status = None
        self.heater_enable_mcodes = True
        self.heater_disable_eof = True
        self.ignore_endstop = False
        self.prepare_endswitches()
        self.machine_ready = False
        self.move = Move(self.cfg, self)
        self.gcode = GCode(self.cfg)
        dim = self.cfg.settings["num_motors"]
        audiodev = self.cfg.settings["sound_device"]
        self.current_e = 0
        self.extruder_safety_timeout = 300  # FIXME
        self.extruder_safety_time = time.time() + self.extruder_safety_timeout
        for n in ["ext", "bed"]:
            name = n.upper()
            o = GPOutput("heater_" + name)
            s = ScaledSensor(self.cfg, name)
            t = Thermistor100k(s)
            self.pid[n] = PidController(t, o, 0.3, 0.004, 0.5)
            self.launch_pid(n, 20)
        self.loop = asyncio.get_event_loop()
        self.sc = StepperCluster(audiodev, dim, self.cfg, self.esw)
        self.sc.connect_cmd_buffer(self.move.get_output_buffer())
        self.loop.add_writer(self.sc.fileno(), self.handle_sc_write)
        asyncio. async (self.gcode_processor())
        asyncio. async (self.coro_check_machine())

    def add_webui(self, webui):
        self.webui = webui

    def launch_pid(self, name, sp):
        self.pid[name].spawn()
        self.set_setpoint(name, sp)

    def shutdown(self):
        self.loop.stop()
        for name in self.pid:
            self.pid[name].set_setpoint(0)
            self.pid[name].shutdown()
        if self.sc is not None:
            self.sc.zero_output()
            self.sc.zero_output()
            self.sc.zero_output()
            self.sc.zero_output()
            self.sc.close()

    def set_setpoint(self, name, sp, report=True):
        if sp and sp < 10:
            sp = 10
        elif name == "ext" and sp > 280:
            sp = 280
        elif name == "bed" and sp > 120:
            sp = 120
        print("Set", name, "temperature:", sp, "deg. C")
        self.setpoint[name] = sp
        self.setpoint_fail_time[name] = 0
        self.pid[name].set_setpoint(sp)
        if report and self.webui:
            self.webui.queue_setpoint(name, sp)

    def set_zoffset(self, zoff):
        print("PRINTER: Set Z-offset:", zoff)
        self.gcode.set_zoffset(zoff)

    def get_temperature(self, name):
        return self.pid[name].get_input()

    def check_setpoint_immediate(self, name):
        temp = self.get_temperature(name)
        sp = self.setpoint[name]
        dt = abs(temp - sp)
        if sp < 30:  # Heater off = ok
            dt = 0
        ok = (dt < self.tolerance)
        return ok

    def check_setpoint(self, name):
        ok = self.check_setpoint_immediate(name)
        if ok:
            self.setpoint_fail_time[name] = 0
        elif not self.setpoint_fail_time[name]:
            self.setpoint_fail_time[name] = time.time() + 10
        return (ok or time.time() < self.setpoint_fail_time[name])

    def check_setpoints(self):
        return self.check_setpoint("ext") and self.check_setpoint("bed")

    @asyncio.coroutine
    def coro_check_machine(self):
        self.tolerance = 3
        wasok = True
        while True:
            res = self.check_setpoints()
            if res:  # Hysteresis
                self.tolerance = 10
            else:
                self.tolerance = 3
            if not res and wasok:
                print("Printer not ready")
            elif res and not wasok:
                print("Printer ready")
            wasok = res
            self.machine_ready = res
            self.update_status()
            yield from asyncio.sleep(2.0)

    def set_position_mm(self, x, y, z, e):
        if self.webui:
            self.webui.queue_move(x, y, z, e)
        if e != self.current_e:
            self.current_e = e
            self.extruder_safety_time = time.time(
            ) + self.extruder_safety_timeout

    def printer_handler(self):
        ti = time.time()
        if self.extruder_safety_time < ti and "ext" in self.pid and \
          self.setpoint["ext"] > 150:
            print("Extruder safety timeout hit. Lowering setpoint!")
            self.pid["ext"].set_setpoint(self.setpoint["ext"] - 50)

    @asyncio.coroutine
    def print_file(self, fname):
        if self.gcode_file is not None:
            return False
        print("Starting print:", fname)
        self.gcode_file = AIOFileReader(fname)
        asyncio.sleep(0)
        return True

    @asyncio.coroutine
    def wait_for_setpoints(self):
        while True:
            if self.check_setpoint_immediate(
                    "ext") and self.check_setpoint_immediate("bed"):
                break
            yield from asyncio.sleep(2)

    @asyncio.coroutine
    def start_auto(self, sp_ext, en_ext, sp_bed, en_bed, fname):
        if self.gcode_file is not None:
            return False
        if en_bed:
            # Heat up bed first
            self.set_setpoint("bed", sp_bed)
            while True:
                t_bed = self.get_temperature("bed")
                if t_bed > (sp_bed - 10):
                    break
                yield from asyncio.sleep(5)
        if en_ext:
            # Bed near ok, so start hotend
            self.set_setpoint("ext", sp_ext)
            while True:
                t_ext = self.get_temperature("ext")
                if t_ext > (sp_ext - 10):
                    break
                yield from asyncio.sleep(5)
        # Temperatures high enough to start homing
        self.reset()
        yield from self.execute_gcode("G28 X0 Y0")
        yield from self.wait_for_setpoints()
        yield from self.execute_gcode("G28 Z0")
        yield from self.print_file(fname)

    @asyncio.coroutine
    def execute_gcode(self, cmd):
        try:
            self.gcode_queue.put_nowait(cmd)
        except queue.Full:
            return False
        yield from asyncio.sleep(0)
        return True

    def _read_gcode(self):
        try:
            ret = self.gcode_queue.get_nowait()
        except queue.Empty:
            ret = ""
        return ret

    @asyncio.coroutine
    def _queue_move(self, obj):
        if self.move.buffer_ready():
            self.move.process_command(obj)
            yield from asyncio.sleep(0)
        else:
            self.ev_buffer.clear()
            yield from self.ev_buffer.wait()
            self.move.process_command(obj)

    @asyncio.coroutine
    def gcode_processor(self):
        idle = True
        while True:
            if (self.gcode_file is None
                    or self.pause) and self.gcode_queue.empty():
                if not idle:
                    yield from self._queue_move({"command": "eof"})
                    idle = True
                yield from asyncio.sleep(0.2)
                continue
            if self.gcode_file and not self.pause:
                if not self.machine_ready:
                    yield from asyncio.sleep(0.2)
                    continue
                l = self.gcode_file.readline()
                if l is None:  # End of file
                    self.gcode_file = None
                    if self.heater_disable_eof:
                        self.set_setpoint("ext", 0)
                        self.set_setpoint("bed", 0)
                    yield from self._queue_move({"command": "eof"})
                    self.move.reset()
                    continue
            else:
                l = self._read_gcode()
            if len(l) == 0:  # File reader stalled
                yield from self._queue_move({"command": "eof"})
                self.move.reset()
                continue
            obj = self.gcode.process_line(l)
            if obj is None:
                continue
            # print("PRINTER GCODE:", repr(obj))
            cmd = obj["command"]
            if cmd == "setpoint":
                if self.heater_enable_mcodes:
                    self.set_setpoint(obj["type"], obj["value"])
                    if obj["wait"]:
                        yield from self.wait_for_setpoints()
            elif cmd == "log":
                self.webui.queue_log(obj['type'], obj['value'])
            else:
                yield from self._queue_move(obj)
                idle = False
                self.set_idle(False)

    def _heater_status(self, name):
        ok = self.check_setpoint(name)
        sp = self.setpoint[name]
        temp = self.get_temperature(name)
        if sp == 0:
            return "off"
        if ok:
            return "ok"
        if sp > temp:
            return "low"
        if sp < temp:
            return "high"

    def update_status(self, force=False):
        if self.idling:
            motors = "idle"
        elif self.gcode_file is not None:
            motors = "processing"
        else:
            motors = "moving"
        ext = self._heater_status("ext")
        bed = self._heater_status("bed")
        status = (motors, ext, bed)
        if self.webui is None:
            return
        if self.current_status == status:
            return
        self.current_status = status
        self.webui.queue_status(*status)

    def set_idle(self, idle):
        if idle != self.idling:
            self.idling = idle
            self.update_status()

    def handle_sc_write(self):
        if not self.idling:
            ret = self.sc.pull_cmd_buffer()
            if ret == 1:
                self.set_idle(True)
            if self.move.buffer_ready() and not self.ev_buffer.is_set():
                # print("PRINTER: cond notify")
                self.ev_buffer.set()
        else:
            self.sc.zero_output()

    def set_pause(self, pause):
        self.pause = pause
        print("Set pause:", repr(pause))

    @asyncio.coroutine
    def stop(self):
        print("Stopping...")
        self.abort()
        yield from self.execute_gcode("G91")
        yield from self.execute_gcode("G1 Z5 F5000")
        yield from self.execute_gcode("G90")

    def abort(self):
        print("Aborting...")
        if self.gcode_file:
            self.gcode_file.close()
            self.gcode_file = None
        while not self.gcode_queue.empty():
            self.gcode_queue.get_nowait()
        self.sc.cancel_destination()
        self.sc.flush_queue()
        # We may have interrupted a move. Make sure we know where we are...
        scpos = self.sc.get_position()
        gpos = self.move.reverse_transform(scpos)
        self.gcode.set_position(gpos)
        self.set_setpoint("ext", 0)
        self.set_setpoint("bed", 0)

    def reset(self):
        self.gcode.reset()
        self.sc.set_position([0, 0, 0, 0])
        self.move.reset()
        self.set_position_mm(0, 0, 0, 0)

    def set_heater_enable_mcodes(self, value):
        self.heater_enable_mcodes = value

    def set_heater_disable_eof(self, value):
        self.heater_disable_eof = value

    def set_ignore_endstop(self, value):
        if self.ignore_endstop != value:
            self.ignore_endstop = value
            if value:
                self.disable_endswitches()
            else:
                self.enable_endswitches()

    def disable_endswitches(self):
        for e in self.esw:
            e.disable_exceptions()

    def enable_endswitches(self):
        for e in self.esw:
            e.enable_exceptions()

    def prepare_endswitches(self):
        self.esw = []
        for axis in ["X", "Y", "Z"]:
            eswname = "endstop_" + axis
            self.esw.append(AsyncGPInput(eswname, self))

    def gpio_event(self, name, val):
        print("GPIO Event from", name, "value:", val)
        self.sc.stop()
        self.sc.cancel_destination()
        self.sc.restart()

    def run(self):
        self.loop.run_forever()
class MainWindow(QWidget):
    def __init__(self, appinst, profilecon, settingscon, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.app = appinst
        self.profilecon = profilecon  # connector class instance for reading/writing profile settings
        self.settingscon = settingscon
        self.gcode = None
        self.machine = None

        self.backgroundTask = None
        self.postBackgroundTask = None

        self.coord_plot_items = list(
        )  # list of all plot items added to the coord plot

        self.mainlayout = QVBoxLayout(self)
        self.mainlayout.setContentsMargins(0, 0, 0, 0)

        self.toolBar = QToolBar()
        self.toolBar.setStyleSheet("""QToolBar {background-color: white;
                                                border-top: 1px solid black}"""
                                   )
        self.mainlayout.addWidget(self.toolBar)

        self.add_toolbar_action("./res/folder.svg", "Open",
                                self.open_file_dialog)
        self.add_toolbar_action("./res/x-square.svg", "Close", self.close_file)
        self.add_toolbar_action("./res/save.svg", "Export", self.export)
        self.toolBar.addSeparator()
        self.add_toolbar_action("./res/sliders.svg", "Settings",
                                self.open_settings_dialog)
        self.add_toolbar_action("./res/play.svg", "Simulate",
                                self.start_simulation)
        self.toolBar.addSeparator()
        self.add_toolbar_action("./res/maximize.svg", "Fit to View",
                                self.fit_plot_to_window)
        self.add_toolbar_action("./res/maximize-2.svg", "Reset View",
                                self.reset_plot_view)
        self.toolBar.addSeparator()
        self.profileSelector = QComboBox()
        for name in self.profilecon.list_profiles():
            self.profileSelector.addItem(name)
        self.profileSelector.setCurrentText(
            self.settingscon.get_value("Current_Profile"))
        self.profilecon.select_profile(
            self.settingscon.get_value("Current_Profile"))
        self.toolBar.addWidget(self.profileSelector)
        self.profileSelector.currentTextChanged.connect(
            self.selected_profile_changed)
        divider = QWidget()
        divider.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.toolBar.addWidget(divider)
        self.add_toolbar_action("./res/info.svg", "About",
                                self.open_about_dialog)

        self.contentLayout = QHBoxLayout()
        self.contentLayout.setContentsMargins(10, 10, 10, 10)
        self.mainlayout.addLayout(self.contentLayout)

        self.layerSlider = QSlider()
        self.layerSlider.setMinimum(0)
        self.layerSlider.setValue(0)
        self.layerSlider.setDisabled(True)
        self.layerSlider.valueChanged.connect(self.show_layer)
        self.contentLayout.addWidget(self.layerSlider)

        self.coordPlot = PlotWidget()
        self.coordPlot.setAspectLocked(True)
        # self.coordPlot.setLimits(xMin=0, yMin=0)
        self.configure_plot(
        )  # is done in a seperate funciton because values need to be updated after settings are changed
        self.contentLayout.addWidget(self.coordPlot)

        self.sidebarlayout = QVBoxLayout()
        self.contentLayout.addLayout(self.sidebarlayout)

        self.sidebarheader = QLabel("Options")
        self.sidebarheader.setFixedSize(300, 50)
        self.sidebarlayout.addWidget(self.sidebarheader)

    def configure_plot(self):
        self.coordPlot.invertX(
            self.profilecon.get_value("invert_x")
        )  # needs to be done before setting the axis ranges because
        self.coordPlot.invertY(
            self.profilecon.get_value("invert_y")
        )  # inverting does not update the viewbox, but setting the range does
        self.coordPlot.setXRange(self.profilecon.get_value("bed_min_x"),
                                 self.profilecon.get_value("bed_max_x"))
        self.coordPlot.setYRange(self.profilecon.get_value("bed_min_y"),
                                 self.profilecon.get_value("bed_max_y"))

    def selected_profile_changed(self, new_profile):
        # select the new profile in the settings connector and update the ui accordingly
        self.profilecon.select_profile(new_profile)
        self.settingscon.set_value("Current_Profile",
                                   new_profile)  # remember selected profile
        self.settingscon.save_to_file()
        self.configure_plot()

    def add_toolbar_action(self, icon, text, function):
        # wrapper function for adding a toolbar button and connecting it to trigger a function
        open_icon = QIcon(icon)
        action = self.toolBar.addAction(open_icon, text)
        action.triggered.connect(function)

    def finish_background_task(self):
        # function is called when a background task finishes
        if self.postBackgroundTask:
            # run cleanup task (i.e. ui update); runs on main ui thread!
            self.postBackgroundTask()
        # reset variables
        self.postBackgroundTask = None
        self.backgroundTask = None

    def run_in_background(self, task, after=None, args=None):
        # wrapper function for creating and starting a thread to run a function in the background
        # arguments can be passed to the function in the thread and a cleanup function can be specified
        # which is run on the main ui thread when the background task is finished
        self.backgroundTask = BackgroundTask(task)
        if args:
            self.backgroundTask.set_arguments(args)
        self.backgroundTask.finished.connect(self.finish_background_task)
        self.postBackgroundTask = after
        self.backgroundTask.start()

    def open_file_dialog(self):
        # in case a file is open already, close it properly first
        if self.machine:
            ret = self.close_file()
            if not ret:
                # user canceled closing of current file; can't open new one
                return

        # open dialog for selecting a gcode file to be loaded
        dialog = QFileDialog(self)
        dialog.setFileMode(QFileDialog.ExistingFile)
        filters = ["G-code (*.gcode)", "Any files (*)"]
        dialog.setNameFilters(filters)
        dialog.selectNameFilter(filters[0])
        dialog.setViewMode(QFileDialog.Detail)

        filename = None
        if dialog.exec_():
            filename = dialog.selectedFiles()

        if filename:
            self.run_in_background(self.load_data,
                                   after=self.show_layer,
                                   args=filename)

    def open_settings_dialog(self):
        # open a dialog with settings
        dialog = SettingsDialog(self, self.profilecon)
        dialog.exec()

        # update settings
        self.configure_plot()

    def open_about_dialog(self):
        # open the about dialog
        dialog = QDialog()
        dialog.setWindowTitle("About...")

        layout = QVBoxLayout()
        dialog.setLayout(layout)

        text = QLabel(strings.about)
        layout.addWidget(text)

        dialog.exec()

    def close_file(self):
        # close the current gcode file, discard all data
        # Before, ask for user confirmation
        cfmsgbox = QMessageBox()
        cfmsgbox.setWindowTitle("Close file?")
        cfmsgbox.setText(
            "Are you sure you want to close the current file and discard all unsaved data?"
        )
        cfmsgbox.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
        cfmsgbox.setDefaultButton(QMessageBox.No)
        ret = cfmsgbox.exec()

        if ret == QMessageBox.Yes:
            for item in self.coord_plot_items:
                self.coordPlot.removeItem(item)

            self.machine = None
            self.gcode = None
            # TODO: fix: this will not terminate a running background process
            return True

        return False

    def export(self):
        pass

    def start_simulation(self):
        pass

    def fit_plot_to_window(self):
        x, y = self.machine.get_path_coordinates(
            layer_number=self.layerSlider.value())
        self.coordPlot.setRange(xRange=(min(x), max(x)),
                                yRange=(min(y), max(y)))

    def reset_plot_view(self):
        self.coordPlot.setXRange(self.profilecon.get_value("bed_min_x"),
                                 self.profilecon.get_value("bed_max_x"))
        self.coordPlot.setYRange(self.profilecon.get_value("bed_min_y"),
                                 self.profilecon.get_value("bed_max_y"))

    def load_data(self, filename):
        # initalizes a virtual machine from the gcode in the file given
        # all path data for this gcode is calculated; this is a cpu intensive task!
        self.gcode = GCode()
        self.gcode.load_file(filename)
        self.machine = Machine(self.gcode, self.profilecon)
        self.machine.create_path()

        # set the layer sliders maximum to represent the given amount of layers and enable the slider
        self.layerSlider.setMaximum(len(self.machine.layers) - 1)
        self.layerSlider.setEnabled(True)

    def show_layer(self):
        # plot path for the layer selected by the layer slider
        x, y = self.machine.get_path_coordinates(
            layer_number=self.layerSlider.value())
        pltitm = self.coordPlot.plot(x, y, clear=True)
        self.coord_plot_items.append(pltitm)
Beispiel #46
0
class Slic3rEngineRunner(QObject):
    '''
    This is just connector to console version of Slic3r software
    first version
    '''
    step_increased = pyqtSignal(int)
    filament_info = pyqtSignal(str)
    finished = pyqtSignal()
    send_message = pyqtSignal(str)
    send_gcodedata = pyqtSignal(GCode)

    support_parameters = ["support_material_angle",
                            "support_material_buildplate_only",
                            "support_material_contact_distance",
                            "support_material_enforce_layers",
                            "support_material_extruder",
                            "support_material_extrusion_width",
                            "support_material_interface_extruder",
                            "support_material_interface_layers",
                            "support_material_interface_spacing",
                            "support_material_interface_speed",
                            "support_material_pattern",
                            "support_material_spacing",
                            "support_material_threshold",
                            "support_material_with_sheath",
                            "support_material_xy_spacing"]

    multimaterial_spec_parameters = ["bridge_fan_speed",
                        "cooling",
                        "deretract_speed",
                        "disable_fan_first_layers",
                        "extrusion_multiplier",
                        "fan_always_on",
                        "fan_below_layer_time",
                        "filament_density",
                        "filament_diameter",
                        "filament_max_volumetric_speed",
                        "filament_type",
                        "filament_soluble",
                        "first_layer_bed_temperature",
                        "first_layer_temperature",
                        "max_fan_speed",
                        "max_layer_height",
                        "min_fan_speed",
                        "min_layer_height",
                        "min_print_speed",
                        "nozzle_diameter",
                        "retract_before_travel",
                        "retract_before_wipe",
                        "retract_layer_change",
                        "retract_length",
                        "retract_length_toolchange",
                        "retract_lift",
                        "retract_lift_above",
                        "retract_lift_below",
                        "retract_restart_extra",
                        "retract_restart_extra_toolchange",
                        "retract_speed",
                        "slowdown_below_layer_time",
                        "temperature",
                        "wipe"]



    def __init__(self, controller):
        super(Slic3rEngineRunner, self).__init__()
        self.is_running = True
        self.controller = controller

        self.gcode = GCode(self.controller.app_config.tmp_place + 'out.gcode', self.controller, None, None)

        system_platform = platform.system()
        if system_platform in ['Linux']:
            self.slicer_place = [self.controller.app_config.local_path + "tools/Slic3r-Lite/bin/slic3r"]
        elif system_platform in ['Darwin']:
            self.slicer_place = [self.controller.app_config.local_path + "tools/Slic3r-Lite/Slic3r.app/Contents/MacOS/Slic3r"]
        elif system_platform in ['Windows']:
            self.slicer_place = ['tools\\Slic3r-Lite\\slic3r-noconsole.exe']
        else:
            self.slicer_place = ['slic3r']

        #print(self.slicer_place)

        self.step_max = 9
        self.step = 0


    def translate_dictionary(self, old, update):
        translation_table = [
            ['fill_density', 'infill', self.percent_transform],
            ['brim_width', 'brim', self.brim_transform],
            #['support_material', 'support', self.boolean_transform]
            ['support_material', 'support_on_off', self.support1_transform],
            ['support_material_buildplate_only', 'support_build_plate', self.support2_transform],
            ['overhangs', 'overhangs', self.support3_transform],
            ['support_material_extruder', 'support_material_extruder', self.support4_transform],
            ['support_material_interface_extruder', 'support_material_interface_extruder', self.str_transform],

            ['wipe_tower', 'is_wipe_tower', self.str_transform],
            ['wipe_tower_per_color_wipe', 'wipe_size_y', self.str_transform],
            ['wipe_tower_width', 'wipe_size_x', self.str_transform],
            ['wipe_tower_x', 'wipe_pos_x', self.str_transform],
            ['wipe_tower_y', 'wipe_pos_y', self.str_transform],

            ['single_extruder_multi_material', 'is_multimat', self.str_transform]

        ]
        for i in translation_table:
            old[i[0]] = i[2](update[i[1]])
        return old

    def percent_transform(self, in_value):
        return "%s" % str(in_value) + '%'

    def brim_transform(self, in_value):
        return "%s" % str(int(in_value)*10)

    def support1_transform(self, in_value):
        print("Support transform 1: " + str(in_value))
        if in_value == 0:   #None
            return "0"
        elif in_value >= 1: #Build plate only
            return "1"
        return "0"

    def support2_transform(self, in_value):
        print("Support transform 2: " + str(in_value))
        if in_value == 0:   #None
            return "0"
        elif in_value == 1: #Build plate only
            return "1"
        elif in_value == 2: #Everywhere
            return "0"
        elif in_value == 3: #Build plate only with interface
            return "1"
        elif in_value == 4: #Everywhere with interface
            return "0"
        else:
            return "0"
        return "0"

    def support3_transform(self, in_value):
        print("Support transform 3: " + str(in_value))
        if in_value == 0:   #None
            return "0"
        elif in_value >= 1: #other support options
            return "1"
        else:
            return "1"
        return "0"

    def support4_transform(self, in_value):
        print("Support transform 4: " + str(in_value))
        #support material extruder
        [a, b] = in_value
        if b == 0:   #None
            return "0"
        elif b == 1: #Build plate only
            return self.str_transform(a)
        elif b == 2: #Everywhere
            return self.str_transform(a)
        elif b > 2: #Build plate only
            return "0"
        return "0"

    def str_transform(self, in_value):
        return "%s" % str(in_value)

    def list_to_str(self, lst):
        return ','.join(str(e) for e in lst)


    def save_configuration(self, filename):
        actual_printing_data = self.controller.get_actual_printing_data()
        for i in actual_printing_data:
            if i in ['brim', 'support_on_off'] and actual_printing_data[i]==True:
                self.step_max+=1

        #material_printing_data = self.controller.get_printing_parameters_for_material_quality(actual_printing_data['material'], actual_printing_data['quality'])
        material_printing_data = self.controller.printing_parameters.get_actual_settings(self.controller.get_actual_printer(), self.controller.settings['printer_type'], actual_printing_data['material'], actual_printing_data['quality'], self)
        #print("All settings: " + str(material_printing_data))
        new_parameters = self.translate_dictionary(material_printing_data, actual_printing_data)
        new_config = configparser.RawConfigParser()
        new_config.add_section('settings')
        #new_config.set('settings', i, new_parameters)
        for i in new_parameters:
            if type(new_parameters[i]) == list:
                new_config.set('settings', i, self.list_to_str(new_parameters[i]))
            else:
                new_config.set('settings', i, new_parameters[i])

        #write ini file
        with open(filename, 'w') as ini_file:
            fake_file = io.StringIO()
            new_config.write(fake_file)
            ini_file.write(fake_file.getvalue()[11:])

        print("saved")


    def slice(self):
        self.save_configuration(self.controller.app_config.tmp_place + 'prusacontrol.ini')
        self.process = subprocess.Popen(
                    self.slicer_place + [self.controller.app_config.tmp_place + 'tmp.prusa', '--load',
                                         self.controller.app_config.tmp_place + 'prusacontrol.ini', '--output',
                                         self.controller.app_config.tmp_place + 'out.gcode', '--dont-arrange'],
                    stdout=subprocess.PIPE)

        #if self.controller.is_multimaterial() and not self.controller.is_single_material_mode():
        #    self.process = subprocess.Popen(
        #        self.slicer_place + [self.controller.app_config.tmp_place + 'tmp.prusa', '--load',
        #                             self.controller.app_config.tmp_place + 'prusacontrol.ini', '--output',
        #                             self.controller.app_config.tmp_place + 'out.gcode', '--dont-arrange'],
        #        stdout=subprocess.PIPE)
        #else:
        #    self.process = subprocess.Popen(self.slicer_place + [self.controller.app_config.tmp_place + 'tmp.stl', '--load',
        #                            self.controller.app_config.tmp_place + 'prusacontrol.ini', '--output',
        #                            self.controller.app_config.tmp_place + 'out.gcode', '--dont-arrange'],
        #                           stdout=subprocess.PIPE)
        self.check_progress()

    def kill(self):
        self.process.kill()

    def check_progress(self):
        self.step = 1
        while self.is_running is True:
            self.step+=1
            if self.process.returncode == -signal.SIGSEGV:
                self.send_message.emit("Slic3r engine crash")
                break
            line = str(self.process.stdout.readline(), 'utf-8')
            parsed_line = line.rsplit()
            print(parsed_line)
            if not line:
                continue
            if 'Done.' in parsed_line[0]:
                self.step_increased.emit(95)
                self.send_message.emit("Generating G-code preview")
                self.gcode.read_in_realtime()
                self.send_gcodedata.emit(self.gcode)
                self.send_message.emit("")
            elif 'Filament' in parsed_line[0] and 'required:' in parsed_line[1]:
                filament_str = str(parsed_line[2] + ' ' + parsed_line[3])
                print(filament_str)
                self.filament_info.emit(filament_str)
                self.finished.emit()
                #self.step_increased.emit(100)
                break
            else:
                text = line.rsplit()[1:]
                if text[0] == 'Exporting':
                    text = text[:2]
                self.send_message.emit(" ".join(text))
            self.step_increased.emit(int((self.step / 12.) * 100))

    def end(self):
        self.end_callback()

    def get_version(self):
        version_process = subprocess.Popen(self.slicer_place + ["--version"], stdout=subprocess.PIPE)
        version_info = str(version_process.stdout.readline(), 'utf-8')
        return version_info
Beispiel #47
0
from serialComunicator import Device
from gcode import GCode
from time import sleep
from picamera import PiCamera

gcode = GCode(2,2)
gcode.init_file()
gcode.build_file()

camera = PiCamera()

def start():
    arduino = Device(port='/dev/ttyUSB0', baud_rate=115200)
    arduino.connect_device()
    sleep(2)
    arduino.send_command('$X',timeout=4)
    sleep(2)
    arduino.load_grlb_config()
    sleep(5)
    camera.start_preview()
    lines = gcode.get_gcode()
    do_gcode_lines(lines, arduino)


def finish():
    camera.stop_preview()
    camera.close()


def take_picture(c, delay):
    sleep(delay)
Beispiel #48
0
class Slic3rEngineRunner(QObject):
    '''
    This is just connector to console version of Slic3r software
    first version
    '''
    step_increased = pyqtSignal(int)
    filament_info = pyqtSignal(str)
    finished = pyqtSignal()
    send_message = pyqtSignal(str)
    send_gcodedata = pyqtSignal(GCode)

    #support parameters for soluble materials, list of parameters which will be used from soluble materials
    support_parameters = [
        "support_material_angle", "support_material_buildplate_only",
        "support_material_contact_distance", "support_material_enforce_layers",
        "support_material_extruder", "support_material_extrusion_width",
        "support_material_interface_extruder",
        "support_material_interface_layers",
        "support_material_interface_spacing",
        "support_material_interface_speed", "support_material_pattern",
        "support_material_spacing", "support_material_threshold",
        "support_material_with_sheath", "support_material_xy_spacing",
        "support_material_synchronize_layers"
    ]

    multimaterial_spec_parameters = [
        "bridge_fan_speed", "cooling", "deretract_speed",
        "disable_fan_first_layers", "extrusion_multiplier", "fan_always_on",
        "fan_below_layer_time", "filament_density", "filament_diameter",
        "filament_max_volumetric_speed", "filament_type", "filament_soluble",
        "first_layer_bed_temperature", "first_layer_temperature",
        "max_fan_speed", "max_layer_height", "min_fan_speed",
        "min_layer_height", "min_print_speed", "nozzle_diameter",
        "retract_before_travel", "retract_before_wipe", "retract_layer_change",
        "retract_length", "retract_length_toolchange", "retract_lift",
        "retract_lift_above", "retract_lift_below", "retract_restart_extra",
        "retract_restart_extra_toolchange", "retract_speed",
        "slowdown_below_layer_time", "temperature", "wipe"
    ]

    def __init__(self, controller):
        super(Slic3rEngineRunner, self).__init__()
        self.is_running = True
        self.controller = controller

        self.gcode = GCode(self.controller.app_config.tmp_place + 'out.gcode',
                           self.controller, None, None)

        system_platform = platform.system()
        if system_platform in ['Linux']:
            self.slicer_place = [
                self.controller.app_config.local_path +
                "tools/Slic3r-Lite/bin/slic3r"
            ]
        elif system_platform in ['Darwin']:
            self.slicer_place = [
                self.controller.app_config.local_path +
                "tools/Slic3r-Lite/Slic3r.app/Contents/MacOS/Slic3r"
            ]
        elif system_platform in ['Windows']:
            self.slicer_place = ['tools\\Slic3r-Lite\\slic3r-noconsole.exe']
        else:
            self.slicer_place = ['slic3r']

        #print(self.slicer_place)

        self.step_max = 9
        self.step = 0

    def translate_dictionary(self, old, update):
        translation_table = [
            ['fill_density', 'infill', self.percent_transform],
            ['brim_width', 'brim', self.brim_transform],
            #['support_material', 'support', self.boolean_transform]
            ['support_material', 'support_on_off', self.support1_transform],
            [
                'support_material_buildplate_only', 'support_build_plate',
                self.support2_transform
            ],
            ['overhangs', 'overhangs', self.support3_transform],
            [
                'support_material_extruder', 'support_material_extruder',
                self.support4_transform
            ],
            [
                'support_material_interface_extruder',
                'support_material_interface_extruder', self.str_transform
            ],
            ['wipe_tower', 'is_wipe_tower', self.str_transform],
            ['wipe_tower_per_color_wipe', 'wipe_size_y', self.str_transform],
            ['wipe_tower_width', 'wipe_size_x', self.str_transform],
            ['wipe_tower_x', 'wipe_pos_x', self.str_transform],
            ['wipe_tower_y', 'wipe_pos_y', self.str_transform],
            [
                'single_extruder_multi_material', 'is_multimat',
                self.str_transform
            ]
        ]
        for i in translation_table:
            old[i[0]] = i[2](update[i[1]])
        return old

    def percent_transform(self, in_value):
        return "%s" % str(in_value) + '%'

    def brim_transform(self, in_value):
        return "%s" % str(int(in_value) * 10)

    def support1_transform(self, in_value):
        print("Support transform 1: " + str(in_value))
        if in_value == 0:  #None
            return "0"
        elif in_value >= 1:  #Build plate only
            return "1"
        return "0"

    def support2_transform(self, in_value):
        print("Support transform 2: " + str(in_value))
        if in_value == 0:  #None
            return "0"
        elif in_value == 1:  #Build plate only
            return "1"
        elif in_value == 2:  #Everywhere
            return "0"
        elif in_value == 3:  #Build plate only with interface
            return "1"
        elif in_value == 4:  #Everywhere with interface
            return "0"
        else:
            return "0"
        return "0"

    def support3_transform(self, in_value):
        print("Support transform 3: " + str(in_value))
        if in_value == 0:  #None
            return "0"
        elif in_value >= 1:  #other support options
            return "1"
        else:
            return "1"
        return "0"

    def support4_transform(self, in_value):
        print("Support transform 4: " + str(in_value))
        #support material extruder
        [a, b] = in_value
        if b == 0:  #None
            return "0"
        elif b == 1:  #Build plate only
            return self.str_transform(a)
        elif b == 2:  #Everywhere
            return self.str_transform(a)
        elif b > 2:  #Build plate only
            return "0"
        return "0"

    def str_transform(self, in_value):
        return "%s" % str(in_value)

    def list_to_str(self, lst):
        return ','.join(str(e) for e in lst)

    def save_configuration(self, filename):
        actual_printing_data = self.controller.get_actual_printing_data()
        for i in actual_printing_data:
            if i in ['brim', 'support_on_off'
                     ] and actual_printing_data[i] == True:
                self.step_max += 1

        #material_printing_data = self.controller.get_printing_parameters_for_material_quality(actual_printing_data['material'], actual_printing_data['quality'])
        material_printing_data = self.controller.printing_parameters.get_actual_settings(
            self.controller.get_actual_printer(),
            self.controller.settings['printer_type'],
            actual_printing_data['material'], actual_printing_data['quality'],
            self)
        #print("All settings: " + str(material_printing_data))
        new_parameters = self.translate_dictionary(material_printing_data,
                                                   actual_printing_data)
        new_config = configparser.RawConfigParser()
        new_config.add_section('settings')
        #new_config.set('settings', i, new_parameters)
        for i in new_parameters:
            if type(new_parameters[i]) == list:
                new_config.set('settings', i,
                               self.list_to_str(new_parameters[i]))
            else:
                new_config.set('settings', i, new_parameters[i])

        #write ini file
        with open(filename, 'w') as ini_file:
            fake_file = io.StringIO()
            new_config.write(fake_file)
            ini_file.write(fake_file.getvalue()[11:])

        print("saved")

    def slice(self):
        self.save_configuration(self.controller.app_config.tmp_place +
                                'prusacontrol.ini')
        self.process = subprocess.Popen(self.slicer_place + [
            self.controller.app_config.tmp_place + 'tmp.prusa', '--load',
            self.controller.app_config.tmp_place + 'prusacontrol.ini',
            '--output', self.controller.app_config.tmp_place + 'out.gcode',
            '--dont-arrange'
        ],
                                        stdout=subprocess.PIPE)

        #if self.controller.is_multimaterial() and not self.controller.is_single_material_mode():
        #    self.process = subprocess.Popen(
        #        self.slicer_place + [self.controller.app_config.tmp_place + 'tmp.prusa', '--load',
        #                             self.controller.app_config.tmp_place + 'prusacontrol.ini', '--output',
        #                             self.controller.app_config.tmp_place + 'out.gcode', '--dont-arrange'],
        #        stdout=subprocess.PIPE)
        #else:
        #    self.process = subprocess.Popen(self.slicer_place + [self.controller.app_config.tmp_place + 'tmp.stl', '--load',
        #                            self.controller.app_config.tmp_place + 'prusacontrol.ini', '--output',
        #                            self.controller.app_config.tmp_place + 'out.gcode', '--dont-arrange'],
        #                           stdout=subprocess.PIPE)
        self.check_progress()

    def kill(self):
        self.process.kill()

    def check_progress(self):
        #self.gcode.set_running_variable(self.is_running)
        self.step = 16
        step_coef = 40. / (len(self.controller.scene.get_models(False)) * 7.)
        while self.is_running is True:
            self.step += (1. * step_coef)
            if self.process.returncode == -signal.SIGSEGV:
                self.send_message.emit("Slic3r engine crash")
                break
            line = str(self.process.stdout.readline(), 'utf-8')
            parsed_line = line.rsplit()
            print(parsed_line)
            if not line:
                continue
            if 'Done.' in parsed_line[0]:
                self.step_increased.emit(75)
                self.send_message.emit("Generating G-code preview")

                if self.gcode.read_in_realtime(True,
                                               self.set_gcode_progressbar):
                    self.send_gcodedata.emit(self.gcode)
                else:
                    self.send_message.emit("")
                    return
                self.send_message.emit("")
            elif 'Filament' in parsed_line[0] and 'required:' in parsed_line[1]:
                filament_str = str(parsed_line[2] + ' ' + parsed_line[3])
                self.filament_info.emit(filament_str)
                self.finished.emit()
                #self.step_increased.emit(100)
                break
            else:
                text = line.rsplit()[1:]
                if text[0] == 'Exporting':
                    text = text[:2]
                self.send_message.emit(" ".join(text))
            self.step_increased.emit(int(self.step))

    def set_gcode_progressbar(self, value):
        start = 75
        final = int(((value + 0.001) / 100.) * 25.)
        self.step_increased.emit(start + final)

    def end(self):
        self.end_callback()

    def get_version(self):
        version_process = subprocess.Popen(self.slicer_place + ["--version"],
                                           stdout=subprocess.PIPE)
        version_info = str(version_process.stdout.readline(), 'utf-8')
        return version_info
Beispiel #49
0
    def test_invalid_commands(self):
        # none of the lines should load with default parameters
        # therefore every line needs to be checked seperatly
        with open("gc_invalid_commands.gcode", "r") as fobj:
            linenumber = 0
            for line in fobj.readlines():
                gcode = GCode()
                with self.assertRaises(ValueError, msg="GCode Line {}: \n {}".format(linenumber, line)):
                    gcode.parse_line(line, linenumber)

        # load and ignore errors, keep lines
        gcode = GCode(ignore_invalid=True, keep_invalid=True)
        gcode.load_file("gc_invalid_commands.gcode")

        self.assertEqual(len(gcode._lines), 4)  # four commands should be loaded

        for i in range(4):
            self.assertEqual(gcode._lines[i].is_valid(), False)  # no command should be valid

        # load and ignore errors, discard lines
        gcode = GCode(ignore_invalid=True, keep_invalid=False)
        gcode.load_file("gc_invalid_commands.gcode")

        self.assertEqual(len(gcode._lines), 0)   # no commands should be loaded
Beispiel #50
0
class Slic3rEngineRunner(QObject):
    '''
    This is just connector to console version of Slic3r software
    first version
    '''
    step_increased = pyqtSignal(int)
    filament_info = pyqtSignal(str)
    finished = pyqtSignal()
    send_message = pyqtSignal(str)
    send_gcodedata = pyqtSignal(GCode)

    def __init__(self, controller):
        super(Slic3rEngineRunner, self).__init__()
        self.is_running = True
        self.controller = controller

        self.gcode = GCode(self.controller.app_config.tmp_place + 'out.gcode',
                           self.controller, None, None)

        system_platform = platform.system()
        if system_platform in ['Linux']:
            self.slicer_place = ['/home/tibor/dev/Slic3r/bin/slic3r']
            #self.slicer_place = './tools/Slic3r-Lite/slic3r'
        elif system_platform in ['Darwin']:
            self.slicer_place = [
                self.controller.app_config.local_path +
                "tools/Slic3r-Lite/Slic3r.app/Contents/MacOS/Slic3r"
            ]
        elif system_platform in ['Windows']:
            self.slicer_place = ['tools\\Slic3r-Lite\\slic3r-noconsole.exe']
        else:
            self.slicer_place = ['slic3r']

        #print(self.slicer_place)

        self.step_max = 9
        self.step = 0

    def translate_dictionary(self, old, update):
        translation_table = [
            ['fill_density', 'infill', self.percent_transform],
            ['brim_width', 'brim', self.boolean_transform],
            #['support_material', 'support', self.boolean_transform]
            ['support_material', 'support_on_off', self.support1_transform],
            [
                'support_material_buildplate_only', 'support_build_plate',
                self.support2_transform
            ],
            ['overhangs', 'overhangs', self.support3_transform]
        ]
        for i in translation_table:
            old[i[0]] = i[2](update[i[1]])
        return old

    def percent_transform(self, in_value):
        return "%s" % str(in_value) + '%'

    def boolean_transform(self, in_value):
        return "%s" % str(int(in_value) * 10)

    def support1_transform(self, in_value):
        if in_value == 0:  #None
            return "0"
        elif in_value == 1:  #Build plate only
            return "1"
        elif in_value == 2:  #Everywhere
            return "1"
        else:
            return "0"
        return "0"

    def support2_transform(self, in_value):
        if in_value == 0:  #None
            return "0"
        elif in_value == 1:  #Build plate only
            return "1"
        elif in_value == 2:  #Everywhere
            return "0"
        else:
            return "0"
        return "0"

    def support3_transform(self, in_value):
        if in_value == 0:  #None
            return "0"
        elif in_value == 1:  #Build plate only
            return "1"
        elif in_value == 2:  #Everywhere
            return "1"
        else:
            return "1"
        return "0"

    def save_configuration(self, filename):
        actual_printing_data = self.controller.get_actual_printing_data()
        for i in actual_printing_data:
            if i in ['brim', 'support_on_off'
                     ] and actual_printing_data[i] == True:
                self.step_max += 1

        #material_printing_data = self.controller.get_printing_parameters_for_material_quality(actual_printing_data['material'], actual_printing_data['quality'])
        material_printing_data = self.controller.printing_parameters.get_actual_settings(
            self.controller.actual_printer,
            self.controller.settings['printer_type'],
            actual_printing_data['material'], actual_printing_data['quality'])
        #print("All settings: " + str(material_printing_data))
        new_parameters = self.translate_dictionary(material_printing_data,
                                                   actual_printing_data)
        new_config = configparser.RawConfigParser()
        new_config.add_section('settings')
        #new_config.set('settings', i, new_parameters)
        for i in new_parameters:
            new_config.set('settings', i, new_parameters[i])

        #write ini file
        with open(filename, 'w') as ini_file:
            fake_file = io.StringIO()
            new_config.write(fake_file)
            ini_file.write(fake_file.getvalue()[11:])

    def slice(self):
        self.save_configuration(self.controller.app_config.tmp_place +
                                'prusacontrol.ini')

        self.process = subprocess.Popen(self.slicer_place + [
            self.controller.app_config.tmp_place + 'tmp.stl', '--load',
            self.controller.app_config.tmp_place + 'prusacontrol.ini',
            '--output', self.controller.app_config.tmp_place + 'out.gcode',
            '--dont-arrange'
        ],
                                        stdout=subprocess.PIPE)
        self.check_progress()

    def kill(self):
        self.process.kill()

    def check_progress(self):
        self.step = 1
        while self.is_running is True:
            self.step += 1
            if self.process.returncode == -signal.SIGSEGV:
                self.send_message.emit("Slic3r engine crash")
                break
            line = str(self.process.stdout.readline(), 'utf-8')
            parsed_line = line.rsplit()
            print(parsed_line)
            if not line:
                continue
            if 'Done.' in parsed_line[0]:
                self.step_increased.emit(95)
                self.send_message.emit("Generating G-code preview")
                self.gcode.read_in_realtime()
                self.send_gcodedata.emit(self.gcode)
                self.send_message.emit("")
            elif 'Filament' in parsed_line[0] and 'required:' in parsed_line[1]:
                filament_str = str(parsed_line[2] + ' ' + parsed_line[3])
                print(filament_str)
                self.filament_info.emit(filament_str)
                self.finished.emit()
                #self.step_increased.emit(100)
                break
            else:
                text = line.rsplit()[1:]
                if text[0] == 'Exporting':
                    text = text[:2]
                self.send_message.emit(" ".join(text))
            self.step_increased.emit(int((self.step / 12.) * 100))

    def end(self):
        self.end_callback()

    def get_version(self):
        version_process = subprocess.Popen(self.slicer_place + ["--version"],
                                           stdout=subprocess.PIPE)
        version_info = str(version_process.stdout.readline(), 'utf-8')
        return version_info