diff --git a/plugins/PostProcessingPlugin/scripts/AnnealAfterPrint.py b/plugins/PostProcessingPlugin/scripts/AnnealAfterPrint.py new file mode 100644 index 0000000000..a9cffd9e88 --- /dev/null +++ b/plugins/PostProcessingPlugin/scripts/AnnealAfterPrint.py @@ -0,0 +1,160 @@ +# Copyright (c) 2021 Anson Liu +# The PostProcessingPlugin is released under the terms of the AGPLv3 or higher. + +from ..Script import Script + +class AnnealAfterPrint(Script): + """Adds timed annealing GCODE after objects finish printing. + + Bed annealing works best with a glass bed and a plastic container placed on top of the object during annealing. + """ + + def getSettingDataString(self): + return """{ + "name": "Anneal After Print", + "key": "AnnealAfterPrint", + "metadata": {}, + "version": 2, + "settings": + { + "heatingElement": + { + "label": "Heating Element", + "description": "Printer heating element to use for annealing.", + "type": "enum", + "options": + { + "bed": "Bed", + "chamber": "Chamber", + "all": "Bed and Chamber" + }, + "default_value": "bed" + }, + "annealBedTemp": + { + "label": "Bed Temperature", + "description": "Bed temperature annealing. Recommended bed temperature is greater of build plate printing or vendor specified annealing temperature for material. E.g. PC 90-110 C, PLA 60-90 C", + "unit": "C", + "type": "float", + "default_value": 0, + "minimum_value": 0, + "enabled": "heatingElement == \\\"bed\\\" or heatingElement == \\\"all\\\"" + }, + "annealChamberTemp": + { + "label": "Chamber Temperature", + "description": "Chamber temperature for annealing.", + "unit": "C", + "type": "float", + "default_value": 0, + "minimum_value": 0, + "enabled": "heatingElement == \\\"chamber\\\" or heatingElement == \\\"all\\\"" + }, + "annealMinutes": + { + "label": "Annealing Target Temperature Duration", + "description": "Duration in minutes to anneal at target temperature. After duration ends gradually cool down to End Cooling Temperature.", + "unit": "min", + "type": "int", + "default_value": 120, + "minimum_value": 0 + }, + "reminderBeep": + { + "label": "Beep on annealing start", + "description": "", + "type": "bool", + "default_value": false + }, + "endCoolingTemp": + { + "label": "End Cooling Temperature", + "description": "Temperature to end gradual cooling at. After annealing at target temperature for specified duration temperature decreases by 1 degree after 1 minute at each step.", + "unit": "C", + "type": "float", + "default_value": 50, + "minimum_value": 0 + } + } + }""" + + def generateAnnealCode(self, annealBedTemp, annealChamberTemp, annealMinutes, initialBeep, endCoolingTemp): + anneal_code = ';Generated Annealing GCODE by Anson Liu' + + if initialBeep: + anneal_code += '\nM300 ;play beep for plastic container placement reminder' + + anneal_code += '\nM117 ' + if annealBedTemp: + anneal_code += 'Place plastic container over objects on bed now! ' + anneal_code += 'Waiting until annealing temp reached...' + anneal_code += '\nM73 P00 ;reset progress bar to 0' + + if annealBedTemp: + anneal_code += '\nM190 R{} ;wait for buildplate to reach temp in C even if cooling'.format(annealBedTemp) + if annealChamberTemp: + anneal_code += '\nM191 R{} ;wait for chamber to reach temp in C even if cooling'.format(annealChamberTemp) + + anneal_code += '\nM117 ' + if annealBedTemp: + anneal_code += 'Keep plastic container over objects. ' + anneal_code += 'Annealing...' + anneal_code += '\nM73 P00' # reset progress bar to 0 + + def generateDwellAndProgressCode(minutes): # Update progress bar and time every minute + dp_code = 'M73 P0 R{}'.format(minutes) + for x in range(1, minutes+1): + dwellWaitSeconds = 60 + dp_code += '\nG4 S{}'.format(dwellWaitSeconds) + progress = round(x/minutes * 100, 2) + remainingMinutes = minutes - x + dp_code += '\nM73 P{} R{}'.format(progress, remainingMinutes) + + return dp_code + + anneal_code += '\n' + generateDwellAndProgressCode(int(annealMinutes)) + + anneal_code += '\nM117 Annealing complete. Gradually lowering bed temperature...' + + for x in reversed(range(endCoolingTemp, max(annealBedTemp, annealChamberTemp))): + if annealBedTemp and annealBedTemp > x: + anneal_code += '\nM190 S{}'.format(x) # Wait for buildplate only if heating + if annealChamberTemp and annealChamberTemp > x: + anneal_code += '\nM191 S{}'.format(x) + anneal_code += '\nG4 S60' # Wait 60 seconds after reaching each cooldown temperature + + if annealBedTemp: + anneal_code += '\nM140 S0' + if annealChamberTemp: + anneal_code += '\nM141 S0' + anneal_code += '\nM117 Annealing complete.' + + return anneal_code + + def execute(self, data): + heating_element = self.getSettingValueByKey("heatingElement") + + # Set bed and chamber temp to true/false value based on heating element selection + anneal_bed_temp = 0 + anneal_chamber_temp = 0 + if heating_element == "bed" or heating_element == "all": + anneal_bed_temp = self.getSettingValueByKey("annealBedTemp") + if heating_element == "chamber" or heating_element == "all": + anneal_chamber_temp = self.getSettingValueByKey("annealChamberTemp") + + anneal_minutes = self.getSettingValueByKey("annealMinutes") + initial_beep = self.getSettingValueByKey("firmware_config") + final_cooling_temp = self.getSettingValueByKey("endCoolingTemp") + + # Test printing the generated anneal code + #print(self.generateAnnealCode(110, 120, False, 50)) + anneal_code = self.generateAnnealCode(anneal_bed_temp, anneal_chamber_temp, anneal_minutes, initial_beep, final_cooling_temp) + + try: + end_of_gcode_index = data[-1].index(';End sof Gcode') + except ValueError: + data[-1] += anneal_code + '\n' + else: + data[-1] = data[-1][:end_of_gcode_index] + anneal_code + '\n' + data[-1][end_of_gcode_index:] + + return data \ No newline at end of file