Skip to content

Commit 4fec358

Browse files
committed
Major version being implemented
- mainWindow widgets structure simplified, - i18n restructuring, - grblCom & grblComSerial optimization, - new Machine submenu for Origines definitions, - new G92 dialog box for G92 offset definition, - probe interface added in main window tabs (probe XY and probe Z), - Z probing working, XY probing in progress...
1 parent 084aca7 commit 4fec358

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+43994
-28603
lines changed

cn5X.py

+478-123
Large diffs are not rendered by default.

cn5X.qrc

+20-5
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,27 @@
11
<RCC>
22
<qresource prefix="cn5X">
3+
<file>images/origine.svg</file>
34
<file>images/btnEmergency.svg</file>
4-
<file>images/btnProbeMoinsX.svg</file>
5-
<file>images/btnProbeMoinsY.svg</file>
6-
<file>images/btnProbeMoinsZ.svg</file>
7-
<file>images/btnProbePlusX.svg</file>
8-
<file>images/btnProbePlusY.svg</file>
95
<file>images/btnEmergencyOff.svg</file>
6+
<file>images/btnProbeInCercle.svg</file>
7+
<file>images/btnProbeInX+.svg</file>
8+
<file>images/btnProbeInX-.svg</file>
9+
<file>images/btnProbeInX+Y+.svg</file>
10+
<file>images/btnProbeInX+Y-.svg</file>
11+
<file>images/btnProbeInX-Y+.svg</file>
12+
<file>images/btnProbeInX-Y-.svg</file>
13+
<file>images/btnProbeInY+.svg</file>
14+
<file>images/btnProbeInY-.svg</file>
15+
<file>images/btnProbeOutCercle.svg</file>
16+
<file>images/btnProbeOutX+.svg</file>
17+
<file>images/btnProbeOutX-.svg</file>
18+
<file>images/btnProbeOutX+Y+.svg</file>
19+
<file>images/btnProbeOutX+Y-.svg</file>
20+
<file>images/btnProbeOutX-Y+.svg</file>
21+
<file>images/btnProbeOutX-Y-.svg</file>
22+
<file>images/btnProbeOutY+.svg</file>
23+
<file>images/btnProbeOutY-.svg</file>
24+
<file>images/btnProbeZ-.svg</file>
1025
<file>images/btnJogMoinsC.svg</file>
1126
<file>images/btnJogPlusC.svg</file>
1227
<file>images/ledRougeAlumee.svg</file>

cn5Xapropos.py cn5X_apropos.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
from grblCom import grblCom
2929
from dlgAPropos import *
3030
from msgbox import *
31-
from compilOptions import grblCompilOptions
31+
###from compilOptions import grblCompilOptions
3232

3333
class cn5XAPropos(QObject):
3434
''' Classe assurant la gestion de la boite de dialogue A Propos '''
@@ -56,5 +56,5 @@ def showDialog(self):
5656
self.__dlgApropos.setWindowFlags(Qt.Dialog)
5757

5858
RC = self.__dlgApropos.exec()
59-
return(RC)
59+
return RC
6060

cn5X_config.py

+7-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626

2727
ORG_NAME = "fra589"
2828
APP_NAME = "cn5X++"
29-
APP_VERSION_STRING = "0.5.j"
29+
APP_VERSION_STRING = "0.8.a"
3030

3131
DEFAULT_NB_AXIS = 3 # Laisser 3 permet de gerer un Grbl original a 3 axes
3232
DEFAULT_AXIS_NAMES = ['X', 'Y', 'Z']
@@ -114,3 +114,9 @@ class logSeverity(Enum):
114114
COM_FLAG_NO_FLAG = 0
115115
COM_FLAG_NO_OK = 1
116116
COM_FLAG_NO_ERROR = 2
117+
118+
CN5X_TAB_GRBL = 0
119+
CN5X_TAB_FILE = 1
120+
CN5X_TAB_LOG = 2
121+
CN5X_TAB_DEBUG = 3
122+

cn5X_gcodeFile.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ def showConfirmChangeLost(self):
246246
defButton = msgButtonList.Save,
247247
escButton = msgButtonList.Cancel
248248
)
249-
return(m.afficheMsg())
249+
return (m.afficheMsg())
250250

251251

252252
def closeFile(self):

cn5X_probe.py

+284
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,284 @@
1+
# -*- coding: UTF-8 -*-
2+
3+
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
4+
' '
5+
' Copyright 2018-2021 Gauthier Brière (gauthier.briere "at" gmail.com) '
6+
' '
7+
' This file is part of cn5X++ '
8+
' '
9+
' cn5X++ is free software: you can redistribute it and/or modify it '
10+
' under the terms of the GNU General Public License as published by '
11+
' the Free Software Foundation, either version 3 of the License, or '
12+
' (at your option) any later version. '
13+
' '
14+
' cn5X++ is distributed in the hope that it will be useful, but '
15+
' WITHOUT ANY WARRANTY; without even the implied warranty of '
16+
' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the '
17+
' GNU General Public License for more details. '
18+
' '
19+
' You should have received a copy of the GNU General Public License '
20+
' along with this program. If not, see <http://www.gnu.org/licenses/>. '
21+
' '
22+
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
23+
24+
from PyQt5 import QtCore
25+
from PyQt5.QtCore import QCoreApplication, QObject, pyqtSignal, pyqtSlot
26+
from cn5X_config import *
27+
from grblCom import grblCom
28+
29+
30+
class grblProbe(QObject):
31+
''' Classe de gestion du palpage (probe) '''
32+
33+
# Communication inter objets :
34+
sig_log = pyqtSignal(int, str) # Message de fonctionnement du composant grblComSerial, renvoie : logSeverity, message string
35+
36+
def __init__(self, grbl: grblCom):
37+
super().__init__()
38+
self.__grblCom = grbl
39+
self.__axisNames = []
40+
self.__lastProbe = probeResult()
41+
42+
self.__ok_recu = False
43+
self.__error_recu = False
44+
self.__alarm_recu = False
45+
self.__probe_recu = False
46+
self.__probe_attendu = False
47+
48+
self.__grblCom.sig_ok.connect(self.on_sig_ok)
49+
self.__grblCom.sig_error.connect(self.on_sig_error)
50+
self.__grblCom.sig_alarm.connect(self.on_sig_alarm)
51+
self.__grblCom.sig_probe.connect(self.on_sig_probe)
52+
53+
54+
@pyqtSlot()
55+
def on_sig_ok(self):
56+
self.__ok_recu = True
57+
58+
59+
@pyqtSlot(int)
60+
def on_sig_error(self, errNum: int):
61+
self.__error_recu = True
62+
63+
64+
@pyqtSlot(int)
65+
def on_sig_alarm(self, alarmNum: int):
66+
self.__alarm_recu = True
67+
68+
69+
@pyqtSlot(str)
70+
def on_sig_probe(self, data: str):
71+
if self.__probe_attendu:
72+
tblData = data.split(":")
73+
tblValues = tblData[1].split(",")
74+
if tblData[2] == "1]":
75+
self.__lastProbe.setProbeOK(True)
76+
else:
77+
self.__lastProbe.setProbeOK(False)
78+
num = 0
79+
for v in tblValues:
80+
if num > 5:
81+
self.sig_log.emit(logSeverity.warning.value, self.tr("grblProbe.on_sig_probe(): Warning: Grbl probe response have more than 6 axis. Values of axis number > 6 are ommited!"))
82+
break
83+
self.__lastProbe.setAxis(num, v)
84+
num += 1
85+
self.__probe_attendu = False
86+
self.__probe_recu = True
87+
88+
89+
def setAxisNames(self, axisNames:list):
90+
self.__axisNames = axisNames
91+
self.__lastProbe.setAxisNames(axisNames)
92+
93+
94+
def g38(self, P:int=0,
95+
X:float=None, Y:float=None, Z:float=None,
96+
A:float=None, B:float=None, C:float=None,
97+
U:float=None, V:float=None, W:float=None,
98+
F=0,
99+
g2p:bool=False
100+
):
101+
'''
102+
Probe routine, P = mantisse du G38 => 2, 3, 4 ou 5 :
103+
- 2 => G38.2 = palpe vers la pièce, stoppe au toucher, signale une erreur en cas de défaut.
104+
- 3 => G38.3 = palpe vers la pièce, stoppe au toucher.
105+
- 4 => G38.4 = palpe en quittant la pièce, stoppe en perdant le contact, signal une erreur en cas de défaut.
106+
- 5 => G38.5 = palpe en quittant la pièce, stoppe en perdant le contact.
107+
- X, Y, Z, A, B, C, U, V & W : Destination vers laquelle on palpe à partir du point courant,
108+
- g2p = True => effectue un déplacement aux coordonnées palpées (le probe s'arrête légèrement après le
109+
contact en fonction de la décélération, donc, on retourne au point palpé).
110+
si g2p = False (par défaut), pas de déplacement après palpage.
111+
'''
112+
113+
# On lance un nouveau Probe on ne sait pas s'il sera OK...
114+
self.__lastProbe.setProbeOK(False)
115+
116+
# Vérification des arguments, les nom d'axes demandés dans les mouvements doivent exister dans Grbl
117+
if P<2 or P>5:
118+
self.sig_log.emit(logSeverity.error.value, self.tr("grblProbe.g38(): ArgumentError: 'P' must be 2, 3, 4 or 5 for respectively G38.2, G38.3, G38.4 or G38.5."))
119+
return
120+
if (X is not None) and ('X' not in self.__axisNames):
121+
self.sig_log.emit(logSeverity.error.value, self.tr("grblProbe.g38(): ArgumentError: 'X' is not in the axisNames list."))
122+
return
123+
if (Y is not None) and ('Y' not in self.__axisNames):
124+
self.sig_log.emit(logSeverity.error.value, self.tr("grblProbe.g38(): ArgumentError: 'Y' is not in the axisNames list."))
125+
return
126+
if (Z is not None) and ('Z' not in self.__axisNames):
127+
self.sig_log.emit(logSeverity.error.value, self.tr("grblProbe.g38(): ArgumentError: 'Z' is not in the axisNames list."))
128+
return
129+
if (A is not None) and ('A' not in self.__axisNames):
130+
self.sig_log.emit(logSeverity.error.value, self.tr("grblProbe.g38(): ArgumentError: 'A' is not in the axisNames list."))
131+
return
132+
if (B is not None) and ('B' not in self.__axisNames):
133+
self.sig_log.emit(logSeverity.error.value, self.tr("grblProbe.g38(): ArgumentError: 'B' is not in the axisNames list."))
134+
return
135+
if (C is not None) and ('C' not in self.__axisNames):
136+
self.sig_log.emit(logSeverity.error.value, self.tr("grblProbe.g38(): ArgumentError: 'C' is not in the axisNames list."))
137+
return
138+
if (U is not None) and ('U' not in self.__axisNames):
139+
self.sig_log.emit(logSeverity.error.value, self.tr("grblProbe.g38(): ArgumentError: 'U' is not in the axisNames list."))
140+
return
141+
if (V is not None) and ('V' not in self.__axisNames):
142+
self.sig_log.emit(logSeverity.error.value, self.tr("grblProbe.g38(): ArgumentError: 'V' is not in the axisNames list."))
143+
return
144+
if (W is not None) and ('W' not in self.__axisNames):
145+
self.sig_log.emit(logSeverity.error.value, self.tr("grblProbe.g38(): ArgumentError: 'W' is not in the axisNames list."))
146+
return
147+
if F <= 0:
148+
self.sig_log.emit(logSeverity.error.value, self.tr("grblProbe.g38(): ArgumentError: Probe speed: F undefinied or null."))
149+
return
150+
# Vérification que Grl est bien connecté et initialisé
151+
if (not self.__grblCom.isOpen) or (not self.__grblCom.grblInitStatus):
152+
self.sig_log.emit(logSeverity.error.value, self.tr("grblProbe.g38(): Error: Grbl is not connected or not initialized."))
153+
return
154+
# Récupération et vérification du décodeur
155+
self.__decode = self.__grblCom.getDecoder()
156+
if self.__decode is None:
157+
self.sig_log.emit(logSeverity.error.value, self.tr("grblProbe.g38(): cn5X++ error: no active Grbl decoder, this should never happen!?!?"))
158+
return
159+
160+
# Construction de l'ordre probe
161+
probeGCode = "G38.{}F{}".format(P, F)
162+
if X is not None:
163+
probeGCode += "X{}".format(X)
164+
if Y is not None:
165+
probeGCode += "Y{}".format(Y)
166+
if Z is not None:
167+
probeGCode += "Z{}".format(Z)
168+
if A is not None:
169+
probeGCode += "A{}".format(A)
170+
if B is not None:
171+
probeGCode += "B{}".format(B)
172+
if C is not None:
173+
probeGCode += "C{}".format(C)
174+
if U is not None:
175+
probeGCode += "U{}".format(U)
176+
if V is not None:
177+
probeGCode += "V{}".format(V)
178+
if W is not None:
179+
probeGCode += "W{}".format(W)
180+
181+
# On se prépare à attendre la réponse...
182+
self.__probe_attendu = True
183+
self.__ok_recu = False
184+
self.__error_recu = False
185+
self.__alarm_recu = False
186+
self.__probe_recu = False
187+
self.__lastProbe.setProbeOK(False)
188+
189+
# On prévient le communicator qu'on attend le résultat
190+
self.__grblCom.getDecoder().getNextProbe()
191+
192+
# Envoi du GCode à Grbl
193+
self.__grblCom.gcodePush(probeGCode)
194+
195+
# Attente du résultat
196+
while not self.__probe_recu:
197+
# Process events to receive signals;
198+
QCoreApplication.processEvents()
199+
if (self.__ok_recu or self.__error_recu or self.__alarm_recu) and (not self.__probe_recu):
200+
self.sig_log.emit(logSeverity.error.value, self.tr("grblProbe.g38(): Probe error: No probe response before OK, error or Alarm!"))
201+
return
202+
203+
self.sig_log.emit(logSeverity.info.value, self.tr("grblProbe.g38(): Response probe received."))
204+
205+
if not self.__lastProbe.isProbeOK():
206+
self.sig_log.emit(logSeverity.error.value, self.tr("grblProbe.g38(): Error: Last probe failure"))
207+
208+
else: # Probe OK.
209+
# Déplacement éventuel après probe OK pour revenir au point exact.
210+
# Le probe renvoie les coordonnées machine du point, d'ou l'utilisation de G53
211+
if g2p:
212+
retractGCode = "G53G1F{}".format(F)
213+
if X is not None: # On ne se déplace que sur les axes utilisés par le palpage
214+
retractGCode += "X{}".format(self.__lastProbe.getAxisByName("X"))
215+
if Y is not None:
216+
retractGCode += "Y{}".format(self.__lastProbe.getAxisByName("Y"))
217+
if Z is not None:
218+
retractGCode += "Z{}".format(self.__lastProbe.getAxisByName("Z"))
219+
if A is not None:
220+
retractGCode += "A{}".format(self.__lastProbe.getAxisByName("A"))
221+
if B is not None:
222+
retractGCode += "B{}".format(self.__lastProbe.getAxisByName("B"))
223+
if C is not None:
224+
retractGCode += "C{}".format(self.__lastProbe.getAxisByName("C"))
225+
if U is not None:
226+
retractGCode += "U{}".format(self.__lastProbe.getAxisByName("U"))
227+
if V is not None:
228+
retractGCode += "V{}".format(self.__lastProbe.getAxisByName("V"))
229+
if W is not None:
230+
retractGCode += "W{}".format(self.__lastProbe.getAxisByName("W"))
231+
232+
# Envoi du GCode à Grbl
233+
self.__grblCom.gcodePush(retractGCode)
234+
235+
return self.__lastProbe
236+
237+
238+
class probeResult(QObject):
239+
''' Objet de stockage d'un résultat de probe. Stocke les 6 valeurs d'axes ainsi que le statut du probe '''
240+
241+
def __init__(self):
242+
super().__init__()
243+
self.__axis = [None,None,None,None,None,None]
244+
'''self.__axis[0] = None
245+
self.__axis[1] = None
246+
self.__axis[2] = None
247+
self.__axis[3] = None
248+
self.__axis[4] = None
249+
self.__axis[5] = None'''
250+
self.__probeOK = False
251+
self.__axisNames = ""
252+
253+
254+
def setAxisNames(self, names: list):
255+
self.__axisNames = names
256+
257+
258+
def setAxis(self, num: int, value: float):
259+
'''Stocke une valeur d'axe'''
260+
if num < 0 or num > 5:
261+
raise ValueError("steAxisValue(): axisNum must be between 0 and 5")
262+
self.__axis[num] = value
263+
264+
265+
def getAxis(self, num: int):
266+
'''Stocke une valeur d'axe'''
267+
if num < 0 or num > 5:
268+
raise ValueError("steAxisValue(): axisNum must be between 0 and 5")
269+
return self.__axis[num]
270+
271+
272+
def getAxisByName(self, name: str):
273+
if name in self.__axisNames:
274+
return self.__axis[self.__axisNames.index(name)]
275+
276+
277+
def setProbeOK(self, value: bool):
278+
self.__probeOK = value
279+
280+
281+
def isProbeOK(self):
282+
return self.__probeOK
283+
284+

0 commit comments

Comments
 (0)