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
39 #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.
42 from fabmetheus_utilities import archive
43 from fabmetheus_utilities import euclidean
44 from fabmetheus_utilities import gcodec
45 from fabmetheus_utilities import intercircle
46 from fabmetheus_utilities.fabmetheus_tools import fabmetheus_interpret
47 from fabmetheus_utilities import settings
48 from skeinforge_application.skeinforge_utilities import skeinforge_craft
49 from skeinforge_application.skeinforge_utilities import skeinforge_polyfile
50 from skeinforge_application.skeinforge_utilities import skeinforge_profile
55 __author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
56 __date__ = '$Date: 2008/21/04 $'
57 __license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
60 def getCraftedText( fileName, gcodeText, repository=None):
61 "Unpause a gcode linear move file or text."
62 return getCraftedTextFromText( archive.getTextIfEmpty( fileName, gcodeText ), repository )
64 def getCraftedTextFromText(gcodeText, repository=None):
65 "Unpause a gcode linear move text."
66 if gcodec.isProcedureDoneOrFileIsEmpty( gcodeText, 'unpause'):
68 if repository == None:
69 repository = settings.getReadRepository( UnpauseRepository() )
70 if not repository.activateUnpause.value:
72 return UnpauseSkein().getCraftedGcode(gcodeText, repository)
74 def getNewRepository():
76 return UnpauseRepository()
78 def getSelectedPlugin(repository):
79 "Get the selected plugin."
80 for plugin in repository.unpausePlugins:
85 def writeOutput(fileName, shouldAnalyze=True):
86 "Unpause a gcode linear move file."
87 skeinforge_craft.writeChainTextWithNounMessage(fileName, 'unpause', shouldAnalyze)
90 class UnpauseRepository:
91 "A class to handle the unpause settings."
93 "Set the default settings, execute title & settings fileName."
94 skeinforge_profile.addListsToCraftTypeRepository('skeinforge_application.skeinforge_plugins.craft_plugins.unpause.html', self)
95 self.fileNameInput = settings.FileNameInput().getFromFileName( fabmetheus_interpret.getGNUTranslatorGcodeFileTypeTuples(), 'Open File for Unpause', self, '')
96 self.openWikiManualHelpPage = settings.HelpPage().getOpenFromAbsolute('http://fabmetheus.crsndoo.com/wiki/index.php/Skeinforge_Unpause')
97 self.activateUnpause = settings.BooleanSetting().getFromValue('Activate Unpause', self, False )
98 self.delay = settings.FloatSpin().getFromValue( 2.0, 'Delay (milliseconds):', self, 42.0, 28.0 )
99 self.maximumSpeed = settings.FloatSpin().getFromValue( 1.1, 'Maximum Speed (ratio):', self, 1.9, 1.3 )
100 self.executeTitle = 'Unpause'
103 "Unpause button has been clicked."
104 fileNames = skeinforge_polyfile.getFileOrDirectoryTypesUnmodifiedGcode(self.fileNameInput.value, fabmetheus_interpret.getImportPluginFileNames(), self.fileNameInput.wasCancelled)
105 for fileName in fileNames:
106 writeOutput(fileName)
110 "A class to unpause a skein of extrusions."
112 self.distanceFeedRate = gcodec.DistanceFeedRate()
113 self.feedRateMinute = 959.0
116 self.oldLocation = None
118 def getCraftedGcode(self, gcodeText, repository):
119 "Parse gcode text and store the unpause gcode."
120 self.delaySecond = repository.delay.value * 0.001
121 self.maximumSpeed = repository.maximumSpeed.value
122 self.minimumSpeedUpReciprocal = 1.0 / self.maximumSpeed
123 self.repository = repository
124 self.lines = archive.getTextLines(gcodeText)
125 self.parseInitialization()
126 for self.lineIndex in xrange(self.lineIndex, len(self.lines)):
127 line = self.lines[self.lineIndex]
129 return self.distanceFeedRate.output.getvalue()
131 def getUnpausedArcMovement( self, line, splitLine ):
132 "Get an unpaused arc movement."
133 self.feedRateMinute = gcodec.getFeedRateMinute( self.feedRateMinute, splitLine )
134 if self.oldLocation == None:
136 relativeLocation = gcodec.getLocationFromSplitLine(self.oldLocation, splitLine)
137 self.oldLocation += relativeLocation
138 distance = gcodec.getArcDistance(relativeLocation, splitLine)
139 return self.getUnpausedMovement(distance, line, splitLine)
141 def getUnpausedLinearMovement( self, line, splitLine ):
142 "Get an unpaused linear movement."
143 self.feedRateMinute = gcodec.getFeedRateMinute( self.feedRateMinute, splitLine )
144 location = gcodec.getLocationFromSplitLine(self.oldLocation, splitLine)
145 if self.oldLocation == None:
146 self.oldLocation = location
148 distance = abs(self.oldLocation - location)
149 self.oldLocation = location
150 return self.getUnpausedMovement(distance, line, splitLine)
152 def getUnpausedMovement(self, distance, line, splitLine):
153 "Get an unpaused movement."
156 resultantReciprocal = 1.0 - self.delaySecond / distance * self.feedRateMinute / 60.0
157 resultantReciprocal = max(self.minimumSpeedUpReciprocal, resultantReciprocal)
158 return self.distanceFeedRate.getLineWithFeedRate(self.feedRateMinute / resultantReciprocal, line, splitLine)
160 def parseInitialization(self):
161 'Parse gcode initialization and store the parameters.'
162 for self.lineIndex in xrange(len(self.lines)):
163 line = self.lines[self.lineIndex]
164 splitLine = gcodec.getSplitLineBeforeBracketSemicolon(line)
165 firstWord = gcodec.getFirstWord(splitLine)
166 self.distanceFeedRate.parseSplitLine(firstWord, splitLine)
167 if firstWord == '(</extruderInitialization>)':
168 self.distanceFeedRate.addTagBracketedProcedure('unpause')
170 self.distanceFeedRate.addLine(line)
172 def parseLine(self, line):
173 "Parse a gcode line."
174 splitLine = gcodec.getSplitLineBeforeBracketSemicolon(line)
175 if len(splitLine) < 1:
177 firstWord = splitLine[0]
178 if firstWord == 'G1':
179 line = self.getUnpausedLinearMovement( line, splitLine )
180 if firstWord == 'G2' or firstWord == 'G3':
181 line = self.getUnpausedArcMovement( line, splitLine )
182 self.distanceFeedRate.addLine(line)
186 "Display the unpause dialog."
187 if len(sys.argv) > 1:
188 writeOutput(' '.join(sys.argv[1 :]))
190 settings.startMainLoopFromConstructor(getNewRepository())
192 if __name__ == "__main__":