diff --git a/portail_coulissant/porcou.py b/portail_coulissant/porcou.py index eccd1fa..69b4a03 100644 --- a/portail_coulissant/porcou.py +++ b/portail_coulissant/porcou.py @@ -28,26 +28,26 @@ scene = bge.logic.getCurrentScene() public_vars = { 't' : [['System','time'], [], []], - 'bp_ext' : [['Bp cote rue','activated'], ['pin', 'd','i'], ['o','-', 'green', 1]], - 'bp_ext_r' : [['Bp cote rue','activated_real'], [], ['o','--', 'green', 1]], - 'bp_int' : [['Bp cote cour','activated'], ['pin', 'd','i'], ['o','-', 'darkgreen', 1]], - 'bp_int_r' : [['Bp cote cour','activated_real'], [], ['o','--', 'darkgreen', 1]], - 'fdc_o' : [['Microrupteur fdc ouvert','activated'], ['pin', 'd','i'], ['o','-', 'orange', 1]], - 'fdc_o_r' : [['Microrupteur fdc ouvert','activated_real'], [], ['o','--', 'orange', 1]], - 'fdc_f' : [['Microrupteur fdc ferme','activated'], ['pin', 'd','i'], ['o','-', 'darkorange', 1]], - 'fdc_f_r' : [['Microrupteur fdc ferme','activated_real'], [], ['o','--', 'darkorange', 1]], - 'mot_o' : [['Moteur','open'], ['pin_open', 'd','o'], ['o','-', 'violet', 1]], - 'mot_f' : [['Moteur','close'], ['pin_close', 'd','o'], ['o','-', 'darkviolet', 1]], - 'mot_angle' : [['Moteur','alpha'], [], ['o','-', 'blue', 1]], - 'mot_vitesse' : [['Moteur','speed'], [], ['o','-', 'darkblue', 1]], + 'bp_ext' : [['Bp cote rue','activated'], ['pin', 'd','i'], ['.','-', 'green', 1]], + 'bp_ext_r' : [['Bp cote rue','activated_real'], [], ['.','--', 'green', 1]], + 'bp_int' : [['Bp cote cour','activated'], ['pin', 'd','i'], ['.','-', 'darkgreen', 1]], + 'bp_int_r' : [['Bp cote cour','activated_real'], [], ['.','--', 'darkgreen', 1]], + 'fdc_o' : [['Microrupteur fdc ouvert','activated'], ['pin', 'd','i'], ['.','-', 'orange', 1]], + 'fdc_o_r' : [['Microrupteur fdc ouvert','activated_real'], [], ['.','--', 'orange', 1]], + 'fdc_f' : [['Microrupteur fdc ferme','activated'], ['pin', 'd','i'], ['.','-', 'darkorange', 1]], + 'fdc_f_r' : [['Microrupteur fdc ferme','activated_real'], [], ['.','--', 'darkorange', 1]], + 'mot_o' : [['Moteur','open'], ['pin_open', 'd','o'], ['.','-', 'violet', 1]], + 'mot_f' : [['Moteur','close'], ['pin_close', 'd','o'], ['.','-', 'darkviolet', 1]], + 'mot_angle' : [['Moteur','alpha'], [], ['.','-', 'blue', 1]], + 'mot_vitesse' : [['Moteur','speed'], [], ['.','-', 'darkblue', 1]], 'mot_pas' : [['Moteur','step'], [], []], - 'portail_x' : [['Portail','x'], [], ['o','-', 'turquoise', 1]], - 'portail_vitesse' : [['Portail','speed'], [], ['o','-', 'darkturquoise', 1]], + 'portail_x' : [['Portail','x'], [], ['.','-', 'turquoise', 1]], + 'portail_vitesse' : [['Portail','speed'], [], ['.','-', 'darkturquoise', 1]], 'portail_pas' : [['Portail','step'], [], []], - 'gyr' : [['Led','activated'], ['pin', 'd','o'], ['o','-', 'gold', 1]], - 'ir_emet' : [['Emetteur IR', 'activated'], ['pin', 'd','o'],['o','-', 'red', 1]], - 'ir_recep' : [['Recepteur IR','activated'], ['pin', 'd','i'],['o','-', 'darkred', 1]], - 'ir_recep_r' : [['Recepteur IR','activated_real'], [],['o','--', 'darkred', 1]]} + 'gyr' : [['Led','activated'], ['pin', 'd','.'], ['.','-', 'gold', 1]], + 'ir_emet' : [['Emetteur IR', 'activated'], ['pin', 'd','o'],['.','-', 'red', 1]], + 'ir_recep' : [['Recepteur IR','activated'], ['pin', 'd','i'],['.','-', 'darkred', 1]], + 'ir_recep_r' : [['Recepteur IR','activated_real'], [],['.','--', 'darkred', 1]]} # Couleurs color_passive = (0.800, 0.005, 0.315,1) # bouton non activable : magenta diff --git a/portail_coulissant/porcou_cmd.py b/portail_coulissant/porcou_cmd.py index 89f8e03..f82f874 100644 --- a/portail_coulissant/porcou_cmd.py +++ b/portail_coulissant/porcou_cmd.py @@ -47,9 +47,11 @@ def commandes(): gyr(False) print ("") - daq(['mot_angle', 'mot_vitesse', 'portail_x', 'portail_vitesse']) + # daq(['mot_angle', 'mot_vitesse', 'portail_x', 'portail_vitesse']) + daq(['bp_ext', 'bp_ext_r', 'bp_int', 'bp_int_r', 'fdc_o', 'fdc_o_r', 'fdc_f', 'fdc_f_r', 'mot_o', 'mot_f', 'mot_angle', 'mot_vitesse', 'portail_x', 'portail_vitesse', 'gyr', 'ir_emet', 'ir_recep', 'ir_recep_r']) + # daq(['bp_ext', 'bp_ext_r', 'bp_int', 'bp_int_r', 'fdc_o', 'fdc_o_r', 'fdc_f', 'fdc_f_r', 'mot_o', 'mot_f', 'gyr']) reset_t() - + # Fermeture mot_digitset (1256) # Vitesse par défaut 125,6 rad /s ( 20 tr / s ) t0,x0, a0= get('t'), get('portail_x'), get('mot_angle') @@ -68,7 +70,7 @@ def commandes(): # " rad - portail_vitesse : " +str(round(portail_vitesse, 3))+" mm/s - moteur_vitesse : " +str(round(mot_vitesse, 3))+ # " rad/s - portail_pas : " +str(round(portail_pas, 3))+" mm/impulsion - moteur_pas : " +str(round(mot_pas, 3))+" rad/impulsion") # print ("") - + # Ouverture mot_digitset () # Vitesse par défaut 125,6 rad /s ( 20 tr / s ) mot_digitset (2000) # Vitesse par défaut 125,6 rad /s ( 20 tr / s ) @@ -88,15 +90,16 @@ def commandes(): # " rad - portail_vitesse : " +str(round(portail_vitesse, 3))+" mm/s - moteur_vitesse : " +str(round(mot_vitesse, 3))+ # " rad/s - portail_pas : " +str(round(portail_pas, 3))+" mm/impulsion - moteur_pas : " +str(round(mot_pas, 3))+" rad/impulsion") - plot() + plot(['bp_ext', 'bp_ext_r', 'bp_int', 'bp_int_r', 'fdc_o', 'fdc_o_r', 'fdc_f', 'fdc_f_r', 'mot_o', 'mot_f', 'gyr', ['mot_angle', 'mot_vitesse', 'portail_x', 'portail_vitesse']]) fin() # A garder - -############################################################################### -# En: External call << DONT CHANGE THIS SECTION >> -# Fr: Appel externe << NE PAS MODIFIER CETTE SECTION >> -############################################################################### - + + ############################################################################### + # En: External call << DONT CHANGE THIS SECTION >> + # Fr: Appel externe << NE PAS MODIFIER CETTE SECTION >> + ############################################################################### + if __name__=='start': thread_cmd_start(commandes) if __name__=='stop': stop() + diff --git a/portail_coulissant/portail_coulissant-17.blend b/portail_coulissant/portail_coulissant-17.blend index 94d7e0d..1bd6329 100644 Binary files a/portail_coulissant/portail_coulissant-17.blend and b/portail_coulissant/portail_coulissant-17.blend differ diff --git a/twin.py b/twin.py index 423a601..6cf10f5 100644 --- a/twin.py +++ b/twin.py @@ -33,8 +33,7 @@ system=importlib.import_module(scene.objects['System']['script'][:-4]) # Systèm sys.setrecursionlimit(10**5) # Limite sur la récursivité (valeur par défaut : 1000) -> segfault de Blender # Config file -twin_config = ET.parse('twin_config.xml') -twin_config_tree = twin_config.getroot() +twin_config = ET.parse('twin_config.xml').getroot() # Couleurs color_cmd = (0.8, 0.8, 0.8, 1) # Blanc @@ -73,10 +72,10 @@ def keyboard(cont): # Maj du fichier de config (screen size : data/config/screen/width-> [0][0].text) screen_width = bge.render.getWindowWidth() screen_height = bge.render.getWindowHeight() - twin_config_tree[0][0].text=str(screen_width) - twin_config_tree[0][1].text=str(screen_height) - twin_config_tree[0][2].text=str(scene.objects['About']['quality']) - buffer_xml = ET.tostring(twin_config_tree) + twin_config[0][0].text=str(screen_width) + twin_config[0][1].text=str(screen_height) + twin_config[0][2].text=str(scene.objects['About']['quality']) + buffer_xml = ET.tostring(twin_config) with open("twin_config.xml", "wb") as f: f.write(buffer_xml) @@ -128,9 +127,9 @@ def keyboard(cont): def cmd_init(): # Fichier de config (screen size : data/config/screen/width-> [0][0].text, height-> [0][1].text) - bge.render.setWindowSize(int(twin_config_tree[0][0].text),int(twin_config_tree[0][1].text)) + bge.render.setWindowSize(int(twin_config[0][0].text),int(twin_config[0][1].text)) quality_eevee=('NOSMAA', 'LOW', 'MEDIUM','HIGH','ULTRA') - scene.objects['About']['quality'] = int(twin_config_tree[0][2].text) + scene.objects['About']['quality'] = int(twin_config[0][2].text) if quality_eevee[scene.objects['About']['quality']] == 'NOSMAA': eevee.smaa_quality= 'LOW' eevee.use_eevee_smaa = False diff --git a/twin_about.py b/twin_about.py index 3ee5774..29345ce 100644 --- a/twin_about.py +++ b/twin_about.py @@ -217,7 +217,7 @@ def quality_up(cont): eevee.use_eevee_smaa = False else: eevee.use_eevee_smaa = True - print (sys.platform) + # print (sys.platform) if sys.platform=="linux": # Plantage sur Windows eevee.smaa_quality= quality_eevee[scene.objects['About']['quality']] diff --git a/twin_config.xml b/twin_config.xml index 888d7b7..bfb958d 100644 --- a/twin_config.xml +++ b/twin_config.xml @@ -1,7 +1,10 @@ - 1609 - 905 - 1 - + 792 + 445 + 4 + + + True + \ No newline at end of file diff --git a/twin_daq.py b/twin_daq.py index 4ab56e1..f306692 100644 --- a/twin_daq.py +++ b/twin_daq.py @@ -5,6 +5,7 @@ import importlib import subprocess # Multiprocessus import time import csv +import xml.etree.ElementTree as ET # Creating/parsing XML file ############################################################################### # twin_daq.py @@ -44,24 +45,30 @@ def get(data): # Enregistrement des données ############################################################################### +## # Activation du mode DAQ +## + def daq(data): daq_data.clear() scene.objects['System']['daq_var'] =[] - data_line = ['t'] + row = ['t'] for var in data: scene.objects['System']['daq_var'].append([daq_config[var][0][0], daq_config[var][0][1]]) - data_line.append(var) - print ("Acquisition des données :", scene.objects['System']['daq_var']) - daq_data.append(data_line) + row.append(var) + # print ("Acquisition des données :", scene.objects['System']['daq_var']) + daq_data.append(row) scene.objects['System']['daq']=True +## # Ajout des données (fps = 60) +## + def daq_add(cont): - data_line = [round(scene.objects['System']['time'], 3)] + row = [round(scene.objects['System']['time'], 3)] for var in scene.objects['System']['daq_var']: - data_line.append(round(scene.objects[var[0]][var[1]], 3)) - daq_data.append(data_line) + row.append(round(scene.objects[var[0]][var[1]], 3)) + daq_data.append(row) ############################################################################### # Tableau CSV @@ -74,11 +81,13 @@ def localize_floats(row): for el in row ] +## # Génération du fichier +## + def csv_generate(): scene.objects['System']['daq']=False fichier_csv=scene.objects['System']['system']+'.csv' - print ("Génération du fichier :", fichier_csv) scene.objects['Cmd-text']['modal']= True scene.objects['Cmd-text']['Text']= "Génération du fichier : "+fichier_csv scene.objects['Cmd-text'].setVisible(True,False) @@ -91,17 +100,70 @@ def csv_generate(): # Graphique statique ############################################################################### +## +# Création du fichier twin_plot.xml (configuration du graphique) +## + +def plot_config_generate(data_groups): + + # Création du XML + daq_config_list=list(daq_config) + xml_data = ET.Element('data') + xml_figure = ET.SubElement(xml_data, 'figure') + xml_plot = ET.SubElement(xml_figure, 'plot') + for var in daq_config_list: + xml_var = ET.SubElement(xml_plot, 'var') + xml_var.text=var + if len(daq_config[var][2]) >=4: + xml_mark = ET.SubElement(xml_var, 'marker') + xml_mark.text=daq_config[var][2][0] + xml_line = ET.SubElement(xml_var, 'linestyle') + xml_line.text=daq_config[var][2][1] + xml_color = ET.SubElement(xml_var, 'color') + xml_color.text=daq_config[var][2][2] + xml_size = ET.SubElement(xml_var, 'linewidth') + xml_size.text=str(daq_config[var][2][3]) + + # Détection de groupe de graphique + data_group_i=0 + xml_group = ET.SubElement(xml_var, 'group') + xml_group.text="-1" # Pas de groupe par défaut + for data_group in data_groups: + if isinstance(data_group, list): + data_group_i+=1 + for data_subgroup in data_group: # Scan du sous-groupe + if data_subgroup == var: + xml_group.text=str(data_group_i) + else: + if data_group == var: # Pas de groupe + xml_group.text="0" + + # Ecriture fichier + plot_config = ET.ElementTree(xml_data) + with open("plot_config.xml", "wb") as f: # XML généré plat (not pretty print) + plot_config.write(f) + +## # Activation du mode Plot -def plot(): +## + +def plot(data_groups): + plot_config_generate(data_groups) scene.objects['System']['plot']=True +## # Fermer le processus du graphique +## + def plot_close(): if scene.objects['System']['plot_proc'] is not None: if scene.objects['System']['plot_proc'].poll()==None: scene.objects['System']['plot_proc'].terminate() +## # Génération du graphique +## + def plot_generate(): plot_close() fichier_csv=scene.objects['System']['system']+'.csv' @@ -113,12 +175,18 @@ def plot_generate(): # FIXME : ne marche pas ############################################################################### +## # Mise en forme de décimaux +## + def truncate(n, decimals=0): multiplier = 10**decimals return int(n* multiplier)/multiplier +## # Création du graphique interactif +## + def plot_start(data): # subprocess.run([sys.executable, os.path.join(os.getcwd(), "twin_plot.py")], , stdin=subprocess.PIPE) # Process bloquant @@ -141,7 +209,10 @@ def plot_start(data): # # print("Blender stout : ", stout) scene.objects['System']['plot']=True +## # Ajout des données (fps = 60) +## + def plot_add(cont): if cont.sensors['Plot'].positive : diff --git a/twin_plot_qt.py b/twin_plot_qt.py index 46061f5..90b6a66 100644 --- a/twin_plot_qt.py +++ b/twin_plot_qt.py @@ -1,6 +1,10 @@ import sys import random +import importlib import matplotlib +import csv +import xml.etree.ElementTree as ET # Creating/parsing XML file + matplotlib.use('Qt5Agg') from PyQt5 import QtCore, QtGui, QtWidgets from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg, NavigationToolbar2QT as NavigationToolbar @@ -16,12 +20,22 @@ from matplotlib.figure import Figure # @license: GNU GPL ############################################################################### -# UPBGE scene -# scene = bge.logic.getCurrentScene() +# Lecture des configurations +twin_config = ET.parse('twin_config.xml').getroot() +plot_config_tree = ET.parse('plot_config.xml').getroot() +plot_config={} -# Récupérer le brochage du jumeau réel -# system=importlib.import_module(scene.objects['Doc']['system']) # Système -# pin_config = system.get_pin_config() +############################################################################### +# Configuration des plots +############################################################################### + +def plot_config_dict(): + for var in plot_config_tree[0][0]: + var_dict={} + for i in range (len(var)): + if var[i] is not None: + var_dict.update({var[i].tag : var[i].text}) + plot_config.update({var.text: var_dict}) ############################################################################### # Zone de dessin @@ -98,11 +112,6 @@ class DynamicPlot(QtWidgets.QMainWindow): # self.xdata = self.xdata + [float(msg_list[0])] # self.ydata = self.ydata + [float(msg_list[1])] - - - - - # # Lecture du Pipe # # i=0 # # lines = sys.stdin.readlines() @@ -130,12 +139,7 @@ class DynamicPlot(QtWidgets.QMainWindow): # if msg_list[0] != "": # self.xdata = self.xdata + [float(msg_list[0])] # self.ydata = self.ydata + [float(msg_list[1])] - - - - - - + # for line in msg_lines: # msg_list=line.split(',') @@ -144,7 +148,6 @@ class DynamicPlot(QtWidgets.QMainWindow): # self.xdata = self.xdata + [float(msg_list[0])] # self.ydata = self.ydata + [float(msg_list[1])] - # for line in sys.stdin: # msg_list=msg.split(',') # print(msg_list) @@ -152,7 +155,6 @@ class DynamicPlot(QtWidgets.QMainWindow): # self.xdata = self.xdata + [float(msg_list[0])] # self.ydata = self.ydata + [float(msg_list[1])] - # self.ydata = self.ydata + [random.randint(0, 10)] # Drop off the first y element, append a new one. # self.ydata = self.ydata[1:] + [random.randint(0, 10)] @@ -176,9 +178,10 @@ class MainWindow(QtWidgets.QMainWindow): super(MainWindow, self).__init__(*args, **kwargs) self.canvas = MplCanvas(self, width=5, height=4, dpi=100) toolbar = NavigationToolbar(self.canvas, self) - plt = self.canvas.subplot + # plt = self.canvas.subplot + # plt.cla() - # Implantation + # Implantation de la fenêtre layout = QtWidgets.QVBoxLayout() layout.addWidget(toolbar) layout.addWidget(self.canvas) @@ -186,15 +189,56 @@ class MainWindow(QtWidgets.QMainWindow): widget.setLayout(layout) self.setCentralWidget(widget) - # Lecture des données - print ("Qt : fichier de données :", sys.argv[1]) - n_data = 50 - self.xdata = list(range(n_data)) - self.ydata = [random.randint(0, 10) for i in range(n_data)] + # Lecture fichier CSV + fields = [] + rows = [] + with open(sys.argv[1], newline='') as csvfile: + csvreader = csv.reader(csvfile, delimiter=';') + fields = next(csvreader) + for row in csvreader: + rows.append(row) - # Plot - plt.cla() - plt.plot(self.xdata, self.ydata, 'b') + # Mise en tableau à deux colonnes (xdata,ydata) + xdata=[] + ydata=[] + i=0 + for field in fields: + xdata_row=[] + ydata_row=[] + for row in rows: + xdata_row.append(float(row[0].replace(',', '.'))) # Revenir au format US des décimaux + ydata_row.append(float(row[i].replace(',', '.'))) # Revenir au format US des décimaux + xdata.append(xdata_row) + ydata.append(ydata_row) + i+=1 + + # Plots + plot_config_dict() # Configuration des plots + # FIXME : multiplot à faire + # plts = [] + # plt_i=0 + # for i in range(len(fields)): + # if i != 0 or plot_config[fields[i]]['group']=="-1" : # i=0 -> Ne pas afficher car c'est temps (variable t) + # if plot_config[fields[i]]['group']=="0" : # Pas de groupe : nouveau plot + # plts.append(self.canvas.subplot) + + plt = self.canvas.subplot + plt.cla() + for i in range(len(fields)): + if i != 0 : # i=0 -> Ne pas afficher car c'est temps (variable t) + if twin_config[1][0].text == "True": # Configuration des plots activée + plt.plot(xdata[i], ydata[i], label=fields[i], color=plot_config[fields[i]]['color'], + linewidth=plot_config[fields[i]]['linewidth'], linestyle=plot_config[fields[i]]['linestyle'], marker=plot_config[fields[i]]['marker']) + else: + plt.plot(xdata[i], ydata[i], '.-', label=fields[i]) + + # Décoration + plt.set_xlabel("Temps (s)") + plt.set_ylabel("Valeurs") + plt.set_title(sys.argv[1]) + plt.axhline(linewidth=1, color='k') + plt.grid(True, linestyle='--') + plt.legend() # Redraw self.canvas.draw()