Improved the serial port management, fixed some bugs. Code commenting and cleanup.
							parent
							
								
									57ed9cdd54
								
							
						
					
					
						commit
						549fbf30c5
					
				| 
						 | 
				
			
			@ -1,6 +1,6 @@
 | 
			
		|||
#!/usr/bin/python
 | 
			
		||||
 | 
			
		||||
###### Cyclone PCB console v0.1 ######
 | 
			
		||||
###### Cyclone PCB console v0.2 ######
 | 
			
		||||
#
 | 
			
		||||
# DESCRIPTION:
 | 
			
		||||
#   Controller for the Cyclone PCB Factory:
 | 
			
		||||
| 
						 | 
				
			
			@ -14,7 +14,7 @@
 | 
			
		|||
#   Attribution - Share Alike - Creative Commons (http://creativecommons.org/licenses/by-sa/3.0/)
 | 
			
		||||
#
 | 
			
		||||
# DISCLAIMER:
 | 
			
		||||
#   This software is provided “as is," and you use the software at your own risk. Under no
 | 
			
		||||
#   This software is provided "as is", and you use the software at your own risk. Under no
 | 
			
		||||
#   circumstances shall Carlosgs be liable for direct, indirect, special, incidental, or
 | 
			
		||||
#   consequential damages resulting from the use, misuse, or inability to use this software,
 | 
			
		||||
#   even if Carlosgs has been advised of the possibility of such damages.
 | 
			
		||||
| 
						 | 
				
			
			@ -32,7 +32,7 @@
 | 
			
		|||
 | 
			
		||||
# Begin configuration
 | 
			
		||||
BAUDRATE = 115200
 | 
			
		||||
DEVICE = "/dev/ttyUSB0"
 | 
			
		||||
DEVICE = "/dev/ttyUSB1"
 | 
			
		||||
# End configuration
 | 
			
		||||
 | 
			
		||||
import sys
 | 
			
		||||
| 
						 | 
				
			
			@ -43,20 +43,22 @@ from datetime import datetime
 | 
			
		|||
#fileToFeed = sys.argv[1]  # Will use this later on to load 
 | 
			
		||||
#gcode = open(fileToFeed, "r")
 | 
			
		||||
 | 
			
		||||
millis_wait = 0.1 # Delay used when re-trying to send/receive from the serial port [seconds]
 | 
			
		||||
serial_timeout = 0.1 # Timeout for the serial port [seconds]
 | 
			
		||||
millis_wait = 0.5 # Delay used when re-trying to send/receive from the serial port [seconds]
 | 
			
		||||
serial_timeout = 5 # Timeout for the serial port [seconds]
 | 
			
		||||
 | 
			
		||||
OK_response = "ok" # First two characters of an OK response (case insensitive)
 | 
			
		||||
 | 
			
		||||
def getCurrentTime():
 | 
			
		||||
	timeNow = datetime.now()
 | 
			
		||||
	print "Time:", str(timeNow)
 | 
			
		||||
	return timeNow
 | 
			
		||||
 | 
			
		||||
def emptyMachineRecvBuffer():
 | 
			
		||||
def emptyMachineRecvBuffer(): # We could also use flushInput(), but showing the data that is being discarded is useful for debugging
 | 
			
		||||
	while CNC_Machine.inWaiting() > 0:
 | 
			
		||||
		response = CNC_Machine.readline()
 | 
			
		||||
	while response != '':
 | 
			
		||||
		if response != '':
 | 
			
		||||
			print "IGNO: ", response
 | 
			
		||||
		time.sleep(millis_wait) # Wait some milliseconds between attempts
 | 
			
		||||
		response = CNC_Machine.readline()
 | 
			
		||||
 | 
			
		||||
def sendToMachine(line):
 | 
			
		||||
	emptyMachineRecvBuffer()
 | 
			
		||||
| 
						 | 
				
			
			@ -67,21 +69,28 @@ def recvFromMachine():
 | 
			
		|||
	response = CNC_Machine.readline()
 | 
			
		||||
	if response != '':
 | 
			
		||||
		print "RECV: ", response
 | 
			
		||||
	else:
 | 
			
		||||
		print "RECV: Receive timed out!"
 | 
			
		||||
	return response
 | 
			
		||||
 | 
			
		||||
def machineSaysOK():
 | 
			
		||||
	response = recvFromMachine()
 | 
			
		||||
	if response[:2] == "ok":
 | 
			
		||||
	if response[:2].lower() == OK_response.lower():
 | 
			
		||||
		return 1
 | 
			
		||||
	return 0
 | 
			
		||||
 | 
			
		||||
def waitForOK():
 | 
			
		||||
def waitForOK(): # This is a blocking function
 | 
			
		||||
	print "Waiting for confirmation"
 | 
			
		||||
	while machineSaysOK() != 1:
 | 
			
		||||
		#print "."
 | 
			
		||||
		print "  Checking again..."
 | 
			
		||||
		time.sleep(millis_wait) # Wait some milliseconds between attempts
 | 
			
		||||
 | 
			
		||||
def sendCommandToMachine(command): # Send command and wait for OK
 | 
			
		||||
	sendToMachine(command)
 | 
			
		||||
	waitForOK()
 | 
			
		||||
 | 
			
		||||
def checkConnection():
 | 
			
		||||
	print "Checking the connection..."
 | 
			
		||||
	sendToMachine("G21\n") # We check the connection setting millimiters as the unit and waiting for the OK response
 | 
			
		||||
	time.sleep(0.5)
 | 
			
		||||
	while machineSaysOK() != 1:
 | 
			
		||||
| 
						 | 
				
			
			@ -94,73 +103,61 @@ CNC_Machine = serial.Serial(DEVICE, BAUDRATE, timeout = serial_timeout)
 | 
			
		|||
 | 
			
		||||
print "Serial port opened, checking connection..."
 | 
			
		||||
 | 
			
		||||
time.sleep(0.5)
 | 
			
		||||
time.sleep(1)
 | 
			
		||||
 | 
			
		||||
checkConnection();
 | 
			
		||||
 | 
			
		||||
print "CONNECTED"
 | 
			
		||||
 | 
			
		||||
time.sleep(1)
 | 
			
		||||
 | 
			
		||||
sendToMachine("G90\n") # Set absolute positioning
 | 
			
		||||
waitForOK()
 | 
			
		||||
sendCommandToMachine("G90\n") # Set absolute positioning
 | 
			
		||||
 | 
			
		||||
def machineHomeZXY():
 | 
			
		||||
	print "Homing all axis..."
 | 
			
		||||
	sendToMachine("G28 Z0\n") # move Z to min endstop
 | 
			
		||||
	waitForOK()
 | 
			
		||||
	sendToMachine("G28 X0\n") # move X to min endstop
 | 
			
		||||
	waitForOK()
 | 
			
		||||
	sendToMachine("G28 Y0\n") # move Y to min endstop
 | 
			
		||||
	waitForOK()
 | 
			
		||||
	sendCommandToMachine("G28 Z0\n") # move Z to min endstop
 | 
			
		||||
	sendCommandToMachine("G28 X0\n") # move X to min endstop
 | 
			
		||||
	sendCommandToMachine("G28 Y0\n") # move Y to min endstop
 | 
			
		||||
 | 
			
		||||
machineHomeZXY() # Home all the axis
 | 
			
		||||
 | 
			
		||||
F_slowMove = 200 # Move speed [mm/min?]
 | 
			
		||||
F_fastMove = 600
 | 
			
		||||
F_fastMove = 700
 | 
			
		||||
 | 
			
		||||
def floats(val): # This is used to convert a float value to a string (avoiding exponent notation)
 | 
			
		||||
	return '{:f}'.format(float(val)) # It would be interesting to truncate the decimals that aren't used
 | 
			
		||||
	return '{:.3f}'.format(float(val)) # It truncates the decimals that aren't used
 | 
			
		||||
 | 
			
		||||
def machineToCoords(X, Y, Z, F):
 | 
			
		||||
	print "Moving to:"
 | 
			
		||||
	sendToMachine("G1 X"+floats(X)+" Y"+floats(Y)+" Z"+floats(Z)+" F"+floats(F)+"\n")
 | 
			
		||||
	waitForOK()
 | 
			
		||||
	sendCommandToMachine("G1 X"+floats(X)+" Y"+floats(Y)+" Z"+floats(Z)+" F"+floats(F)+"\n")
 | 
			
		||||
 | 
			
		||||
def machineToCoordsXY(X, Y, F):
 | 
			
		||||
	print "Moving to:"
 | 
			
		||||
	sendToMachine("G1 X"+floats(X)+" Y"+floats(Y)+" F"+floats(F)+"\n")
 | 
			
		||||
	waitForOK()
 | 
			
		||||
	sendCommandToMachine("G1 X"+floats(X)+" Y"+floats(Y)+" F"+floats(F)+"\n")
 | 
			
		||||
 | 
			
		||||
def machineToCoordsZ(Z, F):
 | 
			
		||||
	print "Moving Z absolute:"
 | 
			
		||||
	sendToMachine("G1 Z"+floats(Z)+" F"+floats(F)+"\n")
 | 
			
		||||
	waitForOK()
 | 
			
		||||
	sendCommandToMachine("G1 Z"+floats(Z)+" F"+floats(F)+"\n")
 | 
			
		||||
 | 
			
		||||
def machineToCoordsZrelative(Z, F):
 | 
			
		||||
	print "Moving Z relative:"
 | 
			
		||||
	sendToMachine("G91\n") # Set relative positioning
 | 
			
		||||
	waitForOK()
 | 
			
		||||
	sendToMachine("G1 Z"+floats(Z)+" F"+floats(F)+"\n")
 | 
			
		||||
	waitForOK()
 | 
			
		||||
	sendToMachine("G90\n") # Set absolute positioning
 | 
			
		||||
	waitForOK()
 | 
			
		||||
	sendCommandToMachine("G91\n") # Set relative positioning
 | 
			
		||||
	sendCommandToMachine("G1 Z"+floats(Z)+" F"+floats(F)+"\n")
 | 
			
		||||
	sendCommandToMachine("G90\n") # Set absolute positioning
 | 
			
		||||
 | 
			
		||||
grid_origin_X = float(0) # Initial point of the grid
 | 
			
		||||
grid_origin_X = float(0) # Initial point of the grid [mm]
 | 
			
		||||
grid_origin_Y = float(0)
 | 
			
		||||
 | 
			
		||||
grid_len_X = float(135) # Distance to probe [mm]
 | 
			
		||||
grid_len_Y = float(84)
 | 
			
		||||
grid_len_X = float(135) #135 # Distance to probe [mm]
 | 
			
		||||
grid_len_Y = float(84) #84
 | 
			
		||||
 | 
			
		||||
grid_N_X = int(12) # Number of points
 | 
			
		||||
grid_N_Y = int(6)
 | 
			
		||||
grid_N_X = int(12) #12 # Number of points
 | 
			
		||||
grid_N_Y = int(6) #6
 | 
			
		||||
 | 
			
		||||
grid_inc_X = grid_len_X/float(grid_N_X-1) # mm
 | 
			
		||||
grid_inc_X = grid_len_X/float(grid_N_X-1) # [mm]
 | 
			
		||||
grid_inc_Y = grid_len_Y/float(grid_N_Y-1)
 | 
			
		||||
 | 
			
		||||
probe_grid = [ [ 0 for i in range(grid_N_X) ] for j in range(grid_N_Y) ]
 | 
			
		||||
 | 
			
		||||
# Show our grid
 | 
			
		||||
# Show our grid (initialised as zeros)
 | 
			
		||||
for row in probe_grid:
 | 
			
		||||
	print row
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -168,23 +165,29 @@ print "Probing begins!"
 | 
			
		|||
print "WARNING: Keep an eye on the machine, unplug if something goes wrong!"
 | 
			
		||||
beginTime = getCurrentTime() # Store current time in a variable, will be used to measure duration of the probing
 | 
			
		||||
 | 
			
		||||
# Warning: Do not lower too much or you will cause damage!
 | 
			
		||||
# machineToCoordsZrelative(-10,F_slowMove/2) # Move Z towards the PCB (saves some probing time for the first coord)
 | 
			
		||||
 # Move to grid's origin
 | 
			
		||||
machineToCoordsXY(grid_origin_X, grid_origin_Y, F_fastMove)
 | 
			
		||||
 | 
			
		||||
# Warning: Do not lower too much or you will potentially cause damage!
 | 
			
		||||
initial_Z_lowering_distance = -15
 | 
			
		||||
sendCommandToMachine("M121\n") # Enable endstops (for protection! it should tap the copper SLOWLY)
 | 
			
		||||
machineToCoordsZrelative(initial_Z_lowering_distance,F_slowMove) # Move Z towards the PCB (saves some probing time for the first coord)
 | 
			
		||||
sendCommandToMachine("M120\n") # Disable endstops (we only use them for homing)
 | 
			
		||||
 | 
			
		||||
def machineProbeZ():
 | 
			
		||||
	print "Probing Z"
 | 
			
		||||
	sendToMachine("G30\n") # Launch probe command
 | 
			
		||||
	response = recvFromMachine() # Read the response, it is a variable time so we make multiple attempts
 | 
			
		||||
	response = recvFromMachine() # Read the response, it is a variable run time so we may need to make multiple attempts
 | 
			
		||||
	while response == '':
 | 
			
		||||
		#print "."
 | 
			
		||||
		time.sleep(millis_wait) # Wait some milliseconds between attempts
 | 
			
		||||
		response = recvFromMachine()
 | 
			
		||||
	response_vals = response.split() # Split the response (i.e. "ok Z:1.23")
 | 
			
		||||
	if response_vals[0][:2] == "ok":
 | 
			
		||||
		Zres = response_vals[1][2:] # Ignore the "Z:" and read the coordinate
 | 
			
		||||
	if response_vals[0][:2].lower() == OK_response.lower():
 | 
			
		||||
		Zres = response_vals[1][2:] # Ignore the "Z:" and read the coordinate value
 | 
			
		||||
		print "Result is Z=",Zres
 | 
			
		||||
		return float(Zres)
 | 
			
		||||
	return 400 # Error case, it has never happened :)
 | 
			
		||||
	return 400 # Error case, don't worry: it has never happened :)
 | 
			
		||||
 | 
			
		||||
def isOdd(number):
 | 
			
		||||
	if number % 2 == 0:
 | 
			
		||||
| 
						 | 
				
			
			@ -192,25 +195,29 @@ def isOdd(number):
 | 
			
		|||
	else:
 | 
			
		||||
		return 1 # Odd number
 | 
			
		||||
 | 
			
		||||
for x_i in range(grid_N_X):
 | 
			
		||||
	x_val = float(x_i)*grid_inc_X+grid_origin_X;
 | 
			
		||||
Z_probing_lift = 0.5 # lift between Z probings [mm]
 | 
			
		||||
# Note: The lift is relative to the PCB board, you can usually set a low value to speedup the process.
 | 
			
		||||
# But PLEASE keep an eye for possible collisions!
 | 
			
		||||
 | 
			
		||||
for x_i in range(grid_N_X): # For each point on the grid...
 | 
			
		||||
	x_val = float(x_i)*grid_inc_X + grid_origin_X; # Calculate X coordinate
 | 
			
		||||
	optimal_range = range(grid_N_Y)
 | 
			
		||||
	if isOdd(x_i): # This creates a more optimal path for the probing
 | 
			
		||||
	if isOdd(x_i): # This optimises a bit the probing path
 | 
			
		||||
		optimal_range = reversed(optimal_range)
 | 
			
		||||
	for y_i in optimal_range:
 | 
			
		||||
		y_val = float(y_i)*grid_inc_Y+grid_origin_Y;
 | 
			
		||||
		machineToCoordsXY(x_val,y_val,F_fastMove)
 | 
			
		||||
		val = machineProbeZ()
 | 
			
		||||
		machineToCoordsZrelative(0.5,F_fastMove/2)
 | 
			
		||||
		probe_grid[y_i][x_i]= val
 | 
			
		||||
		y_val = float(y_i)*grid_inc_Y + grid_origin_Y; # Calculate Y coordinate
 | 
			
		||||
		machineToCoordsXY(x_val, y_val, F_fastMove) # Move to position
 | 
			
		||||
		probe_grid[y_i][x_i] = machineProbeZ() # Do the Z probing
 | 
			
		||||
		machineToCoordsZrelative(Z_probing_lift, F_fastMove/2) # Lift the probe
 | 
			
		||||
 | 
			
		||||
# Once we have all the points, we set the origin as (0,0) and offset the rest of values
 | 
			
		||||
ZoffsetOrigin = probe_grid[0][0]
 | 
			
		||||
print "The origin Z height is", ZoffsetOrigin
 | 
			
		||||
probe_grid = [[elem - ZoffsetOrigin for elem in row] for row in probe_grid]
 | 
			
		||||
 | 
			
		||||
# Return to the grid's origin
 | 
			
		||||
machineToCoordsZrelative(10,F_slowMove)
 | 
			
		||||
machineToCoordsXY(grid_origin_X,grid_origin_Y,F_fastMove)
 | 
			
		||||
machineToCoordsZrelative(10, F_slowMove) # Lift Z
 | 
			
		||||
machineToCoordsXY(grid_origin_X, grid_origin_Y, F_fastMove) # Move to grid's origin
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Show our grid
 | 
			
		||||
| 
						 | 
				
			
			@ -250,7 +257,11 @@ print "Probing duration:",str(datetime.now()-beginTime)
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
#gcode.close()
 | 
			
		||||
CNC_Machine.close() # Close the serial port
 | 
			
		||||
 | 
			
		||||
# IMPORTANT: Before closing the serial port we must make a blocking move in order to wait for all the buffered commands to end
 | 
			
		||||
sendCommandToMachine("G28 Z0\n") # move Z to min endstop
 | 
			
		||||
 | 
			
		||||
CNC_Machine.close() # Close the serial port connection
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Bilinear interpolation code by Raymond Hettinger from http://stackoverflow.com/a/8662355
 | 
			
		||||
| 
						 | 
				
			
			@ -282,3 +293,4 @@ def bilinear_interpolation(x, y, points):
 | 
			
		|||
			q12 * (x2 - x) * (y - y1) +
 | 
			
		||||
			q22 * (x - x1) * (y - y1)
 | 
			
		||||
		) / ((x2 - x1) * (y2 - y1) + 0.0)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue