diff --git a/Software/CycloneHost/CycloneHost.py b/Software/CycloneHost/CycloneHost.py index 58f9651..b2f16fa 100644 --- a/Software/CycloneHost/CycloneHost.py +++ b/Software/CycloneHost/CycloneHost.py @@ -139,7 +139,8 @@ def homeZXY(): sendCommand("G28 Y0\n",timeoutResend) # move Y to min endstop if Emulate: time.sleep(2) - lastDrillPos = [0,0,0] + lastDrillPos = [0,0,0] + print "Done homing" def moveXYZ(X, Y, Z, F): global lastDrillPos @@ -151,7 +152,7 @@ def moveXYZ(X, Y, Z, F): dist = ((X-lastDrillPos[0])**2+(Y-lastDrillPos[1])**2+(Z-lastDrillPos[2])**2)**0.5 # [mm] speed = float(F)/60.0 # [mm/s] time.sleep(float(dist)/speed) - lastDrillPos = [X,Y,Z] + lastDrillPos = [X,Y,Z] def moveXY(X, Y, F): global lastDrillPos @@ -163,7 +164,7 @@ def moveXY(X, Y, F): dist = ((X-lastDrillPos[0])**2+(Y-lastDrillPos[1])**2)**0.5 # [mm] speed = float(F)/60.0 # [mm/s] time.sleep(float(dist)/speed) - lastDrillPos = [X,Y,lastDrillPos[2]] + lastDrillPos = [X,Y,lastDrillPos[2]] def moveZ(Z, F): global lastDrillPos @@ -175,22 +176,28 @@ def moveZ(Z, F): dist = abs(Z-lastDrillPos[2]) # [mm] speed = float(F)/60.0 # [mm/s] time.sleep(float(dist)/speed) - lastDrillPos = [lastDrillPos[0],lastDrillPos[1],Z] + lastDrillPos = [lastDrillPos[0],lastDrillPos[1],Z] def moveZrel(Z, F): + global lastDrillPos # print "Moving Z relative:" if F <= 0: print "ERROR: F <= 0" sendCommand("G91\n") # Set relative positioning - moveZ(Z, F) + sendCommand("G1 Z"+floats(Z)+" F"+floats(F)+"\n") + if Emulate: + dist = abs(Z) # [mm] + speed = float(F)/60.0 # [mm/s] + time.sleep(float(dist)/speed) + lastDrillPos = [lastDrillPos[0],lastDrillPos[1],lastDrillPos[2]+Z] # Relative movement sendCommand("G90\n") # Set absolute positioning def moveZrelSafe(Z, F): if F <= 0: print "ERROR: F <= 0" + print "Moving Z", Z, "mm safely..." sendCommand("M121\n") # Enable endstops (for protection! usually it should **NOT** hit neither the endstop nor the PCB) moveZrel(Z, F) - print "Moving Z safely..." dist = abs(Z-lastDrillPos[2]) # [mm] speed = float(F)/60.0 # [mm/s] wait = float(dist)/speed # [s] diff --git a/Software/CycloneHost/GcodeParser.py b/Software/CycloneHost/GcodeParser.py index ed4a664..3d20f0a 100644 --- a/Software/CycloneHost/GcodeParser.py +++ b/Software/CycloneHost/GcodeParser.py @@ -20,13 +20,13 @@ import os.path def parseGcodeRaw(filePath, etch_definition = 0, close_shapes = 0): # Gcode parser from Etch_Z_adjust.1.8.py (modified by Carlosgs to output toolpaths) - gcode_sizeXY = (0,0) - gcode_originXY = (0,0) + gcode_maxXY = (0,0) + gcode_minXY = (0,0) travel_moves = [] etch_moves = [] if os.path.isfile(filePath) == False : - return etch_moves, travel_moves, gcode_originXY, gcode_sizeXY + return etch_moves, travel_moves, gcode_minXY, gcode_maxXY gcode = open(filePath, "r") @@ -152,16 +152,17 @@ def parseGcodeRaw(filePath, etch_definition = 0, close_shapes = 0): # Gcode pars if is_first_X == False : # then there were etch moves so get to work! - gcode_sizeXY = (X_max - X_min, Y_max - Y_min) - gcode_originXY = (X_min, Y_min) + gcode_maxXY = [X_max, Y_max] + gcode_minXY = [X_min, Y_min] - print "Gcode XY origin:",str(gcode_originXY) - print "Gcode XY length:",str(gcode_sizeXY) - - else : print "No etch moves found!" + print "Gcode XY min:",str(gcode_minXY) + print "Gcode XY max:",str(gcode_maxXY) + else : + print "No etch moves found!" + return etch_moves, travel_moves, [0,0], [0,0] gcode.close() - return etch_moves, travel_moves, gcode_originXY, gcode_sizeXY + return etch_moves, travel_moves, gcode_minXY, gcode_maxXY def optimize(etch_moves_in, origin=[0,0], travel_height = 5): # Optimizes the toolpath using closest neighbour (author: Carlosgs) diff --git a/Software/CycloneHost/GcodeViewer.py b/Software/CycloneHost/GcodeViewer.py index ce1f7dc..f88e66d 100644 --- a/Software/CycloneHost/GcodeViewer.py +++ b/Software/CycloneHost/GcodeViewer.py @@ -70,6 +70,15 @@ def view(filePath,fileName,showAll=0,showEtch=0,showEtch2=0,showEtch3=0,showDril edge_color = 'b' travel_color = 'c' + gcode_minXY_global = [1e9,1e9] + gcode_maxXY_global = [-1e9,-1e9] + + def checkMinMax(gcode_minXY,gcode_maxXY): + if gcode_minXY[0] < gcode_minXY_global[0]: gcode_minXY_global[0] = gcode_minXY[0] + if gcode_minXY[1] < gcode_minXY_global[1]: gcode_minXY_global[1] = gcode_minXY[1] + if gcode_maxXY[0] > gcode_maxXY_global[0]: gcode_maxXY_global[0] = gcode_maxXY[0] + if gcode_maxXY[1] > gcode_maxXY_global[1]: gcode_maxXY_global[1] = gcode_maxXY[1] + if draw: plt.title("Gcode viewer") plt.axis('equal') # 1:1 aspect ratio @@ -78,40 +87,41 @@ def view(filePath,fileName,showAll=0,showEtch=0,showEtch2=0,showEtch3=0,showDril if showAll or showEtch: print "\n Loading etch..." gcode_file = filePath+fileName+"_etch.gcode" - (etch_moves, travel_moves, gcode_originXY, grid_sizeXY) = gcp.parseGcodeRaw(gcode_file) + (etch_moves, travel_moves, gcode_minXY, gcode_maxXY) = gcp.parseGcodeRaw(gcode_file) (etch_moves, travel_moves) = gcp.optimize(etch_moves) if draw: plotPath(etch_moves, travel_moves, etch_color, travel_color, etch_diam, travel_diam) + checkMinMax(gcode_minXY,gcode_maxXY) if showAll or showEtch2: print "\n Loading etch (2nd pass)..." gcode_file = filePath+fileName+"_etch2pass.gcode" - (etch_moves, travel_moves, gcode_originXY, grid_sizeXY) = gcp.parseGcodeRaw(gcode_file) + (etch_moves, travel_moves, gcode_minXY, gcode_maxXY) = gcp.parseGcodeRaw(gcode_file) (etch_moves, travel_moves) = gcp.optimize(etch_moves) if draw: plotPath(etch_moves, travel_moves, etch2pass_color, travel_color, etch2pass_diam, travel_diam) if showAll or showEtch3: print "\n Loading etch (3nd pass)..." gcode_file = filePath+fileName+"_etch3pass.gcode" - (etch_moves, travel_moves, gcode_originXY, grid_sizeXY) = gcp.parseGcodeRaw(gcode_file) + (etch_moves, travel_moves, gcode_minXY, gcode_maxXY) = gcp.parseGcodeRaw(gcode_file) (etch_moves, travel_moves) = gcp.optimize(etch_moves) if draw: plotPath(etch_moves, travel_moves, etch3pass_color, travel_color, etch3pass_diam, travel_diam) if showAll or showDrill: print "\n Loading drill..." gcode_file = filePath+fileName+"_drill.gcode" - (etch_moves, travel_moves, gcode_originXY, grid_sizeXY) = gcp.parseGcodeRaw(gcode_file) + (etch_moves, travel_moves, gcode_minXY, gcode_maxXY) = gcp.parseGcodeRaw(gcode_file) (etch_moves, travel_moves) = gcp.optimize(etch_moves) if draw: plotPath(etch_moves, travel_moves, drill_color, travel_color, drill_diam, travel_diam) if showAll or showEdge: print "\n Loading edge..." gcode_file = filePath+fileName+"_edge.gcode" - (etch_moves, travel_moves, gcode_originXY, grid_sizeXY) = gcp.parseGcodeRaw(gcode_file) + (etch_moves, travel_moves, gcode_minXY, gcode_maxXY) = gcp.parseGcodeRaw(gcode_file) (etch_moves, travel_moves) = gcp.optimize(etch_moves) if draw: plotPath(etch_moves, travel_moves, edge_color, travel_color, edge_diam, travel_diam) #if draw : plt.hold(False) if draw and newFigure: pltShowNonBlocking() - return (etch_moves, travel_moves) + return (etch_moves, travel_moves, gcode_minXY_global, gcode_maxXY_global) diff --git a/Software/gcode_Z_adjust/GUI_v0.2.png b/Software/gcode_Z_adjust/GUI_v0.2.png new file mode 100644 index 0000000..5c8d060 Binary files /dev/null and b/Software/gcode_Z_adjust/GUI_v0.2.png differ diff --git a/Software/gcode_Z_adjust/Send.py b/Software/gcode_Z_adjust/Send.py index 988e379..9bc5125 100644 --- a/Software/gcode_Z_adjust/Send.py +++ b/Software/gcode_Z_adjust/Send.py @@ -25,6 +25,7 @@ import time import numpy as np from scipy import interpolate import matplotlib.pyplot as plt +from matplotlib import cm sys.path.append("../CycloneHost") import GcodeViewer as gcv @@ -56,7 +57,9 @@ def pltRefresh(fig): fig.canvas.draw() def pltShow(): + #plt.ion() # IMPORTANT: Enable real-time plotting plt.draw() + #plt.ioff() @@ -93,14 +96,15 @@ def probingResults(): # quick and dirty temporal code # Interpolation Z_workbed_surface = interpolate.RectBivariateSpline(y_points, x_points, probe_result) - x_points = np.linspace(min(x_points),max(x_points),100) - y_points = np.linspace(min(y_points),max(y_points),100) + x_points = np.linspace(min(x_points),max(x_points),50) + y_points = np.linspace(min(y_points),max(y_points),50) z_points = Z_workbed_surface(y_points,x_points) # plt.figure() plt.hold(True) - plt.pcolor(x_points, y_points, z_points) + + z_cf = plt.pcolor(x_points, y_points, z_points, alpha=0.2, cmap=cm.copper, edgecolors='k', linewidths=0) # Show Z probing height, with a light-tone colormap plt.colorbar() # plt.title("Z probing results (interpolated) [mm]") plt.axis('equal') # 1:1 aspect ratio @@ -111,30 +115,29 @@ def getZoffset(x,y): - - - - plt.ion() # IMPORTANT: Enable real-time plotting -gcodeviewer = pltNewFig() # Define a new figure, this doesnt open a window by itself - +gcodeviewer = pltNewFig() # Define a new figure, this doesnt open a window by itself (real-time plotting disabled) probingResults() print "Must be zero:",floats(getZoffset(0,0)) - # Display the Gcode that is going to be etched -(etch_moves, travel_moves) = gcv.view(filePath,fileName,showEtch=1) +(etch_moves, travel_moves, gcode_minXY_global, gcode_maxXY_global) = gcv.view(filePath,fileName,showEtch=1) #(etch_moves, travel_moves) = gcv.view(filePath,fileName,showEtch1=1) #(etch_moves, travel_moves) = gcv.view(filePath,fileName,showEtch2=1) #(etch_moves, travel_moves) = gcv.view(filePath,fileName,showDrill=1) #(etch_moves, travel_moves) = gcv.view(filePath,fileName,showEdge=1) +# Truncate the background to the dimensions of the PCB +x_dat = [gcode_minXY_global[0],gcode_minXY_global[0],gcode_maxXY_global[0],gcode_maxXY_global[0],gcode_minXY_global[0]] +y_dat = [gcode_minXY_global[1],gcode_maxXY_global[1],gcode_maxXY_global[1],gcode_minXY_global[1],gcode_minXY_global[1]] +plt.plot(x_dat,y_dat) + pltRefresh(gcodeviewer) # Draw the figure contents, still no window pltShow() # Open the window showing our figure -plt.show() # THIS SHOULD BE COMMENTED, USE FOR DEBUG +#plt.show() # THIS SHOULD BE COMMENTED, USE FOR DEBUG toolPos_point = [] @@ -211,8 +214,8 @@ Zlift = 1.0 Z_manual_offset = 0.0 -maxDistance = 2**2 # [mm^2] 3mm (longer moves will be split to regulate Z) -minDistance = 0.005**2 # [mm^2] 0.005mm is the smallest distance that will be sent +maxDistance = 2**2 # [mm^2] 2mm (longer moves will be split to regulate Z) +minDistance = 0.001**2 # [mm^2] 0.001mm is the smallest distance that will be sent def splitLongEtchMove(distance): global toolPos_X, toolPos_Y, toolPos_Z, toolPos_F, X_dest, Y_dest, Z_dest, F_dest diff --git a/Software/gcode_Z_adjust/test.py b/Software/gcode_Z_adjust/test.py deleted file mode 100644 index f8681cd..0000000 --- a/Software/gcode_Z_adjust/test.py +++ /dev/null @@ -1,55 +0,0 @@ -# -*- encoding: utf-8 -*- -# Based on http://scipy-user.10969.n7.nabble.com/2D-Interpolation-td4248.html - -import scipy -import scipy.interpolate - -def pltShowNonBlocking(): - plt.ion() # Enable real-time plotting to avoid blocking behaviour for plt.show() - plt.show() - plt.ioff() # Disable real-time plotting - -# the two axes -x = scipy.array([0.0, 12.272727272727273, 24.545454545454547, 36.81818181818182, 49.09090909090909, 61.36363636363637, 73.63636363636364, 85.9090909090909, 98.18181818181819, 110.45454545454547, 122.72727272727273, 135.0]) -y = scipy.array([0.0, 16.8, 33.6, 50.400000000000006, 67.2, 84.0]) - -# make some pretend data -gridy, gridx = scipy.meshgrid(x,y) -z = scipy.array([[0.0, 0.2, 0.4, 0.53, 0.58, 0.6, 0.56, 0.53, 0.5, 0.44, 0.33, 0.2], [-0.03, 0.07, 0.16, 0.26, 0.32, 0.33, 0.33, 0.33, 0.29, 0.23, 0.15, 0.05], [-0.07, 0.0, 0.05, 0.12, 0.16, 0.2, 0.2, 0.22, 0.2, 0.16, 0.08, 0.0], [-0.07, -0.03, 0.04, 0.11, 0.15, 0.19, 0.2, 0.22, 0.22, 0.19, 0.11, 0.04], [0.0, 0.04, 0.08, 0.19, 0.23, 0.29, 0.33, 0.36, 0.37, 0.32, 0.2, 0.11], [0.13, 0.2, 0.27, 0.37, 0.44, 0.51, 0.55, 0.61, 0.64, 0.55, 0.41, 0.22]]) - -# create a spline interpolator -spl = scipy.interpolate.RectBivariateSpline(y,x,z) - -# make some new axes to interpolate to -nx = scipy.linspace(min(x),max(x),100) -ny = scipy.linspace(min(y),max(y),100) - -# evaluate -nz = spl(ny, nx) - -import matplotlib.pyplot as plt - -plt.figure() -plt.pcolor(x, y, z) -plt.title("Datos [mm]") -plt.colorbar() -plt.axis('equal') # 1:1 aspect ratio -pltShowNonBlocking() - -plt.figure() -plt.pcolor(nx, ny, nz) -plt.title("Datos interpolados [mm]") -plt.colorbar() -plt.axis('equal') # 1:1 aspect ratio -pltShowNonBlocking() - -# Comprobación de que el error es mínimo -plt.figure() -plt.pcolor(x, y, spl(y,x) - z) -plt.title("Diferencia entre datos originales e interpolados (error) [mm]") -plt.colorbar() -plt.axis('equal') # 1:1 aspect ratio -pltShowNonBlocking() - -raw_input("Press enter to exit...") -