2 This page is in the table of contents.
3 Lash is a script to partially compensate for the backlash of the tool head.
5 The lash manual page is at:
6 http://fabmetheus.crsndoo.com/wiki/index.php/Skeinforge_Lash
8 The lash tool is ported from Erik de Bruijn's 3D-to-5D-Gcode php GPL'd script at:
9 http://objects.reprap.org/wiki/3D-to-5D-Gcode.php
11 The default values are from the settings in Erik's 3D-to-5D-Gcode, I believe the settings are used on his Darwin reprap.
14 The default 'Activate Lash' checkbox is off. When it is on, the functions described below will work, when it is off, nothing will be done.
18 Default is 0.2 millimeters.
20 Defines the distance the tool head will be lashed in the X direction.
23 Default is 0.2 millimeters.
25 Defines the distance the tool head will be lashed in the Y direction.
28 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.
31 This brings up the lash dialog.
33 > python lash.py Screw Holder Bottom.stl
34 The lash tool is parsing the file:
35 Screw Holder Bottom.stl
37 The lash tool has created the file:
38 .. Screw Holder Bottom_lash.gcode
42 from __future__ import absolute_import
43 #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.
46 from fabmetheus_utilities.fabmetheus_tools import fabmetheus_interpret
47 from fabmetheus_utilities import archive
48 from fabmetheus_utilities import gcodec
49 from fabmetheus_utilities import settings
50 from skeinforge_application.skeinforge_utilities import skeinforge_craft
51 from skeinforge_application.skeinforge_utilities import skeinforge_polyfile
52 from skeinforge_application.skeinforge_utilities import skeinforge_profile
56 __author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
57 __date__ = '$Date: 2008/21/04 $'
58 __license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
61 def getCraftedText( fileName, text, lashRepository = None ):
62 "Get a lashed gcode linear move text."
63 return getCraftedTextFromText( archive.getTextIfEmpty(fileName, text), lashRepository )
65 def getCraftedTextFromText( gcodeText, lashRepository = None ):
66 "Get a lashed gcode linear move text from text."
67 if gcodec.isProcedureDoneOrFileIsEmpty( gcodeText, 'lash'):
69 if lashRepository == None:
70 lashRepository = settings.getReadRepository( LashRepository() )
71 if not lashRepository.activateLash.value:
73 return LashSkein().getCraftedGcode( gcodeText, lashRepository )
75 def getNewRepository():
77 return LashRepository()
79 def writeOutput(fileName, shouldAnalyze=True):
80 "Lash a gcode linear move file."
81 skeinforge_craft.writeChainTextWithNounMessage(fileName, 'lash', shouldAnalyze)
85 "A class to handle the lash settings."
87 "Set the default settings, execute title & settings fileName."
88 skeinforge_profile.addListsToCraftTypeRepository('skeinforge_application.skeinforge_plugins.craft_plugins.lash.html', self)
89 self.fileNameInput = settings.FileNameInput().getFromFileName( fabmetheus_interpret.getGNUTranslatorGcodeFileTypeTuples(), 'Open File for Lash', self, '')
90 self.openWikiManualHelpPage = settings.HelpPage().getOpenFromAbsolute('http://fabmetheus.crsndoo.com/wiki/index.php/Skeinforge_Lash')
91 self.activateLash = settings.BooleanSetting().getFromValue('Activate Lash', self, False )
92 self.xBacklash = settings.FloatSpin().getFromValue( 0.1, 'X Backlash (mm):', self, 0.5, 0.2 )
93 self.yBacklash = settings.FloatSpin().getFromValue( 0.1, 'Y Backlash (mm):', self, 0.5, 0.3 )
94 self.executeTitle = 'Lash'
97 "Lash button has been clicked."
98 fileNames = skeinforge_polyfile.getFileOrDirectoryTypesUnmodifiedGcode(self.fileNameInput.value, fabmetheus_interpret.getImportPluginFileNames(), self.fileNameInput.wasCancelled)
99 for fileName in fileNames:
100 writeOutput(fileName)
104 "A class to lash a skein of extrusions."
106 self.distanceFeedRate = gcodec.DistanceFeedRate()
107 self.feedRateMinute = 958.0
110 self.oldLocation = None
112 def getCraftedGcode( self, gcodeText, lashRepository ):
113 "Parse gcode text and store the lash gcode."
114 self.lines = archive.getTextLines(gcodeText)
115 self.lashRepository = lashRepository
116 self.xBacklash = lashRepository.xBacklash.value
117 self.yBacklash = lashRepository.yBacklash.value
118 self.parseInitialization()
119 for self.lineIndex in xrange(self.lineIndex, len(self.lines)):
120 line = self.lines[self.lineIndex]
122 return self.distanceFeedRate.output.getvalue()
124 def getLashedLine( self, line, location, splitLine ):
125 "Get lashed gcode line."
126 if self.oldLocation == None:
128 if location.x > self.oldLocation.x:
129 line = self.distanceFeedRate.getLineWithX( line, splitLine, location.x + self.xBacklash )
131 line = self.distanceFeedRate.getLineWithX( line, splitLine, location.x - self.xBacklash )
132 if location.y > self.oldLocation.y:
133 line = self.distanceFeedRate.getLineWithY( line, splitLine, location.y + self.yBacklash )
135 line = self.distanceFeedRate.getLineWithY( line, splitLine, location.y - self.yBacklash )
138 def parseInitialization(self):
139 'Parse gcode initialization and store the parameters.'
140 for self.lineIndex in xrange(len(self.lines)):
141 line = self.lines[self.lineIndex]
142 splitLine = gcodec.getSplitLineBeforeBracketSemicolon(line)
143 firstWord = gcodec.getFirstWord(splitLine)
144 self.distanceFeedRate.parseSplitLine(firstWord, splitLine)
145 if firstWord == '(</extruderInitialization>)':
146 self.distanceFeedRate.addTagBracketedProcedure('lash')
148 self.distanceFeedRate.addLine(line)
150 def parseLash(self, line):
151 "Parse a gcode line and add it to the lash skein."
152 splitLine = gcodec.getSplitLineBeforeBracketSemicolon(line)
153 if len(splitLine) < 1:
155 firstWord = splitLine[0]
156 if firstWord == 'G1':
157 location = gcodec.getLocationFromSplitLine(self.oldLocation, splitLine)
158 line = self.getLashedLine( line, location, splitLine )
159 self.oldLocation = location
160 self.distanceFeedRate.addLine(line)
164 "Display the lash dialog."
165 if len(sys.argv) > 1:
166 writeOutput(' '.join(sys.argv[1 :]))
168 settings.startMainLoopFromConstructor(getNewRepository())
170 if __name__ == "__main__":