2 This page is in the table of contents.
3 Speed is a plugin to set the feed rate and flow rate.
5 The speed manual page is at:
6 http://fabmetheus.crsndoo.com/wiki/index.php/Skeinforge_Speed
9 The default 'Activate Speed' checkbox is on. When it is on, the functions described below will work, when it is off, nothing will be done.
15 When selected, the flow rate will be added to the gcode.
18 ====Bridge Feed Rate Multiplier====
21 Defines the ratio of the feed rate (head speed) on the bridge layers over the feed rate of the typical non bridge layers.
23 ====Bridge Flow Rate Multiplier====
26 Defines the ratio of the flow rate (extruder speed) on the bridge layers over the flow rate of the typical non bridge layers.
29 ====Duty Cyle at Beginning====
30 Default is one, which will set the extruder motor to full current.
32 Defines the duty cycle of the stepper motor pulse width modulation by adding an M113 command toward the beginning of the gcode text. If the hardware has the option of using a potentiometer to set the duty cycle, to select the potentiometer option set 'Duty Cyle at Beginning' to an empty string. To turn off the extruder, set the 'Duty Cyle at Beginning' to zero.
34 ====Duty Cyle at Ending====
35 Default is zero, which will turn off the extruder motor.
37 Defines the duty cycle of the stepper motor pulse width modulation by adding an M113 command toward the ending of the gcode text. If the hardware has the option of using a potentiometer to set the duty cycle, to select the potentiometer option set 'Duty Cyle at Beginning' to an empty string. To turn off the extruder, set the 'Duty Cyle at Ending' to zero.
40 Default is sixteen millimeters per second.
42 Defines the operating feed rate, the speed your printing head moves in XY plane, before any modifiers.
44 ===Flow Rate Setting===
47 Defines the operating flow rate.
49 RapMan uses this parameter to define the RPM of the extruder motor. The extruder motor RPM is flow rate / 10 so if your flow rate is 150.0 that will set the extruder stepper to run at 15 RPM, different printers might read this value differently.
51 ===Maximum Z Feed Rate===
52 Default is one millimeter per second.
54 Defines the speed of a vertical hop, like the infill hop in skin. Also, if the Limit plugin is activated, it will limit the maximum speed of the tool head in the z direction to this value.
56 ===Object First Layer===
58 ====Object First Layer Feed Rate Infill Multiplier====
61 Defines the object first layer infill feed rate multiplier. The greater the 'Object First Layer Feed Rate Infill Multiplier, the thinner the infill, the lower the 'Object First Layer Feed Rate Infill Multiplier', the thicker the infill.
63 ====Object First Layer Feed Rate Perimeter Multiplier====
66 Defines the object first layer edge feed rate multiplier. The greater the 'Object First Layer Feed Rate Perimeter Multiplier, the thinner the edge, the lower the 'Object First Layer Feed Rate Perimeter Multiplier', the thicker the edge.
68 ====Object First Layer Flow Rate Infill Multiplier====
71 Defines the object first layer infill flow rate multiplier. The greater the 'Object First Layer Flow Rate Infill Multiplier', the thicker the infill, the lower the 'Object First Layer Flow Rate Infill Multiplier, the thinner the infill.
73 ====Object First Layer Flow Rate Perimeter Multiplier====
76 Defines the object first layer edge flow rate multiplier. The greater the 'Object First Layer Flow Rate Perimeter Multiplier', the thicker the edge, the lower the 'Object First Layer Flow Rate Perimeter Multiplier, the thinner the edge.
78 ===Orbital Feed Rate over Operating Feed Rate===
81 Defines the speed when the head is orbiting compared to the operating extruder speed. If you want the orbit to be very short, set the "Orbital Feed Rate over Operating Feed Rate" setting to a low value like 0.1.
84 To have higher build quality on the outside at the expense of slower build speed, a typical setting for the 'Perimeter Feed Rate over Operating Feed Rate' would be 0.5. To go along with that, if you are using a speed controlled extruder like a stepper extruder, the 'Perimeter Flow Rate over Operating Flow Rate' should also be 0.5.
86 A stepper motor is the best way of driving the extruder; however, if you are stuck with a DC motor extruder using Pulse Width Modulation to control the speed, then you'll probably need a slightly higher ratio because there is a minimum voltage 'Flow Rate PWM Setting' required for the extruder motor to turn. The flow rate PWM ratio would be determined by trial and error, with the first trial being:
87 Perimeter Flow Rate over Operating Flow Rate ~ Perimeter Feed Rate over Operating Feed Rate * (Flow Rate PWM Setting - Minimum Flow Rate PWM Setting) + Minimum Flow Rate PWM Setting
89 ====Perimeter Feed Rate Multiplier====
92 Defines the ratio of the feed rate of the edge (outside shell) over the feed rate of the infill. If you for example set this to 0.8 you will have a "stronger" outside edge than inside extrusion as the outside edge will be printed slower hence better lamination will occur and more filament will be placed there.
94 ====Perimeter Flow Rate Multiplier====
97 Defines the ratio of the flow rate of the edge (outside shell) over the flow rate of the infill. If you want the same thickness of the edge but better lamination you need to compensate for the slower feed rate by slowing down the flow rate, but all combinations are possible for different results.
99 ===Travel Feed Rate===
100 Default is sixteen millimeters per second.
102 Defines the feed rate when the extruder is off (not printing). The 'Travel Feed Rate' could be set as high as the extruder can be moved, it is not limited by the maximum extrusion rate.
105 The following examples speed the file Screw Holder Bottom.stl. The examples are run in a terminal in the folder which contains Screw Holder Bottom.stl and speed.py.
108 This brings up the speed dialog.
110 > python speed.py Screw Holder Bottom.stl
111 The speed tool is parsing the file:
112 Screw Holder Bottom.stl
114 The speed tool has created the file:
115 .. Screw Holder Bottom_speed.gcode
119 from __future__ import absolute_import
120 #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.
123 from fabmetheus_utilities import archive
124 from fabmetheus_utilities import euclidean
125 from fabmetheus_utilities import gcodec
126 from fabmetheus_utilities import intercircle
127 from fabmetheus_utilities.fabmetheus_tools import fabmetheus_interpret
128 from fabmetheus_utilities import settings
129 from skeinforge_application.skeinforge_utilities import skeinforge_craft
130 from skeinforge_application.skeinforge_utilities import skeinforge_polyfile
131 from skeinforge_application.skeinforge_utilities import skeinforge_profile
136 __author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
137 __date__ = '$Date: 2008/21/04 $'
138 __license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
141 def getCraftedText( fileName, text='', repository=None):
142 "Speed the file or text."
143 return getCraftedTextFromText(archive.getTextIfEmpty(fileName, text), repository)
145 def getCraftedTextFromText(gcodeText, repository=None):
146 "Speed a gcode linear move text."
147 if gcodec.isProcedureDoneOrFileIsEmpty( gcodeText, 'speed'):
149 if repository == None:
150 repository = settings.getReadRepository( SpeedRepository() )
151 if not repository.activateSpeed.value:
153 return SpeedSkein().getCraftedGcode(gcodeText, repository)
155 def getNewRepository():
156 'Get new repository.'
157 return SpeedRepository()
159 def writeOutput(fileName, shouldAnalyze=True):
160 "Speed a gcode linear move file."
161 skeinforge_craft.writeChainTextWithNounMessage(fileName, 'speed', shouldAnalyze)
164 class SpeedRepository:
165 "A class to handle the speed settings."
167 "Set the default settings, execute title & settings fileName."
168 skeinforge_profile.addListsToCraftTypeRepository('skeinforge_application.skeinforge_plugins.craft_plugins.speed.html', self )
169 self.baseNameSynonymDictionary = {
170 'Object First Layer Feed Rate Infill Multiplier (ratio):' : 'raft.csv',
171 'Object First Layer Feed Rate Perimeter Multiplier (ratio):' : 'raft.csv',
172 'Object First Layer Flow Rate Infill Multiplier (ratio):' : 'raft.csv',
173 'Object First Layer Flow Rate Perimeter Multiplier (ratio):' : 'raft.csv'}
174 self.fileNameInput = settings.FileNameInput().getFromFileName( fabmetheus_interpret.getGNUTranslatorGcodeFileTypeTuples(), 'Open File for Speed', self, '')
175 self.openWikiManualHelpPage = settings.HelpPage().getOpenFromAbsolute('http://fabmetheus.crsndoo.com/wiki/index.php/Skeinforge_Speed')
176 self.activateSpeed = settings.BooleanSetting().getFromValue('Activate Speed', self, True )
177 self.addFlowRate = settings.BooleanSetting().getFromValue('Add Flow Rate:', self, False )
178 settings.LabelSeparator().getFromRepository(self)
179 settings.LabelDisplay().getFromName('- Bridge -', self )
180 self.bridgeFeedRateMultiplier = settings.FloatSpin().getFromValue( 0.8, 'Bridge Feed Rate Multiplier (ratio):', self, 1.2, 1.0 )
181 self.bridgeFlowRateMultiplier = settings.FloatSpin().getFromValue( 0.8, 'Bridge Flow Rate Multiplier (ratio):', self, 1.2, 1.0 )
182 settings.LabelSeparator().getFromRepository(self)
183 settings.LabelDisplay().getFromName('- Duty Cyle -', self )
184 self.dutyCycleAtBeginning = settings.FloatSpin().getFromValue( 0.0, 'Duty Cyle at Beginning (portion):', self, 1.0, 1.0 )
185 self.dutyCycleAtEnding = settings.FloatSpin().getFromValue( 0.0, 'Duty Cyle at Ending (portion):', self, 1.0, 0.0 )
186 settings.LabelSeparator().getFromRepository(self)
187 self.feedRatePerSecond = settings.FloatSpin().getFromValue( 2.0, 'Feed Rate (mm/s):', self, 250.0, 50.0 )
188 self.flowRateSetting = settings.FloatSpin().getFromValue( 50.0, 'Flow Rate Setting (float):', self, 250.0, 50.0 )
189 settings.LabelSeparator().getFromRepository(self)
190 settings.LabelDisplay().getFromName('- Object First Layers -', self)
191 self.objectFirstLayerFeedRateInfillMultiplier = settings.FloatSpin().getFromValue(
192 0.2, 'Object First Layer Feed Rate Infill Multiplier (ratio):', self, 1.0, 0.4)
193 self.objectFirstLayerFeedRatePerimeterMultiplier = settings.FloatSpin().getFromValue(
194 0.2, 'Object First Layer Feed Rate Perimeter Multiplier (ratio):', self, 1.0, 0.4)
195 self.objectFirstLayerFeedRateTravelMultiplier = settings.FloatSpin().getFromValue(
196 0.2, 'Object First Layer Feed Rate Travel Multiplier (ratio):', self, 1.0, 0.4)
197 self.objectFirstLayerFlowRateInfillMultiplier = settings.FloatSpin().getFromValue(
198 0.2, 'Object First Layer Flow Rate Infill Multiplier (ratio):', self, 1.0, 0.4)
199 self.objectFirstLayerFlowRatePerimeterMultiplier = settings.FloatSpin().getFromValue(
200 0.2, 'Object First Layer Flow Rate Perimeter Multiplier (ratio):', self, 1.0, 0.4)
201 self.objectFirstLayersLayerAmount = settings.IntSpin().getFromValue(
202 1, 'Object First Layers Amount Of Layers For Speed Change:', self, 10, 3)
203 settings.LabelSeparator().getFromRepository(self)
204 self.orbitalFeedRateOverOperatingFeedRate = settings.FloatSpin().getFromValue( 0.1, 'Orbital Feed Rate over Operating Feed Rate (ratio):', self, 0.9, 0.5 )
205 self.maximumZFeedRatePerSecond = settings.FloatSpin().getFromValue(0.5, 'Maximum Z Feed Rate (mm/s):', self, 10.0, 1.0)
206 settings.LabelSeparator().getFromRepository(self)
207 settings.LabelDisplay().getFromName('- Perimeter -', self )
208 self.perimeterFeedRateMultiplier = settings.FloatSpin().getFromValue(0.5, 'Perimeter Feed Rate Multiplier (ratio):', self, 1.0, 1.0)
209 self.perimeterFlowRateMultiplier = settings.FloatSpin().getFromValue(0.5, 'Perimeter Flow Rate Multiplier (ratio):', self, 1.0, 1.0)
210 settings.LabelSeparator().getFromRepository(self)
211 self.travelFeedRatePerSecond = settings.FloatSpin().getFromValue( 2.0, 'Travel Feed Rate (mm/s):', self, 350.0, 250.0 )
212 self.executeTitle = 'Speed'
215 "Speed button has been clicked."
216 fileNames = skeinforge_polyfile.getFileOrDirectoryTypesUnmodifiedGcode(self.fileNameInput.value, fabmetheus_interpret.getImportPluginFileNames(), self.fileNameInput.wasCancelled)
217 for fileName in fileNames:
218 writeOutput(fileName)
222 "A class to speed a skein of extrusions."
225 self.distanceFeedRate = gcodec.DistanceFeedRate()
226 self.feedRatePerSecond = 16.0
227 self.isBridgeLayer = False
228 self.isEdgePath = False
229 self.isExtruderActive = False
233 self.oldFlowRate = None
235 def addFlowRateLine(self):
236 "Add flow rate line."
237 if not self.repository.addFlowRate.value:
239 flowRate = self.repository.flowRateSetting.value
240 if self.isBridgeLayer:
241 flowRate *= self.repository.bridgeFlowRateMultiplier.value
243 flowRate *= self.repository.perimeterFlowRateMultiplier.value
244 if self.layerIndex < self.repository.objectFirstLayersLayerAmount.value:
246 flowRate *= ((self.repository.objectFirstLayerFlowRatePerimeterMultiplier.value * (self.repository.objectFirstLayersLayerAmount.value - self.layerIndex)) + self.layerIndex) / self.repository.objectFirstLayersLayerAmount.value
248 flowRate *= ((self.repository.objectFirstLayerFlowRateInfillMultiplier.value * (self.repository.objectFirstLayersLayerAmount.value - self.layerIndex)) + self.layerIndex) / self.repository.objectFirstLayersLayerAmount.value
249 if flowRate != self.oldFlowRate:
250 self.distanceFeedRate.addLine('M108 S' + euclidean.getFourSignificantFigures(flowRate))
251 self.oldFlowRate = flowRate
253 def addParameterString( self, firstWord, parameterWord ):
254 "Add parameter string."
255 if parameterWord == '':
256 self.distanceFeedRate.addLine(firstWord)
258 self.distanceFeedRate.addParameter( firstWord, parameterWord )
260 def getCraftedGcode(self, gcodeText, repository):
261 "Parse gcode text and store the speed gcode."
262 self.repository = repository
263 self.feedRatePerSecond = repository.feedRatePerSecond.value
264 self.travelFeedRateMinute = 60.0 * self.repository.travelFeedRatePerSecond.value
265 self.lines = archive.getTextLines(gcodeText)
266 self.parseInitialization()
267 for line in self.lines[self.lineIndex :]:
269 self.addParameterString('M113', self.repository.dutyCycleAtEnding.value ) # Set duty cycle .
270 return self.distanceFeedRate.output.getvalue()
272 def getSpeededLine(self, line, splitLine):
273 'Get gcode line with feed rate.'
274 if gcodec.getIndexOfStartingWithSecond('F', splitLine) > 0:
276 feedRateMinute = 60.0 * self.feedRatePerSecond
277 if self.isBridgeLayer:
278 feedRateMinute *= self.repository.bridgeFeedRateMultiplier.value
280 feedRateMinute *= self.repository.perimeterFeedRateMultiplier.value
281 if self.layerIndex < self.repository.objectFirstLayersLayerAmount.value:
283 feedRateMinute *= ((self.repository.objectFirstLayerFeedRatePerimeterMultiplier.value * (self.repository.objectFirstLayersLayerAmount.value - self.layerIndex)) + self.layerIndex) / self.repository.objectFirstLayersLayerAmount.value
285 feedRateMinute *= ((self.repository.objectFirstLayerFeedRateInfillMultiplier.value * (self.repository.objectFirstLayersLayerAmount.value - self.layerIndex)) + self.layerIndex) / self.repository.objectFirstLayersLayerAmount.value
286 self.addFlowRateLine()
287 if not self.isExtruderActive:
288 feedRateMinute = self.travelFeedRateMinute
289 if self.layerIndex < self.repository.objectFirstLayersLayerAmount.value:
290 feedRateMinute *= ((self.repository.objectFirstLayerFeedRateTravelMultiplier.value * (self.repository.objectFirstLayersLayerAmount.value - self.layerIndex)) + self.layerIndex) / self.repository.objectFirstLayersLayerAmount.value
291 return self.distanceFeedRate.getLineWithFeedRate(feedRateMinute, line, splitLine)
293 def parseInitialization(self):
294 'Parse gcode initialization and store the parameters.'
295 for self.lineIndex in xrange(len(self.lines)):
296 line = self.lines[self.lineIndex]
297 splitLine = gcodec.getSplitLineBeforeBracketSemicolon(line)
298 firstWord = gcodec.getFirstWord(splitLine)
299 self.distanceFeedRate.parseSplitLine(firstWord, splitLine)
300 if firstWord == '(<layerHeight>':
301 self.layerHeight = float(splitLine[1])
302 elif firstWord == '(</extruderInitialization>)':
303 self.distanceFeedRate.addTagBracketedProcedure('speed')
305 elif firstWord == '(<edgeWidth>':
306 self.absoluteEdgeWidth = abs(float(splitLine[1]))
307 self.distanceFeedRate.addTagBracketedLine('maximumZFeedRatePerSecond', self.repository.maximumZFeedRatePerSecond.value )
308 self.distanceFeedRate.addTagBracketedLine('objectFirstLayerFeedRateInfillMultiplier', self.repository.objectFirstLayerFeedRateInfillMultiplier.value)
309 self.distanceFeedRate.addTagBracketedLine('operatingFeedRatePerSecond', self.feedRatePerSecond )
310 if self.repository.addFlowRate.value:
311 self.distanceFeedRate.addTagBracketedLine('objectFirstLayerFlowRateInfillMultiplier', self.repository.objectFirstLayerFlowRateInfillMultiplier.value)
312 self.distanceFeedRate.addTagBracketedLine('operatingFlowRate', self.repository.flowRateSetting.value )
313 orbitalFeedRatePerSecond = self.feedRatePerSecond * self.repository.orbitalFeedRateOverOperatingFeedRate.value
314 self.distanceFeedRate.addTagBracketedLine('orbitalFeedRatePerSecond', orbitalFeedRatePerSecond )
315 self.distanceFeedRate.addTagBracketedLine('travelFeedRatePerSecond', self.repository.travelFeedRatePerSecond.value )
316 self.distanceFeedRate.addLine(line)
318 def parseLine(self, line):
319 "Parse a gcode line and add it to the speed skein."
320 splitLine = gcodec.getSplitLineBeforeBracketSemicolon(line)
321 if len(splitLine) < 1:
323 firstWord = splitLine[0]
324 if firstWord == '(<crafting>)':
325 self.distanceFeedRate.addLine(line)
326 self.addParameterString('M113', self.repository.dutyCycleAtBeginning.value ) # Set duty cycle .
328 elif firstWord == 'G1':
329 line = self.getSpeededLine(line, splitLine)
330 elif firstWord == 'M101':
331 self.isExtruderActive = True
332 elif firstWord == 'M103':
333 self.isExtruderActive = False
334 elif firstWord == '(<bridgeRotation>':
335 self.isBridgeLayer = True
336 elif firstWord == '(<layer>':
338 settings.printProgress(self.layerIndex, 'speed')
339 self.isBridgeLayer = False
340 self.addFlowRateLine()
341 elif firstWord == '(<edge>' or firstWord == '(<edgePath>)':
342 self.isEdgePath = True
343 elif firstWord == '(</edge>)' or firstWord == '(</edgePath>)':
344 self.isEdgePath = False
345 self.distanceFeedRate.addLine(line)
349 "Display the speed dialog."
350 if len(sys.argv) > 1:
351 writeOutput(' '.join(sys.argv[1 :]))
353 settings.startMainLoopFromConstructor(getNewRepository())
355 if __name__ == "__main__":