Configuration du plot statique

This commit is contained in:
Philippe Roy 2023-01-25 06:03:02 +01:00
parent 72dbc3f914
commit 5243d26bd4
8 changed files with 198 additions and 78 deletions

View File

@ -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

View File

@ -47,7 +47,9 @@ 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
@ -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()

15
twin.py
View File

@ -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

View File

@ -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']]

View File

@ -1,7 +1,10 @@
<data>
<screen>
<width>1609</width>
<height>905</height>
<quality>1</quality>
<width>792</width>
<height>445</height>
<quality>4</quality>
</screen>
<plot>
<config>True</config>
</plot>
</data>

View File

@ -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 :

View File

@ -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()
@ -132,11 +141,6 @@ class DynamicPlot(QtWidgets.QMainWindow):
# self.ydata = self.ydata + [float(msg_list[1])]
# for line in msg_lines:
# msg_list=line.split(',')
# # print(msg_list)
@ -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
# 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()
plt.plot(self.xdata, self.ydata, 'b')
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()