""" This page is in the table of contents. Lash is a script to partially compensate for the backlash of the tool head. The lash manual page is at: http://www.bitsfrombytes.com/wiki/index.php?title=Skeinforge_Lash The lash tool is ported from Erik de Bruijn's 3D-to-5D-Gcode php GPL'd script at: http://objects.reprap.org/wiki/3D-to-5D-Gcode.php The default values are from the settings in Erik's 3D-to-5D-Gcode, I believe the settings are used on his Darwin reprap. ==Operation== The default 'Activate Lash' checkbox is off. When it is on, the functions described below will work, when it is off, the functions will not be called. ==Settings== ===X Backlash=== Default is 0.2 millimeters. Defines the distance the tool head will be lashed in the X direction. ===Y Backlash=== Default is 0.2 millimeters. Defines the distance the tool head will be lashed in the Y direction. ==Examples== The following examples lash the file Screw Holder Bottom.stl. The examples are run in a terminal in the folder which contains Screw Holder Bottom.stl and lash.py. > python lash.py This brings up the lash dialog. > python lash.py Screw Holder Bottom.stl The lash tool is parsing the file: Screw Holder Bottom.stl .. The lash tool has created the file: .. Screw Holder Bottom_lash.gcode > python Python 2.5.1 (r251:54863, Sep 22 2007, 01:43:31) [GCC 4.2.1 (SUSE Linux)] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> import lash >>> lash.main() This brings up the lash dialog. >>> lash.writeOutput( 'Screw Holder Bottom.stl' ) The lash tool is parsing the file: Screw Holder Bottom.stl .. The lash tool has created the file: .. Screw Holder Bottom_lash.gcode """ from __future__ import absolute_import #Init has to be imported first because it has code to workaround the python bug where relative imports don't work if the module is imported as a main module. import __init__ from skeinforge_tools import profile from skeinforge_tools.meta_plugins import polyfile from skeinforge_tools.skeinforge_utilities import consecution from skeinforge_tools.skeinforge_utilities import gcodec from skeinforge_tools.skeinforge_utilities import interpret from skeinforge_tools.skeinforge_utilities import settings import sys __author__ = "Enrique Perez (perez_enrique@yahoo.com)" __date__ = "$Date: 2008/21/04 $" __license__ = "GPL 3.0" def getCraftedText( fileName, text, lashRepository = None ): "Get a lashed gcode linear move text." return getCraftedTextFromText( gcodec.getTextIfEmpty( fileName, text ), lashRepository ) def getCraftedTextFromText( gcodeText, lashRepository = None ): "Get a lashed gcode linear move text from text." if gcodec.isProcedureDoneOrFileIsEmpty( gcodeText, 'lash' ): return gcodeText if lashRepository == None: lashRepository = settings.getReadRepository( LashRepository() ) if not lashRepository.activateLash.value: return gcodeText return LashSkein().getCraftedGcode( gcodeText, lashRepository ) def getNewRepository(): "Get the repository constructor." return LashRepository() def writeOutput( fileName = '' ): "Lash a gcode linear move file." fileName = interpret.getFirstTranslatorFileNameUnmodified( fileName ) if fileName != '': consecution.writeChainTextWithNounMessage( fileName, 'lash' ) class LashRepository: "A class to handle the lash settings." def __init__( self ): "Set the default settings, execute title & settings fileName." settings.addListsToRepository( 'skeinforge_tools.craft_plugins.lash.html', '', self ) self.fileNameInput = settings.FileNameInput().getFromFileName( interpret.getGNUTranslatorGcodeFileTypeTuples(), 'Open File for Lash', self, '' ) self.openWikiManualHelpPage = settings.HelpPage().getOpenFromAbsolute( 'http://www.bitsfrombytes.com/wiki/index.php?title=Skeinforge_Lash' ) self.activateLash = settings.BooleanSetting().getFromValue( 'Activate Lash', self, False ) self.xBacklash = settings.FloatSpin().getFromValue( 0.1, 'X Backlash (mm):', self, 0.5, 0.2 ) self.yBacklash = settings.FloatSpin().getFromValue( 0.1, 'Y Backlash (mm):', self, 0.5, 0.3 ) self.executeTitle = 'Lash' def execute( self ): "Lash button has been clicked." fileNames = polyfile.getFileOrDirectoryTypesUnmodifiedGcode( self.fileNameInput.value, interpret.getImportPluginFileNames(), self.fileNameInput.wasCancelled ) for fileName in fileNames: writeOutput( fileName ) class LashSkein: "A class to lash a skein of extrusions." def __init__( self ): self.distanceFeedRate = gcodec.DistanceFeedRate() self.feedRateMinute = 958.0 self.lineIndex = 0 self.lines = None self.oldLocation = None def getCraftedGcode( self, gcodeText, lashRepository ): "Parse gcode text and store the lash gcode." self.lines = gcodec.getTextLines( gcodeText ) self.lashRepository = lashRepository self.xBacklash = lashRepository.xBacklash.value self.yBacklash = lashRepository.yBacklash.value self.parseInitialization() for self.lineIndex in xrange( self.lineIndex, len( self.lines ) ): line = self.lines[ self.lineIndex ] self.parseLash( line ) return self.distanceFeedRate.output.getvalue() def getLashedLine( self, line, location, splitLine ): "Get lashed gcode line." if self.oldLocation == None: return line if location.x > self.oldLocation.x: line = self.distanceFeedRate.getLineWithX( line, splitLine, location.x + self.xBacklash ) else: line = self.distanceFeedRate.getLineWithX( line, splitLine, location.x - self.xBacklash ) if location.y > self.oldLocation.y: line = self.distanceFeedRate.getLineWithY( line, splitLine, location.y + self.yBacklash ) else: line = self.distanceFeedRate.getLineWithY( line, splitLine, location.y - self.yBacklash ) return line def parseInitialization( self ): "Parse gcode initialization and store the parameters." for self.lineIndex in xrange( len( self.lines ) ): line = self.lines[ self.lineIndex ] splitLine = gcodec.getSplitLineBeforeBracketSemicolon( line ) firstWord = gcodec.getFirstWord( splitLine ) self.distanceFeedRate.parseSplitLine( firstWord, splitLine ) if firstWord == '()': self.distanceFeedRate.addLine( '( lash )' ) return self.distanceFeedRate.addLine( line ) def parseLash( self, line ): "Parse a gcode line and add it to the lash skein." splitLine = gcodec.getSplitLineBeforeBracketSemicolon( line ) if len( splitLine ) < 1: return firstWord = splitLine[ 0 ] if firstWord == 'G1': location = gcodec.getLocationFromSplitLine( self.oldLocation, splitLine ) line = self.getLashedLine( line, location, splitLine ) self.oldLocation = location self.distanceFeedRate.addLine( line ) def main(): "Display the lash dialog." if len( sys.argv ) > 1: writeOutput( ' '.join( sys.argv[ 1 : ] ) ) else: settings.startMainLoopFromConstructor( getNewRepository() ) if __name__ == "__main__": main()