2 This page is in the table of contents.
3 At the beginning of a layer, depending on the settings, wipe will move the nozzle with the extruder off to the arrival point, then to the wipe point, then to the departure point, then back to the layer.
5 The wipe path is machine specific, so you'll probably have to change all the default locations.
7 The wipe manual page is at:
8 http://fabmetheus.crsndoo.com/wiki/index.php/Skeinforge_Wipe
11 The default 'Activate Wipe' checkbox is off. When it is on, the functions described below will work, when it is off, nothing will be done.
14 ===Arrival Location===
16 Default is minus seventy millimeters.
18 Defines the x coordinate of the arrival location.
21 Default is minus fifty millimeters.
23 Defines the y coordinate of the arrival location.
26 Default is fifty millimeters.
28 Defines the z coordinate of the arrival location.
30 ===Departure Location===
32 Default is minus seventy millimeters.
34 Defines the x coordinate of the departure location.
37 Default is minus forty millimeters.
39 Defines the y coordinate of the departure location.
42 Default is fifty millimeters.
44 Defines the z coordinate of the departure location.
48 Default is minus seventy millimeters.
50 Defines the x coordinate of the wipe location.
53 Default is minus seventy millimeters.
55 Defines the y coordinate of the wipe location.
58 Default is fifty millimeters.
60 Defines the z coordinate of the wipe location.
65 Defines the number of layers between wipes. Wipe will always wipe just before layer zero, afterwards it will wipe every "Wipe Period" layers. With the default of three, wipe will wipe just before layer zero, layer three, layer six and so on.
68 The following examples wipe the file Screw Holder Bottom.stl. The examples are run in a terminal in the folder which contains Screw Holder Bottom.stl and wipe.py.
71 This brings up the wipe dialog.
73 > python wipe.py Screw Holder Bottom.stl
74 The wipe tool is parsing the file:
75 Screw Holder Bottom.stl
77 The wipe tool has created the file:
78 .. Screw Holder Bottom_wipe.gcode
82 from __future__ import absolute_import
83 #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.
86 from fabmetheus_utilities.fabmetheus_tools import fabmetheus_interpret
87 from fabmetheus_utilities.vector3 import Vector3
88 from fabmetheus_utilities import archive
89 from fabmetheus_utilities import euclidean
90 from fabmetheus_utilities import gcodec
91 from fabmetheus_utilities import settings
92 from skeinforge_application.skeinforge_utilities import skeinforge_craft
93 from skeinforge_application.skeinforge_utilities import skeinforge_polyfile
94 from skeinforge_application.skeinforge_utilities import skeinforge_profile
99 __author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
100 __date__ = '$Date: 2008/21/04 $'
101 __license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
104 def getCraftedText( fileName, text, wipeRepository = None ):
105 "Wipe a gcode linear move text."
106 return getCraftedTextFromText( archive.getTextIfEmpty(fileName, text), wipeRepository )
108 def getCraftedTextFromText( gcodeText, wipeRepository = None ):
109 "Wipe a gcode linear move text."
110 if gcodec.isProcedureDoneOrFileIsEmpty( gcodeText, 'wipe'):
112 if wipeRepository == None:
113 wipeRepository = settings.getReadRepository( WipeRepository() )
114 if not wipeRepository.activateWipe.value:
116 return WipeSkein().getCraftedGcode( gcodeText, wipeRepository )
118 def getNewRepository():
119 'Get new repository.'
120 return WipeRepository()
122 def writeOutput(fileName, shouldAnalyze=True):
123 "Wipe a gcode linear move file."
124 skeinforge_craft.writeChainTextWithNounMessage(fileName, 'wipe', shouldAnalyze)
127 class WipeRepository:
128 "A class to handle the wipe settings."
130 "Set the default settings, execute title & settings fileName."
131 skeinforge_profile.addListsToCraftTypeRepository('skeinforge_application.skeinforge_plugins.craft_plugins.wipe.html', self)
132 self.fileNameInput = settings.FileNameInput().getFromFileName(fabmetheus_interpret.getGNUTranslatorGcodeFileTypeTuples(), 'Open File for Wipe', self, '')
133 self.openWikiManualHelpPage = settings.HelpPage().getOpenFromAbsolute('http://fabmetheus.crsndoo.com/wiki/index.php/Skeinforge_Wipe')
134 self.activateWipe = settings.BooleanSetting().getFromValue('Activate Wipe', self, False)
135 settings.LabelSeparator().getFromRepository(self)
136 settings.LabelDisplay().getFromName('- Arrival Location -', self)
137 self.locationArrivalX = settings.FloatSpin().getFromValue(-100.0, 'Arrival X (mm):', self, 100.0, -70.0)
138 self.locationArrivalY = settings.FloatSpin().getFromValue(-100.0, 'Arrival Y (mm):', self, 100.0, -50.0)
139 self.locationArrivalZ = settings.FloatSpin().getFromValue(-100.0, 'Arrival Z (mm):', self, 100.0, 50.0)
140 settings.LabelSeparator().getFromRepository(self)
141 settings.LabelDisplay().getFromName('- Departure Location -', self)
142 self.locationDepartureX = settings.FloatSpin().getFromValue(-100.0, 'Departure X (mm):', self, 100.0, -70.0)
143 self.locationDepartureY = settings.FloatSpin().getFromValue(-100.0, 'Departure Y (mm):', self, 100.0, -40.0)
144 self.locationDepartureZ = settings.FloatSpin().getFromValue(-100.0, 'Departure Z (mm):', self, 100.0, 50.0)
145 settings.LabelSeparator().getFromRepository(self)
146 settings.LabelDisplay().getFromName('- Wipe Location -', self)
147 self.locationWipeX = settings.FloatSpin().getFromValue(-100.0, 'Wipe X (mm):', self, 100.0, -70.0)
148 self.locationWipeY = settings.FloatSpin().getFromValue(-100.0, 'Wipe Y (mm):', self, 100.0, -70.0)
149 self.locationWipeZ = settings.FloatSpin().getFromValue(-100.0, 'Wipe Z (mm):', self, 100.0, 50.0)
150 settings.LabelSeparator().getFromRepository(self)
151 self.wipePeriod = settings.IntSpin().getFromValue(1, 'Wipe Period (layers):', self, 5, 3)
152 self.executeTitle = 'Wipe'
155 "Wipe button has been clicked."
156 fileNames = skeinforge_polyfile.getFileOrDirectoryTypesUnmodifiedGcode(self.fileNameInput.value, fabmetheus_interpret.getImportPluginFileNames(), self.fileNameInput.wasCancelled)
157 for fileName in fileNames:
158 writeOutput(fileName)
162 "A class to wipe a skein of extrusions."
164 self.distanceFeedRate = gcodec.DistanceFeedRate()
165 self.extruderActive = False
170 self.oldLocation = None
171 self.shouldWipe = False
172 self.travelFeedRateMinute = 957.0
174 def addHop( self, begin, end ):
175 "Add hop to highest point."
176 beginEndDistance = begin.distance(end)
177 if beginEndDistance < 3.0 * self.absoluteEdgeWidth:
179 alongWay = self.absoluteEdgeWidth / beginEndDistance
180 closeToOldLocation = euclidean.getIntermediateLocation( alongWay, begin, end )
181 closeToOldLocation.z = self.highestZ
182 self.distanceFeedRate.addLine( self.getLinearMoveWithFeedRate( self.travelFeedRateMinute, closeToOldLocation ) )
183 closeToOldArrival = euclidean.getIntermediateLocation( alongWay, end, begin )
184 closeToOldArrival.z = self.highestZ
185 self.distanceFeedRate.addLine( self.getLinearMoveWithFeedRate( self.travelFeedRateMinute, closeToOldArrival ) )
187 def addWipeTravel( self, splitLine ):
188 "Add the wipe travel gcode."
189 location = gcodec.getLocationFromSplitLine(self.oldLocation, splitLine)
190 self.highestZ = max( self.highestZ, location.z )
191 if not self.shouldWipe:
193 self.shouldWipe = False
194 if self.extruderActive:
195 self.distanceFeedRate.addLine('M103')
196 if self.oldLocation != None:
197 self.addHop( self.oldLocation, self.locationArrival )
198 self.distanceFeedRate.addLine( self.getLinearMoveWithFeedRate( self.travelFeedRateMinute, self.locationArrival ) )
199 self.distanceFeedRate.addLine( self.getLinearMoveWithFeedRate( self.travelFeedRateMinute, self.locationWipe ) )
200 self.distanceFeedRate.addLine( self.getLinearMoveWithFeedRate( self.travelFeedRateMinute, self.locationDeparture ) )
201 self.addHop( self.locationDeparture, location )
202 if self.extruderActive:
203 self.distanceFeedRate.addLine('M101')
205 def getCraftedGcode( self, gcodeText, wipeRepository ):
206 "Parse gcode text and store the wipe gcode."
207 self.lines = archive.getTextLines(gcodeText)
208 self.wipePeriod = wipeRepository.wipePeriod.value
209 self.parseInitialization( wipeRepository )
210 self.locationArrival = Vector3( wipeRepository.locationArrivalX.value, wipeRepository.locationArrivalY.value, wipeRepository.locationArrivalZ.value )
211 self.locationDeparture = Vector3( wipeRepository.locationDepartureX.value, wipeRepository.locationDepartureY.value, wipeRepository.locationDepartureZ.value )
212 self.locationWipe = Vector3( wipeRepository.locationWipeX.value, wipeRepository.locationWipeY.value, wipeRepository.locationWipeZ.value )
213 for self.lineIndex in xrange(self.lineIndex, len(self.lines)):
214 line = self.lines[self.lineIndex]
216 return self.distanceFeedRate.output.getvalue()
218 def getLinearMoveWithFeedRate( self, feedRate, location ):
219 "Get a linear move line with the feedRate."
220 return self.distanceFeedRate.getLinearGcodeMovementWithFeedRate( feedRate, location.dropAxis(), location.z )
222 def parseInitialization( self, wipeRepository ):
223 'Parse gcode initialization and store the parameters.'
224 for self.lineIndex in xrange(len(self.lines)):
225 line = self.lines[self.lineIndex]
226 splitLine = gcodec.getSplitLineBeforeBracketSemicolon(line)
227 firstWord = gcodec.getFirstWord(splitLine)
228 self.distanceFeedRate.parseSplitLine(firstWord, splitLine)
229 if firstWord == '(</extruderInitialization>)':
230 self.distanceFeedRate.addTagBracketedProcedure('wipe')
232 elif firstWord == '(<edgeWidth>':
233 self.absoluteEdgeWidth = abs(float(splitLine[1]))
234 elif firstWord == '(<travelFeedRatePerSecond>':
235 self.travelFeedRateMinute = 60.0 * float(splitLine[1])
236 self.distanceFeedRate.addLine(line)
238 def parseLine(self, line):
239 "Parse a gcode line and add it to the bevel gcode."
240 splitLine = gcodec.getSplitLineBeforeBracketSemicolon(line)
241 if len(splitLine) < 1:
243 firstWord = splitLine[0]
244 if firstWord == 'G1':
245 self.addWipeTravel(splitLine)
246 self.oldLocation = gcodec.getLocationFromSplitLine(self.oldLocation, splitLine)
247 elif firstWord == '(<layer>':
249 settings.printProgress(self.layerIndex, 'wipe')
250 if self.layerIndex % self.wipePeriod == 0:
251 self.shouldWipe = True
252 elif firstWord == 'M101':
253 self.extruderActive = True
254 elif firstWord == 'M103':
255 self.extruderActive = False
256 self.distanceFeedRate.addLine(line)
260 "Display the wipe dialog."
261 if len(sys.argv) > 1:
262 writeOutput(' '.join(sys.argv[1 :]))
264 settings.startMainLoopFromConstructor(getNewRepository())
266 if __name__ == "__main__":