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
121 from fabmetheus_utilities import archive
122 from fabmetheus_utilities import euclidean
123 from fabmetheus_utilities import gcodec
124 from fabmetheus_utilities.fabmetheus_tools import fabmetheus_interpret
125 from fabmetheus_utilities import settings
126 from skeinforge_application.skeinforge_utilities import skeinforge_craft
127 from skeinforge_application.skeinforge_utilities import skeinforge_polyfile
128 from skeinforge_application.skeinforge_utilities import skeinforge_profile
132 __author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
133 __date__ = '$Date: 2008/21/04 $'
134 __license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
137 def getCraftedText( fileName, text='', repository=None):
138 "Speed the file or text."
139 return getCraftedTextFromText(archive.getTextIfEmpty(fileName, text), repository)
141 def getCraftedTextFromText(gcodeText, repository=None):
142 "Speed a gcode linear move text."
143 if gcodec.isProcedureDoneOrFileIsEmpty( gcodeText, 'speed'):
145 if repository == None:
146 repository = settings.getReadRepository( SpeedRepository() )
147 if not repository.activateSpeed.value:
149 return SpeedSkein().getCraftedGcode(gcodeText, repository)
151 def getNewRepository():
152 'Get new repository.'
153 return SpeedRepository()
155 def writeOutput(fileName, shouldAnalyze=True):
156 "Speed a gcode linear move file."
157 skeinforge_craft.writeChainTextWithNounMessage(fileName, 'speed', shouldAnalyze)
160 class SpeedRepository(object):
161 "A class to handle the speed settings."
163 "Set the default settings, execute title & settings fileName."
164 skeinforge_profile.addListsToCraftTypeRepository('skeinforge_application.skeinforge_plugins.craft_plugins.speed.html', self )
165 self.baseNameSynonymDictionary = {
166 'Object First Layer Feed Rate Infill Multiplier (ratio):' : 'raft.csv',
167 'Object First Layer Feed Rate Perimeter Multiplier (ratio):' : 'raft.csv',
168 'Object First Layer Flow Rate Infill Multiplier (ratio):' : 'raft.csv',
169 'Object First Layer Flow Rate Perimeter Multiplier (ratio):' : 'raft.csv'}
170 self.fileNameInput = settings.FileNameInput().getFromFileName( fabmetheus_interpret.getGNUTranslatorGcodeFileTypeTuples(), 'Open File for Speed', self, '')
171 self.openWikiManualHelpPage = settings.HelpPage().getOpenFromAbsolute('http://fabmetheus.crsndoo.com/wiki/index.php/Skeinforge_Speed')
172 self.activateSpeed = settings.BooleanSetting().getFromValue('Activate Speed', self, True )
173 self.addFlowRate = settings.BooleanSetting().getFromValue('Add Flow Rate:', self, False )
174 settings.LabelSeparator().getFromRepository(self)
175 settings.LabelDisplay().getFromName('- Bridge -', self )
176 self.bridgeFeedRateMultiplier = settings.FloatSpin().getFromValue( 0.8, 'Bridge Feed Rate Multiplier (ratio):', self, 1.2, 1.0 )
177 self.bridgeFlowRateMultiplier = settings.FloatSpin().getFromValue( 0.8, 'Bridge Flow Rate Multiplier (ratio):', self, 1.2, 1.0 )
178 settings.LabelSeparator().getFromRepository(self)
179 settings.LabelDisplay().getFromName('- Duty Cyle -', self )
180 self.dutyCycleAtBeginning = settings.FloatSpin().getFromValue( 0.0, 'Duty Cyle at Beginning (portion):', self, 1.0, 1.0 )
181 self.dutyCycleAtEnding = settings.FloatSpin().getFromValue( 0.0, 'Duty Cyle at Ending (portion):', self, 1.0, 0.0 )
182 settings.LabelSeparator().getFromRepository(self)
183 self.feedRatePerSecond = settings.FloatSpin().getFromValue( 2.0, 'Feed Rate (mm/s):', self, 250.0, 50.0 )
184 self.flowRateSetting = settings.FloatSpin().getFromValue( 50.0, 'Flow Rate Setting (float):', self, 250.0, 50.0 )
185 settings.LabelSeparator().getFromRepository(self)
186 settings.LabelDisplay().getFromName('- Object First Layers -', self)
187 self.objectFirstLayerFeedRateInfillMultiplier = settings.FloatSpin().getFromValue(
188 0.2, 'Object First Layer Feed Rate Infill Multiplier (ratio):', self, 1.0, 0.4)
189 self.objectFirstLayerFeedRatePerimeterMultiplier = settings.FloatSpin().getFromValue(
190 0.2, 'Object First Layer Feed Rate Perimeter Multiplier (ratio):', self, 1.0, 0.4)
191 self.objectFirstLayerFeedRateTravelMultiplier = settings.FloatSpin().getFromValue(
192 0.2, 'Object First Layer Feed Rate Travel Multiplier (ratio):', self, 1.0, 0.4)
193 self.objectFirstLayerFlowRateInfillMultiplier = settings.FloatSpin().getFromValue(
194 0.2, 'Object First Layer Flow Rate Infill Multiplier (ratio):', self, 1.0, 0.4)
195 self.objectFirstLayerFlowRatePerimeterMultiplier = settings.FloatSpin().getFromValue(
196 0.2, 'Object First Layer Flow Rate Perimeter Multiplier (ratio):', self, 1.0, 0.4)
197 self.objectFirstLayersLayerAmount = settings.IntSpin().getFromValue(
198 1, 'Object First Layers Amount Of Layers For Speed Change:', self, 10, 3)
199 settings.LabelSeparator().getFromRepository(self)
200 self.orbitalFeedRateOverOperatingFeedRate = settings.FloatSpin().getFromValue( 0.1, 'Orbital Feed Rate over Operating Feed Rate (ratio):', self, 0.9, 0.5 )
201 self.maximumZFeedRatePerSecond = settings.FloatSpin().getFromValue(0.5, 'Maximum Z Feed Rate (mm/s):', self, 10.0, 1.0)
202 settings.LabelSeparator().getFromRepository(self)
203 settings.LabelDisplay().getFromName('- Perimeter -', self )
204 self.perimeterFeedRateMultiplier = settings.FloatSpin().getFromValue(0.5, 'Perimeter Feed Rate Multiplier (ratio):', self, 1.0, 1.0)
205 self.perimeterFlowRateMultiplier = settings.FloatSpin().getFromValue(0.5, 'Perimeter Flow Rate Multiplier (ratio):', self, 1.0, 1.0)
206 settings.LabelSeparator().getFromRepository(self)
207 self.travelFeedRatePerSecond = settings.FloatSpin().getFromValue( 2.0, 'Travel Feed Rate (mm/s):', self, 350.0, 250.0 )
208 self.executeTitle = 'Speed'
210 self.bottomLayerFlowRateMultiplier = settings.FloatSpin().getFromValue(0.0, 'Bottom layer flow rate (ratio):', self, 10.0, 1.0)
213 "Speed button has been clicked."
214 fileNames = skeinforge_polyfile.getFileOrDirectoryTypesUnmodifiedGcode(self.fileNameInput.value, fabmetheus_interpret.getImportPluginFileNames(), self.fileNameInput.wasCancelled)
215 for fileName in fileNames:
216 writeOutput(fileName)
219 class SpeedSkein(object):
220 "A class to speed a skein of extrusions."
223 self.distanceFeedRate = gcodec.DistanceFeedRate()
224 self.feedRatePerSecond = 16.0
225 self.isBridgeLayer = False
226 self.isEdgePath = False
227 self.isExtruderActive = False
231 self.oldFlowRate = None
233 def addFlowRateLine(self):
234 "Add flow rate line."
235 if not self.repository.addFlowRate.value:
237 flowRate = self.repository.flowRateSetting.value
238 if self.isBridgeLayer:
239 flowRate *= self.repository.bridgeFlowRateMultiplier.value
241 flowRate *= self.repository.perimeterFlowRateMultiplier.value
242 if self.layerIndex < self.repository.objectFirstLayersLayerAmount.value:
244 flowRate *= ((self.repository.objectFirstLayerFlowRatePerimeterMultiplier.value * (self.repository.objectFirstLayersLayerAmount.value - self.layerIndex)) + self.layerIndex) / self.repository.objectFirstLayersLayerAmount.value
246 flowRate *= ((self.repository.objectFirstLayerFlowRateInfillMultiplier.value * (self.repository.objectFirstLayersLayerAmount.value - self.layerIndex)) + self.layerIndex) / self.repository.objectFirstLayersLayerAmount.value
247 if self.layerIndex == 0:
248 flowRate *= self.repository.bottomLayerFlowRateMultiplier.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 * self.repository.bottomLayerFlowRateMultiplier.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__":