Added code for webserver
This commit is contained in:
parent
0bbd50e95b
commit
ddf19371ab
|
@ -0,0 +1,548 @@
|
||||||
|
#
|
||||||
|
# Copyright (C) 2021 Thomas Van Acker
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify it under
|
||||||
|
# the terms of the GNU General Public License as published by the Free Software
|
||||||
|
# Foundation, either version 3 of the License, or (at your option) any later
|
||||||
|
# version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License along with
|
||||||
|
# this program. If not, see <https://www.gnu.org/licenses/>.""")
|
||||||
|
#
|
||||||
|
|
||||||
|
import serial
|
||||||
|
import time
|
||||||
|
import threading
|
||||||
|
import math
|
||||||
|
|
||||||
|
|
||||||
|
print("PrintBuddy V0.1")
|
||||||
|
print("""
|
||||||
|
Copyright (C) 2021 Thomas Van Acker
|
||||||
|
|
||||||
|
This program comes with ABSOLUTELY NO WARRANTY.
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify it under
|
||||||
|
the terms of the GNU General Public License as published by the Free Software
|
||||||
|
Foundation, either version 3 of the License, or (at your option) any later
|
||||||
|
version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along with
|
||||||
|
this program. If not, see <https://www.gnu.org/licenses/>.""")
|
||||||
|
print("")
|
||||||
|
|
||||||
|
# Static var init
|
||||||
|
COMMANDS = {
|
||||||
|
"help":"List all commands with explanation",
|
||||||
|
"exit":"Disconnect from printer and exit",
|
||||||
|
"raw":"Send raw gcode commands",
|
||||||
|
"home":"Auto-home the machine",
|
||||||
|
"load":"Load a gcode file",
|
||||||
|
"add":"Manipulate the loaded gcode",
|
||||||
|
"print":"Print the loaded gcode",
|
||||||
|
"level":"Start bed leveling wizard",
|
||||||
|
"mesh":"Start mesh bed leveling wizard"
|
||||||
|
}
|
||||||
|
|
||||||
|
GCODE_FILCH_LAYER = ["G28 X Y", "M84", "M300 P3000", "M0", "M600", "M400", "G28 X Y", "G0 F1500"]
|
||||||
|
|
||||||
|
# Function declarations
|
||||||
|
def send(c, silent=False):
|
||||||
|
global s
|
||||||
|
if not silent:
|
||||||
|
print("%s"%c)
|
||||||
|
c += "\n"
|
||||||
|
s.write(c.encode("utf-8"))
|
||||||
|
while True:
|
||||||
|
r = s.readline().decode("utf-8").strip()
|
||||||
|
if not silent:
|
||||||
|
print(" > %s"%r)
|
||||||
|
if r[0:2] == "ok":
|
||||||
|
break
|
||||||
|
|
||||||
|
def threadPrintInput():
|
||||||
|
# Checks for input from user during printing process
|
||||||
|
global abortPrint
|
||||||
|
while printing:
|
||||||
|
i = input()
|
||||||
|
|
||||||
|
if i == "stop" or i == "exit":
|
||||||
|
abortPrint = True
|
||||||
|
break
|
||||||
|
|
||||||
|
def meshZ(X, Y):
|
||||||
|
# Interpolates values of mesh
|
||||||
|
x = X/300*(MESH_SIZE-1)
|
||||||
|
y = Y/300*(MESH_SIZE-1)
|
||||||
|
|
||||||
|
xmin = math.floor(x)
|
||||||
|
xmax = math.ceil(x)
|
||||||
|
ymin = math.floor(y)
|
||||||
|
ymax = math.ceil(y)
|
||||||
|
|
||||||
|
z0 = mesh[ymin][xmin] + (mesh[ymin][xmax]-mesh[ymin][xmin])*(x-xmin)
|
||||||
|
z1 = mesh[ymax][xmin] + (mesh[ymax][xmax]-mesh[ymax][xmin])*(x-xmin)
|
||||||
|
|
||||||
|
z = z0 + (z1-z0)*(y-ymin)
|
||||||
|
return z
|
||||||
|
|
||||||
|
# Var init
|
||||||
|
serialPort = "/dev/ttyUSB0"
|
||||||
|
serialBaud = 115200
|
||||||
|
|
||||||
|
gcodeRaw = ""
|
||||||
|
gcodeLines = []
|
||||||
|
gcodeLayers = 1
|
||||||
|
printing = False
|
||||||
|
abortPrint = False
|
||||||
|
|
||||||
|
MESH_SIZE = 9 # Number of points of a side in the mesh.
|
||||||
|
MESH_OFFSET = 1.00 # The distance above Z=0 where printbed is located. Mesh needs to be added to this number to get the absolute Z height.
|
||||||
|
mesh = [[0 for _ in range(MESH_SIZE)] for __ in range(MESH_SIZE)]
|
||||||
|
meshPositions = [["X%d Y%d"%(280/(MESH_SIZE-1)*x+10, 280/(MESH_SIZE-1)*y+10) for x in range(MESH_SIZE)] for y in range(MESH_SIZE)]
|
||||||
|
|
||||||
|
levelingCornersPos = {0:"X10 Y45",1:"X10 Y260",2:"X280 Y260",3:"X280 Y45"}
|
||||||
|
|
||||||
|
|
||||||
|
# Read mesh file
|
||||||
|
print("Reading mesh file...")
|
||||||
|
try:
|
||||||
|
f = open("mesh.txt", "r")
|
||||||
|
t = f.read()[:-1]
|
||||||
|
f.close()
|
||||||
|
|
||||||
|
lines = t.split("\n")
|
||||||
|
MESH_SIZE = int(lines[0])
|
||||||
|
mesh = [[0 for _ in range(MESH_SIZE)] for __ in range(MESH_SIZE)]
|
||||||
|
meshPositions = [["X%d Y%d"%(280/(MESH_SIZE-1)*x+10, 280/(MESH_SIZE-1)*y+10) for x in range(MESH_SIZE)] for y in range(MESH_SIZE)]
|
||||||
|
|
||||||
|
for i in range(MESH_SIZE*MESH_SIZE):
|
||||||
|
mesh[int(i/MESH_SIZE)][int(i%MESH_SIZE)] = float(lines[i+1])
|
||||||
|
|
||||||
|
print("Mesh loaded.")
|
||||||
|
except Exception as e:
|
||||||
|
print("Couldn't read mesh file. Using default mesh.")
|
||||||
|
print(e)
|
||||||
|
print("Current mesh:")
|
||||||
|
for i in mesh:
|
||||||
|
for j in i:
|
||||||
|
print("{:5.2f}".format(j), end=" ")
|
||||||
|
print()
|
||||||
|
|
||||||
|
# Connect to printer
|
||||||
|
print("\nConnecting to printer...")
|
||||||
|
s = serial.Serial(serialPort, serialBaud)
|
||||||
|
time.sleep(1)
|
||||||
|
s.write(b"\r\n\r\n") # Wake printer
|
||||||
|
time.sleep(2)
|
||||||
|
readBytes = s.inWaiting()
|
||||||
|
r = s.read(readBytes).decode("utf-8")
|
||||||
|
print(" > %s"%r)
|
||||||
|
time.sleep(5)
|
||||||
|
print("Connected!")
|
||||||
|
|
||||||
|
# Start main loop
|
||||||
|
while True:
|
||||||
|
print("\n# Please enter a command ('help' for command list)")
|
||||||
|
cmd = input()
|
||||||
|
|
||||||
|
if cmd == "help":
|
||||||
|
# List all commands
|
||||||
|
print("\nCOMMAND\t\tACTION")
|
||||||
|
for k in COMMANDS.keys():
|
||||||
|
print("%s\t\t%s"%(k, COMMANDS[k]))
|
||||||
|
|
||||||
|
elif cmd == "home":
|
||||||
|
# Home machine
|
||||||
|
send("G28", silent=True) #Auto-home
|
||||||
|
send("M84", silent=True) #Disable steppers
|
||||||
|
|
||||||
|
elif cmd == "raw":
|
||||||
|
# Send raw gcode commands
|
||||||
|
print("Entering raw mode. Proceed at your own risk. Type 'exit' to exit raw mode.")
|
||||||
|
|
||||||
|
while True:
|
||||||
|
print("\n# RAW: Please enter a gcode command (or 'exit' to exit)");
|
||||||
|
r = input()
|
||||||
|
if r == "exit":
|
||||||
|
break
|
||||||
|
send(r)
|
||||||
|
|
||||||
|
print("Exiting raw mode.")
|
||||||
|
|
||||||
|
elif cmd == "load":
|
||||||
|
# Load gcode file
|
||||||
|
print("# Please enter the path to the gcode file you want to load")
|
||||||
|
path = input()
|
||||||
|
|
||||||
|
# Try to open and parse file
|
||||||
|
try:
|
||||||
|
print("Trying to open file...")
|
||||||
|
f = open(path, "r")
|
||||||
|
print("Reading...")
|
||||||
|
gcodeRaw = f.read()[:-1]
|
||||||
|
f.close()
|
||||||
|
print("Parsing...")
|
||||||
|
gcodeLines = gcodeRaw.split("\n")
|
||||||
|
|
||||||
|
# Iterate through all lines to get info
|
||||||
|
gcodeLines = 0
|
||||||
|
for l in range(len(gcodeLines)):
|
||||||
|
line = gcodeLines[l]
|
||||||
|
|
||||||
|
if line[0] == ";":
|
||||||
|
# When comment
|
||||||
|
if line.startswith(";LAYER:"):
|
||||||
|
l = int(line[line.index(":") +1:])
|
||||||
|
if l > gcodeLayers:
|
||||||
|
gcodeLayers = l
|
||||||
|
|
||||||
|
print("#Layers: %d"%gcodeLayers)
|
||||||
|
print("%d lines"%len(gcodeLines))
|
||||||
|
|
||||||
|
print("File loaded! Use 'add' to manipulate this gcode.")
|
||||||
|
except Exception as e:
|
||||||
|
print("Couldn't read file:")
|
||||||
|
print(e)
|
||||||
|
|
||||||
|
# Reset gcode vars
|
||||||
|
gcodeRaw = ""
|
||||||
|
gcodeLines = []
|
||||||
|
gcodeLayers = 1
|
||||||
|
|
||||||
|
elif cmd == "add":
|
||||||
|
# Manipulate gcode
|
||||||
|
|
||||||
|
# Check if gcode present
|
||||||
|
if gcodeRaw == "" or len(gcodeLines) == 0:
|
||||||
|
print("No gcode loaded. Use 'load' to load gcode.")
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Display all commands
|
||||||
|
print("COMMAND\t\tEXPLANATION")
|
||||||
|
print("exit\t\tReturn")
|
||||||
|
print("mesh\t\tEnable Mesh Bed Leveling")
|
||||||
|
print("filch\t\tFilament change at specific layer")
|
||||||
|
print("")
|
||||||
|
print("# Please enter one of the above actions.")
|
||||||
|
|
||||||
|
# Getting input
|
||||||
|
act = input()
|
||||||
|
|
||||||
|
if act == "exit":
|
||||||
|
print("Exiting.")
|
||||||
|
pass
|
||||||
|
|
||||||
|
elif act == "mesh":
|
||||||
|
# Add Mesh Bed Leveling
|
||||||
|
print("Recalculating Z with Mesh Bed Leveling...")
|
||||||
|
layerZ = 0
|
||||||
|
layerIndex = 0
|
||||||
|
for l in range(len(gcodeLines)):
|
||||||
|
line = gcodeLines[l]
|
||||||
|
|
||||||
|
# Check if comment
|
||||||
|
if line[0] == ";":
|
||||||
|
# Check if new layer
|
||||||
|
if line.startswith(";LAYER:"):
|
||||||
|
layerIndex = int(line[line.index(":") +1:])
|
||||||
|
|
||||||
|
if not (line.startswith("G0") or line.startswith("G1")):
|
||||||
|
continue
|
||||||
|
|
||||||
|
# When this is a movement line
|
||||||
|
tokens = line.split(" ")
|
||||||
|
indexX = -1
|
||||||
|
indexY = -1
|
||||||
|
indexZ = -1
|
||||||
|
for t in range(len(tokens)):
|
||||||
|
if tokens[t][0] == "X":
|
||||||
|
indexX = t
|
||||||
|
elif tokens[t][0] == "Y":
|
||||||
|
indexY = t
|
||||||
|
elif tokens[t][0] == "Z":
|
||||||
|
indexZ = t
|
||||||
|
|
||||||
|
# Check if Z is given
|
||||||
|
if not indexZ == -1:
|
||||||
|
# When Z is set -> save as layer height
|
||||||
|
layerZ = float(tokens[indexZ][1:])
|
||||||
|
|
||||||
|
# Add Z if X or Y are set
|
||||||
|
if indexX == -1 or indexY == -1:
|
||||||
|
continue
|
||||||
|
|
||||||
|
X = float(tokens[indexX][1:])
|
||||||
|
Y = float(tokens[indexY][1:])
|
||||||
|
Z = layerZ + MESH_OFFSET + (meshZ(X, Y)*max(0, float(10-layerIndex)/10.0) if layerIndex < 10 else 0)
|
||||||
|
|
||||||
|
# Add Z coordinate
|
||||||
|
tokens.append("Z{:.3f}".format(Z))
|
||||||
|
newLine = " ".join(tokens)
|
||||||
|
gcodeLines[l] = newLine
|
||||||
|
print("Done!")
|
||||||
|
|
||||||
|
elif act == "filch":
|
||||||
|
# Filament change at layer
|
||||||
|
layer = 0
|
||||||
|
while True:
|
||||||
|
# Ask for layer
|
||||||
|
print("# FILCH: At which layer do you want to change filament?")
|
||||||
|
l = input()
|
||||||
|
|
||||||
|
# Check if valid
|
||||||
|
try:
|
||||||
|
layer = int(l)
|
||||||
|
|
||||||
|
if layer > 0 and layer <= gcodeLayers:
|
||||||
|
break
|
||||||
|
|
||||||
|
print("Invalid.")
|
||||||
|
except:
|
||||||
|
print("Invalid.")
|
||||||
|
|
||||||
|
if layer == 0:
|
||||||
|
continue # exit
|
||||||
|
|
||||||
|
# Search for start of this layer
|
||||||
|
print("Searching for layer...")
|
||||||
|
success = False
|
||||||
|
for l in range(len(gcodeLines)):
|
||||||
|
line = gcodeLines[l]
|
||||||
|
|
||||||
|
if line[0] == ";":
|
||||||
|
if line.startswith(";LAYER:"):
|
||||||
|
thisLayer = int(line[line.find(":")+1:])
|
||||||
|
|
||||||
|
# Check if right layer
|
||||||
|
if thisLayer == layer:
|
||||||
|
# Add filch gcode
|
||||||
|
print("Adding gcode for filch...")
|
||||||
|
gcodeLines[l:l] = GCODE_FILCH_LAYER
|
||||||
|
success = True
|
||||||
|
break
|
||||||
|
print("Done." if success else "Couldn't find layer.")
|
||||||
|
|
||||||
|
else:
|
||||||
|
# When add action not found
|
||||||
|
print("Command not found.")
|
||||||
|
|
||||||
|
elif cmd == "print":
|
||||||
|
# Print loaded gcode
|
||||||
|
if len(gcodeLines) == 0:
|
||||||
|
print("No file loaded yet. Use 'load' to load gcode.")
|
||||||
|
else:
|
||||||
|
# Start print
|
||||||
|
printing = True
|
||||||
|
abortPrint = False
|
||||||
|
print("Print started. Type 'stop' at any time to abort the print.")
|
||||||
|
send("M75", silent=True) # Start timer
|
||||||
|
|
||||||
|
# Start thread to check for commands
|
||||||
|
threadInput = threading.Thread(target=threadPrintInput, daemon=True)
|
||||||
|
threadInput.start()
|
||||||
|
|
||||||
|
# Send gcode line by line to printer
|
||||||
|
for l in range(len(gcodeLines)):
|
||||||
|
line = gcodeLines[l]
|
||||||
|
|
||||||
|
# Check if needs to abort print
|
||||||
|
if abortPrint:
|
||||||
|
print("Aborting print!")
|
||||||
|
break
|
||||||
|
|
||||||
|
# Check if comment
|
||||||
|
if line[0] == ";":
|
||||||
|
# Check if new layer
|
||||||
|
if line.startswith(";LAYER:"):
|
||||||
|
layer = int(line[line.index(":") +1:])
|
||||||
|
print("Printing layer %d/%d"%(layer, gcodeLayers))
|
||||||
|
else:
|
||||||
|
# Send line to printer
|
||||||
|
send(line, silent=True)
|
||||||
|
|
||||||
|
# Stop input thread
|
||||||
|
printing = False
|
||||||
|
|
||||||
|
# Stop print
|
||||||
|
send("M104 S0", silent=True) # Hotend off
|
||||||
|
send("M140 S0", silent=True) # Bed off
|
||||||
|
send("M107", silent=True) # Fan off
|
||||||
|
send("M77", silent=True) # Stop timer
|
||||||
|
send("M31", silent=True) # Display time on lcd
|
||||||
|
send("G28 X Y", silent=True) # Home X and Y
|
||||||
|
send("G0 Y300 F1500", silent=True) # Move platform to user
|
||||||
|
send("M84", silent=True) # Disable steppers
|
||||||
|
send("M400", silent=True) # Wait for previous commands to finish
|
||||||
|
send("M300 P3000", silent=True) # Beep
|
||||||
|
print("Print done!")
|
||||||
|
|
||||||
|
elif cmd == "level":
|
||||||
|
# Normal leveling wizard
|
||||||
|
print("Starting leveling wizard...")
|
||||||
|
send("G28", silent=True) #Home
|
||||||
|
send("G0 F7500", silent=True) # Set feedrate
|
||||||
|
|
||||||
|
print("Please adjust the knob under the nozzle so that a piece of paper can slide under the nozzle with just a little bit of friction.")
|
||||||
|
|
||||||
|
# Start corner loop
|
||||||
|
i = 0
|
||||||
|
while True:
|
||||||
|
# Move to corner
|
||||||
|
print("Moving to corner %d..."%i)
|
||||||
|
send("G0 Z10", silent=True)
|
||||||
|
send("G0 %s"%levelingCornersPos[i], silent=True)
|
||||||
|
send("G0 Z0", silent=True)
|
||||||
|
send("M84", silent=True) #Disable steppers
|
||||||
|
|
||||||
|
# Prompt user
|
||||||
|
print("Press ENTER to move to next corner. Type 'exit' to exit wizard.")
|
||||||
|
r = input()
|
||||||
|
|
||||||
|
if r == "exit":
|
||||||
|
break
|
||||||
|
|
||||||
|
# Next corner
|
||||||
|
i = (i+1)%4
|
||||||
|
|
||||||
|
# End wizard
|
||||||
|
send("G0 F1500", silent=True) #Set slower feedrate
|
||||||
|
send("G28", silent=True) #Home
|
||||||
|
send("M84", silent=True) #Disable steppers
|
||||||
|
|
||||||
|
|
||||||
|
elif cmd == "mesh":
|
||||||
|
# Mesh leveling wizard
|
||||||
|
print("Starting mesh leveling wizard...")
|
||||||
|
send("G28", silent=True) #Home
|
||||||
|
send("G0 F7500", silent=True) # Set feedrate
|
||||||
|
|
||||||
|
print("\nSTEP 1: Normal leveling")
|
||||||
|
print("Please adjust the knob under the nozzle so that a piece of paper can slide under the nozzle with just a little bit of friction.")
|
||||||
|
|
||||||
|
# Start corner loop
|
||||||
|
i = 0
|
||||||
|
stop = False
|
||||||
|
while True:
|
||||||
|
# Move to corner
|
||||||
|
print("Moving to corner %d..."%i)
|
||||||
|
send("G0 Z10", silent=True)
|
||||||
|
send("G0 %s"%levelingCornersPos[i], silent=True)
|
||||||
|
send("G0 Z{:.2f}".format(MESH_OFFSET), silent=True)
|
||||||
|
|
||||||
|
# Prompt user
|
||||||
|
print("Press ENTER to move to next corner. Type 'next' to go to step 2. Type 'exit' to exit wizard.")
|
||||||
|
r = input()
|
||||||
|
|
||||||
|
if r == "exit":
|
||||||
|
stop = True
|
||||||
|
break
|
||||||
|
elif r == "next":
|
||||||
|
break
|
||||||
|
|
||||||
|
# Next corner
|
||||||
|
i = (i+1)%4
|
||||||
|
|
||||||
|
# Step 2: get mesh deltas
|
||||||
|
if not stop:
|
||||||
|
print("\nSTEP 2: Mesh leveling")
|
||||||
|
print("For every mesh point, lower the nozzle using the '+' and '-' buttons until the nozzle is at the right height. Then, enter 'next' to go to the next mesh point. Type 'exit' to exit the wizard.")
|
||||||
|
|
||||||
|
# Move through mesh
|
||||||
|
for y in range(MESH_SIZE):
|
||||||
|
for x in range(MESH_SIZE):
|
||||||
|
Z = 1.00 # Offset on top of MESH_OFFSET
|
||||||
|
print("\nMoving to mesh point x=%d, y=%d"%(x,y))
|
||||||
|
send("G0 Z10", silent=True)
|
||||||
|
send("G0 %s"%meshPositions[y][x], silent=True)
|
||||||
|
send("G0 Z{:.3f}".format(Z+MESH_OFFSET), silent=True)
|
||||||
|
|
||||||
|
# Input loop
|
||||||
|
stop = False
|
||||||
|
while True:
|
||||||
|
i = input()
|
||||||
|
|
||||||
|
if i == "+":
|
||||||
|
Z += 0.01
|
||||||
|
send("G0 Z{:.3f}".format(Z+MESH_OFFSET), silent=True)
|
||||||
|
elif i == "-":
|
||||||
|
Z -= 0.01
|
||||||
|
send("G0 Z{:.3f}".format(Z+MESH_OFFSET), silent=True)
|
||||||
|
elif i == "++":
|
||||||
|
Z += 0.1
|
||||||
|
send("G0 Z{:.3f}".format(Z+MESH_OFFSET), silent=True)
|
||||||
|
elif i == "--":
|
||||||
|
Z -= 0.1
|
||||||
|
send("G0 Z{:.3f}".format(Z+MESH_OFFSET), silent=True)
|
||||||
|
elif i == "+++":
|
||||||
|
Z += 0.5
|
||||||
|
send("G0 Z{:.3f}".format(Z+MESH_OFFSET), silent=True)
|
||||||
|
elif i == "---":
|
||||||
|
Z -= 0.5
|
||||||
|
send("G0 Z{:.3f}".format(Z+MESH_OFFSET), silent=True)
|
||||||
|
elif i == "exit":
|
||||||
|
stop = True
|
||||||
|
break
|
||||||
|
elif i == "next":
|
||||||
|
mesh[y][x] = Z
|
||||||
|
print("Mesh value saved (Z={:.3f})".format(Z))
|
||||||
|
break
|
||||||
|
|
||||||
|
# Check if needs to exit
|
||||||
|
if stop:
|
||||||
|
break
|
||||||
|
# Check if needs to exit
|
||||||
|
if stop:
|
||||||
|
break
|
||||||
|
|
||||||
|
# Print mesh
|
||||||
|
print("\nCurrent Mesh:")
|
||||||
|
for i in mesh:
|
||||||
|
for j in i:
|
||||||
|
print("{:6.3f}".format(j), end=" ")
|
||||||
|
print()
|
||||||
|
|
||||||
|
|
||||||
|
# Save mesh to file
|
||||||
|
print("Writing mesh to file...")
|
||||||
|
try:
|
||||||
|
t = ""
|
||||||
|
t += "%d\n"%MESH_SIZE
|
||||||
|
for y in range(MESH_SIZE):
|
||||||
|
for x in range(MESH_SIZE):
|
||||||
|
t += "{:.3f}\n".format(mesh[y][x])
|
||||||
|
f = open("mesh.txt", "w")
|
||||||
|
f.write(t)
|
||||||
|
f.close()
|
||||||
|
except Exception as e:
|
||||||
|
print("Couldn't write mesh to file.")
|
||||||
|
print(e)
|
||||||
|
|
||||||
|
|
||||||
|
# End wizard
|
||||||
|
send("G0 F1500", silent=True) #Set slower feedrate
|
||||||
|
send("G28", silent=True) #Home
|
||||||
|
send("M84", silent=True) #Disable steppers
|
||||||
|
|
||||||
|
|
||||||
|
elif cmd == "exit":
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
print("Command not found. Enter 'help' to list all commands.")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Close serial
|
||||||
|
print("Disconnecting from printer...")
|
||||||
|
s.close()
|
||||||
|
|
||||||
|
# End of script
|
||||||
|
print("Thank you for using PrintBuddy!")
|
550
main.py
550
main.py
|
@ -1,548 +1,6 @@
|
||||||
#
|
from printserver import PrintServer
|
||||||
# Copyright (C) 2021 Thomas Van Acker
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify it under
|
|
||||||
# the terms of the GNU General Public License as published by the Free Software
|
|
||||||
# Foundation, either version 3 of the License, or (at your option) any later
|
|
||||||
# version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
||||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License along with
|
|
||||||
# this program. If not, see <https://www.gnu.org/licenses/>.""")
|
|
||||||
#
|
|
||||||
|
|
||||||
import serial
|
# Start server
|
||||||
import time
|
server = PrintServer()
|
||||||
import threading
|
server.start()
|
||||||
import math
|
|
||||||
|
|
||||||
|
|
||||||
print("PrintBuddy V0.1")
|
|
||||||
print("""
|
|
||||||
Copyright (C) 2021 Thomas Van Acker
|
|
||||||
|
|
||||||
This program comes with ABSOLUTELY NO WARRANTY.
|
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify it under
|
|
||||||
the terms of the GNU General Public License as published by the Free Software
|
|
||||||
Foundation, either version 3 of the License, or (at your option) any later
|
|
||||||
version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
||||||
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License along with
|
|
||||||
this program. If not, see <https://www.gnu.org/licenses/>.""")
|
|
||||||
print("")
|
|
||||||
|
|
||||||
# Static var init
|
|
||||||
COMMANDS = {
|
|
||||||
"help":"List all commands with explanation",
|
|
||||||
"exit":"Disconnect from printer and exit",
|
|
||||||
"raw":"Send raw gcode commands",
|
|
||||||
"home":"Auto-home the machine",
|
|
||||||
"load":"Load a gcode file",
|
|
||||||
"add":"Manipulate the loaded gcode",
|
|
||||||
"print":"Print the loaded gcode",
|
|
||||||
"level":"Start bed leveling wizard",
|
|
||||||
"mesh":"Start mesh bed leveling wizard"
|
|
||||||
}
|
|
||||||
|
|
||||||
GCODE_FILCH_LAYER = ["G28 X Y", "M84", "M300 P3000", "M0", "M600", "M400", "G28 X Y", "G0 F1500"]
|
|
||||||
|
|
||||||
# Function declarations
|
|
||||||
def send(c, silent=False):
|
|
||||||
global s
|
|
||||||
if not silent:
|
|
||||||
print("%s"%c)
|
|
||||||
c += "\n"
|
|
||||||
s.write(c.encode("utf-8"))
|
|
||||||
while True:
|
|
||||||
r = s.readline().decode("utf-8").strip()
|
|
||||||
if not silent:
|
|
||||||
print(" > %s"%r)
|
|
||||||
if r[0:2] == "ok":
|
|
||||||
break
|
|
||||||
|
|
||||||
def threadPrintInput():
|
|
||||||
# Checks for input from user during printing process
|
|
||||||
global abortPrint
|
|
||||||
while printing:
|
|
||||||
i = input()
|
|
||||||
|
|
||||||
if i == "stop" or i == "exit":
|
|
||||||
abortPrint = True
|
|
||||||
break
|
|
||||||
|
|
||||||
def meshZ(X, Y):
|
|
||||||
# Interpolates values of mesh
|
|
||||||
x = X/300*(MESH_SIZE-1)
|
|
||||||
y = Y/300*(MESH_SIZE-1)
|
|
||||||
|
|
||||||
xmin = math.floor(x)
|
|
||||||
xmax = math.ceil(x)
|
|
||||||
ymin = math.floor(y)
|
|
||||||
ymax = math.ceil(y)
|
|
||||||
|
|
||||||
z0 = mesh[ymin][xmin] + (mesh[ymin][xmax]-mesh[ymin][xmin])*(x-xmin)
|
|
||||||
z1 = mesh[ymax][xmin] + (mesh[ymax][xmax]-mesh[ymax][xmin])*(x-xmin)
|
|
||||||
|
|
||||||
z = z0 + (z1-z0)*(y-ymin)
|
|
||||||
return z
|
|
||||||
|
|
||||||
# Var init
|
|
||||||
serialPort = "/dev/ttyUSB0"
|
|
||||||
serialBaud = 115200
|
|
||||||
|
|
||||||
gcodeRaw = ""
|
|
||||||
gcodeLines = []
|
|
||||||
gcodeLayers = 1
|
|
||||||
printing = False
|
|
||||||
abortPrint = False
|
|
||||||
|
|
||||||
MESH_SIZE = 9 # Number of points of a side in the mesh.
|
|
||||||
MESH_OFFSET = 1.00 # The distance above Z=0 where printbed is located. Mesh needs to be added to this number to get the absolute Z height.
|
|
||||||
mesh = [[0 for _ in range(MESH_SIZE)] for __ in range(MESH_SIZE)]
|
|
||||||
meshPositions = [["X%d Y%d"%(280/(MESH_SIZE-1)*x+10, 280/(MESH_SIZE-1)*y+10) for x in range(MESH_SIZE)] for y in range(MESH_SIZE)]
|
|
||||||
|
|
||||||
levelingCornersPos = {0:"X10 Y45",1:"X10 Y260",2:"X280 Y260",3:"X280 Y45"}
|
|
||||||
|
|
||||||
|
|
||||||
# Read mesh file
|
|
||||||
print("Reading mesh file...")
|
|
||||||
try:
|
|
||||||
f = open("mesh.txt", "r")
|
|
||||||
t = f.read()[:-1]
|
|
||||||
f.close()
|
|
||||||
|
|
||||||
lines = t.split("\n")
|
|
||||||
MESH_SIZE = int(lines[0])
|
|
||||||
mesh = [[0 for _ in range(MESH_SIZE)] for __ in range(MESH_SIZE)]
|
|
||||||
meshPositions = [["X%d Y%d"%(280/(MESH_SIZE-1)*x+10, 280/(MESH_SIZE-1)*y+10) for x in range(MESH_SIZE)] for y in range(MESH_SIZE)]
|
|
||||||
|
|
||||||
for i in range(MESH_SIZE*MESH_SIZE):
|
|
||||||
mesh[int(i/MESH_SIZE)][int(i%MESH_SIZE)] = float(lines[i+1])
|
|
||||||
|
|
||||||
print("Mesh loaded.")
|
|
||||||
except Exception as e:
|
|
||||||
print("Couldn't read mesh file. Using default mesh.")
|
|
||||||
print(e)
|
|
||||||
print("Current mesh:")
|
|
||||||
for i in mesh:
|
|
||||||
for j in i:
|
|
||||||
print("{:5.2f}".format(j), end=" ")
|
|
||||||
print()
|
|
||||||
|
|
||||||
# Connect to printer
|
|
||||||
print("\nConnecting to printer...")
|
|
||||||
s = serial.Serial(serialPort, serialBaud)
|
|
||||||
time.sleep(1)
|
|
||||||
s.write(b"\r\n\r\n") # Wake printer
|
|
||||||
time.sleep(2)
|
|
||||||
readBytes = s.inWaiting()
|
|
||||||
r = s.read(readBytes).decode("utf-8")
|
|
||||||
print(" > %s"%r)
|
|
||||||
time.sleep(5)
|
|
||||||
print("Connected!")
|
|
||||||
|
|
||||||
# Start main loop
|
|
||||||
while True:
|
|
||||||
print("\n# Please enter a command ('help' for command list)")
|
|
||||||
cmd = input()
|
|
||||||
|
|
||||||
if cmd == "help":
|
|
||||||
# List all commands
|
|
||||||
print("\nCOMMAND\t\tACTION")
|
|
||||||
for k in COMMANDS.keys():
|
|
||||||
print("%s\t\t%s"%(k, COMMANDS[k]))
|
|
||||||
|
|
||||||
elif cmd == "home":
|
|
||||||
# Home machine
|
|
||||||
send("G28", silent=True) #Auto-home
|
|
||||||
send("M84", silent=True) #Disable steppers
|
|
||||||
|
|
||||||
elif cmd == "raw":
|
|
||||||
# Send raw gcode commands
|
|
||||||
print("Entering raw mode. Proceed at your own risk. Type 'exit' to exit raw mode.")
|
|
||||||
|
|
||||||
while True:
|
|
||||||
print("\n# RAW: Please enter a gcode command (or 'exit' to exit)");
|
|
||||||
r = input()
|
|
||||||
if r == "exit":
|
|
||||||
break
|
|
||||||
send(r)
|
|
||||||
|
|
||||||
print("Exiting raw mode.")
|
|
||||||
|
|
||||||
elif cmd == "load":
|
|
||||||
# Load gcode file
|
|
||||||
print("# Please enter the path to the gcode file you want to load")
|
|
||||||
path = input()
|
|
||||||
|
|
||||||
# Try to open and parse file
|
|
||||||
try:
|
|
||||||
print("Trying to open file...")
|
|
||||||
f = open(path, "r")
|
|
||||||
print("Reading...")
|
|
||||||
gcodeRaw = f.read()[:-1]
|
|
||||||
f.close()
|
|
||||||
print("Parsing...")
|
|
||||||
gcodeLines = gcodeRaw.split("\n")
|
|
||||||
|
|
||||||
# Iterate through all lines to get info
|
|
||||||
gcodeLines = 0
|
|
||||||
for l in range(len(gcodeLines)):
|
|
||||||
line = gcodeLines[l]
|
|
||||||
|
|
||||||
if line[0] == ";":
|
|
||||||
# When comment
|
|
||||||
if line.startswith(";LAYER:"):
|
|
||||||
l = int(line[line.index(":") +1:])
|
|
||||||
if l > gcodeLayers:
|
|
||||||
gcodeLayers = l
|
|
||||||
|
|
||||||
print("#Layers: %d"%gcodeLayers)
|
|
||||||
print("%d lines"%len(gcodeLines))
|
|
||||||
|
|
||||||
print("File loaded! Use 'add' to manipulate this gcode.")
|
|
||||||
except Exception as e:
|
|
||||||
print("Couldn't read file:")
|
|
||||||
print(e)
|
|
||||||
|
|
||||||
# Reset gcode vars
|
|
||||||
gcodeRaw = ""
|
|
||||||
gcodeLines = []
|
|
||||||
gcodeLayers = 1
|
|
||||||
|
|
||||||
elif cmd == "add":
|
|
||||||
# Manipulate gcode
|
|
||||||
|
|
||||||
# Check if gcode present
|
|
||||||
if gcodeRaw == "" or len(gcodeLines) == 0:
|
|
||||||
print("No gcode loaded. Use 'load' to load gcode.")
|
|
||||||
continue
|
|
||||||
|
|
||||||
# Display all commands
|
|
||||||
print("COMMAND\t\tEXPLANATION")
|
|
||||||
print("exit\t\tReturn")
|
|
||||||
print("mesh\t\tEnable Mesh Bed Leveling")
|
|
||||||
print("filch\t\tFilament change at specific layer")
|
|
||||||
print("")
|
|
||||||
print("# Please enter one of the above actions.")
|
|
||||||
|
|
||||||
# Getting input
|
|
||||||
act = input()
|
|
||||||
|
|
||||||
if act == "exit":
|
|
||||||
print("Exiting.")
|
|
||||||
pass
|
|
||||||
|
|
||||||
elif act == "mesh":
|
|
||||||
# Add Mesh Bed Leveling
|
|
||||||
print("Recalculating Z with Mesh Bed Leveling...")
|
|
||||||
layerZ = 0
|
|
||||||
layerIndex = 0
|
|
||||||
for l in range(len(gcodeLines)):
|
|
||||||
line = gcodeLines[l]
|
|
||||||
|
|
||||||
# Check if comment
|
|
||||||
if line[0] == ";":
|
|
||||||
# Check if new layer
|
|
||||||
if line.startswith(";LAYER:"):
|
|
||||||
layerIndex = int(line[line.index(":") +1:])
|
|
||||||
|
|
||||||
if not (line.startswith("G0") or line.startswith("G1")):
|
|
||||||
continue
|
|
||||||
|
|
||||||
# When this is a movement line
|
|
||||||
tokens = line.split(" ")
|
|
||||||
indexX = -1
|
|
||||||
indexY = -1
|
|
||||||
indexZ = -1
|
|
||||||
for t in range(len(tokens)):
|
|
||||||
if tokens[t][0] == "X":
|
|
||||||
indexX = t
|
|
||||||
elif tokens[t][0] == "Y":
|
|
||||||
indexY = t
|
|
||||||
elif tokens[t][0] == "Z":
|
|
||||||
indexZ = t
|
|
||||||
|
|
||||||
# Check if Z is given
|
|
||||||
if not indexZ == -1:
|
|
||||||
# When Z is set -> save as layer height
|
|
||||||
layerZ = float(tokens[indexZ][1:])
|
|
||||||
|
|
||||||
# Add Z if X or Y are set
|
|
||||||
if indexX == -1 or indexY == -1:
|
|
||||||
continue
|
|
||||||
|
|
||||||
X = float(tokens[indexX][1:])
|
|
||||||
Y = float(tokens[indexY][1:])
|
|
||||||
Z = layerZ + MESH_OFFSET + (meshZ(X, Y)*max(0, float(10-layerIndex)/10.0) if layerIndex < 10 else 0)
|
|
||||||
|
|
||||||
# Add Z coordinate
|
|
||||||
tokens.append("Z{:.3f}".format(Z))
|
|
||||||
newLine = " ".join(tokens)
|
|
||||||
gcodeLines[l] = newLine
|
|
||||||
print("Done!")
|
|
||||||
|
|
||||||
elif act == "filch":
|
|
||||||
# Filament change at layer
|
|
||||||
layer = 0
|
|
||||||
while True:
|
|
||||||
# Ask for layer
|
|
||||||
print("# FILCH: At which layer do you want to change filament?")
|
|
||||||
l = input()
|
|
||||||
|
|
||||||
# Check if valid
|
|
||||||
try:
|
|
||||||
layer = int(l)
|
|
||||||
|
|
||||||
if layer > 0 and layer <= gcodeLayers:
|
|
||||||
break
|
|
||||||
|
|
||||||
print("Invalid.")
|
|
||||||
except:
|
|
||||||
print("Invalid.")
|
|
||||||
|
|
||||||
if layer == 0:
|
|
||||||
continue # exit
|
|
||||||
|
|
||||||
# Search for start of this layer
|
|
||||||
print("Searching for layer...")
|
|
||||||
success = False
|
|
||||||
for l in range(len(gcodeLines)):
|
|
||||||
line = gcodeLines[l]
|
|
||||||
|
|
||||||
if line[0] == ";":
|
|
||||||
if line.startswith(";LAYER:"):
|
|
||||||
thisLayer = int(line[line.find(":")+1:])
|
|
||||||
|
|
||||||
# Check if right layer
|
|
||||||
if thisLayer == layer:
|
|
||||||
# Add filch gcode
|
|
||||||
print("Adding gcode for filch...")
|
|
||||||
gcodeLines[l:l] = GCODE_FILCH_LAYER
|
|
||||||
success = True
|
|
||||||
break
|
|
||||||
print("Done." if success else "Couldn't find layer.")
|
|
||||||
|
|
||||||
else:
|
|
||||||
# When add action not found
|
|
||||||
print("Command not found.")
|
|
||||||
|
|
||||||
elif cmd == "print":
|
|
||||||
# Print loaded gcode
|
|
||||||
if len(gcodeLines) == 0:
|
|
||||||
print("No file loaded yet. Use 'load' to load gcode.")
|
|
||||||
else:
|
|
||||||
# Start print
|
|
||||||
printing = True
|
|
||||||
abortPrint = False
|
|
||||||
print("Print started. Type 'stop' at any time to abort the print.")
|
|
||||||
send("M75", silent=True) # Start timer
|
|
||||||
|
|
||||||
# Start thread to check for commands
|
|
||||||
threadInput = threading.Thread(target=threadPrintInput, daemon=True)
|
|
||||||
threadInput.start()
|
|
||||||
|
|
||||||
# Send gcode line by line to printer
|
|
||||||
for l in range(len(gcodeLines)):
|
|
||||||
line = gcodeLines[l]
|
|
||||||
|
|
||||||
# Check if needs to abort print
|
|
||||||
if abortPrint:
|
|
||||||
print("Aborting print!")
|
|
||||||
break
|
|
||||||
|
|
||||||
# Check if comment
|
|
||||||
if line[0] == ";":
|
|
||||||
# Check if new layer
|
|
||||||
if line.startswith(";LAYER:"):
|
|
||||||
layer = int(line[line.index(":") +1:])
|
|
||||||
print("Printing layer %d/%d"%(layer, gcodeLayers))
|
|
||||||
else:
|
|
||||||
# Send line to printer
|
|
||||||
send(line, silent=True)
|
|
||||||
|
|
||||||
# Stop input thread
|
|
||||||
printing = False
|
|
||||||
|
|
||||||
# Stop print
|
|
||||||
send("M104 S0", silent=True) # Hotend off
|
|
||||||
send("M140 S0", silent=True) # Bed off
|
|
||||||
send("M107", silent=True) # Fan off
|
|
||||||
send("M77", silent=True) # Stop timer
|
|
||||||
send("M31", silent=True) # Display time on lcd
|
|
||||||
send("G28 X Y", silent=True) # Home X and Y
|
|
||||||
send("G0 Y300 F1500", silent=True) # Move platform to user
|
|
||||||
send("M84", silent=True) # Disable steppers
|
|
||||||
send("M400", silent=True) # Wait for previous commands to finish
|
|
||||||
send("M300 P3000", silent=True) # Beep
|
|
||||||
print("Print done!")
|
|
||||||
|
|
||||||
elif cmd == "level":
|
|
||||||
# Normal leveling wizard
|
|
||||||
print("Starting leveling wizard...")
|
|
||||||
send("G28", silent=True) #Home
|
|
||||||
send("G0 F7500", silent=True) # Set feedrate
|
|
||||||
|
|
||||||
print("Please adjust the knob under the nozzle so that a piece of paper can slide under the nozzle with just a little bit of friction.")
|
|
||||||
|
|
||||||
# Start corner loop
|
|
||||||
i = 0
|
|
||||||
while True:
|
|
||||||
# Move to corner
|
|
||||||
print("Moving to corner %d..."%i)
|
|
||||||
send("G0 Z10", silent=True)
|
|
||||||
send("G0 %s"%levelingCornersPos[i], silent=True)
|
|
||||||
send("G0 Z0", silent=True)
|
|
||||||
send("M84", silent=True) #Disable steppers
|
|
||||||
|
|
||||||
# Prompt user
|
|
||||||
print("Press ENTER to move to next corner. Type 'exit' to exit wizard.")
|
|
||||||
r = input()
|
|
||||||
|
|
||||||
if r == "exit":
|
|
||||||
break
|
|
||||||
|
|
||||||
# Next corner
|
|
||||||
i = (i+1)%4
|
|
||||||
|
|
||||||
# End wizard
|
|
||||||
send("G0 F1500", silent=True) #Set slower feedrate
|
|
||||||
send("G28", silent=True) #Home
|
|
||||||
send("M84", silent=True) #Disable steppers
|
|
||||||
|
|
||||||
|
|
||||||
elif cmd == "mesh":
|
|
||||||
# Mesh leveling wizard
|
|
||||||
print("Starting mesh leveling wizard...")
|
|
||||||
send("G28", silent=True) #Home
|
|
||||||
send("G0 F7500", silent=True) # Set feedrate
|
|
||||||
|
|
||||||
print("\nSTEP 1: Normal leveling")
|
|
||||||
print("Please adjust the knob under the nozzle so that a piece of paper can slide under the nozzle with just a little bit of friction.")
|
|
||||||
|
|
||||||
# Start corner loop
|
|
||||||
i = 0
|
|
||||||
stop = False
|
|
||||||
while True:
|
|
||||||
# Move to corner
|
|
||||||
print("Moving to corner %d..."%i)
|
|
||||||
send("G0 Z10", silent=True)
|
|
||||||
send("G0 %s"%levelingCornersPos[i], silent=True)
|
|
||||||
send("G0 Z{:.2f}".format(MESH_OFFSET), silent=True)
|
|
||||||
|
|
||||||
# Prompt user
|
|
||||||
print("Press ENTER to move to next corner. Type 'next' to go to step 2. Type 'exit' to exit wizard.")
|
|
||||||
r = input()
|
|
||||||
|
|
||||||
if r == "exit":
|
|
||||||
stop = True
|
|
||||||
break
|
|
||||||
elif r == "next":
|
|
||||||
break
|
|
||||||
|
|
||||||
# Next corner
|
|
||||||
i = (i+1)%4
|
|
||||||
|
|
||||||
# Step 2: get mesh deltas
|
|
||||||
if not stop:
|
|
||||||
print("\nSTEP 2: Mesh leveling")
|
|
||||||
print("For every mesh point, lower the nozzle using the '+' and '-' buttons until the nozzle is at the right height. Then, enter 'next' to go to the next mesh point. Type 'exit' to exit the wizard.")
|
|
||||||
|
|
||||||
# Move through mesh
|
|
||||||
for y in range(MESH_SIZE):
|
|
||||||
for x in range(MESH_SIZE):
|
|
||||||
Z = 1.00 # Offset on top of MESH_OFFSET
|
|
||||||
print("\nMoving to mesh point x=%d, y=%d"%(x,y))
|
|
||||||
send("G0 Z10", silent=True)
|
|
||||||
send("G0 %s"%meshPositions[y][x], silent=True)
|
|
||||||
send("G0 Z{:.3f}".format(Z+MESH_OFFSET), silent=True)
|
|
||||||
|
|
||||||
# Input loop
|
|
||||||
stop = False
|
|
||||||
while True:
|
|
||||||
i = input()
|
|
||||||
|
|
||||||
if i == "+":
|
|
||||||
Z += 0.01
|
|
||||||
send("G0 Z{:.3f}".format(Z+MESH_OFFSET), silent=True)
|
|
||||||
elif i == "-":
|
|
||||||
Z -= 0.01
|
|
||||||
send("G0 Z{:.3f}".format(Z+MESH_OFFSET), silent=True)
|
|
||||||
elif i == "++":
|
|
||||||
Z += 0.1
|
|
||||||
send("G0 Z{:.3f}".format(Z+MESH_OFFSET), silent=True)
|
|
||||||
elif i == "--":
|
|
||||||
Z -= 0.1
|
|
||||||
send("G0 Z{:.3f}".format(Z+MESH_OFFSET), silent=True)
|
|
||||||
elif i == "+++":
|
|
||||||
Z += 0.5
|
|
||||||
send("G0 Z{:.3f}".format(Z+MESH_OFFSET), silent=True)
|
|
||||||
elif i == "---":
|
|
||||||
Z -= 0.5
|
|
||||||
send("G0 Z{:.3f}".format(Z+MESH_OFFSET), silent=True)
|
|
||||||
elif i == "exit":
|
|
||||||
stop = True
|
|
||||||
break
|
|
||||||
elif i == "next":
|
|
||||||
mesh[y][x] = Z
|
|
||||||
print("Mesh value saved (Z={:.3f})".format(Z))
|
|
||||||
break
|
|
||||||
|
|
||||||
# Check if needs to exit
|
|
||||||
if stop:
|
|
||||||
break
|
|
||||||
# Check if needs to exit
|
|
||||||
if stop:
|
|
||||||
break
|
|
||||||
|
|
||||||
# Print mesh
|
|
||||||
print("\nCurrent Mesh:")
|
|
||||||
for i in mesh:
|
|
||||||
for j in i:
|
|
||||||
print("{:6.3f}".format(j), end=" ")
|
|
||||||
print()
|
|
||||||
|
|
||||||
|
|
||||||
# Save mesh to file
|
|
||||||
print("Writing mesh to file...")
|
|
||||||
try:
|
|
||||||
t = ""
|
|
||||||
t += "%d\n"%MESH_SIZE
|
|
||||||
for y in range(MESH_SIZE):
|
|
||||||
for x in range(MESH_SIZE):
|
|
||||||
t += "{:.3f}\n".format(mesh[y][x])
|
|
||||||
f = open("mesh.txt", "w")
|
|
||||||
f.write(t)
|
|
||||||
f.close()
|
|
||||||
except Exception as e:
|
|
||||||
print("Couldn't write mesh to file.")
|
|
||||||
print(e)
|
|
||||||
|
|
||||||
|
|
||||||
# End wizard
|
|
||||||
send("G0 F1500", silent=True) #Set slower feedrate
|
|
||||||
send("G28", silent=True) #Home
|
|
||||||
send("M84", silent=True) #Disable steppers
|
|
||||||
|
|
||||||
|
|
||||||
elif cmd == "exit":
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
print("Command not found. Enter 'help' to list all commands.")
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Close serial
|
|
||||||
print("Disconnecting from printer...")
|
|
||||||
s.close()
|
|
||||||
|
|
||||||
# End of script
|
|
||||||
print("Thank you for using PrintBuddy!")
|
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
|
||||||
|
def resolve(path):
|
||||||
|
# Returns a resultCode and webpage for this path
|
||||||
|
page = "<html><body><p>Hello, world!</p></body></html>"
|
||||||
|
return (200, page)
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
from http.server import HTTPServer
|
||||||
|
from webserver import WebServer
|
||||||
|
|
||||||
|
# Server config
|
||||||
|
SERVER_HOST = "localhost"
|
||||||
|
SERVER_PORT = 4000
|
||||||
|
|
||||||
|
|
||||||
|
class PrintServer(object):
|
||||||
|
def __init__(self):
|
||||||
|
self.server = HTTPServer((SERVER_HOST, SERVER_PORT), WebServer)
|
||||||
|
|
||||||
|
def start(self):
|
||||||
|
# Start serving pages
|
||||||
|
self.server.serve_forever()
|
||||||
|
self.server.server_close()
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
from http.server import BaseHTTPRequestHandler
|
||||||
|
import pageresolver
|
||||||
|
|
||||||
|
class WebServer(BaseHTTPRequestHandler):
|
||||||
|
def do_GET(self):
|
||||||
|
# Create page contents
|
||||||
|
(responseCode, page) = pageresolver.resolve(self.path)
|
||||||
|
|
||||||
|
# Return page
|
||||||
|
self.send_response(responseCode)
|
||||||
|
self.send_header("Content-type", "text/html")
|
||||||
|
self.end_headers()
|
||||||
|
self.wfile.write(bytes(page, "utf-8"))
|
||||||
|
|
Loading…
Reference in New Issue