diff --git a/monte_charge/montchg_cmd.py b/monte_charge/montchg_cmd.py index 454ba81..efab4fe 100644 --- a/monte_charge/montchg_cmd.py +++ b/monte_charge/montchg_cmd.py @@ -48,6 +48,8 @@ def commandes(): voy_0(False) print ("") + daq(['mot_angle', 'mot_vitesse', 'cabine_z', 'cabine_vitesse']) + # Monter mot_digitset (500) t0,z0, a0= get('t'), get('cabine_z'), get('mot_angle') diff --git a/monte_charge/montchg_doc.py b/monte_charge/montchg_doc.py index aabc72c..8bef976 100644 --- a/monte_charge/montchg_doc.py +++ b/monte_charge/montchg_doc.py @@ -12,7 +12,7 @@ # Documentation du système ################################################################################ -system_card=["twins-card", "pin-card", "data-card", "plot-card", "movement-card", "board-card", "model-card", "firmata-card", "arduino-card"] +system_card=["twins-card", "pin-card", "data-card", "daq-card", "movement-card", "board-card", "model-card", "firmata-card", "arduino-card"] system_card_description ={} # Jumeau numérique @@ -45,20 +45,22 @@ card_data_title="Accès aux données" card_data_text=""" get(variable) \n -> Retourne la valeur de la variable à \n l'instant t. Par exemple : val = get('ba_0').\n Entrées/sorties : 'ba_0', 'ba_1', 'pc_0', 'pc_1', \n 'mot_m', 'mot_d', 'voy_0' et 'voy_1'.\n Variables réels (si il y a jumelage) : 'ba_0_r', \n 'ba_1_r', 'pc_0_r', 'pc_1_r'.\n - Autres variables : 't' (temps), 'mot_angle', 'mot_vitesse', \n 'cabine_z'.""" + Autres variables : 't' (temps), 'mot_angle', \n 'mot_vitesse', 'cabine_z'.""" card_data_url=[] system_card_description.update({"data-card" : [card_data_title, card_data_text, card_data_url]}) # Monitoring -card_plot_title="Acquisition de données" -card_plot_text=""" plot([variables]) \n -> Affiche le chronogramme des variables \n spécifiées. - Par exemple : plot(['ba_0', 'cabine_z']).\n - csv([variables]) \n -> Déclenche l'acquisition de données afin \n de génèrer un fichier de données CSV à \n l'arrêt du cycle.\n +card_daq_title="Acquisition de données" +# card_daq_text="aaa"+"\u2192"+"ddd" +card_daq_text=""" daq([variables]) \n -> Déclenche l'acquisition de données afin \n de génèrer un fichier de données CSV à \n l'arrêt du cycle. + Par exemple : daq(['ba_0', 'cabine_z']).\n + plot() \n Affiche le chronogramme à l'arrêt du + cycle. Le chronogramme interactif est en \n cours d'implémentation.\n Les variables pouvant être suivies sont les \n mêmes que celles de la page "Données".""" # Blender étant cadencé à 60 fps, la fréquence \n d'acquisition est 16 ms.""" -card_plot_url=[["Bibliothèque Matplotlib","https://matplotlib.org/"], - ["Wikipedia Français : fichier CSV","https://fr.wikipedia.org/wiki/Comma-separated_values"]] -system_card_description.update({"plot-card" : [card_plot_title, card_plot_text, card_plot_url]}) +card_daq_url=[["Wikipedia Français : fichier CSV","https://fr.wikipedia.org/wiki/Comma-separated_values"], + ["Bibliothèque Matplotlib","https://matplotlib.org/"]] +system_card_description.update({"daq-card" : [card_daq_title, card_daq_text, card_daq_url]}) # Ouvrir et fermer card_movement_title="Monter et descendre" diff --git a/monte_charge/montchg_lib.py b/monte_charge/montchg_lib.py index 284df14..a97c0f7 100644 --- a/monte_charge/montchg_lib.py +++ b/monte_charge/montchg_lib.py @@ -1,7 +1,7 @@ import bge # Bibliothèque Blender Game Engine (UPBGE) from twin_threading import thread_cmd_start, thread_cmd_stop, thread_cmd_end # Multithreading from twin_serial import jumeau, jumeau_stop, serial_close # Liaison série -from twin_plot import plot, get # Visualisation des données +from twin_daq import get, daq, csv_generate, plot, plot_generate # Acquisition des données import time ############################################################################### @@ -94,14 +94,16 @@ def ba_1 (): # Cycle ############################################################################### +## # Temporisation +## + def tempo (duree): time.sleep(duree) +## # t (temps) -def truncate(n, decimals=0): - multiplier = 10**decimals - return int(n* multiplier)/multiplier +## def get_t (): # return truncate(scene.objects['System']['time'], 3) @@ -113,20 +115,46 @@ def set_t (date): def reset_t (): scene.objects['System']['time']=0 +## # Arrêt +## + def stop(): + + # Jumeau if scene.objects['System']['twins']: serial_close(scene.objects['System']['board']) time.sleep(1) - scene.objects['System']['plot_draw']=False + + # Suivi de données + if scene.objects['System']['daq']: + csv_generate() + if scene.objects['System']['plot']: + plot_generate() + scene.objects['System']['plot_draw']=False # Plot + + # Thread thread_cmd_stop() +## # Fin naturelle +## + def end(): + + # Jumeau if scene.objects['System']['twins']: serial_close(scene.objects['System']['board']) time.sleep(1) - scene.objects['System']['plot_draw']=False + + # Suivi de données + if scene.objects['System']['daq']: + csv_generate() + if scene.objects['System']['plot']: + plot_generate() + scene.objects['System']['plot_draw']=False # Plot + + # Thread thread_cmd_end() def fin(): @@ -134,4 +162,3 @@ def fin(): def quit(): end() - diff --git a/monte_charge/monte_charge-4.blend b/monte_charge/monte_charge-4.blend index 4d306ce..d02edee 100644 Binary files a/monte_charge/monte_charge-4.blend and b/monte_charge/monte_charge-4.blend differ diff --git a/monte_charge/twin_daq.py b/monte_charge/twin_daq.py new file mode 120000 index 0000000..beebba5 --- /dev/null +++ b/monte_charge/twin_daq.py @@ -0,0 +1 @@ +/home/phroy/Bureau/seriousgames/blender-edutech/git/digital_twin/twin_daq.py \ No newline at end of file diff --git a/poppy_ergo_jr/twin_daq.py b/poppy_ergo_jr/twin_daq.py new file mode 120000 index 0000000..beebba5 --- /dev/null +++ b/poppy_ergo_jr/twin_daq.py @@ -0,0 +1 @@ +/home/phroy/Bureau/seriousgames/blender-edutech/git/digital_twin/twin_daq.py \ No newline at end of file diff --git a/portail_coulissant/porcou_cmd.py b/portail_coulissant/porcou_cmd.py index 6093525..4ba4925 100644 --- a/portail_coulissant/porcou_cmd.py +++ b/portail_coulissant/porcou_cmd.py @@ -47,6 +47,8 @@ def commandes(): gyr(False) print ("") + daq(['mot_angle', 'mot_vitesse', 'portail_x', 'portail_vitesse']) + # 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') diff --git a/portail_coulissant/porcou_doc.py b/portail_coulissant/porcou_doc.py index 1b0f9ee..dfed331 100644 --- a/portail_coulissant/porcou_doc.py +++ b/portail_coulissant/porcou_doc.py @@ -14,7 +14,7 @@ # Documentation du système ################################################################################ -system_card=["twins-card", "pin-card", "data-card", "plot-card", "movement-card", "sensor-card", "gyro-card", "board-card", "model-card", "firmata-card", "arduino-card"] +system_card=["twins-card", "pin-card", "data-card", "daq-card", "movement-card", "sensor-card", "gyro-card", "board-card", "model-card", "firmata-card", "arduino-card"] system_card_description ={} # Jumeau numérique @@ -52,15 +52,17 @@ card_data_url=[] system_card_description.update({"data-card" : [card_data_title, card_data_text, card_data_url]}) # Monitoring -card_plot_title="Acquisition de données" -card_plot_text=""" plot([variables]) \n -> Affiche le chronogramme des variables \n spécifiées. - Par exemple : plot(['bp_ext', 'portail_x']).\n - csv([variables]) \n -> Déclenche l'acquisition de données afin \n de génèrer un fichier de données CSV à \n l'arrêt du cycle.\n +card_daq_title="Acquisition de données" +# card_daq_text="aaa"+"\u2192"+"ddd" +card_daq_text=""" daq([variables]) \n -> Déclenche l'acquisition de données afin \n de génèrer un fichier de données CSV à \n l'arrêt du cycle. + Par exemple : daq(['bp_ext', 'portail_x']).\n + plot() \n Affiche le chronogramme à l'arrêt du + cycle. Le chronogramme interactif est en \n cours d'implémentation.\n Les variables pouvant être suivies sont les \n mêmes que celles de la page "Données".""" # Blender étant cadencé à 60 fps, la fréquence \n d'acquisition est 16 ms.""" -card_plot_url=[["Bibliothèque Matplotlib","https://matplotlib.org/"], - ["Wikipedia Français : fichier CSV","https://fr.wikipedia.org/wiki/Comma-separated_values"]] -system_card_description.update({"plot-card" : [card_plot_title, card_plot_text, card_plot_url]}) +card_daq_url=[["Wikipedia Français : fichier CSV","https://fr.wikipedia.org/wiki/Comma-separated_values"], + ["Bibliothèque Matplotlib","https://matplotlib.org/"]] +system_card_description.update({"daq-card" : [card_daq_title, card_daq_text, card_daq_url]}) # Ouvrir et fermer card_movement_title="Ouvrir et fermer" diff --git a/portail_coulissant/porcou_lib.py b/portail_coulissant/porcou_lib.py index 1287bfd..5076edf 100644 --- a/portail_coulissant/porcou_lib.py +++ b/portail_coulissant/porcou_lib.py @@ -1,7 +1,7 @@ import bge # Bibliothèque Blender Game Engine (UPBGE) from twin_threading import thread_cmd_start, thread_cmd_stop, thread_cmd_end # Multithreading (multitâches) from twin_serial import jumeau, jumeau_stop, serial_close # Liaison série -from twin_plot import plot, get # Visualisation des données +from twin_daq import get, daq, csv_generate, plot, plot_generate # Acquisition des données import time ############################################################################### @@ -102,14 +102,16 @@ def bp_int (): # Cycle ############################################################################### +## # Temporisation +## + def tempo (duree): time.sleep(duree) +## # t (temps) -def truncate(n, decimals=0): - multiplier = 10**decimals - return int(n* multiplier)/multiplier +## def get_t (): # return truncate(scene.objects['System']['time'], 3) @@ -121,20 +123,46 @@ def set_t (date): def reset_t (): scene.objects['System']['time']=0 +## # Arrêt +## + def stop(): + + # Jumeau if scene.objects['System']['twins']: serial_close(scene.objects['System']['board']) time.sleep(1) - scene.objects['System']['plot_draw']=False + + # Suivi de données + if scene.objects['System']['daq']: + csv_generate() + if scene.objects['System']['plot']: + plot_generate() + scene.objects['System']['plot_draw']=False # Plot + + # Thread thread_cmd_stop() +## # Fin naturelle +## + def end(): + + # Jumeau if scene.objects['System']['twins']: serial_close(scene.objects['System']['board']) time.sleep(1) - scene.objects['System']['plot_draw']=False + + # Suivi de données + if scene.objects['System']['daq']: + csv_generate() + if scene.objects['System']['plot']: + plot_generate() + scene.objects['System']['plot_draw']=False # Plot + + # Thread thread_cmd_end() def fin(): @@ -142,4 +170,3 @@ def fin(): def quit(): end() - diff --git a/portail_coulissant/portail_coulissant-17.blend b/portail_coulissant/portail_coulissant-17.blend index 68ba7e4..9e58e6c 100644 Binary files a/portail_coulissant/portail_coulissant-17.blend and b/portail_coulissant/portail_coulissant-17.blend differ diff --git a/portail_coulissant/twin_daq.py b/portail_coulissant/twin_daq.py new file mode 120000 index 0000000..beebba5 --- /dev/null +++ b/portail_coulissant/twin_daq.py @@ -0,0 +1 @@ +/home/phroy/Bureau/seriousgames/blender-edutech/git/digital_twin/twin_daq.py \ No newline at end of file diff --git a/twin_config.xml b/twin_config.xml index 67ee8a6..888d7b7 100644 --- a/twin_config.xml +++ b/twin_config.xml @@ -1,7 +1,7 @@ - 1590 - 895 + 1609 + 905 1 \ No newline at end of file diff --git a/twin_daq.py b/twin_daq.py new file mode 100644 index 0000000..e47a2d7 --- /dev/null +++ b/twin_daq.py @@ -0,0 +1,170 @@ +import bge # Bibliothèque Blender Game Engine (UPBGE) +import os +import sys +import importlib +import subprocess # Multiprocessus +import time +import csv + +############################################################################### +# twin_daq.py +# @title: Enregistement et visualisation des données +# @project: Blender-EduTech +# @lang: fr +# @authors: Philippe Roy +# @copyright: Copyright (C) 2023 Philippe Roy +# @license: GNU GPL +############################################################################### + +# UPBGE scene +scene = bge.logic.getCurrentScene() + +# Récupérer la configuration du graphique +system=importlib.import_module(scene.objects['System']['system']) # Système +daq_config = system.get_public_vars() + +# CSV +daq_data=[] + +############################################################################### +# Accès aux variables publiques du système +############################################################################### + +def get(data): + if data in daq_config: + if len (daq_config[data][0])>2: # Echelle à prendre en compte + return(scene.objects[daq_config[data][0][0]][daq_config[data][0][1]]*daq_config[data][0][2]) + else: + return(scene.objects[daq_config[data][0][0]][daq_config[data][0][1]]) + else: + print ("Erreur sur l'accès aux variables par get("+data+"), la variable '"+data+"' absente du système.") + return None + +############################################################################### +# Enregistrement des données +############################################################################### + +# Démarage et configuration des variables +def daq(data): + scene.objects['System']['daq_var'] =[] + data_line = ['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) + scene.objects['System']['daq']=True + +# Ajout des données (fps = 60) +def daq_add(cont): + data_line = [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) + +############################################################################### +# Tableau CSV +############################################################################### + +# Format français des décimaux +def localize_floats(row): + return [ + str(el).replace('.', ',') if isinstance(el, float) else el + 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']['Text']= "Génération du fichier :", fichier_csv + with open(fichier_csv, 'w') as csvfile: + writer = csv.writer(csvfile, delimiter = ';', lineterminator = '\n') + for t_data in daq_data: + writer.writerow(localize_floats(t_data)) + +############################################################################### +# Graphique statique +############################################################################### + +# Génération du fichier +def plot_generate(): + pass + +############################################################################### +# Graphique interactif +# 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(data): + # subprocess.run([sys.executable, os.path.join(os.getcwd(), "twin_plot.py")], , stdin=subprocess.PIPE) # Process bloquant + + # Terminer le processus précédent + if scene.objects['System']['plot_proc'] is not None: + if scene.objects['System']['plot_proc'].poll()==None: + scene.objects['System']['plot_proc'].terminate() + scene.objects['System']['plot_draw'] = True + scene.objects['System']['plot_time'] = 0 + + # Configuration des données + scene.objects['System']['plot_data'] =[] + for obj in data: + scene.objects['System']['plot_data'].append(daq_config[obj][0][0]) + + # Démarrer le processus + scene.objects['System']['plot_proc'] = subprocess.Popen([sys.executable, os.path.join(os.getcwd(), "twin_plot_qt.py")], stdin=subprocess.PIPE, encoding = 'utf8', universal_newlines=True) + # # scene.objects['System']['plot_proc'] = subprocess.Popen([sys.executable, os.path.join(os.getcwd(), "twin_plot_qt.py")], stdin=subprocess.PIPE, stdout=subprocess.PIPE, encoding = 'utf8') + # # stout = scene.objects['System']['plot_proc'].communicate() # FIXME : attente du message retour pour lancer l'acquisition + # # print("Blender stout : ", stout) + scene.objects['System']['plot']=True + +# Ajout des données (fps = 60) +def plot_add(cont): + if cont.sensors['Plot'].positive : + + # Affichage du graphique + if scene.objects['System']['plot_draw']: + if scene.objects['System']['plot_time'] != truncate(scene.objects['System']['time'], 0) or True: + + # Préparation du message + # FIXME : ajouter les valeurs réelles et valeurs numériques ('activated_real') + scene.objects['System']['plot_time'] = truncate(scene.objects['System']['time'], 0) + # msg=str(round(scene.objects['System']['plot_time'], 1)) + # msg=format(scene.objects['System']['plot_time'],".2f") + msg=format(scene.objects['System']['plot_time'],".2f") + for obj in scene.objects['System']['plot_data']: + if scene.objects[obj]['activated']: + msg = msg+",1" + else: + msg = msg+",0" + msg = msg+"\n" + + # Envoi (Pipe) + if scene.objects['System']['plot_proc'].poll()==None: + # # scene.objects['System']['plot_proc'].communicate(input=time_send.encode())[0] # Communication bloquante + # scene.objects['System']['plot_proc'].communicate(input=msg.encode())[0] # Communication bloquante + scene.objects['System']['plot_proc'].communicate(input=msg.encode()) # Communication bloquante + # scene.objects['System']['plot_proc'].stdin.write(msg) + print ("twin : ", msg) + else: + # Arrêt + print ("Stop") + scene.objects['System']['plot']=False + scene.objects['System']['plot_draw'] =False + scene.objects['System']['plot_proc'].terminate() + + # Arrêt de l'affichage du graphique + if scene.objects['System']['plot_proc'].poll()==None: + pass + else: + print ("Stop") + scene.objects['System']['plot']=False + scene.objects['System']['plot_draw'] =False + scene.objects['System']['plot_proc'].terminate() diff --git a/volet_roulant/twin_daq.py b/volet_roulant/twin_daq.py new file mode 120000 index 0000000..beebba5 --- /dev/null +++ b/volet_roulant/twin_daq.py @@ -0,0 +1 @@ +/home/phroy/Bureau/seriousgames/blender-edutech/git/digital_twin/twin_daq.py \ No newline at end of file diff --git a/volet_roulant/volet_roulant-17.blend b/volet_roulant/volet_roulant-17.blend index 27b2554..1cfb229 100644 Binary files a/volet_roulant/volet_roulant-17.blend and b/volet_roulant/volet_roulant-17.blend differ diff --git a/volet_roulant/volrou_cmd.py b/volet_roulant/volrou_cmd.py index cef9f13..35979b9 100644 --- a/volet_roulant/volrou_cmd.py +++ b/volet_roulant/volrou_cmd.py @@ -41,7 +41,7 @@ from volrou_lib import * # Bibliothèque utilisateur du volet roulant def commandes(): - csv_start(['mot_angle']) + daq(['mot_angle']) # Init -> Descendre while fdc_b() ==False : diff --git a/volet_roulant/volrou_doc.py b/volet_roulant/volrou_doc.py index f416157..ca7f2fb 100644 --- a/volet_roulant/volrou_doc.py +++ b/volet_roulant/volrou_doc.py @@ -12,7 +12,7 @@ # Documentation du système ################################################################################ -system_card=["twins-card", "pin-card", "data-card", "plot-card", "movement-card", "sensor-card", "board-card", "model-card", "firmata-card", "arduino-card"] +system_card=["twins-card", "pin-card", "data-card", "daq-card", "movement-card", "sensor-card", "board-card", "model-card", "firmata-card", "arduino-card"] system_card_description ={} # Jumeau numérique @@ -49,16 +49,18 @@ card_data_text=""" get(variable) \n -> Retourne la valeur de la variable à \n l card_data_url=[] system_card_description.update({"data-card" : [card_data_title, card_data_text, card_data_url]}) - # Monitoring -card_plot_title="Acquisition de données" -card_plot_text=""" plot([variables]) \n -> Affiche le chronogramme des variables \n spécifiées. - Par exemple : plot(['bp_m', 'moteur_angle']).\n - csv([variables]) \n -> Déclenche l'acquisition de données afin \n de génèrer un fichier de données CSV à \n l'arrêt du cycle.\n +# Monitoring +card_daq_title="Acquisition de données" +# card_daq_text="aaa"+"\u2192"+"ddd" +card_daq_text=""" daq([variables]) \n -> Déclenche l'acquisition de données afin \n de génèrer un fichier de données CSV à \n l'arrêt du cycle. + Par exemple : daq(['bp_ext', 'portail_x']).\n + plot() \n \u2192 Affiche le chronogramme à l'arrêt du + cycle. Le chronogramme interactif est en \n cours d'implémentation.\n Les variables pouvant être suivies sont les \n mêmes que celles de la page "Données".""" # Blender étant cadencé à 60 fps, la fréquence \n d'acquisition est 16 ms.""" -card_plot_url=[["Bibliothèque Matplotlib","https://matplotlib.org/"], - ["Wikipedia Français : fichier CSV","https://fr.wikipedia.org/wiki/Comma-separated_values"]] -system_card_description.update({"plot-card" : [card_plot_title, card_plot_text, card_plot_url]}) +card_daq_url=[["Wikipedia Français : fichier CSV","https://fr.wikipedia.org/wiki/Comma-separated_values"], + ["Bibliothèque Matplotlib","https://matplotlib.org/"]] +system_card_description.update({"daq-card" : [card_daq_title, card_daq_text, card_daq_url]}) # Ouvrir et fermer card_movement_title="Monter et descendre" diff --git a/volet_roulant/volrou_lib.py b/volet_roulant/volrou_lib.py index 6551498..354a91f 100644 --- a/volet_roulant/volrou_lib.py +++ b/volet_roulant/volrou_lib.py @@ -1,7 +1,7 @@ import bge # Bibliothèque Blender Game Engine (UPBGE) from twin_threading import thread_cmd_start, thread_cmd_stop, thread_cmd_end # Multithreading from twin_serial import jumeau, jumeau_stop, serial_close # Liaison série -from twin_plot import get, csv_start, csv_generate, plot # Visualisation des données +from twin_daq import get, daq, csv_generate, plot, plot_generate # Acquisition des données import time ############################################################################### @@ -106,14 +106,16 @@ def bp_auto (): # Cycle ############################################################################### +## # Temporisation +## + def tempo (duree): time.sleep(duree) +## # t (temps) -def truncate(n, decimals=0): - multiplier = 10**decimals - return int(n* multiplier)/multiplier +## def get_t (): # return truncate(scene.objects['System']['time'], 3) @@ -125,7 +127,10 @@ def set_t (date): def reset_t (): scene.objects['System']['time']=0 +## # Arrêt +## + def stop(): # Jumeau @@ -134,12 +139,19 @@ def stop(): time.sleep(1) # Suivi de données - if scene.objects['System']['csv']: + if scene.objects['System']['daq']: csv_generate() - scene.objects['System']['plot_draw']=False # Plot - thread_cmd_stop() # Thread + if scene.objects['System']['plot']: + plot_generate() + scene.objects['System']['plot_draw']=False # Plot + # Thread + thread_cmd_stop() + +## # Fin naturelle +## + def end(): # Jumeau @@ -148,15 +160,17 @@ def end(): time.sleep(1) # Suivi de données - if scene.objects['System']['csv']: + if scene.objects['System']['daq']: csv_generate() + if scene.objects['System']['plot']: + plot_generate() + scene.objects['System']['plot_draw']=False # Plot - scene.objects['System']['plot_draw']=False # Plot - thread_cmd_end() # Thread + # Thread + thread_cmd_end() def fin(): end() def quit(): end() -