2 This page is in the table of contents.
3 The unpause plugin is based on the Shane Hathaway's patch to speed up a line segment to compensate for the delay of the microprocessor. The description is at:
4 http://shane.willowrise.com/archives/delay-compensation-in-firmware/
6 The unpause manual page is at:
7 http://fabmetheus.crsndoo.com/wiki/index.php/Skeinforge_Unpause
10 The default 'Activate Unpause' checkbox is off. When it is on, the functions described below will work, when it is off, nothing will be done.
14 Default is 28 milliseconds, which Shane found for the Arduino.
16 Defines the delay on the microprocessor that will be at least partially compensated for.
21 Defines the maximum amount that the feed rate will be sped up to, compared to the original feed rate.
24 The following examples unpause the file Screw Holder Bottom.stl. The examples are run in a terminal in the folder which contains Screw Holder Bottom.stl and unpause.py.
27 This brings up the unpause dialog.
29 > python unpause.py Screw Holder Bottom.stl
30 The unpause tool is parsing the file:
31 Screw Holder Bottom.stl
33 The unpause tool has created the file:
34 .. Screw Holder Bottom_unpause.gcode
38 from __future__ import absolute_import
40 from fabmetheus_utilities import archive
41 from fabmetheus_utilities import gcodec
42 from fabmetheus_utilities.fabmetheus_tools import fabmetheus_interpret
43 from fabmetheus_utilities import settings
44 from skeinforge_application.skeinforge_utilities import skeinforge_craft
45 from skeinforge_application.skeinforge_utilities import skeinforge_polyfile
46 from skeinforge_application.skeinforge_utilities import skeinforge_profile
50 __author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
51 __date__ = '$Date: 2008/21/04 $'
52 __license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
55 def getCraftedText( fileName, gcodeText, repository=None):
56 "Unpause a gcode linear move file or text."
57 return getCraftedTextFromText( archive.getTextIfEmpty( fileName, gcodeText ), repository )
59 def getCraftedTextFromText(gcodeText, repository=None):
60 "Unpause a gcode linear move text."
61 if gcodec.isProcedureDoneOrFileIsEmpty( gcodeText, 'unpause'):
63 if repository == None:
64 repository = settings.getReadRepository( UnpauseRepository() )
65 if not repository.activateUnpause.value:
67 return UnpauseSkein().getCraftedGcode(gcodeText, repository)
69 def getNewRepository():
71 return UnpauseRepository()
73 def getSelectedPlugin(repository):
74 "Get the selected plugin."
75 for plugin in repository.unpausePlugins:
80 def writeOutput(fileName, shouldAnalyze=True):
81 "Unpause a gcode linear move file."
82 skeinforge_craft.writeChainTextWithNounMessage(fileName, 'unpause', shouldAnalyze)
85 class UnpauseRepository(object):
86 "A class to handle the unpause settings."
88 "Set the default settings, execute title & settings fileName."
89 skeinforge_profile.addListsToCraftTypeRepository('skeinforge_application.skeinforge_plugins.craft_plugins.unpause.html', self)
90 self.fileNameInput = settings.FileNameInput().getFromFileName( fabmetheus_interpret.getGNUTranslatorGcodeFileTypeTuples(), 'Open File for Unpause', self, '')
91 self.openWikiManualHelpPage = settings.HelpPage().getOpenFromAbsolute('http://fabmetheus.crsndoo.com/wiki/index.php/Skeinforge_Unpause')
92 self.activateUnpause = settings.BooleanSetting().getFromValue('Activate Unpause', self, False )
93 self.delay = settings.FloatSpin().getFromValue( 2.0, 'Delay (milliseconds):', self, 42.0, 28.0 )
94 self.maximumSpeed = settings.FloatSpin().getFromValue( 1.1, 'Maximum Speed (ratio):', self, 1.9, 1.3 )
95 self.executeTitle = 'Unpause'
98 "Unpause button has been clicked."
99 fileNames = skeinforge_polyfile.getFileOrDirectoryTypesUnmodifiedGcode(self.fileNameInput.value, fabmetheus_interpret.getImportPluginFileNames(), self.fileNameInput.wasCancelled)
100 for fileName in fileNames:
101 writeOutput(fileName)
104 class UnpauseSkein(object):
105 "A class to unpause a skein of extrusions."
107 self.distanceFeedRate = gcodec.DistanceFeedRate()
108 self.feedRateMinute = 959.0
111 self.oldLocation = None
113 def getCraftedGcode(self, gcodeText, repository):
114 "Parse gcode text and store the unpause gcode."
115 self.delaySecond = repository.delay.value * 0.001
116 self.maximumSpeed = repository.maximumSpeed.value
117 self.minimumSpeedUpReciprocal = 1.0 / self.maximumSpeed
118 self.repository = repository
119 self.lines = archive.getTextLines(gcodeText)
120 self.parseInitialization()
121 for self.lineIndex in xrange(self.lineIndex, len(self.lines)):
122 line = self.lines[self.lineIndex]
124 return self.distanceFeedRate.output.getvalue()
126 def getUnpausedArcMovement( self, line, splitLine ):
127 "Get an unpaused arc movement."
128 self.feedRateMinute = gcodec.getFeedRateMinute( self.feedRateMinute, splitLine )
129 if self.oldLocation == None:
131 relativeLocation = gcodec.getLocationFromSplitLine(self.oldLocation, splitLine)
132 self.oldLocation += relativeLocation
133 distance = gcodec.getArcDistance(relativeLocation, splitLine)
134 return self.getUnpausedMovement(distance, line, splitLine)
136 def getUnpausedLinearMovement( self, line, splitLine ):
137 "Get an unpaused linear movement."
138 self.feedRateMinute = gcodec.getFeedRateMinute( self.feedRateMinute, splitLine )
139 location = gcodec.getLocationFromSplitLine(self.oldLocation, splitLine)
140 if self.oldLocation == None:
141 self.oldLocation = location
143 distance = abs(self.oldLocation - location)
144 self.oldLocation = location
145 return self.getUnpausedMovement(distance, line, splitLine)
147 def getUnpausedMovement(self, distance, line, splitLine):
148 "Get an unpaused movement."
151 resultantReciprocal = 1.0 - self.delaySecond / distance * self.feedRateMinute / 60.0
152 resultantReciprocal = max(self.minimumSpeedUpReciprocal, resultantReciprocal)
153 return self.distanceFeedRate.getLineWithFeedRate(self.feedRateMinute / resultantReciprocal, line, splitLine)
155 def parseInitialization(self):
156 'Parse gcode initialization and store the parameters.'
157 for self.lineIndex in xrange(len(self.lines)):
158 line = self.lines[self.lineIndex]
159 splitLine = gcodec.getSplitLineBeforeBracketSemicolon(line)
160 firstWord = gcodec.getFirstWord(splitLine)
161 self.distanceFeedRate.parseSplitLine(firstWord, splitLine)
162 if firstWord == '(</extruderInitialization>)':
163 self.distanceFeedRate.addTagBracketedProcedure('unpause')
165 self.distanceFeedRate.addLine(line)
167 def parseLine(self, line):
168 "Parse a gcode line."
169 splitLine = gcodec.getSplitLineBeforeBracketSemicolon(line)
170 if len(splitLine) < 1:
172 firstWord = splitLine[0]
173 if firstWord == 'G1':
174 line = self.getUnpausedLinearMovement( line, splitLine )
175 if firstWord == 'G2' or firstWord == 'G3':
176 line = self.getUnpausedArcMovement( line, splitLine )
177 self.distanceFeedRate.addLine(line)
181 "Display the unpause dialog."
182 if len(sys.argv) > 1:
183 writeOutput(' '.join(sys.argv[1 :]))
185 settings.startMainLoopFromConstructor(getNewRepository())
187 if __name__ == "__main__":