chiark / gitweb /
181614ba5a10e937557f890b08c577c86462f080
[cura.git] / Cura / skeinforge_application / skeinforge_plugins / craft_plugins / chamber.py
1 """
2 This page is in the table of contents.
3 Some filaments contract too much and warp the extruded object.  To prevent this you have to print the object in a temperature regulated chamber and/or on a temperature regulated bed. The chamber tool allows you to control the bed and chamber temperature and the holding pressure.
4
5 The chamber gcodes are also described at:
6
7 http://reprap.org/wiki/Mendel_User_Manual:_RepRapGCodes
8
9 The chamber manual page is at:
10
11 http://fabmetheus.crsndoo.com/wiki/index.php/Skeinforge_Chamber
12
13 ==Operation==
14 The default 'Activate Chamber' checkbox is on.  When it is on, the functions described below will work, when it is off, nothing will be done.
15
16 ==Settings==
17 ===Bed===
18 The initial bed temperature is defined by 'Bed Temperature'.  If the 'Bed Temperature End Change Height' is greater or equal to the 'Bed Temperature Begin Change Height' and the 'Bed Temperature Begin Change Height' is greater or equal to zero, then the temperature will be ramped toward the 'Bed Temperature End'.  The ramp will start once the extruder reaches the 'Bed Temperature Begin Change Height', then the bed temperature will approach the 'Bed Temperature End' as the extruder reaches the 'Bed Temperature End Change Height', finally the bed temperature will stay at the 'Bed Temperature End' for the remainder of the build.
19
20 The idea is described at:
21 http://www.makerbot.com/blog/2011/03/17/if-you-cant-stand-the-heat/
22
23 ====Bed Temperature====
24 Default: 60C
25
26 Defines the initial print bed temperature in Celcius by adding an M140 command.
27
28 ====Bed Temperature Begin Change Height====
29 Default: -1 mm
30
31 Defines the height of the beginning of the temperature ramp.  If the 'Bed Temperature End Change Height' is less than zero, the bed temperature will remain at the initial 'Bed Temperature'.
32
33 ====Bed Temperature End Change Height====
34 Default: -1 mm
35
36 Defines the height of the end of the temperature ramp.  If the 'Bed Temperature End Change Height' is less than zero or less than the 'Bed Temperature Begin Change Height', the bed temperature will remain at the initial 'Bed Temperature'.
37
38 ====Bed Temperature End====
39 Default: 20C
40
41 Defines the end bed temperature if there is a temperature ramp.
42
43 ===Chamber Temperature===
44 Default: 30C
45
46 Defines the chamber temperature in Celcius by adding an M141 command.
47
48 ===Holding Force===
49 Default: 0
50
51 Defines the holding pressure of a mechanism, like a vacuum table or electromagnet, to hold the bed surface or object, by adding an M142 command.  The holding pressure is in bars. For hardware which only has on/off holding, when the holding pressure is zero, turn off holding, when the holding pressure is greater than zero, turn on holding. 
52
53 ==Heated Beds==
54 ===Bothacker===
55 A resistor heated aluminum plate by Bothacker:
56
57 http://bothacker.com
58
59 with an article at:
60
61 http://bothacker.com/2009/12/18/heated-build-platform/
62
63 ===Domingo===
64 A heated copper build plate by Domingo:
65
66 http://casainho-emcrepstrap.blogspot.com/
67
68 with articles at:
69
70 http://casainho-emcrepstrap.blogspot.com/2010/01/first-time-with-pla-testing-it-also-on.html
71
72 http://casainho-emcrepstrap.blogspot.com/2010/01/call-for-helpideas-to-develop-heated.html
73
74 http://casainho-emcrepstrap.blogspot.com/2010/01/new-heated-build-platform.html
75
76 http://casainho-emcrepstrap.blogspot.com/2010/01/no-acrylic-and-instead-kapton-tape-on.html
77
78 http://casainho-emcrepstrap.blogspot.com/2010/01/problems-with-heated-build-platform-and.html
79
80 http://casainho-emcrepstrap.blogspot.com/2010/01/perfect-build-platform.html
81
82 http://casainho-emcrepstrap.blogspot.com/2009/12/almost-no-warp.html
83
84 http://casainho-emcrepstrap.blogspot.com/2009/12/heated-base-plate.html
85
86 ===Jmil===
87 A heated build stage by jmil, over at:
88
89 http://www.hive76.org
90
91 with articles at:
92
93 http://www.hive76.org/handling-hot-build-surfaces
94
95 http://www.hive76.org/heated-build-stage-success
96
97 ===Metalab===
98 A heated base by the Metalab folks:
99
100 http://reprap.soup.io
101
102 with information at:
103
104 http://reprap.soup.io/?search=heated%20base
105
106 ===Nophead===
107 A resistor heated aluminum bed by Nophead:
108
109 http://hydraraptor.blogspot.com
110
111 with articles at:
112
113 http://hydraraptor.blogspot.com/2010/01/will-it-stick.html
114
115 http://hydraraptor.blogspot.com/2010/01/hot-metal-and-serendipity.html
116
117 http://hydraraptor.blogspot.com/2010/01/new-year-new-plastic.html
118
119 http://hydraraptor.blogspot.com/2010/01/hot-bed.html
120
121 ===Prusajr===
122 A resistive wire heated plexiglass plate by prusajr:
123
124 http://prusadjs.cz/
125
126 with articles at:
127
128 http://prusadjs.cz/2010/01/heated-reprap-print-bed-mk2/
129
130 http://prusadjs.cz/2009/11/look-ma-no-warping-heated-reprap-print-bed/
131
132 ===Zaggo===
133 A resistor heated aluminum plate by Zaggo at Pleasant Software:
134
135 http://pleasantsoftware.com/developer/3d/
136
137 with articles at:
138
139 http://pleasantsoftware.com/developer/3d/2009/12/05/raftless/
140
141 http://pleasantsoftware.com/developer/3d/2009/11/15/living-in-times-of-warp-free-printing/
142
143 http://pleasantsoftware.com/developer/3d/2009/11/12/canned-heat/
144
145 ==Examples==
146 The following examples chamber the file Screw Holder Bottom.stl.  The examples are run in a terminal in the folder which contains Screw Holder Bottom.stl and chamber.py.
147
148 > python chamber.py
149 This brings up the chamber dialog.
150
151 > python chamber.py Screw Holder Bottom.stl
152 The chamber tool is parsing the file:
153 Screw Holder Bottom.stl
154 ..
155 The chamber tool has created the file:
156 Screw Holder Bottom_chamber.gcode
157
158 """
159
160
161 from __future__ import absolute_import
162 #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.
163 import __init__
164
165 from fabmetheus_utilities.fabmetheus_tools import fabmetheus_interpret
166 from fabmetheus_utilities import archive
167 from fabmetheus_utilities import euclidean
168 from fabmetheus_utilities import gcodec
169 from fabmetheus_utilities import settings
170 from skeinforge_application.skeinforge_utilities import skeinforge_craft
171 from skeinforge_application.skeinforge_utilities import skeinforge_polyfile
172 from skeinforge_application.skeinforge_utilities import skeinforge_profile
173 import sys
174
175
176 __author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
177 __date__ = '$Date: 2008/21/04 $'
178 __license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
179
180
181 def getCraftedText(fileName, text='', repository=None):
182         "Chamber the file or text."
183         return getCraftedTextFromText(archive.getTextIfEmpty(fileName, text), repository)
184
185 def getCraftedTextFromText(gcodeText, repository=None):
186         "Chamber a gcode linear move text."
187         if gcodec.isProcedureDoneOrFileIsEmpty( gcodeText, 'chamber'):
188                 return gcodeText
189         if repository == None:
190                 repository = settings.getReadRepository(ChamberRepository())
191         if not repository.activateChamber.value:
192                 return gcodeText
193         return ChamberSkein().getCraftedGcode(gcodeText, repository)
194
195 def getNewRepository():
196         'Get new repository.'
197         return ChamberRepository()
198
199 def writeOutput(fileName, shouldAnalyze=True):
200         "Chamber a gcode linear move file."
201         skeinforge_craft.writeChainTextWithNounMessage(fileName, 'chamber', shouldAnalyze)
202
203
204 class ChamberRepository:
205         "A class to handle the chamber settings."
206         def __init__(self):
207                 "Set the default settings, execute title & settings fileName."
208                 skeinforge_profile.addListsToCraftTypeRepository('skeinforge_application.skeinforge_plugins.craft_plugins.chamber.html', self )
209                 self.fileNameInput = settings.FileNameInput().getFromFileName( fabmetheus_interpret.getGNUTranslatorGcodeFileTypeTuples(), 'Open File for Chamber', self, '')
210                 self.openWikiManualHelpPage = settings.HelpPage().getOpenFromAbsolute('http://fabmetheus.crsndoo.com/wiki/index.php/Skeinforge_Chamber')
211                 self.activateChamber = settings.BooleanSetting().getFromValue('Activate Chamber', self, False )
212                 settings.LabelSeparator().getFromRepository(self)
213                 settings.LabelDisplay().getFromName('- Bed -', self )
214                 self.bedTemperature = settings.FloatSpin().getFromValue(20.0, 'Bed Temperature (Celcius):', self, 90.0, 60.0)
215                 self.bedTemperatureBeginChangeHeight = settings.FloatSpin().getFromValue(-1.0, 'Bed Temperature Begin Change Height (mm):', self, 20.0, -1.0)
216                 self.bedTemperatureEndChangeHeight = settings.FloatSpin().getFromValue(-1.0, 'Bed Temperature End Change Height (mm):', self, 40.0, -1.0)
217                 self.bedTemperatureEnd = settings.FloatSpin().getFromValue(20.0, 'Bed Temperature End (Celcius):', self, 90.0, 20.0)
218                 settings.LabelSeparator().getFromRepository(self)
219                 self.chamberTemperature = settings.FloatSpin().getFromValue( 20.0, 'Chamber Temperature (Celcius):', self, 90.0, 30.0 )
220                 self.holdingForce = settings.FloatSpin().getFromValue( 0.0, 'Holding Force (bar):', self, 100.0, 0.0 )
221                 self.executeTitle = 'Chamber'
222
223         def execute(self):
224                 "Chamber button has been clicked."
225                 fileNames = skeinforge_polyfile.getFileOrDirectoryTypesUnmodifiedGcode(self.fileNameInput.value, fabmetheus_interpret.getImportPluginFileNames(), self.fileNameInput.wasCancelled)
226                 for fileName in fileNames:
227                         writeOutput(fileName)
228
229
230
231 class ChamberSkein:
232         "A class to chamber a skein of extrusions."
233         def __init__(self):
234                 'Initialize.'
235                 self.changeWidth = None
236                 self.distanceFeedRate = gcodec.DistanceFeedRate()
237                 self.lineIndex = 0
238                 self.lines = None
239                 self.oldBedTemperature = None
240
241         def addBedTemperature(self, bedTemperature):
242                 'Add bed temperature if it is different from the old.'
243                 if bedTemperature != self.oldBedTemperature:
244                         self.distanceFeedRate.addParameter('M140', bedTemperature)
245                         self.oldBedTemperature = bedTemperature
246
247         def getCraftedGcode(self, gcodeText, repository):
248                 "Parse gcode text and store the chamber gcode."
249                 endAtLeastBegin = repository.bedTemperatureEndChangeHeight.value >= repository.bedTemperatureBeginChangeHeight.value
250                 if endAtLeastBegin and repository.bedTemperatureBeginChangeHeight.value >= 0.0:
251                         self.changeWidth = repository.bedTemperatureEndChangeHeight.value - repository.bedTemperatureBeginChangeHeight.value
252                 self.repository = repository
253                 self.lines = archive.getTextLines(gcodeText)
254                 self.parseInitialization()
255                 for line in self.lines[self.lineIndex :]:
256                         self.parseLine(line)
257                 return self.distanceFeedRate.output.getvalue()
258
259         def parseInitialization(self):
260                 'Parse gcode initialization and store the parameters.'
261                 for self.lineIndex in xrange(len(self.lines)):
262                         line = self.lines[self.lineIndex]
263                         splitLine = gcodec.getSplitLineBeforeBracketSemicolon(line)
264                         firstWord = gcodec.getFirstWord(splitLine)
265                         self.distanceFeedRate.parseSplitLine(firstWord, splitLine)
266                         if firstWord == '(</extruderInitialization>)':
267                                 self.distanceFeedRate.addTagBracketedProcedure('chamber')
268                                 return
269                         self.distanceFeedRate.addLine(line)
270
271         def parseLine(self, line):
272                 "Parse a gcode line and add it to the chamber skein."
273                 splitLine = gcodec.getSplitLineBeforeBracketSemicolon(line)
274                 if len(splitLine) < 1:
275                         return
276                 firstWord = splitLine[0]
277                 if firstWord == '(<crafting>)':
278                         self.distanceFeedRate.addLine(line)
279                         self.addBedTemperature(self.repository.bedTemperature.value)
280                         self.distanceFeedRate.addParameter('M141', self.repository.chamberTemperature.value) # Set chamber temperature.
281                         self.distanceFeedRate.addParameter('M142', self.repository.holdingForce.value) # Set holding pressure.
282                         return
283                 self.distanceFeedRate.addLine(line)
284                 if firstWord == '(<layer>' and self.changeWidth != None:
285                         z = float(splitLine[1])
286                         if z >= self.repository.bedTemperatureEndChangeHeight.value:
287                                 self.addBedTemperature(self.repository.bedTemperatureEnd.value)
288                                 return
289                         if z <= self.repository.bedTemperatureBeginChangeHeight.value:
290                                 return
291                         along = (z - self.repository.bedTemperatureBeginChangeHeight.value) / self.changeWidth
292                         self.addBedTemperature(self.repository.bedTemperature.value * (1 - along) + self.repository.bedTemperatureEnd.value * along)
293
294
295 def main():
296         "Display the chamber dialog."
297         if len(sys.argv) > 1:
298                 writeOutput(' '.join(sys.argv[1 :]))
299         else:
300                 settings.startMainLoopFromConstructor(getNewRepository())
301
302 if __name__ == "__main__":
303         main()