From 548d16a7d5274c6632698fdc37a8cc6f73ead9b2 Mon Sep 17 00:00:00 2001 From: Marius Stanciu Date: Wed, 13 Nov 2019 01:29:50 +0200 Subject: [PATCH] - added two new postprocessor files for ISEL CNC and for BERTA CNC - clicking on a FCTable GUI element empty space will also clear the focus now --- FlatCAMCommon.py | 3 +- README.md | 6 +- flatcamGUI/GUIElements.py | 3 +- postprocessors/PP_Berta_CNC.py | 227 +++++++++++++++++++++++++++++++++ postprocessors/PP_ISEL_CNC.py | 159 +++++++++++++++++++++++ 5 files changed, 395 insertions(+), 3 deletions(-) create mode 100644 postprocessors/PP_Berta_CNC.py create mode 100644 postprocessors/PP_ISEL_CNC.py diff --git a/FlatCAMCommon.py b/FlatCAMCommon.py index 8113a67d..c343dee9 100644 --- a/FlatCAMCommon.py +++ b/FlatCAMCommon.py @@ -781,7 +781,8 @@ class ToolsDB(QtWidgets.QWidget): nr_crt = row + 1 id_item = QtWidgets.QTableWidgetItem('%d' % int(nr_crt)) # id_item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) - id_item.setFlags(id_item.flags() & ~QtCore.Qt.ItemIsEditable) + flags = id_item.flags() & ~QtCore.Qt.ItemIsEditable + id_item.setFlags(flags) widget.setItem(row, 0, id_item) # Tool name/id tool_name_item = QtWidgets.QTableWidgetItem(name) diff --git a/README.md b/README.md index 09d8b8a4..ede42df3 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,11 @@ CAD program, and create G-Code for Isolation routing. ================================================= +12.11.2019 + +- added two new postprocessor files for ISEL CNC and for BERTA CNC +- clicking on a FCTable GUI element empty space will also clear the focus now + 11.11.2019 - in Tools Database added a contextual menu to add/copy/delete tool; CTRL+C, DEL keys work too; key T for adding a tool is now only partially working @@ -26,7 +31,6 @@ CAD program, and create G-Code for Isolation routing. - added a new feature: Tools Database for Geometry objects; resolved issue #308 - added tooltips for the Tools Database table headers and buttons - 8.11.2019 - updated the make file for frozen executable diff --git a/flatcamGUI/GUIElements.py b/flatcamGUI/GUIElements.py index fba3420d..5a93b096 100644 --- a/flatcamGUI/GUIElements.py +++ b/flatcamGUI/GUIElements.py @@ -1776,8 +1776,9 @@ class FCTable(QtWidgets.QTableWidget): # if user is clicking an blank area inside the QTableWidget it will deselect currently selected rows def mousePressEvent(self, event): - if self.itemAt(event.pos()) is None: + if not self.itemAt(event.pos()): self.clearSelection() + self.clearFocus() else: QtWidgets.QTableWidget.mousePressEvent(self, event) diff --git a/postprocessors/PP_Berta_CNC.py b/postprocessors/PP_Berta_CNC.py new file mode 100644 index 00000000..0b77dca2 --- /dev/null +++ b/postprocessors/PP_Berta_CNC.py @@ -0,0 +1,227 @@ +############################################################## +# FlatCAM: 2D Post-processing for Manufacturing # +# http://flatcam.org # +# File Author: Matthieu Berthomé # +# Date: 5/26/2017 # +# # +# Correction & Adaptation for Berta CNC machine # +# Date: 24/10/2019 # +# # +# MIT Licence # +############################################################## + +from FlatCAMPostProc import * + + +class PP_Berta_CNC(FlatCAMPostProc): + coordinate_format = "%.*f" + feedrate_format = '%.*f' + + def start_code(self, p): + units = ' ' + str(p['units']).lower() + coords_xy = p['xy_toolchange'] + gcode = '' + + xmin = '%.*f' % (p.coords_decimals, p['options']['xmin']) + xmax = '%.*f' % (p.coords_decimals, p['options']['xmax']) + ymin = '%.*f' % (p.coords_decimals, p['options']['ymin']) + ymax = '%.*f' % (p.coords_decimals, p['options']['ymax']) + + if str(p['options']['type']) == 'Geometry': + gcode += '(TOOL DIAMETER: ' + str(p['options']['tool_dia']) + units + ')\n' + + gcode += '(Feedrate: ' + str(p['feedrate']) + units + '/min' + ')\n' + + if str(p['options']['type']) == 'Geometry': + gcode += '(Feedrate_Z: ' + str(p['z_feedrate']) + units + '/min' + ')\n' + + gcode += '(Feedrate rapids ' + str(p['feedrate_rapid']) + units + '/min' + ')\n' + '\n' + gcode += '(Z_Cut: ' + str(p['z_cut']) + units + ')\n' + + if str(p['options']['type']) == 'Geometry': + if p['multidepth'] is True: + gcode += '(DepthPerCut: ' + str(p['z_depthpercut']) + units + ' <=>' + \ + str(math.ceil(abs(p['z_cut']) / p['z_depthpercut'])) + ' passes' + ')\n' + + gcode += '(Z_Move: ' + str(p['z_move']) + units + ')\n' + gcode += '(Z Toolchange: ' + str(p['z_toolchange']) + units + ')\n' + + if coords_xy is not None: + gcode += '(X,Y Toolchange: ' + "%.4f, %.4f" % (coords_xy[0], coords_xy[1]) + units + ')\n' + else: + gcode += '(X,Y Toolchange: ' + "None" + units + ')\n' + + gcode += '(Z Start: ' + str(p['startz']) + units + ')\n' + gcode += '(Z End: ' + str(p['z_end']) + units + ')\n' + gcode += '(Steps per circle: ' + str(p['steps_per_circle']) + ')\n' + + if str(p['options']['type']) == 'Excellon' or str(p['options']['type']) == 'Excellon Geometry': + gcode += '(Postprocessor Excellon: ' + str(p['pp_excellon_name']) + ')\n' + '\n' + else: + gcode += '(Postprocessor Geometry: ' + str(p['pp_geometry_name']) + ')\n' + '\n' + + gcode += '(X range: ' + '{: >9s}'.format(xmin) + ' ... ' + '{: >9s}'.format(xmax) + ' ' + units + ')\n' + gcode += '(Y range: ' + '{: >9s}'.format(ymin) + ' ... ' + '{: >9s}'.format(ymax) + ' ' + units + ')\n\n' + + gcode += '(Spindle Speed: %s RPM)\n' % str(p['spindlespeed']) + + gcode += '(Berta)\n' + gcode += 'G90 G94 G17 G91.1' + gcode += ( + # This line allow you to sets the machine to METRIC / INCH in the GUI + 'G20\n' if p.units.upper() == 'IN' else 'G21\n') + # gcode += 'G21\n' # This line sets the machine to METRIC ONLY + # gcode += 'G20\n' # This line sets the machine to INCH ONLY + gcode += 'G64 P0.03\n' + gcode += 'M110\n' + gcode += 'G54\n' + gcode += 'G0\n' + gcode += '(Berta)\n' + + return gcode + + def startz_code(self, p): + if p.startz is not None: + return 'G00 Z' + self.coordinate_format % (p.coords_decimals, p.startz) + else: + return '' + + def lift_code(self, p): + return 'G00 Z' + self.coordinate_format % (p.coords_decimals, p.z_move) + + def down_code(self, p): + return 'G01 Z' + self.coordinate_format % (p.coords_decimals, p.z_cut) + + def toolchange_code(self, p): + z_toolchange = p.z_toolchange + toolchangexy = p.xy_toolchange + f_plunge = p.f_plunge + gcode = '' + + if toolchangexy is not None: + x_toolchange = toolchangexy[0] + y_toolchange = toolchangexy[1] + else: + x_toolchange = 0 + y_toolchange = 0 + + no_drills = 1 + + if int(p.tool) == 1 and p.startz is not None: + z_toolchange = p.startz + + if p.units.upper() == 'MM': + toolC_formatted = format(p.toolC, '.2f') + else: + toolC_formatted = format(p.toolC, '.4f') + + if str(p['options']['type']) == 'Excellon': + for i in p['options']['Tools_in_use']: + if i[0] == p.tool: + no_drills = i[2] + + if toolchangexy is not None: + gcode = """ +M5 +G00 Z{z_toolchange} +G00 X{x_toolchange} Y{y_toolchange} +T{tool} +M6 +(MSG, Change to Tool Dia = {toolC} ||| Total drills for tool T{tool} = {t_drills}) +M0 +""".format(x_toolchange=self.coordinate_format % (p.coords_decimals, x_toolchange), + y_toolchange=self.coordinate_format % (p.coords_decimals, y_toolchange), + z_toolchange=self.coordinate_format % (p.coords_decimals, z_toolchange), + tool=int(p.tool), + t_drills=no_drills, + toolC=toolC_formatted) + else: + gcode = """ +M5 +G00 Z{z_toolchange} +T{tool} +M6 +(MSG, Change to Tool Dia = {toolC} ||| Total drills for tool T{tool} = {t_drills}) +M0""".format(z_toolchange=self.coordinate_format % (p.coords_decimals, z_toolchange), + tool=int(p.tool), + t_drills=no_drills, + toolC=toolC_formatted) + + if f_plunge is True: + gcode += '\nG00 Z%.*f' % (p.coords_decimals, p.z_move) + return gcode + + else: + if toolchangexy is not None: + gcode = """ +M5 +G00 Z{z_toolchange} +G00 X{x_toolchange} Y{y_toolchange} +T{tool} +M6 +(MSG, Change to Tool Dia = {toolC}) +M0""".format(x_toolchange=self.coordinate_format % (p.coords_decimals, x_toolchange), + y_toolchange=self.coordinate_format % (p.coords_decimals, y_toolchange), + z_toolchange=self.coordinate_format % (p.coords_decimals, z_toolchange), + tool=int(p.tool), + toolC=toolC_formatted) + else: + gcode = """ +M5 +G00 Z{z_toolchange} +T{tool} +M6 +(MSG, Change to Tool Dia = {toolC}) +M0""".format(z_toolchange=self.coordinate_format % (p.coords_decimals, z_toolchange), + tool=int(p.tool), + toolC=toolC_formatted) + + if f_plunge is True: + gcode += '\nG00 Z%.*f' % (p.coords_decimals, p.z_move) + return gcode + + def up_to_zero_code(self, p): + return 'G01 Z0' + + def position_code(self, p): + return ('X' + self.coordinate_format + ' Y' + self.coordinate_format) % \ + (p.coords_decimals, p.x, p.coords_decimals, p.y) + + def rapid_code(self, p): + return ('G00 ' + self.position_code(p)).format(**p) + + def linear_code(self, p): + return ('G01 ' + self.position_code(p)).format(**p) + + def end_code(self, p): + coords_xy = p['xy_toolchange'] + gcode = ('G00 Z' + self.feedrate_format % (p.fr_decimals, p.z_end) + "\n") + + if coords_xy is not None: + gcode += 'G00 X{x} Y{y}'.format(x=coords_xy[0], y=coords_xy[1]) + "\n" + + gcode += '(Berta)\n' + gcode += 'M111\n' + gcode += 'M30\n' + gcode += '(Berta)\n' + return gcode + + def feedrate_code(self, p): + return 'G01 F' + str(self.feedrate_format % (p.fr_decimals, p.feedrate)) + + def z_feedrate_code(self, p): + return 'G01 F' + str(self.feedrate_format % (p.fr_decimals, p.z_feedrate)) + + def spindle_code(self, p): + sdir = {'CW': 'M03', 'CCW': 'M04'}[p.spindledir] + if p.spindlespeed: + return '%s S%s' % (sdir, str(p.spindlespeed)) + else: + return sdir + + def dwell_code(self, p): + if p.dwelltime: + return 'G4 P' + str(p.dwelltime) + + def spindle_stop_code(self, p): + return 'M05' diff --git a/postprocessors/PP_ISEL_CNC.py b/postprocessors/PP_ISEL_CNC.py new file mode 100644 index 00000000..d23693d7 --- /dev/null +++ b/postprocessors/PP_ISEL_CNC.py @@ -0,0 +1,159 @@ +# ########################################################## ## +# FlatCAM: 2D Post-processing for Manufacturing # +# http://flatcam.org # +# File Author: Matthieu Berthomé # +# Date: 5/26/2017 # +# MIT Licence # +# ########################################################## ## + +from FlatCAMPostProc import * + + +class default(FlatCAMPostProc): + + coordinate_format = "%.*f" + feedrate_format = '%.*f' + + def start_code(self, p): + units = ' ' + str(p['units']).lower() + coords_xy = p['xy_toolchange'] + gcode = '' + + xmin = '%.*f' % (p.coords_decimals, p['options']['xmin']) + xmax = '%.*f' % (p.coords_decimals, p['options']['xmax']) + ymin = '%.*f' % (p.coords_decimals, p['options']['ymin']) + ymax = '%.*f' % (p.coords_decimals, p['options']['ymax']) + + if str(p['options']['type']) == 'Geometry': + gcode += '(TOOL DIAMETER: ' + str(p['options']['tool_dia']) + units + ')\n' + + gcode += '(Feedrate: ' + str(p['feedrate']) + units + '/min' + ')\n' + + if str(p['options']['type']) == 'Geometry': + gcode += '(Feedrate_Z: ' + str(p['z_feedrate']) + units + '/min' + ')\n' + + gcode += '(Feedrate rapids ' + str(p['feedrate_rapid']) + units + '/min' + ')\n' + '\n' + gcode += '(Z_Cut: ' + str(p['z_cut']) + units + ')\n' + + if str(p['options']['type']) == 'Geometry': + if p['multidepth'] is True: + gcode += '(DepthPerCut: ' + str(p['z_depthpercut']) + units + ' <=>' + \ + str(math.ceil(abs(p['z_cut']) / p['z_depthpercut'])) + ' passes' + ')\n' + + gcode += '(Z_Move: ' + str(p['z_move']) + units + ')\n' + gcode += '(Z Toolchange: ' + str(p['z_toolchange']) + units + ')\n' + + if coords_xy is not None: + gcode += '(X,Y Toolchange: ' + "%.4f, %.4f" % (coords_xy[0], coords_xy[1]) + units + ')\n' + else: + gcode += '(X,Y Toolchange: ' + "None" + units + ')\n' + + gcode += '(Z Start: ' + str(p['startz']) + units + ')\n' + gcode += '(Z End: ' + str(p['z_end']) + units + ')\n' + gcode += '(Steps per circle: ' + str(p['steps_per_circle']) + ')\n' + + if str(p['options']['type']) == 'Excellon' or str(p['options']['type']) == 'Excellon Geometry': + gcode += '(Postprocessor Excellon: ' + str(p['pp_excellon_name']) + ')\n' + '\n' + else: + gcode += '(Postprocessor Geometry: ' + str(p['pp_geometry_name']) + ')\n' + '\n' + + gcode += '(X range: ' + '{: >9s}'.format(xmin) + ' ... ' + '{: >9s}'.format(xmax) + ' ' + units + ')\n' + gcode += '(Y range: ' + '{: >9s}'.format(ymin) + ' ... ' + '{: >9s}'.format(ymax) + ' ' + units + ')\n\n' + + gcode += '(Spindle Speed: %s RPM)\n' % str(p['spindlespeed']) + + gcode += 'G71\n' + gcode += 'G90\n' + gcode += 'G94\n' + + return gcode + + def startz_code(self, p): + if p.startz is not None: + return 'G00 Z' + self.coordinate_format%(p.coords_decimals, p.startz) + else: + return '' + + def lift_code(self, p): + return 'G00 Z' + self.coordinate_format%(p.coords_decimals, p.z_move) + + def down_code(self, p): + return 'G01 Z' + self.coordinate_format%(p.coords_decimals, p.z_cut) + + def toolchange_code(self, p): + f_plunge = p.f_plunge + no_drills = 1 + + if p.units.upper() == 'MM': + toolC_formatted = format(p.toolC, '.2f') + else: + toolC_formatted = format(p.toolC, '.4f') + + if str(p['options']['type']) == 'Excellon': + for i in p['options']['Tools_in_use']: + if i[0] == p.tool: + no_drills = i[2] + + gcode = """ +M05 +T{tool} +M06 +(MSG, Change to Tool Dia = {toolC} ||| Total drills for tool T{tool} = {t_drills}) +M01""".format(tool=int(p.tool), t_drills=no_drills, toolC=toolC_formatted) + + if f_plunge is True: + gcode += '\nG00 Z%.*f' % (p.coords_decimals, p.z_move) + return gcode + + else: + gcode = """ +M05 +T{tool} +M06 +(MSG, Change to Tool Dia = {toolC}) +M01""".format(tool=int(p.tool), toolC=toolC_formatted) + + if f_plunge is True: + gcode += '\nG00 Z%.*f' % (p.coords_decimals, p.z_move) + return gcode + + def up_to_zero_code(self, p): + return 'G01 Z0' + + def position_code(self, p): + return ('X' + self.coordinate_format + ' Y' + self.coordinate_format) % \ + (p.coords_decimals, p.x, p.coords_decimals, p.y) + + def rapid_code(self, p): + return ('G00 ' + self.position_code(p)).format(**p) + + def linear_code(self, p): + return ('G01 ' + self.position_code(p)).format(**p) + + def end_code(self, p): + coords_xy = p['xy_toolchange'] + gcode = ('G00 Z' + self.feedrate_format %(p.fr_decimals, p.z_end) + "\n") + + if coords_xy is not None: + gcode += 'G00 X{x} Y{y}'.format(x=coords_xy[0], y=coords_xy[1]) + "\n" + return gcode + + def feedrate_code(self, p): + return 'G01 F' + str(self.feedrate_format %(p.fr_decimals, p.feedrate)) + + def z_feedrate_code(self, p): + return 'G01 F' + str(self.feedrate_format %(p.fr_decimals, p.z_feedrate)) + + def spindle_code(self, p): + sdir = {'CW': 'M03', 'CCW': 'M04'}[p.spindledir] + if p.spindlespeed: + return '%s S%s' % (sdir, str(p.spindlespeed)) + else: + return sdir + + def dwell_code(self, p): + if p.dwelltime: + return 'G4 P' + str(p.dwelltime) + + def spindle_stop_code(self,p): + return 'M05'