def home(self): '''home() ... homes all axes''' status = self['status'] command = self['command'] if status and command: sequence = [[cmd] for cmd in MKUtils.taskModeManual(status)] toHome = [ axis.index for axis in status['motion.axis'] if not axis.homed ] order = {} for axis in status['config.axis']: if axis.index in toHome: batch = order.get(axis.home_sequence) if batch is None: batch = [] batch.append(axis.index) order[axis.home_sequence] = batch for key in sorted(order): batch = order[key] sequence.append( [MKCommandAxisHome(index, True) for index in batch]) for index in batch: sequence.append([ MKCommandWaitUntil(lambda index=index: status[ "motion.axis.%d.homed" % index]) ]) sequence.append(MKUtils.taskModeMDI(self, True)) sequence.append([MKCommandTaskExecute('G10 L20 P0 X0 Y0 Z0')]) command.sendCommandSequence(sequence)
def executeRun(self): sequence = MKUtils.taskModeMDI(self.mk) sequence.append(MKCommandTaskExecute('M6 T0')) sequence.append( MKCommandWaitUntil(lambda: self.mk['status.io.tool.nr'] <= 0)) sequence.extend(MKUtils.taskModeAuto(self.mk, True)) sequence.append(MKCommandTaskRun(False)) self.mk['command'].sendCommands(sequence)
def executeUpload(self): '''Post process the current Path.Job and upload the resulting g-code into MK. Tag the uploaded g-code with the job and a hash so we can determine if the uploaded version is consistent with what is currently in FC.''' job = self.job if job: currTool = None postlist = [] for obj in job.Operations.Group: tc = PathUtil.toolControllerForOp(obj) if tc is not None: if tc.ToolNumber != currTool: postlist.append(tc) currTool = tc.ToolNumber postlist.append(obj) post = PathPost.CommandPathPost() fail, gcode = post.exportObjectsWith(postlist, job, False) if not fail: print("POST: ", fail) preamble = "(FreeCAD.Job: %s)\n(FreeCAD.File: %s)\n(FreeCAD.Signature: %d)\n" % ( job.Name, job.Document.FileName, MKUtils.pathSignature(job.Path)) buf = io.BytesIO((preamble + gcode).encode()) endpoint = self.mk.instance.endpoint.get('file') if endpoint: ftp = ftplib.FTP() ftp.connect(endpoint.address(), endpoint.port()) ftp.login() ftp.storbinary("STOR %s" % self.mk.RemoteFilename, buf) ftp.quit() sequence = MKUtils.taskModeMDI(self.mk) for tc in job.ToolController: t = tc.Tool radius = float(t.Diameter) / 2 if hasattr( t, 'Diameter') else 0. offset = t.LengthOffset if hasattr( t, 'LengthOffset') else 0. sequence.append( MKCommandTaskExecute( "G10 L1 P%d R%g Z%g" % (tc.ToolNumber, radius, offset))) sequence.extend(MKUtils.taskModeAuto(self.mk)) sequence.append(MKCommandTaskReset(False)) sequence.extend([ MKCommandOpenFile(self.mk.remoteFilePath(), True), MKCommandOpenFile(self.mk.remoteFilePath(), False) ]) sequence.append(MKCommandTaskRun(True)) self.mk['command'].sendCommands(sequence) else: PathLog.error('No endpoint found') else: PathLog.error('Post processing failed')
def mdi(self, cmd): '''mdi(cmd) ... send given g-code as MDI to MK (switch to MDI mode if necessary).''' command = self['command'] if command: sequence = MKUtils.taskModeMDI(self) sequence.append(MKCommandTaskExecute(cmd)) command.sendCommands(sequence)
def addSelection(self, doc, obj, sub, pnt): '''FC callback if the selection in the 3d view changes - used to determine the destination when the user wants to jog the tool to a specific position.''' PathLog.track() if self.ui.jogGoto.isChecked() and self.mk[ 'status.motion.state'] == TYPES.RCS_DONE and not self.ui.jogGoto.visibleRegion( ).isEmpty(): x = pnt[0] y = pnt[1] z = pnt[2] mkx = self.displayPos('x') mky = self.displayPos('y') mkz = self.displayPos('z') if PathGeom.isRoughly(x, mkx, Tolerance) and PathGeom.isRoughly( y, mky, Tolerance): if not PathGeom.isRoughly(z, mkz, Tolerance): # only jog the Z axis if XY already match index, velocity = self.getJogIndexAndVelocity('z') jog = [MKCommandAxisJog(index, velocity, mkz - z)] PathLog.debug("jog z from %.2f to %.2f" % (mkz, z)) else: jog = None PathLog.debug( "z already aligned (%.2f), no jogging required" % z) else: # by default we just jog X & Y jog = self._jogXYCmdsFromTo(FreeCAD.Vector(mkx, mky, 0), FreeCAD.Vector(x, y, 0)) sequence = [[cmd] for cmd in MKUtils.taskModeManual(self.mk)] sequence.append(jog) self.mk['command'].sendCommandSequence(sequence)
def addSelection(self, doc, obj, sub, pnt): PathLog.track() if self.ui.jogGoto.isChecked( ) and self.mk['status.motion.state'] == TYPES.RCS_DONE: x = pnt[0] y = pnt[1] z = pnt[2] mkx = self.displayPos('x') mky = self.displayPos('y') mkz = self.displayPos('z') if PathGeom.isRoughly(x, mkx, Tolerance) and PathGeom.isRoughly( y, mky, Tolerance): if not PathGeom.isRoughly(z, mkz, Tolerance): # only jog the Z axis if XY already match index, velocity = self.getJogIndexAndVelocity('z') jog = [MKCommandAxisJog(index, velocity, mkz - z)] PathLog.debug("jog z from %.2f to %.2f" % (mkz, z)) else: jog = None PathLog.debug( "z already aligned (%.2f), no jogging required" % z) else: # by default we just jog X & Y jog = self._jogXYCmdsFromTo(FreeCAD.Vector(mkx, mky, 0), FreeCAD.Vector(x, y, 0)) sequence = [[cmd] for cmd in MKUtils.taskModeManual(self.mk)] sequence.append(jog) self.mk['command'].sendCommandSequence(sequence)
def jogAxesStop(self): '''Explicitly stop all jog motions currently in progress.''' PathLog.track() sequence = [[cmd] for cmd in MKUtils.taskModeManual(self.mk)] sequence.append([MKCommandAxisAbort(i) for i in range(3)]) self.mk['command'].abortCommandSequence() self.mk['command'].sendCommandSequence(sequence)
def executeUpload(self): job = self.job if job: currTool = None postlist = [] for obj in job.Operations.Group: tc = PathUtil.toolControllerForOp(obj) if tc is not None: if tc.ToolNumber != currTool: postlist.append(tc) currTool = tc.ToolNumber postlist.append(obj) post = PathPost.CommandPathPost() fail, gcode = post.exportObjectsWith(postlist, job, False) if not fail: print("POST: ", fail) preamble = "(FreeCAD.Job: %s)\n(FreeCAD.File: %s)\n(FreeCAD.Signature: %d)\n" % ( job.Name, job.Document.FileName, MKUtils.pathSignature(job.Path)) buf = io.BytesIO((preamble + gcode).encode()) endpoint = self.mk.instance.endpoint.get('file') if endpoint: ftp = ftplib.FTP() ftp.connect(endpoint.address(), endpoint.port()) ftp.login() ftp.storbinary("STOR %s" % self.mk.RemoteFilename, buf) ftp.quit() sequence = MKUtils.taskModeMDI(self.mk) for tc in job.ToolController: t = tc.Tool sequence.append( MKCommandTaskExecute("G10 L1 P%d R%g Z%g" % (tc.ToolNumber, t.Diameter / 2., t.LengthOffset))) sequence.extend(MKUtils.taskModeAuto(self.mk)) sequence.append(MKCommandTaskReset(False)) sequence.append( MKCommandOpenFile(self.mk.remoteFilePath(), False)) self.mk['command'].sendCommands(sequence) else: PathLog.error('No endpoint found') else: PathLog.error('Post processing failed')
def jogAxesEnd(self, axes): PathLog.track(axes) if self.jogContinuously(): jog = [] for axis in axes: index, velocity = self.getJogIndexAndVelocity(axis) jog.append(MKCommandAxisAbort(index)) if jog: sequence = [[cmd] for cmd in MKUtils.taskModeManual(self.mk)] sequence.append(jog) self.mk['command'].sendCommandSequence(sequence)
def toggleHomed(self): if self.mk.isHomed(): sequence = [[cmd] for cmd in MKUtils.taskModeManual(self.mk['status'])] commands = [] for axis in self.mk['status.config.axis']: commands.append(MKCommandAxisHome(axis.index, False)) sequence.append(commands) self.mk['command'].sendCommandSequence(sequence) else: self.mk.home()
def jogAxesZero(self, axes): PathLog.track() PathLog.track(axes) jog = [] for axis in (['x', 'y'] if axes[0] == '-' else ['z']): distance = self.displayPos(axis) if distance != 0.0: index, velocity = self.getJogIndexAndVelocity(axis) jog.append(MKCommandAxisJog(index, velocity, distance)) if jog: sequence = [[cmd] for cmd in MKUtils.taskModeManual(self.mk)] sequence.append(jog) self.mk['command'].sendCommandSequence(sequence)
def jogAxesEnd(self, axes): '''Calback when the user releases one of the jog buttons - if continuous jogging is configured this ends the jog.''' PathLog.track(axes) if self.jogContinuously(): jog = [] for axis in axes: index, velocity = self.getJogIndexAndVelocity(axis) jog.append(MKCommandAxisAbort(index)) if jog: sequence = [[cmd] for cmd in MKUtils.taskModeManual(self.mk)] sequence.append(jog) self.mk['command'].sendCommandSequence(sequence)
def jogAxes(self, axes): PathLog.track(axes) if not self.jogContinuously(): jog = [] for axis in axes: index, velocity = self.getJogIndexAndVelocity(axis) units = EmcLinearUnits[self.mk['status.config.units.linear']] distance = FreeCAD.Units.Quantity( self.ui.jogDistance.currentItem().text()).getValueAs(units) jog.append(MKCommandAxisJog(index, velocity, distance)) if jog: sequence = [[cmd] for cmd in MKUtils.taskModeManual(self.mk)] sequence.append(jog) self.mk['command'].sendCommandSequence(sequence)
def updateJob(self): '''Download the g-code currently loaded into MK, check if it could be a FC Path.Job. If the Path.Job is currently loaded trigger an update to everyone caring about these things.''' job = None path = self['status.task.file'] rpath = self.remoteFilePath() endpoint = self.instance.endpoint.get('file') PathLog.info("%s, %s, %s" % (path, rpath, endpoint)) if path is None or rpath is None or endpoint is None: self.needUpdateJob = True else: self.needUpdateJob = False if rpath == path: buf = io.BytesIO() ftp = ftplib.FTP() ftp.connect(endpoint.address(), endpoint.port()) ftp.login() ftp.retrbinary("RETR %s" % self.RemoteFilename, buf.write) ftp.quit() buf.seek(0) line1 = buf.readline().decode() line2 = buf.readline().decode() line3 = buf.readline().decode() if line1.startswith('(FreeCAD.Job: ') and line2.startswith( '(FreeCAD.File: ') and line3.startswith( '(FreeCAD.Signature: '): title = line1[14:-2] filename = line2[15:-2] signature = line3[20:-2] PathLog.debug("Loaded document: '%s' - '%s'" % (filename, title)) for docName, doc in FreeCAD.listDocuments().items(): PathLog.debug("Document: '%s' - '%s'" % (docName, doc.FileName)) if doc.FileName == filename: job = doc.getObject(title) if job: sign = MKUtils.pathSignature(job.Path) if str(sign) == signature: PathLog.info( "Job %s.%s loaded." % (job.Document.Label, job.Label)) else: PathLog.warning( "Job %s.%s is out of date!" % (job.Document.Label, job.Label)) self.setJob(job)
def setPosition(self, label, widget): PathLog.track() commands = MKUtils.taskModeMDI(self.mk) cmds = ['G10', 'L20', 'P0'] for l in label: value = 0 if widget is None else widget.value() offset = self.mk["status.motion.offset.g5x.%s" % l] PathLog.debug("set pos[%s]=%.2f (%.2f)" % (l, value, offset)) cmds.append("%s%g" % (l, value)) code = ' '.join(cmds) PathLog.debug("set pos-%s: '%s'" % (label, code)) commands.append(MKCommandTaskExecute(code)) self.mk['command'].sendCommands(commands)
def jogAxesZero(self, axes): '''jogAxesZero(axes) ... jog each of the specified axes to its 0 position. Note that no velocity adaption is going on so if two or more axis are specified each will reach its destination in its own time regardless of the progress of the other axes.''' PathLog.track() PathLog.track(axes) jog = [] for axis in (['x', 'y'] if axes[0] == '-' else ['z']): distance = self.displayPos(axis) if distance != 0.0: index, velocity = self.getJogIndexAndVelocity(axis) jog.append(MKCommandAxisJog(index, velocity, distance)) if jog: sequence = [[cmd] for cmd in MKUtils.taskModeManual(self.mk)] sequence.append(jog) self.mk['command'].sendCommandSequence(sequence)
def executeStep(self): sequence = MKUtils.taskModeAuto(self.mk) sequence.append(MKCommandTaskStep()) self.mk['command'].sendCommands(sequence)
def jogAxesStop(self): PathLog.track() sequence = [[cmd] for cmd in MKUtils.taskModeManual(self.mk)] sequence.append([MKCommandAxisAbort(i) for i in range(3)]) self.mk['command'].abortCommandSequence() self.mk['command'].sendCommandSequence(sequence)
def executeStep(self): '''Perform a single step of the uploaded g-code.''' sequence = MKUtils.taskModeAuto(self.mk) sequence.append(MKCommandTaskStep()) self.mk['command'].sendCommands(sequence)
def scanJob(self, forward): PathLog.track() job = self.mk.getJob() if job and hasattr(job, 'Path') and job.Path: bb = job.Path.BoundBox if bb.isValid(): off = self.mk['status.motion.offset.g5x'] bb.move(FreeCAD.Vector(off['x'], off['y'], off['z'])) if self.mk.boundBox().isInside(bb): mkx = self.displayPos('x') mky = self.displayPos('y') begin = FreeCAD.Vector(mkx, mky, 0) pts = [] bb = job.Path.BoundBox if forward: pts.append(FreeCAD.Vector(bb.XMin, bb.YMin, 0)) pts.append(FreeCAD.Vector(bb.XMax, bb.YMin, 0)) pts.append(FreeCAD.Vector(bb.XMax, bb.YMax, 0)) pts.append(FreeCAD.Vector(bb.XMin, bb.YMax, 0)) else: pts.append(FreeCAD.Vector(bb.XMin, bb.YMin, 0)) pts.append(FreeCAD.Vector(bb.XMin, bb.YMax, 0)) pts.append(FreeCAD.Vector(bb.XMax, bb.YMax, 0)) pts.append(FreeCAD.Vector(bb.XMax, bb.YMin, 0)) dist = [begin.distanceToPoint(p) for p in pts] rot = dist.index(min(dist)) pts = pts[rot:] + pts[:rot] pts.append(pts[0]) PathLog.info(" begin = (%5.2f, %5.2f)" % (begin.x, begin.y)) for i, p in enumerate(pts): PathLog.info(" pts[%d] = (%5.2f, %5.2f)" % (i, p.x, p.y)) jog = [] if not PathGeom.pointsCoincide(begin, pts[0]): PathLog.info("Move to start point (%.2f, %.2f)" % (pts[0].x, pts[0].y)) jog.append(self._jogXYCmdsFromTo(begin, pts[0])) for i, j in zip(pts, pts[1:]): jog.append(self._jogXYCmdsFromTo(i, j)) sequence = [[cmd] for cmd in MKUtils.taskModeManual(self.mk)] sequence.extend(jog) self.mk['command'].sendCommandSequence(sequence) else: mbb = self.mk.boundBox() msg = ["Cannot scan job!"] if mbb.XMin > bb.XMin: msg.append("X limit min exceeded by: %.2f" % (mbb.XMin - bb.XMin)) if mbb.XMax < bb.XMax: msg.append("X limit max exceeded by: %.2f" % (bb.XMax - mbb.XMax)) if mbb.YMin > bb.YMin: msg.append("Y limit min exceeded by: %.2f" % (mbb.YMin - bb.YMin)) if mbb.YMax < bb.YMax: msg.append("Y limit max exceeded by: %.2f" % (bb.YMax - mbb.YMax)) if mbb.ZMin > bb.ZMin: msg.append("Z limit min exceeded by: %.2f" % (mbb.ZMin - bb.ZMin)) if mbb.ZMax < bb.ZMax: msg.append("Z limit max exceeded by: %.2f" % (bb.ZMax - mbb.ZMax)) mb = PySide.QtGui.QMessageBox() mb.setWindowIcon( machinekit.IconResource('machinekiticon.png')) mb.setWindowTitle('Machinekit') mb.setTextFormat(PySide.QtCore.Qt.TextFormat.RichText) mb.setText("<div align='center'>%s</div>" % '<br/>'.join(msg)) mb.setIcon(PySide.QtGui.QMessageBox.Critical) mb.setStandardButtons(PySide.QtGui.QMessageBox.Ok) mb.exec_() else: PathLog.error("BoundBox of job %s is not valid" % job.Label) else: PathLog.error('No job uploaded for scanning')
def mdi(self, cmd): command = self['command'] if command: sequence = MKUtils.taskModeMDI(self) sequence.append(MKCommandTaskExecute(cmd)) command.sendCommands(sequence)