Permalink
Cannot retrieve contributors at this time
Name already in use
A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
mbotmake/mbotmake /
Go to fileThis commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
executable file
265 lines (251 sloc)
9.65 KB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env python3 | |
| import zipfile | |
| import json | |
| import sys | |
| import tempfile | |
| import copy | |
| import math | |
| import re | |
| import traceback | |
| def generateMetajson(temp, vardict): | |
| meta = """ | |
| {{ | |
| "toolhead_0_temperature": {0}, | |
| "toolhead_1_temperature": {1}, | |
| "printer_settings": {{ | |
| "platform_temperature": {2}, | |
| "extruder_temperatures": [ | |
| {0}, | |
| {1} | |
| ], | |
| "heat_platform": {3}, | |
| "extruder": "0" | |
| }}, | |
| "duration_s": {4}, | |
| "total_commands": {5} | |
| }} | |
| """ | |
| meta = meta.format(vardict['tool0temp'], vardict['tool1temp'], | |
| vardict['bedtemp'], | |
| 'true' if vardict['heatbed'] else 'false', | |
| int(math.ceil(vardict['time'])), | |
| vardict['toolpathfilelength']) | |
| with open('{}/meta.json'.format(temp), 'w') as metafile: | |
| metafile.write(meta) | |
| return | |
| def generateCommand(function, metadata, parameters, tags): | |
| return copy.deepcopy([ | |
| {'command': { | |
| 'function': function, | |
| 'parameters': parameters, | |
| 'metadata': metadata, | |
| 'tags': tags | |
| } | |
| } | |
| ]) | |
| def computeTime(prev, current): | |
| if [current['x'], current['y'], current['z']] == [prev['x'], prev['y'], prev['z']] and current['a'] != prev['a']: | |
| # retraction takes time as well, add it in | |
| # time = sqrt((e2-e1)^2)/feedrate | |
| distance = math.dist([current['a']], [prev['a']]) | |
| else: | |
| # get time traveled by the equasion | |
| # time = sqrt((x2-x1)^2 + (y2-y1)^2 + (z2-z1)^2)/feedrate | |
| distance = math.dist([current['x'], current['y'], current['z']], | |
| [prev['x'], prev['y'], prev['z']]) | |
| return distance/current['feedrate'] | |
| def createToolpath(filename, temp): | |
| corpus = open(filename).readlines() | |
| processed = [] | |
| progresslen = len(corpus) | |
| linenum = 0 | |
| printline = '{0:>' + str(len(str(progresslen))) + '}/{1} {2:>3.0f}%' | |
| axis = \ | |
| { | |
| 'a': 0.0, | |
| 'feedrate': 0.0, | |
| 'x': 0.0, | |
| 'y': 0.0, | |
| 'z': 0.0 | |
| } | |
| tempmetadata = \ | |
| { | |
| 'index': -1, | |
| 'temperature': 0 | |
| } | |
| fanstatus = \ | |
| { | |
| 'index': 0, | |
| 'value': False | |
| } | |
| fanduty = \ | |
| { | |
| 'index': 0, | |
| 'value': 0.0 | |
| } | |
| printersettings = \ | |
| { | |
| 'tool0temp': 0, | |
| 'tool1temp': 0, | |
| 'bedtemp': 0, | |
| 'heatbed': False, | |
| 'time': 0.0, | |
| 'toolpathfilelength': 0 | |
| } | |
| printeroffset = \ | |
| { | |
| 'a': 0.0, | |
| 'x': 0.0, | |
| 'y': 0.0, | |
| 'z': 0.0 | |
| } | |
| print('lines processed:') | |
| print(printline.format(0, progresslen, 0.0), end='') | |
| """ | |
| Quick reference: | |
| G0/G1 is move | |
| M104 is set_toolhead_temperature | |
| M140 sets bed temp | |
| M106 is fan_duty (sets fan) | |
| M107 is toggle_fan (off) | |
| M141 sets chamber temperature | |
| G90 toggles absolute positioning | |
| G91 toggles relative positioning | |
| """ | |
| for line in corpus: | |
| if line.find(';') > -1: | |
| line = line[:line.find(';')] | |
| line = [part for part in line.split(' ') if part != ''] | |
| if len(line) == 0: # Most likely a blank line | |
| print(''.join(['\b'] * len( | |
| printline.format(linenum, | |
| progresslen, | |
| linenum/progresslen * 100.0))), end='') | |
| linenum += 1 | |
| print(printline.format( | |
| linenum, progresslen, linenum/progresslen * 100.0), end='') | |
| continue | |
| if line[0] in ['G0', 'G1']: | |
| if len(line) == 2 and line[1][0] == 'F': | |
| axis['feedrate'] = float(line[1][1:]) / 60.0 | |
| else: # Normal move | |
| prev = copy.copy(axis) # copy previous pos for timing | |
| for ax in line[1:]: | |
| if ax[0] == 'E': | |
| axis['a'] = printeroffset['a'] + float(ax[1:]) | |
| elif ax[0] == 'X': | |
| axis['x'] = printeroffset['x'] + float(ax[1:]) | |
| elif ax[0] == 'Y': | |
| axis['y'] = printeroffset['y'] + float(ax[1:]) | |
| elif ax[0] == 'Z': | |
| axis['z'] = printeroffset['z'] + float(ax[1:]) | |
| elif ax[0] == 'F': | |
| axis['feedrate'] = float(ax[1:]) / 60.0 | |
| processed += generateCommand('move', | |
| {'a': False, | |
| 'x': False, | |
| 'y': False, | |
| 'z': False}, | |
| axis, | |
| []) | |
| printersettings['time'] += computeTime(prev, axis) | |
| elif line[0] == 'G92': | |
| for ax in line[1:]: | |
| if ax[0] == 'E': | |
| printeroffset['a'] = axis['a'] + float(ax[1:]) | |
| elif ax[0] == 'X': | |
| printeroffset['x'] = axis['x'] + float(ax[1:]) | |
| elif ax[0] == 'Y': | |
| printeroffset['y'] = axis['y'] + float(ax[1:]) | |
| elif ax[0] == 'Z': | |
| printeroffset['z'] = axis['z'] + float(ax[1:]) | |
| elif line[0] == 'M104': | |
| for ax in line[1:]: | |
| if ax[0] == 'T': | |
| tempmetadata['index'] = int(ax[1:]) | |
| elif ax[0] == 'S': | |
| tempmetadata['temperature'] = int(ax[1:]) | |
| if tempmetadata['index'] != -1: | |
| processed += generateCommand('set_toolhead_temperature', | |
| {}, | |
| tempmetadata, | |
| []) | |
| if printersettings['tool{}temp'.format(tempmetadata['index'])] == 0: | |
| printersettings['tool{}temp'.format(tempmetadata['index'])] = tempmetadata['temperature'] | |
| else: # there is only one extruder | |
| processed += generateCommand('set_toolhead_temperature', | |
| {}, | |
| {'temperature': tempmetadata['temperature']}, | |
| []) | |
| printersettings['tool0temp'] = tempmetadata['temperature'] | |
| elif line[0] == 'M106': | |
| for ax in line[1:]: | |
| if ax[0] == 'P': | |
| fanduty['index'] = int(ax[1:]) | |
| fanstatus['index'] = int(ax[1:]) | |
| elif ax[0] == 'S': | |
| fanduty['value'] = float(ax[1:]) / 255 | |
| if not fanstatus['value']: | |
| fanstatus['value'] = True | |
| processed += generateCommand('toggle_fan', | |
| {}, | |
| fanstatus, | |
| []) | |
| processed += generateCommand('fan_duty', | |
| {}, | |
| fanduty, | |
| []) | |
| elif line[0] == 'M107': | |
| fanstatus['value'] = False | |
| processed += generateCommand('toggle_fan', | |
| {}, | |
| fanstatus, | |
| []) | |
| elif line[0] == 'M140': | |
| printersettings['bedtemp'] = int(line[1][1:]) | |
| printersettings['heatbed'] = True | |
| print(''.join(['\b'] * len( | |
| printline.format(linenum, progresslen, linenum/progresslen * 100.0))), end='') | |
| linenum += 1 | |
| print(printline.format(linenum, progresslen, linenum/progresslen * 100.0), end='') | |
| print() # flush all the crap | |
| print('writing toolpath') | |
| compiledtoolpath = json.dumps(processed, sort_keys=False, indent=4) | |
| with open('{}/print.jsontoolpath'.format(temp), 'w') as toolpathfile: | |
| toolpathfile.write(compiledtoolpath) | |
| printersettings['toolpathfilelength'] = len(re.findall('\n',compiledtoolpath)) | |
| return printersettings | |
| def packageMBotFile(filename, temp): | |
| with zipfile.ZipFile(filename, 'w', compression=zipfile.ZIP_DEFLATED) as mbotfile: | |
| mbotfile.write('{}/meta.json'.format(temp), arcname='meta.json') | |
| mbotfile.write('{}/print.jsontoolpath'.format(temp), arcname='print.jsontoolpath') | |
| return | |
| def main(argv): | |
| try: | |
| for gcode in argv[1:]: | |
| temp = tempfile.mkdtemp() | |
| output = gcode.replace('.gcode', '.makerbot') | |
| print('Generating toolpath for', output) | |
| vardict = createToolpath(gcode, temp) | |
| print('Generating metadata for', output) | |
| generateMetajson(temp, vardict) | |
| print('Packaging', output) | |
| packageMBotFile(output, temp) | |
| print(output, 'done!') | |
| except Exception as e: | |
| print() | |
| print('An error occurred.') | |
| print('Please report this, as this may be a bug.') | |
| print('Go to https://github.com/sckunkle/mbotmake/issues and add a new issue.') | |
| print('Also, add the contents of {} to a zip file and add it to the issue, if there is any.'.format(temp)) | |
| traceback.print_exc() | |
| input() | |
| if __name__ == '__main__': | |
| if len(sys.argv) < 2: | |
| print('Instructions:') | |
| print('Drag and drop your generated gcode file onto this executable.') | |
| print('It will then output a makerbot file in the dir that the original gcode is placed in.') | |
| print('Press enter to continue.') | |
| input() | |
| sys.exit() | |
| main(sys.argv) |