PageRenderTime 44ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/skein_engines/skeinforge-39/skeinforge_application/skeinforge_plugins/craft_plugins/speed.py

https://github.com/hmeyer/ReplicatorG
Python | 321 lines | 289 code | 21 blank | 11 comment | 10 complexity | 670d5b20b8b9d7ff1824d8448bdca820 MD5 | raw file
  1. """
  2. This page is in the table of contents.
  3. Speed is a script to set the feed rate, and flow rate.
  4. The speed manual page is at:
  5. http://fabmetheus.crsndoo.com/wiki/index.php/Skeinforge_Speed
  6. ==Operation==
  7. The default 'Activate Speed' checkbox is on. When it is on, the functions described below will work, when it is off, the functions will not be called. The speed script sets the feed rate, and flow rate.
  8. ==Settings==
  9. ===Add Flow Rate===
  10. Default is on.
  11. When selected, the flow rate will be added to the gcode.
  12. ===Bridge===
  13. ====Bridge Feed Rate Multiplier====
  14. Default is one.
  15. Defines the ratio of the feed rate on the bridge layers over the feed rate of the typical non bridge layers.
  16. ====Bridge Flow Rate Multiplier====
  17. Default is one.
  18. Defines the ratio of the flow rate on the bridge layers over the flow rate of the typical non bridge layers.
  19. ===Duty Cyle===
  20. ====Duty Cyle at Beginning====
  21. Default is one, which will set the extruder motor to full current.
  22. 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.
  23. ====Duty Cyle at Ending====
  24. Default is zero, which will turn off the extruder motor.
  25. 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.
  26. ===Feed Rate===
  27. Default is sixteen millimeters per second.
  28. Defines the operating feed rate.
  29. ===Flow Rate Setting===
  30. Default is 210.
  31. Defines the operating flow rate.
  32. ===Orbital Feed Rate over Operating Feed Rate===
  33. Default is 0.5.
  34. Defines the speed of the orbit 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.
  35. ===Perimeter===
  36. 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, the 'Perimeter Flow Rate over Operating Flow Rate' should also be 0.5. If you are 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:
  37. 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
  38. ====Perimeter Feed Rate over Operating Feed Rate====
  39. Default is one.
  40. Defines the ratio of the feed rate of the perimeter over the feed rate of the infill.
  41. ====Perimeter Flow Rate over Operating Feed Rate====
  42. Default is one.
  43. Defines the ratio of the flow rate of the perimeter over the flow rate of the infill.
  44. ===Travel Feed Rate===
  45. Default is sixteen millimeters per second.
  46. Defines the feed rate when the extruder is off. The 'Travel Feed Rate' could be set as high as the extruder can be moved, it is not limited by the maximum extrusion rate.
  47. ==Examples==
  48. 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.
  49. > python speed.py
  50. This brings up the speed dialog.
  51. > python speed.py Screw Holder Bottom.stl
  52. The speed tool is parsing the file:
  53. Screw Holder Bottom.stl
  54. ..
  55. The speed tool has created the file:
  56. .. Screw Holder Bottom_speed.gcode
  57. > python
  58. Python 2.5.1 (r251:54863, Sep 22 2007, 01:43:31)
  59. [GCC 4.2.1 (SUSE Linux)] on linux2
  60. Type "help", "copyright", "credits" or "license" for more information.
  61. >>> import speed
  62. >>> speed.main()
  63. This brings up the speed dialog.
  64. >>> speed.writeOutput('Screw Holder Bottom.stl')
  65. The speed tool is parsing the file:
  66. Screw Holder Bottom.stl
  67. ..
  68. The speed tool has created the file:
  69. .. Screw Holder Bottom_speed.gcode
  70. """
  71. from __future__ import absolute_import
  72. #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.
  73. import __init__
  74. from fabmetheus_utilities import archive
  75. from fabmetheus_utilities import euclidean
  76. from fabmetheus_utilities import gcodec
  77. from fabmetheus_utilities import intercircle
  78. from fabmetheus_utilities.fabmetheus_tools import fabmetheus_interpret
  79. from fabmetheus_utilities import settings
  80. from skeinforge_application.skeinforge_utilities import skeinforge_craft
  81. from skeinforge_application.skeinforge_utilities import skeinforge_polyfile
  82. from skeinforge_application.skeinforge_utilities import skeinforge_profile
  83. import math
  84. import sys
  85. __author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
  86. __date__ = '$Date: 2008/21/04 $'
  87. __license__ = 'GPL 3.0'
  88. def getCraftedText( fileName, text = '', repository=None):
  89. "Speed the file or text."
  90. return getCraftedTextFromText( archive.getTextIfEmpty( fileName, text ), repository )
  91. def getCraftedTextFromText(gcodeText, repository=None):
  92. "Speed a gcode linear move text."
  93. if gcodec.isProcedureDoneOrFileIsEmpty( gcodeText, 'speed'):
  94. return gcodeText
  95. if repository == None:
  96. repository = settings.getReadRepository( SpeedRepository() )
  97. if not repository.activateSpeed.value:
  98. return gcodeText
  99. return SpeedSkein().getCraftedGcode(gcodeText, repository)
  100. def getNewRepository():
  101. "Get the repository constructor."
  102. return SpeedRepository()
  103. def writeOutput(fileName=''):
  104. "Speed a gcode linear move file."
  105. fileName = fabmetheus_interpret.getFirstTranslatorFileNameUnmodified(fileName)
  106. if fileName != '':
  107. skeinforge_craft.writeChainTextWithNounMessage( fileName, 'speed')
  108. class SpeedRepository:
  109. "A class to handle the speed settings."
  110. def __init__(self):
  111. "Set the default settings, execute title & settings fileName."
  112. skeinforge_profile.addListsToCraftTypeRepository('skeinforge_application.skeinforge_plugins.craft_plugins.speed.html', self )
  113. self.fileNameInput = settings.FileNameInput().getFromFileName( fabmetheus_interpret.getGNUTranslatorGcodeFileTypeTuples(), 'Open File for Speed', self, '')
  114. self.openWikiManualHelpPage = settings.HelpPage().getOpenFromAbsolute('http://fabmetheus.crsndoo.com/wiki/index.php/Skeinforge_Speed')
  115. self.activateSpeed = settings.BooleanSetting().getFromValue('Activate Speed:', self, True )
  116. self.addFlowRate = settings.BooleanSetting().getFromValue('Add Flow Rate:', self, True )
  117. settings.LabelSeparator().getFromRepository(self)
  118. settings.LabelDisplay().getFromName('- Bridge -', self )
  119. self.bridgeFeedRateMultiplier = settings.FloatSpin().getFromValue( 0.8, 'Bridge Feed Rate Multiplier (ratio):', self, 1.2, 1.0 )
  120. self.bridgeFlowRateMultiplier = settings.FloatSpin().getFromValue( 0.8, 'Bridge Flow Rate Multiplier (ratio):', self, 1.2, 1.0 )
  121. settings.LabelSeparator().getFromRepository(self)
  122. settings.LabelDisplay().getFromName('- Duty Cyle -', self )
  123. self.dutyCycleAtBeginning = settings.FloatSpin().getFromValue( 0.0, 'Duty Cyle at Beginning (portion):', self, 1.0, 1.0 )
  124. self.dutyCycleAtEnding = settings.FloatSpin().getFromValue( 0.0, 'Duty Cyle at Ending (portion):', self, 1.0, 0.0 )
  125. settings.LabelSeparator().getFromRepository(self)
  126. self.feedRatePerSecond = settings.FloatSpin().getFromValue( 2.0, 'Feed Rate (mm/s):', self, 50.0, 16.0 )
  127. self.flowRateSetting = settings.FloatSpin().getFromValue( 50.0, 'Flow Rate Setting (float):', self, 250.0, 210.0 )
  128. self.orbitalFeedRateOverOperatingFeedRate = settings.FloatSpin().getFromValue( 0.1, 'Orbital Feed Rate over Operating Feed Rate (ratio):', self, 0.9, 0.5 )
  129. settings.LabelSeparator().getFromRepository(self)
  130. settings.LabelDisplay().getFromName('- Perimeter -', self )
  131. self.perimeterFeedRateOverOperatingFeedRate = settings.FloatSpin().getFromValue( 0.5, 'Perimeter Feed Rate over Operating Feed Rate (ratio):', self, 1.0, 1.0 )
  132. self.perimeterFlowRateOverOperatingFlowRate = settings.FloatSpin().getFromValue( 0.5, 'Perimeter Flow Rate over Operating Flow Rate (ratio):', self, 1.0, 1.0 )
  133. settings.LabelSeparator().getFromRepository(self)
  134. self.travelFeedRatePerSecond = settings.FloatSpin().getFromValue( 2.0, 'Travel Feed Rate (mm/s):', self, 50.0, 16.0 )
  135. self.executeTitle = 'Speed'
  136. def execute(self):
  137. "Speed button has been clicked."
  138. fileNames = skeinforge_polyfile.getFileOrDirectoryTypesUnmodifiedGcode(self.fileNameInput.value, fabmetheus_interpret.getImportPluginFileNames(), self.fileNameInput.wasCancelled)
  139. for fileName in fileNames:
  140. writeOutput(fileName)
  141. class SpeedSkein:
  142. "A class to speed a skein of extrusions."
  143. def __init__(self):
  144. self.distanceFeedRate = gcodec.DistanceFeedRate()
  145. self.feedRatePerSecond = 16.0
  146. self.isBridgeLayer = False
  147. self.isExtruderActive = False
  148. self.isInBoundaryPerimeter = False
  149. self.isPerimeter = False
  150. self.lineIndex = 0
  151. self.lines = None
  152. self.oldFlowRateString = None
  153. def addFlowRateLineIfNecessary(self):
  154. "Add flow rate line."
  155. flowRateString = self.getFlowRateString()
  156. if flowRateString != self.oldFlowRateString:
  157. self.distanceFeedRate.addLine('M108 S' + flowRateString )
  158. self.oldFlowRateString = flowRateString
  159. def addParameterString( self, firstWord, parameterWord ):
  160. "Add parameter string."
  161. if parameterWord == '':
  162. self.distanceFeedRate.addLine(firstWord)
  163. return
  164. self.distanceFeedRate.addParameter( firstWord, parameterWord )
  165. def getCraftedGcode(self, gcodeText, repository):
  166. "Parse gcode text and store the speed gcode."
  167. self.repository = repository
  168. self.feedRatePerSecond = repository.feedRatePerSecond.value
  169. self.travelFeedRatePerMinute = 60.0 * self.repository.travelFeedRatePerSecond.value
  170. self.lines = archive.getTextLines(gcodeText)
  171. self.parseInitialization()
  172. for line in self.lines[self.lineIndex :]:
  173. self.parseLine(line)
  174. self.addParameterString('M113', self.repository.dutyCycleAtEnding.value ) # Set duty cycle .
  175. return self.distanceFeedRate.output.getvalue()
  176. def getFlowRateString(self):
  177. "Get the flow rate string."
  178. if not self.repository.addFlowRate.value:
  179. return None
  180. flowRate = self.repository.flowRateSetting.value
  181. if self.isBridgeLayer:
  182. flowRate *= self.repository.bridgeFlowRateMultiplier.value
  183. if self.isPerimeter:
  184. flowRate *= self.repository.perimeterFlowRateOverOperatingFlowRate.value
  185. return euclidean.getFourSignificantFigures( flowRate )
  186. def getSpeededLine(self, line, splitLine):
  187. 'Get gcode line with feed rate.'
  188. if gcodec.getIndexOfStartingWithSecond('F', splitLine) > 0:
  189. return line
  190. feedRateMinute = 60.0 * self.feedRatePerSecond
  191. if self.isBridgeLayer:
  192. feedRateMinute *= self.repository.bridgeFeedRateMultiplier.value
  193. if self.isPerimeter:
  194. feedRateMinute *= self.repository.perimeterFeedRateOverOperatingFeedRate.value
  195. self.addFlowRateLineIfNecessary()
  196. if not self.isExtruderActive:
  197. feedRateMinute = self.travelFeedRatePerMinute
  198. return self.distanceFeedRate.getLineWithFeedRate(feedRateMinute, line, splitLine)
  199. def parseInitialization(self):
  200. 'Parse gcode initialization and store the parameters.'
  201. for self.lineIndex in xrange(len(self.lines)):
  202. line = self.lines[self.lineIndex]
  203. splitLine = gcodec.getSplitLineBeforeBracketSemicolon(line)
  204. firstWord = gcodec.getFirstWord(splitLine)
  205. self.distanceFeedRate.parseSplitLine(firstWord, splitLine)
  206. if firstWord == '(<layerThickness>':
  207. self.layerThickness = float(splitLine[1])
  208. elif firstWord == '(</extruderInitialization>)':
  209. self.distanceFeedRate.addLine('(<procedureName> speed </procedureName>)')
  210. return
  211. elif firstWord == '(<perimeterWidth>':
  212. self.absolutePerimeterWidth = abs(float(splitLine[1]))
  213. self.distanceFeedRate.addTagBracketedLine('operatingFeedRatePerSecond', self.feedRatePerSecond )
  214. if self.repository.addFlowRate.value:
  215. self.distanceFeedRate.addTagBracketedLine('operatingFlowRate', self.repository.flowRateSetting.value )
  216. orbitalFeedRatePerSecond = self.feedRatePerSecond * self.repository.orbitalFeedRateOverOperatingFeedRate.value
  217. self.distanceFeedRate.addTagBracketedLine('orbitalFeedRatePerSecond', orbitalFeedRatePerSecond )
  218. self.distanceFeedRate.addTagBracketedLine('travelFeedRatePerSecond', self.repository.travelFeedRatePerSecond.value )
  219. self.distanceFeedRate.addLine(line)
  220. def parseLine(self, line):
  221. "Parse a gcode line and add it to the speed skein."
  222. splitLine = gcodec.getSplitLineBeforeBracketSemicolon(line)
  223. if len(splitLine) < 1:
  224. return
  225. firstWord = splitLine[0]
  226. if firstWord == '(<crafting>)':
  227. self.distanceFeedRate.addLine(line)
  228. self.addParameterString('M113', self.repository.dutyCycleAtBeginning.value ) # Set duty cycle .
  229. return
  230. elif firstWord == 'G1':
  231. line = self.getSpeededLine(line, splitLine)
  232. elif firstWord == 'M101':
  233. self.isExtruderActive = True
  234. elif firstWord == 'M103':
  235. self.isExtruderActive = False
  236. elif firstWord == '(<boundaryPerimeter>)':
  237. self.isInBoundaryPerimeter = True
  238. self.isPerimeter = True
  239. elif firstWord == '(<bridgeRotation>':
  240. self.isBridgeLayer = True
  241. elif firstWord == '(<layer>':
  242. self.isBridgeLayer = False
  243. self.addFlowRateLineIfNecessary()
  244. elif firstWord == '(<loop>':
  245. self.isPerimeter = False
  246. elif firstWord == '(<perimeter>':
  247. self.isPerimeter = True
  248. elif firstWord == '(</boundaryPerimeter>)':
  249. self.isInBoundaryPerimeter = False
  250. self.isPerimeter = False
  251. elif firstWord == '(</loop>)':
  252. if self.isInBoundaryPerimeter:
  253. self.isPerimeter = True
  254. self.distanceFeedRate.addLine(line)
  255. def main():
  256. "Display the speed dialog."
  257. if len(sys.argv) > 1:
  258. writeOutput(' '.join(sys.argv[1 :]))
  259. else:
  260. settings.startMainLoopFromConstructor( getNewRepository() )
  261. if __name__ == "__main__":
  262. main()