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")