-
-
Save mnemocron/9825a5c2e1b4eae316c2b2ebd7e88ccb to your computer and use it in GitHub Desktop.
A simple paint application using tkinter in Python 3 to generate GCode for your 3D printer
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- coding: utf-8 -*- | |
""" | |
Created on Mon Apr 29 12:09:09 2019 | |
@author: simon | |
""" | |
from tkinter import * | |
from tkinter.colorchooser import askcolor | |
from pysvg import * | |
import serial | |
event_delay = 7 | |
# size of the paint canvas on screen in px | |
canvas_x = 500 | |
canvas_y = 500 | |
# size of the printer bed in mm | |
printer_x = 200 | |
printer_y = 200 | |
stroke_speed = 5000 | |
comport = 'COM8' | |
baudrate = 115200 | |
z_pos_0 = 10 # when pen is down | |
z_pos_up = 15 # when pen is up | |
x_offset = 20.0 # pen to nozzle offset | |
y_offset = 40.0 # pen to nozzle offset | |
# python -m serial.tools.list_ports | |
class Paint(object): | |
DEFAULT_PEN_SIZE = 5.0 | |
DEFAULT_COLOR = 'black' | |
def __init__(self): | |
self.root = Tk() | |
self.root.winfo_toplevel().title('Paint To 3DPrinter') | |
self.pen_button = Button(self.root, text='pen', command=self.use_pen) | |
self.pen_button.grid(row=0, column=0) | |
self.color_button = Button(self.root, text='color', command=self.choose_color) | |
self.color_button.grid(row=0, column=1) | |
self.eraser_button = Button(self.root, text='clear', command=self.clear_pane) | |
self.eraser_button.grid(row=0, column=2) | |
self.choose_size_button = Scale(self.root, from_=1, to=10, orient=HORIZONTAL) | |
self.choose_size_button.grid(row=0, column=3) | |
self.home_button = Button(self.root, text='home', command=self.home_axis) | |
self.home_button.grid(row=0, column=4) | |
self.c = Canvas(self.root, bg='white', | |
width=canvas_x, | |
height=canvas_y) | |
self.c.grid(row=1, columnspan=5) | |
self.console = Text(self.root, bg='black', fg='white', width=40) | |
self.console.grid(row=0, column=6, rowspan=2) | |
self.console.insert(0.0,'>>> G Code >') | |
self.console_line = 1.0 | |
self.setup() | |
self.root.mainloop() | |
def setup(self): | |
self.old_x = None | |
self.old_y = None | |
self.line_width = self.choose_size_button.get() | |
self.color = self.DEFAULT_COLOR | |
self.eraser_on = False | |
self.active_button = self.pen_button | |
self.c.bind('<B1-Motion>', self.paint) | |
self.c.bind('<ButtonRelease-1>', self.reset_stroke) | |
self.c.bind('<Button-1>', self.begin_stroke) | |
self.old_gcode = '' | |
self.event_delay = 0 | |
def use_pen(self): | |
self.activate_button(self.pen_button) | |
def choose_color(self): | |
self.eraser_on = False | |
self.color = askcolor(color=self.color)[1] | |
def clear_pane(self): | |
self.c.delete('all') | |
self.console.delete('1.0', END) | |
self.console.insert(0.0,'>>> G Code >') | |
self.console_line = 1.0 | |
def activate_button(self, some_button, eraser_mode=False): | |
self.active_button.config(relief=RAISED) | |
some_button.config(relief=SUNKEN) | |
self.active_button = some_button | |
self.eraser_on = eraser_mode | |
def paint(self, event): | |
self.event_delay += 1 | |
if self.event_delay < event_delay: | |
return | |
self.event_delay = 0 | |
self.line_width = self.choose_size_button.get() | |
paint_color = self.color | |
if self.old_x and self.old_y: | |
x = event.x | |
y = event.y | |
if x < 0: | |
x = 0 | |
if x > canvas_x: | |
x = canvas_x | |
if y < 0: | |
y = 0 | |
if y > canvas_y: | |
y = canvas_y | |
self.c.create_line(self.old_x, self.old_y, x, y, | |
width=self.line_width, fill=paint_color, | |
capstyle=ROUND, smooth=TRUE, splinesteps=36) | |
gcode = ('G0 X' + str(round(x/canvas_x*printer_x, 3)+x_offset) + | |
' Y' + str(round(printer_y - | |
y/canvas_y*printer_y, 3)+y_offset) + ' F' + str(stroke_speed) + '\n') | |
# only print, when the distance is at least 1mm | |
if not (gcode in self.old_gcode): | |
self.print_gcode(gcode) | |
self.old_gcode = gcode | |
self.old_x = event.x | |
self.old_y = event.y | |
# place pen on paper | |
def begin_stroke(self, event): | |
gcode = ('G0 X' + str(int(event.x/canvas_x*printer_x + x_offset)) + | |
' Y' + str(int(printer_y - | |
event.y/canvas_y*printer_y) + y_offset) + ' \n') | |
self.print_gcode(gcode) | |
self.print_gcode('G0 Z' + str(z_pos_0) + '\n') | |
# remove pen from paper | |
def reset_stroke(self, event): | |
self.old_x, self.old_y = None, None | |
self.print_gcode('G0 Z' + str(z_pos_up) + '\n') | |
self.event_delay = 6 | |
def home_axis(self): | |
self.print_gcode('G28\n') | |
self.print_gcode('G0 Z' + str(z_pos_up) + '\n') | |
def print_gcode(self, gcode): | |
self.console.insert(self.console_line, gcode) | |
self.console.yview_pickplace("end") | |
ser.write(bytes(gcode, 'utf-8')) | |
self.console_line += 1 | |
if __name__ == '__main__': | |
try: | |
ser = serial.Serial(comport, baudrate) # open serial port | |
Paint() | |
finally: | |
ser.close() | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment