Code to add to bCNC for tooltip measurement functionality
Share on facebook
Share on twitter
Share on linkedin

The Basic premise of this code is that you store 2 items and on boot sequence, you’re able to re-measure the tooltip and adjust for the difference with the existing work material. All of this is added to the ControlFrame class

The two items we end up storing are:

A file with the last measured probe z in machine coordinates- Saved every measurement

A file with the last measured workpiece z=0 ( in machine coordinates) and the current last probe z, also in machine coordinates.

To calculate an adjustment for the tooltip length, on a probe cycle, you’ll have the z of the workpiece, the tooltip measured z during that run, and your new current z during your current tooltip. it’s straightforward math wise but getting to work properly involved a lot of twiddling as the CNC commands are asynchronous.

The main takeaways from the code below are as follows:

CNC.vars is a dictionary available with everything from machine coordinates, workplace coordinates to “states”. Located in the CNC.py file, better reading there.

self.sendGCode(“$H”) can be called in controlFrame to return file

When sending gcode, anything with parenthesis is ignored, helps for better documentation in gcode files. i.e. $H (Send the cnc to home)

G90 will put the CNC in absolute coordinates

G91 will put the CNC in relative coordinates

G54 (will put the machine into the current workspace. Reccommended)

N0G0Z-5.0000 (move the Z -5mm or to -5mm of the current workspace)

N0G0X-2.5000Z-5.0000 (Will move both the X and Z)

Code:

# Function to check if the machine has sent a idle response back. It usually does this after running some commands like motion commands. This one doesn’t always work and it might be better to monitor the current machine coordinates to see if it has stopped for a period of time.

	def waitTillGCodeCompletes(self, stateChange = False):
		if stateChange:
			while CNC.vars["state"] not in "Idle":
				time.sleep(0.2)
			return
			pass
			
		# print(self.app.running)
		previousMeasurement="x: %f,y: %f,z: %f"%(CNC.vars['mx'], CNC.vars['my'], CNC.vars['mz'])
		# print(previousMeasurement)
		time.sleep(0.4)
		while "x: %f,y: %f,z: %f"%(CNC.vars['mx'], CNC.vars['my'], CNC.vars['mz']) not in previousMeasurement:
			previousMeasurement="x: %f,y: %f,z: %f"%(CNC.vars['mx'], CNC.vars['my'], CNC.vars['mz'])
			# print(previousMeasurement)
			time.sleep(0.4)
			pass
		
	def saveWorkZ0(self, event=None):
		LastToolProbeZ = 0.0
		with open("/home/workspace/CNC/LastToolProbeZ.txt", 'r') as fID:
			LastToolProbeZ = float(fID.readline())
						
		with open("/home/workspace/CNC/z0.txt", 'w') as fID:
			fID.write("%f\n"%CNC.vars['mz'])
			fID.write("%f\n"%LastToolProbeZ)
			print("saved new calibration file")
			pass
					
	def ToolChangePos(self, event=None):
		
		self.sendGCode("G55 (Measure tooltip button)")
		self.sendGCode("N0G0Z-5.0000")
		self.waitTillGCodeCompletes()
		
		self.sendGCode("N0G0X-100.0000Y-5.0000")
		self.waitTillGCodeCompletes()
		
		self.sendGCode("G54")
	
	def returnToHomePosition(self, event=None):
		# This is run in G55, which is kept throughout the system to be the machine coordinates. -5, -5, -5 is what the homing command sets the machine to using the inductive switches
		self.sendGCode("G55")
		self.sendGCode("N0G0Z-5.0000")
		self.waitTillGCodeCompletes()
		
		self.sendGCode("N0G0X-5.0000Y-5.0000")
		self.waitTillGCodeCompletes()
		
		self.sendGCode("G54")
		
	def runRepeatedTriangleXY(self):
		# This will run entirely in G54, which is the calibrated local machine space. For the nomad, this makes the X and Y 0 in the center of the work environment
		self.sendGCode("G54")
		# Move to the start position
		self.sendGCode("N0G0X0.0000Y0.0000")
		self.waitTillGCodeCompletes()
		
		# run a triangle for n times
		for _ in range(0,5):
			
			self.sendGCode("N0G0X-90.0000Y-90.0000")
			self.waitTillGCodeCompletes()
			
			self.sendGCode("N0G0X90.0000Y-90.0000")
			self.waitTillGCodeCompletes()
			
			self.sendGCode("N0G0X0.0000Y90.0000")
			self.waitTillGCodeCompletes()		
		
	def runTest(self, event=None ):
		import OakD
		cameraObject = OakD.OakD()
		
		self.resetWCS()
		
		self.sendGCode("$H")
		self.waitTillGCodeCompletes(stateChange = True)
		
		time.sleep(5.0) # Waiting for any focus adjustments to finish
		cameraObject.saveNewImage("SquareTest")
		
		# run the test route a total of 10 , each time returning to origin and snapping a photo
		for iteration in range(0,10):
			self.runRepeatedTriangleXY()
			self.returnToHomePosition()
			cameraObject.saveNewImage("SquareTest_%d"%iteration)
			
		
	def resetWCS(self, event=None):
		CNC.vars["state"] = "BUSY"
		self.sendGCode("$H")
		self.waitTillGCodeCompletes(stateChange = True)
		self.sendGCode("G90")
		
		CNC.vars["state"] = "BUSY"
		self.sendGCode("G54") # Set the X and Y 0
		time.sleep(0.3)
		self.sendGCode("G10 L2 P0 X-123.705 Y-107.690")
		time.sleep(0.3)
		
		time.sleep(0.5)
		
		self.sendGCode("G55 (set into to how we track the machine coordinate space)")
		self.sendGCode("G10 L2 P0 X0 Y0 Z0")
		time.sleep(0.5)
		self.sendGCode("G55 (Measure tooltip button)")
		self.sendGCode("N0G0Z-5.0000")
		self.sendGCode("N0G0X-2.5000Z-5.0000")
		self.sendGCode("N0G0Z-35.0000")
		self.sendGCode("N0G38.2Z-105.0000F800.0")
		self.sendGCode("N0 G4P0.005")
		self.sendGCode("G91")
		self.sendGCode("N0G0Z5")
		self.sendGCode("G90")
		self.sendGCode("N0G38.2Z-180.6000F200.0")
		time.sleep(4.0)
		self.waitTillGCodeCompletes()
		
		print("saving probe at location %f\n"%CNC.vars['mz'])
		with open("/home/workspace/CNC/LastToolProbeZ.txt", 'w') as fID:
			fID.write("%f\n"%CNC.vars['mz'])
			
		z0Value = -5.0
		LastToolProbeZ = 0.0
		
		try:
			with open("/home/workspace/CNC/z0.txt", 'r') as fID:
				z0Value = float(fID.readline())
				LastToolProbeZ = float(fID.readline())
				print("z0Value", z0Value)
				print("LastToolProbeZ", LastToolProbeZ)
		except Exception as e:
			print(str(e))
		
			
		CNC.vars["state"] = "BUSY"
		currentZ = CNC.vars['mz']
		print(currentZ)
		TooltipOffset = currentZ - LastToolProbeZ
		
		self.sendGCode("G54")
		newWorkpieceZ = z0Value + TooltipOffset
		# print(newWorkpieceZ)
		self.sendGCode("G10 L2 Z%.3f"%newWorkpieceZ)
		
		time.sleep(0.5)
		self.sendGCode("G55")
		print("running return command")
		self.sendGCode("N0G0X-5.0000Z-5.0000")
		time.sleep(0.5)
		self.waitTillGCodeCompletes()
		self.sendGCode("G54")
		
		



	def go2origin(self, event=None):
		self.sendGCode("G90")
		self.sendGCode("G0Z%d"%(CNC.vars['safe']))
		self.sendGCode("G0X0Y0")
		self.sendGCode("G0Z0")

Date

More
articles