chiark / gitweb /
Add back the ultimaker platform, and made the platform mesh simpler.
[cura.git] / Cura / slice / cura_sf / 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
163 from fabmetheus_utilities.fabmetheus_tools import fabmetheus_interpret
164 from fabmetheus_utilities import archive
165 from fabmetheus_utilities import euclidean
166 from fabmetheus_utilities import gcodec
167 from fabmetheus_utilities import settings
168 from skeinforge_application.skeinforge_utilities import skeinforge_craft
169 from skeinforge_application.skeinforge_utilities import skeinforge_polyfile
170 from skeinforge_application.skeinforge_utilities import skeinforge_profile
171 import sys
172
173 __author__ = 'Enrique Perez (perez_enrique@yahoo.com)'
174 __date__ = '$Date: 2008/21/04 $'
175 __license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
176
177
178 def getCraftedText(fileName, text='', repository=None):
179         "Chamber the file or text."
180         return getCraftedTextFromText(archive.getTextIfEmpty(fileName, text), repository)
181
182 def getCraftedTextFromText(gcodeText, repository=None):
183         "Chamber a gcode linear move text."
184         if gcodec.isProcedureDoneOrFileIsEmpty( gcodeText, 'chamber'):
185                 return gcodeText
186         if repository == None:
187                 repository = settings.getReadRepository(ChamberRepository())
188         if not repository.activateChamber.value:
189                 return gcodeText
190         return ChamberSkein().getCraftedGcode(gcodeText, repository)
191
192 def getNewRepository():
193         'Get new repository.'
194         return ChamberRepository()
195
196 def writeOutput(fileName, shouldAnalyze=True):
197         "Chamber a gcode linear move file."
198         skeinforge_craft.writeChainTextWithNounMessage(fileName, 'chamber', shouldAnalyze)
199
200
201 class ChamberRepository(object):
202         "A class to handle the chamber settings."
203         def __init__(self):
204                 "Set the default settings, execute title & settings fileName."
205                 skeinforge_profile.addListsToCraftTypeRepository('skeinforge_application.skeinforge_plugins.craft_plugins.chamber.html', self )
206                 self.fileNameInput = settings.FileNameInput().getFromFileName( fabmetheus_interpret.getGNUTranslatorGcodeFileTypeTuples(), 'Open File for Chamber', self, '')
207                 self.openWikiManualHelpPage = settings.HelpPage().getOpenFromAbsolute('http://fabmetheus.crsndoo.com/wiki/index.php/Skeinforge_Chamber')
208                 self.activateChamber = settings.BooleanSetting().getFromValue('Activate Chamber', self, False )
209                 settings.LabelSeparator().getFromRepository(self)
210                 settings.LabelDisplay().getFromName('- Bed -', self )
211                 self.bedTemperature = settings.FloatSpin().getFromValue(20.0, 'Bed Temperature (Celcius):', self, 90.0, 60.0)
212                 self.bedTemperatureBeginChangeHeight = settings.FloatSpin().getFromValue(-1.0, 'Bed Temperature Begin Change Height (mm):', self, 20.0, -1.0)
213                 self.bedTemperatureEndChangeHeight = settings.FloatSpin().getFromValue(-1.0, 'Bed Temperature End Change Height (mm):', self, 40.0, -1.0)
214                 self.bedTemperatureEnd = settings.FloatSpin().getFromValue(20.0, 'Bed Temperature End (Celcius):', self, 90.0, 20.0)
215                 settings.LabelSeparator().getFromRepository(self)
216                 self.chamberTemperature = settings.FloatSpin().getFromValue( 20.0, 'Chamber Temperature (Celcius):', self, 90.0, 30.0 )
217                 self.holdingForce = settings.FloatSpin().getFromValue( 0.0, 'Holding Force (bar):', self, 100.0, 0.0 )
218                 self.executeTitle = 'Chamber'
219
220         def execute(self):
221                 "Chamber button has been clicked."
222                 fileNames = skeinforge_polyfile.getFileOrDirectoryTypesUnmodifiedGcode(self.fileNameInput.value, fabmetheus_interpret.getImportPluginFileNames(), self.fileNameInput.wasCancelled)
223                 for fileName in fileNames:
224                         writeOutput(fileName)
225
226
227
228 class ChamberSkein(object):
229         "A class to chamber a skein of extrusions."
230         def __init__(self):
231                 'Initialize.'
232                 self.changeWidth = None
233                 self.distanceFeedRate = gcodec.DistanceFeedRate()
234                 self.lineIndex = 0
235                 self.lines = None
236                 self.oldBedTemperature = None
237
238         def addBedTemperature(self, bedTemperature):
239                 'Add bed temperature if it is different from the old.'
240                 if bedTemperature != self.oldBedTemperature:
241                         self.distanceFeedRate.addParameter('M140', bedTemperature)
242                         self.oldBedTemperature = bedTemperature
243
244         def getCraftedGcode(self, gcodeText, repository):
245                 "Parse gcode text and store the chamber gcode."
246                 endAtLeastBegin = repository.bedTemperatureEndChangeHeight.value >= repository.bedTemperatureBeginChangeHeight.value
247                 if endAtLeastBegin and repository.bedTemperatureBeginChangeHeight.value >= 0.0:
248                         self.changeWidth = repository.bedTemperatureEndChangeHeight.value - repository.bedTemperatureBeginChangeHeight.value
249                 self.repository = repository
250                 self.lines = archive.getTextLines(gcodeText)
251                 self.parseInitialization()
252                 for line in self.lines[self.lineIndex :]:
253                         self.parseLine(line)
254                 return self.distanceFeedRate.output.getvalue()
255
256         def parseInitialization(self):
257                 'Parse gcode initialization and store the parameters.'
258                 for self.lineIndex in xrange(len(self.lines)):
259                         line = self.lines[self.lineIndex]
260                         splitLine = gcodec.getSplitLineBeforeBracketSemicolon(line)
261                         firstWord = gcodec.getFirstWord(splitLine)
262                         self.distanceFeedRate.parseSplitLine(firstWord, splitLine)
263                         if firstWord == '(</extruderInitialization>)':
264                                 self.distanceFeedRate.addTagBracketedProcedure('chamber')
265                                 return
266                         self.distanceFeedRate.addLine(line)
267
268         def parseLine(self, line):
269                 "Parse a gcode line and add it to the chamber skein."
270                 splitLine = gcodec.getSplitLineBeforeBracketSemicolon(line)
271                 if len(splitLine) < 1:
272                         return
273                 firstWord = splitLine[0]
274                 if firstWord == '(<crafting>)':
275                         self.distanceFeedRate.addLine(line)
276                         self.addBedTemperature(self.repository.bedTemperature.value)
277                         self.distanceFeedRate.addParameter('M141', self.repository.chamberTemperature.value) # Set chamber temperature.
278                         self.distanceFeedRate.addParameter('M142', self.repository.holdingForce.value) # Set holding pressure.
279                         return
280                 self.distanceFeedRate.addLine(line)
281                 if firstWord == '(<layer>' and self.changeWidth != None:
282                         z = float(splitLine[1])
283                         if z >= self.repository.bedTemperatureEndChangeHeight.value:
284                                 self.addBedTemperature(self.repository.bedTemperatureEnd.value)
285                                 return
286                         if z <= self.repository.bedTemperatureBeginChangeHeight.value:
287                                 return
288                         along = (z - self.repository.bedTemperatureBeginChangeHeight.value) / self.changeWidth
289                         self.addBedTemperature(self.repository.bedTemperature.value * (1 - along) + self.repository.bedTemperatureEnd.value * along)
290
291
292 def main():
293         "Display the chamber dialog."
294         if len(sys.argv) > 1:
295                 writeOutput(' '.join(sys.argv[1 :]))
296         else:
297                 settings.startMainLoopFromConstructor(getNewRepository())
298
299 if __name__ == "__main__":
300         main()