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
44 from fabmetheus_utilities.fabmetheus_tools import fabmetheus_interpret
45 from fabmetheus_utilities import archive
46 from fabmetheus_utilities import gcodec
47 from fabmetheus_utilities import settings
48 from skeinforge_application.skeinforge_utilities import skeinforge_craft
49 from skeinforge_application.skeinforge_utilities import skeinforge_polyfile
50 from skeinforge_application.skeinforge_utilities import skeinforge_profile
53 __author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
54 __date__ = '$Date: 2008/21/04 $'
55 __license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
58 def getCraftedText( fileName, text, lashRepository = None ):
59 "Get a lashed gcode linear move text."
60 return getCraftedTextFromText( archive.getTextIfEmpty(fileName, text), lashRepository )
62 def getCraftedTextFromText( gcodeText, lashRepository = None ):
63 "Get a lashed gcode linear move text from text."
64 if gcodec.isProcedureDoneOrFileIsEmpty( gcodeText, 'lash'):
66 if lashRepository == None:
67 lashRepository = settings.getReadRepository( LashRepository() )
68 if not lashRepository.activateLash.value:
70 return LashSkein().getCraftedGcode( gcodeText, lashRepository )
72 def getNewRepository():
74 return LashRepository()
76 def writeOutput(fileName, shouldAnalyze=True):
77 "Lash a gcode linear move file."
78 skeinforge_craft.writeChainTextWithNounMessage(fileName, 'lash', shouldAnalyze)
81 class LashRepository(object):
82 "A class to handle the lash settings."
84 "Set the default settings, execute title & settings fileName."
85 skeinforge_profile.addListsToCraftTypeRepository('skeinforge_application.skeinforge_plugins.craft_plugins.lash.html', self)
86 self.fileNameInput = settings.FileNameInput().getFromFileName( fabmetheus_interpret.getGNUTranslatorGcodeFileTypeTuples(), 'Open File for Lash', self, '')
87 self.openWikiManualHelpPage = settings.HelpPage().getOpenFromAbsolute('http://fabmetheus.crsndoo.com/wiki/index.php/Skeinforge_Lash')
88 self.activateLash = settings.BooleanSetting().getFromValue('Activate Lash', self, False )
89 self.xBacklash = settings.FloatSpin().getFromValue( 0.1, 'X Backlash (mm):', self, 0.5, 0.2 )
90 self.yBacklash = settings.FloatSpin().getFromValue( 0.1, 'Y Backlash (mm):', self, 0.5, 0.3 )
91 self.executeTitle = 'Lash'
94 "Lash button has been clicked."
95 fileNames = skeinforge_polyfile.getFileOrDirectoryTypesUnmodifiedGcode(self.fileNameInput.value, fabmetheus_interpret.getImportPluginFileNames(), self.fileNameInput.wasCancelled)
96 for fileName in fileNames:
100 class LashSkein(object):
101 "A class to lash a skein of extrusions."
103 self.distanceFeedRate = gcodec.DistanceFeedRate()
104 self.feedRateMinute = 958.0
107 self.oldLocation = None
109 def getCraftedGcode( self, gcodeText, lashRepository ):
110 "Parse gcode text and store the lash gcode."
111 self.lines = archive.getTextLines(gcodeText)
112 self.lashRepository = lashRepository
113 self.xBacklash = lashRepository.xBacklash.value
114 self.yBacklash = lashRepository.yBacklash.value
115 self.parseInitialization()
116 for self.lineIndex in xrange(self.lineIndex, len(self.lines)):
117 line = self.lines[self.lineIndex]
119 return self.distanceFeedRate.output.getvalue()
121 def getLashedLine( self, line, location, splitLine ):
122 "Get lashed gcode line."
123 if self.oldLocation == None:
125 if location.x > self.oldLocation.x:
126 line = self.distanceFeedRate.getLineWithX( line, splitLine, location.x + self.xBacklash )
128 line = self.distanceFeedRate.getLineWithX( line, splitLine, location.x - self.xBacklash )
129 if location.y > self.oldLocation.y:
130 line = self.distanceFeedRate.getLineWithY( line, splitLine, location.y + self.yBacklash )
132 line = self.distanceFeedRate.getLineWithY( line, splitLine, location.y - self.yBacklash )
135 def parseInitialization(self):
136 'Parse gcode initialization and store the parameters.'
137 for self.lineIndex in xrange(len(self.lines)):
138 line = self.lines[self.lineIndex]
139 splitLine = gcodec.getSplitLineBeforeBracketSemicolon(line)
140 firstWord = gcodec.getFirstWord(splitLine)
141 self.distanceFeedRate.parseSplitLine(firstWord, splitLine)
142 if firstWord == '(</extruderInitialization>)':
143 self.distanceFeedRate.addTagBracketedProcedure('lash')
145 self.distanceFeedRate.addLine(line)
147 def parseLash(self, line):
148 "Parse a gcode line and add it to the lash skein."
149 splitLine = gcodec.getSplitLineBeforeBracketSemicolon(line)
150 if len(splitLine) < 1:
152 firstWord = splitLine[0]
153 if firstWord == 'G1':
154 location = gcodec.getLocationFromSplitLine(self.oldLocation, splitLine)
155 line = self.getLashedLine( line, location, splitLine )
156 self.oldLocation = location
157 self.distanceFeedRate.addLine(line)
161 "Display the lash dialog."
162 if len(sys.argv) > 1:
163 writeOutput(' '.join(sys.argv[1 :]))
165 settings.startMainLoopFromConstructor(getNewRepository())
167 if __name__ == "__main__":