Ajout des modes d'activation des entrées et des sorties pour le monte-charge et le volet

This commit is contained in:
Philippe Roy 2023-02-03 05:58:20 +01:00
parent f2e450654e
commit 1a7fe3f99f
17 changed files with 415 additions and 473 deletions

View File

@ -19,12 +19,13 @@ scene = bge.logic.getCurrentScene()
# Configuration des variables publiques
# 'nom_variable' :
# - Objet 3D : [nom de l'objet 3D, propriété associée à la valeur (activate ou activated_real), type de la valeur ('d' (digital, binary), 'a', (analog) ou 'n' (numeric)), échelle (1 si ommis)]
# - Configuration de la broche : [nom de la propriété stockant l'object broche (pyfirmata), type de broche par défaut('d','a' ou 'p'), 'mode de la broche par défaut ('i' ou 'o')]
# - Configuration du graphique : ['marque', 'type de ligne', 'couleur', linewidth]] (matplotlib)
# - Configuration de la broche : [nom de la propriété stockant l'object broche (pyfirmata),
# type de broche par défaut : 'd' (digital), 'a' (analog) ou 'p' (pwm)), mode de la broche par défaut : 'i' (input) ou 'o' (output)]
# - Configuration du graphique : ['marque', 'type de ligne', 'couleur', linewidth]] (Codification de Matplotlib)
#
# 'nom_variable_r' est la valeur réelle de la variable (valeur numérique) 'nom_variable' issue du jumelage numérique.
# Dans ce cas, il n'y a pas configuration de broche car elle est présente sur la variable 'nom_variable'.
# Ce distinguo ne concerne que les entrées, car il n'y pas de lecture des "sorties réelles".
# Ce distinguo ne concerne que les entrées, car les sorties sont pilotées par le numérique.
public_vars = {
't' : [['System','time','a'], [], []],
@ -145,7 +146,8 @@ def mot (cont):
# Monter
if obj['up']:
# Physique
# Physique du modèle 3D
if obj['prior']:
obj_vissansfin.applyRotation((0, 0, obj['step']), True)
obj['alpha']= obj['alpha']+obj['step']
if scene.objects['System']['time'] != obj['last_time']:
@ -159,7 +161,7 @@ def mot (cont):
obj['last_time'] = scene.objects['System']['time']
# Modele 3D -> Arduino
if scene.objects['System']['twins']:
if scene.objects['System']['twins'] and obj['prior_real']:
if scene.objects['Moteur']['pin_m'] is not None:
if scene.objects['Moteur']['pin_d'] is not None:
scene.objects['Moteur']['pin_d'].write(0)
@ -169,7 +171,8 @@ def mot (cont):
# else: # Pas de priorité
if obj['down']:
# Physique
# Physique du modèle 3D
if obj['prior']:
obj_vissansfin.applyRotation((0, 0, -obj['step']), True)
obj['alpha']= obj['alpha']-obj['step']
if scene.objects['System']['time'] != obj['last_time']:
@ -183,7 +186,7 @@ def mot (cont):
obj['last_time'] = scene.objects['System']['time']
# Modele 3D -> Arduino
if scene.objects['System']['twins']:
if scene.objects['System']['twins'] and obj['prior_real']:
if scene.objects['Moteur']['pin_d'] is not None:
if scene.objects['Moteur']['pin_m'] is not None:
scene.objects['Moteur']['pin_m'].write(0)
@ -192,13 +195,14 @@ def mot (cont):
# Arrêter
if obj['up']== False and obj['down'] == False :
# Physique
# Physique du modèle 3D
if obj['prior']:
obj['speed']= 0
obj_cabine['speed']= 0
obj['last_time'] = scene.objects['System']['time']
# Modele 3D -> Arduino
if scene.objects['System']['twins']:
if scene.objects['System']['twins'] and obj['prior_real']:
if scene.objects['Moteur']['pin_d'] is not None:
if scene.objects['Moteur']['pin_m'] is not None:
scene.objects['Moteur']['pin_m'].write(0)
@ -218,7 +222,7 @@ def pc_0 (cont):
obj = cont.owner
# Arduino -> Modele 3D
if scene.objects['System']['twins']:
if scene.objects['System']['twins'] and obj['prior_real']:
if obj['pin'] is not None:
if obj['pin'].read()==True and obj['activated_real'] == False :
obj['activated_real'] = True
@ -226,13 +230,13 @@ def pc_0 (cont):
obj['activated_real'] = False
# Etat capteur en fonction de la position de la cabine : localPosition.z entre -40 et -42
if scene.objects['Cabine'].localPosition.z <-40 and scene.objects['Cabine'].localPosition.z >-42 and obj['activated'] == False :
if scene.objects['Cabine'].localPosition.z <-40 and scene.objects['Cabine'].localPosition.z >-42 and obj['activated'] == False and obj['prior']:
obj['activated'] = True
if (scene.objects['Cabine'].localPosition.z > -40 or scene.objects['Cabine'].localPosition.z <-42) and obj['activated'] == True :
if (scene.objects['Cabine'].localPosition.z > -40 or scene.objects['Cabine'].localPosition.z <-42) and obj['activated'] == True and obj['prior']:
obj['activated'] = False
# Forçage par clic
if obj['click'] == True:
if obj['click'] == True and obj['prior']:
obj['activated'] = True
# Couleurs
@ -247,7 +251,7 @@ def pc_1 (cont):
obj = cont.owner
# Arduino -> Modele 3D
if scene.objects['System']['twins']:
if scene.objects['System']['twins'] and obj['prior_real']:
if obj['pin'] is not None:
if obj['pin'].read()==True and obj['activated_real'] == False :
obj['activated_real'] = True
@ -255,13 +259,13 @@ def pc_1 (cont):
obj['activated_real'] = False
# Etat capteur en fonction de la position de la cabine : localPosition.z entre 0 et -2
if scene.objects['Cabine'].localPosition.z <0 and scene.objects['Cabine'].localPosition.z >-2 and obj['activated'] == False :
if scene.objects['Cabine'].localPosition.z <0 and scene.objects['Cabine'].localPosition.z >-2 and obj['activated'] == False and obj['prior']:
obj['activated'] = True
if (scene.objects['Cabine'].localPosition.z > 0 or scene.objects['Cabine'].localPosition.z <-2) and obj['activated'] == True :
if (scene.objects['Cabine'].localPosition.z > 0 or scene.objects['Cabine'].localPosition.z <-2) and obj['activated'] == True and obj['prior']:
obj['activated'] = False
# Forçage par clic
if obj['click'] == True:
if obj['click'] == True and obj['prior']:
obj['activated'] = True
# Couleurs
@ -285,13 +289,24 @@ def system_init ():
def system_reset ():
# Entrées à l'état initial
objs= ['Bp niveau 0', 'Bp niveau 1', 'Microrupteur niveau 0','Microrupteur niveau 1']
for obj in objs:
scene.objects[obj]['activated']=False
scene.objects[obj]['activated_real']=False
# Voyants aux états initiaux
scene.objects['Led niveau 0']['activated']=False
scene.objects['Led niveau 1']['activated']=False
scene.objects['Led niveau 0'].setVisible(True,False)
scene.objects['Led niveau 0-on'].setVisible(False,False)
scene.objects['Led niveau 1'].setVisible(True,False)
scene.objects['Led niveau 1-on'].setVisible(False,False)
# Cabine
scene.objects['Cabine']['z']=0
scene.objects['Cabine']['speed']=0
scene.objects['Cabine']['step']=0
scene.objects['Cabine'].worldPosition.x = scene.objects['Cabine']['init_lx']-scene.objects['System']['init_lx']+scene.objects['System'].worldPosition.x
scene.objects['Cabine'].worldPosition.y = scene.objects['Cabine']['init_ly']-scene.objects['System']['init_ly']+scene.objects['System'].worldPosition.y
scene.objects['Cabine'].worldPosition.z = scene.objects['Cabine']['init_lz']-scene.objects['System']['init_lz']+scene.objects['System'].worldPosition.z
@ -299,25 +314,17 @@ def system_reset ():
scene.objects['Contrepoids'].worldPosition.y = scene.objects['Contrepoids']['init_ly']-scene.objects['System']['init_ly']+scene.objects['System'].worldPosition.y
scene.objects['Contrepoids'].worldPosition.z = scene.objects['Contrepoids']['init_lz']-scene.objects['System']['init_lz']+scene.objects['System'].worldPosition.z
# Moteur à l'état initial : pas utile
# I/O à l'état initial
scene.objects['Led niveau 0']['activated']=False
scene.objects['Led niveau 1']['activated']=False
scene.objects['Bp niveau 0']['activated']=False
scene.objects['Bp niveau 0']['activated_real']=False
scene.objects['Bp niveau 1']['activated']=False
scene.objects['Bp niveau 1']['activated_real']=False
scene.objects['Microrupteur niveau 0']['activated']=False
scene.objects['Microrupteur niveau 0']['activated_real']=False
scene.objects['Microrupteur niveau 1']['activated']=False
scene.objects['Microrupteur niveau 1']['activated_real']=False
# Moteur
scene.objects['Moteur']['up']=False
scene.objects['Moteur']['down']=False
scene.objects['Moteur']['alpha']=0
scene.objects['Moteur']['speed']=0
scene.objects['Moteur']['speed_setting']=31.4 # Vitesse du moteur numérique : 31,4 rad /s ( 5 tr / s )
scene.objects['Moteur']['step']=0
scene.objects['Cabine']['z']=0
scene.objects['Cabine']['speed']=0
scene.objects['Cabine']['step']=0
# Priorités activées
objs= ['Bp niveau 0', 'Bp niveau 1', 'Microrupteur niveau 0','Microrupteur niveau 1', 'Led niveau 0', 'Led niveau 1', 'Moteur']
for obj in objs:
scene.objects[obj]['prior']=True
scene.objects[obj]['prior_real']=True

View File

@ -40,7 +40,9 @@ from montchg_lib import * # Bibliothèque utilisateur du monte-charge
def commandes():
daq(['mot_angle', 'mot_vitesse', 'cabine_z', 'cabine_vitesse'])
jumeau_mode(True, True, True, True)
mot_vitesse (500)
# Init -> Descendre
while pc_0() ==False :
voy_0(True)

View File

@ -17,10 +17,12 @@ system_card_description ={}
# Jumeau numérique
card_twins_title="Jumeau numérique"
card_twins_text=""" jumeau(brochage) \n -> Active le jumeau réel.\n
'brochage' permet de faire le lien entre les \n deux jumeaux (plus de précision sur la \n page "Brochage").\n
jumeau_stop() \n -> Désactive le jumeau réel.\n
Avec "carte=jumeau(brochage)", on peut \n utiliser l'objet 'carte' pour communiquer \n directement avec le protocole Firmata."""
card_twins_text=""" jumeau(brochage) -> Démarrer le jumelage.\n
"brochage" permet de faire le lien entre les \n deux jumeaux (voir la page "Brochage").\n
jumeau_stop() -> Arrêter le jumelage.\n
jumeau_mode(entrées réelles, entrées \n numériques, sorties réelles, sorties \n numériques) -> Définit les modes
d'activation des entrées/sorties : \n - True pour activer (par défaut), \n - False pour désactiver."""
# Avec "carte=jumeau(brochage)", on peut \n utiliser l'objet 'carte' pour communiquer \n directement avec le protocole Firmata.
# jumeau_config(port, vitesse) \n -> Définit la configuration de la liaison \n série.\n
# Si le port n'est pas spécifié, il sera \n recherché automatiquement (carte \n Arduino Uno ou Mega). \n
# La vitesse par défaut est 115200 baud."""
@ -35,8 +37,8 @@ card_pin_text=""" Le brochage est un dictionnaire qui permet \n d'associer les o
- type : a (analogique) ou d (numérique),
- broche : numéro de la broche de carte,
- mode : i (entrée), o (sortie) ou p (pwm).
Par exemple : brochage = { 'voy_0':['d', 3, 'o'] }.\n
Les objets numériques du jumeau sont : \n 'ba_0', 'ba_1', 'pc_0', 'pc_1', 'mot_m', 'mot_d', \n 'voy_0' et 'voy_1'."""
Par exemple : brochage = { 'ba_0':['d',2,'i'] }.\n
Les objets numériques du jumeau sont : \n 'ba_0', 'ba_1', 'pc_0', 'pc_1', 'mot_m', \n 'mot_d', 'voy_0' et 'voy_1'."""
card_pin_url=[]
system_card_description.update({"pin-card" : [card_pin_title, card_pin_text, card_pin_url]})
@ -64,10 +66,11 @@ system_card_description.update({"daq-card" : [card_daq_title, card_daq_text, car
# Ouvrir et fermer
card_movement_title="Monter et descendre"
card_movement_text=""" mot_m(True | False) \n -> Monter la cabine (moteur sens trigo). \n
mot_d(True | False) \n -> Descendre la cabine (mot. sens horaire). \n
pc_0() \n -> Capteur présence cabine niveau 0.\n Retourne True si la cabine est au niveau 0. \n
pc_1() \n -> Capteur présence cabine niveau 1.\n Retourne True si la cabine est au niveau 1."""
card_movement_text=""" mot_m(True | False) -> Monter la cabine. \n
mot_d(True | False) -> Descendre la cabine. \n
mot_vitesse(vitesse) -> Change la vitesse \n du moteur numérique en rad/s. Si 'vitesse' \n est ommis, elle sera réinitialisée. \n
pc_0() -> Capteur présence cabine niveau 0.\n Retourne True si la cabine est au niveau 0. \n
pc_1() -> Capteur présence cabine niveau 1.\n Retourne True si la cabine est au niveau 1."""
card_movement_url=[]
system_card_description.update({"movement-card" : [card_movement_title, card_movement_text, card_movement_url]})
@ -91,10 +94,11 @@ system_card_description.update({"model-card" : [card_model_title, card_model_tex
# Firmata
card_firmata_title="Protocole Firmata"
card_firmata_text=""" Firmata est le protocole de \n communication entre les deux jumeaux.\n
broche = carte.get_pin('type:numéro:mode') \n -> Créer une entrée/sortie (broche) \n - type : a (analogique) ou d (numérique) \n - mode : i (entrée) , o (sortie) ou p (pwm). \n
broche.read() \n -> Retourne la valeur de la broche.\n
broche.write(valeur) \n -> Écrire la valeur sur la broche."""
card_firmata_text=""" Firmata est le protocole de communication \n entre les deux jumeaux via la liaison série.
Lors du jumelage, il faut récupérer l'objet \n "carte" avec carte = jumeau(brochage). \n
broche = carte.get_pin('type:numéro:mode') \n -> Créer une entrée/sortie (broche) : \n - type : a (analogique) ou d (numérique), \n - mode : i (entrée) , o (sortie) ou p (pwm). \n
valeur = broche.read() -> Lit la broche.\n
broche.write(valeur) -> Écrire sur la broche."""
card_firmata_url=[["Protocole Firmata : pyFirmata","https://github.com/tino/pyFirmata"]]
system_card_description.update({"firmata-card" : [card_firmata_title, card_firmata_text, card_firmata_url]})

View File

@ -1,6 +1,6 @@
import bge # Bibliothèque Blender Game Engine (UPBGE)
import twin_threading # Multithreading (multitâches)
from twin_serial import jumeau, jumeau_stop, serial_close # Liaison série
from twin_serial import jumeau, jumeau_stop, serial_close, jumeau_mode_system, jumeau_mode_object # Liaison série
from twin_daq import get, daq, csv_generate, plot, plot_generate # Acquisition des données
import time
@ -54,11 +54,8 @@ def mot_d (order):
scene.objects['Moteur']['down']=order
# Réglage de la vitesse du moteur numérique
def mot_digitset (speed=None):
if speed==None:
scene.objects['Moteur']['speed_setting']=31.4 # Vitesse du moteur numérique : 31,4 rad /s ( 5 tr / s )
else:
scene.objects['Moteur']['speed_setting']=speed
def mot_vitesse (speed=31.4):
scene.objects['Moteur']['speed_setting']=speed # Vitesse du moteur numérique : 31,4 rad /s ( 5 tr / s )
###############################################################################
# Capteurs
@ -68,14 +65,12 @@ def mot_digitset (speed=None):
def pc_0 ():
if scene.objects['Microrupteur niveau 0']['activated'] or scene.objects['Microrupteur niveau 0']['activated_real']:
return True
else:
return False
# Compte-rendu du capteur de présence cabine niveau 0
def pc_1 ():
if scene.objects['Microrupteur niveau 1']['activated'] or scene.objects['Microrupteur niveau 1']['activated_real']:
return True
else:
return False
###############################################################################
@ -86,16 +81,24 @@ def pc_1 ():
def ba_0 ():
if scene.objects['Bp niveau 0']['activated'] or scene.objects['Bp niveau 0']['activated_real']:
return True
else:
return False
# Compte-rendu du bouton pousssoir appel niveau 1
def ba_1 ():
if scene.objects['Bp niveau 1']['activated'] or scene.objects['Bp niveau 1']['activated_real']:
return True
else:
return False
###############################################################################
# Jumelage
###############################################################################
# Mode de jumelage (règles d'activation)
def jumeau_mode (input_real=True, input_digital=True, output_real=True, output_digital=True):
input_objs = ['Bp niveau 0', 'Bp niveau 1', 'Microrupteur niveau 0', 'Microrupteur niveau 1']
output_objs = ['Led niveau 0', 'Led niveau 1', 'Moteur']
jumeau_mode_system (input_objs, output_objs, input_real, input_digital, output_real, output_digital)
###############################################################################
# Cycle
###############################################################################

Binary file not shown.

View File

@ -140,7 +140,8 @@ def mot (cont):
# Ouvrir
if obj['open']:
# Physique
# Physique du modèle 3D
if obj['prior']:
obj_engrenage.applyRotation((0, 0, -obj_engrenage['step']), True)
obj['alpha']= obj['alpha']-obj['step']
if scene.objects['System']['time'] != obj['last_time']:
@ -162,7 +163,8 @@ def mot (cont):
# else: # Pas de priorité
if obj['close']:
# Physique
# Physique du modèle 3D
if obj['prior']:
obj_engrenage.applyRotation((0, 0, obj_engrenage['step']), True)
obj['alpha']= obj['alpha']+obj['step']
if scene.objects['System']['time'] != obj['last_time']:
@ -183,7 +185,8 @@ def mot (cont):
# Arrêrer
if obj['open']== False and obj['close'] == False and obj['prior']:
# Physique
# Physique du modèle 3D
if obj['prior']:
obj['speed']= 0
obj_portail['speed']= 0
obj['last_time'] = scene.objects['System']['time']
@ -277,12 +280,15 @@ def ir_emet (cont):
# Passif
if obj['active'] == False and obj.color !=color_passive:
obj.color =color_passive
# Physique du modèle 3D
if obj['prior']:
scene.objects['Emetteur IR Led'].setVisible(True,False)
scene.objects['Emetteur IR Led-on'].setVisible(False,False)
scene.objects['Recepteur IR']['active'] = False
# Modele 3D -> Arduino
if scene.objects['System']['twins']:
if scene.objects['System']['twins'] and obj['prior_real']:
if scene.objects['Emetteur IR']['pin'] is not None:
scene.objects['Emetteur IR']['pin'].write(0)
return
@ -292,18 +298,21 @@ def ir_emet (cont):
# Allumage
if scene.objects['Emetteur IR Led-on'].visible == False:
# Physique du modèle 3D
if obj['prior']:
scene.objects['Emetteur IR Led-on'].setVisible(True,False)
scene.objects['Emetteur IR Led'].setVisible(False,False)
obj.color = color_active
scene.objects['Recepteur IR']['active'] = True
# Modele 3D -> Arduino
if scene.objects['System']['twins']:
if scene.objects['System']['twins'] and obj['prior_real']:
if scene.objects['Emetteur IR']['pin'] is not None:
scene.objects['Emetteur IR']['pin'].write(1)
# Forçage par clic
if obj['click'] == True:
if obj['click'] == True and obj['prior']:
obj['activated'] = True
scene.objects['Recepteur IR']['activated'] = True
@ -339,8 +348,16 @@ def ir_recep (cont):
# Active
if obj['active']:
# Arduino -> Modele 3D (activé si Pin = False) FIXME : à vérifier avec le jumeau réel
if scene.objects['System']['twins'] and obj['prior_real']:
if obj['pin'] is not None :
if obj['pin'].read()==False and obj['activated_real'] == False :
obj['activated_real'] = True
if obj['pin'].read()==True and obj['activated_real'] == True :
obj['activated_real'] = False
# Forçage par clic
if obj['click'] == True:
if obj['click'] == True and obj['prior']:
obj['activated'] = True
scene.objects['Emetteur IR']['activated'] = True

View File

@ -22,9 +22,8 @@ card_twins_title="Jumeau numérique"
card_twins_text=""" jumeau(brochage) -> Démarrer le jumelage.\n
"brochage" permet de faire le lien entre les \n deux jumeaux (voir la page "Brochage").\n
jumeau_stop() -> Arrêter le jumelage.\n
jumeau_mode(entrées réelles, entrées \n numériques, sorties réelles, sorties \n numériques) -> Définit les modes d'activation
des entrées/sorties : True pour activer \n (par défaut), False pour désactiver. """
jumeau_mode(entrées réelles, entrées \n numériques, sorties réelles, sorties \n numériques) -> Définit les modes
d'activation des entrées/sorties : \n - True pour activer (par défaut), \n - False pour désactiver."""
# Avec "carte=jumeau(brochage)", on peut \n utiliser l'objet 'carte' pour communiquer \n directement avec le protocole Firmata.
# jumeau_config(port, vitesse) \n -> Définit la configuration de la liaison \n série.\n
# Si le port n'est pas spécifié, il sera \n recherché automatiquement (carte \n Arduino Uno ou Mega). \n
@ -40,7 +39,7 @@ card_pin_text=""" Le brochage est un dictionnaire qui permet \n d'associer les o
- type : a (analogique) ou d (binaire),
- broche : numéro de la broche de carte,
- mode : i (entrée), o (sortie) ou p (pwm).
Par exemple : brochage = { 'gyr':['d', 3, 'o'] }.\n
Par exemple : brochage = { 'gyr':['d',3,'o'] }.\n
Les objets numériques du jumeau sont : \n 'bp_ext', 'bp_int', 'fdc_o', 'fdc_f', 'mot_o',\n 'mot_f', 'gyr', 'ir_emet' et 'ir_recep'."""
card_pin_url=[]
system_card_description.update({"pin-card" : [card_pin_title, card_pin_text, card_pin_url]})
@ -73,7 +72,7 @@ card_movement_text=""" mot_o(True | False) \n -> Ouvrir le portail (moteur sens
mot_f(True | False) \n -> Fermer le portail (moteur sens horaire).\n
fdc_o() \n -> Capteur fin de course portail ouvert.
fdc_f() \n -> Capteur fin de course portail fermé.\n
mot_digitset(vitesse) -> Change la vitesse \n du moteur numérique en rad/s. Si 'vitesse' \n est ommis, elle sera réinitialisée."""
mot_vitesse(vitesse) -> Change la vitesse \n du moteur numérique en rad/s. Si 'vitesse' \n est ommis, elle sera réinitialisée."""
# fdc_o() \n -> Capteur fin de course portail ouvert.\n Retourne True si le portail est ouvert. \n
# fdc_f() \n -> Capteur fin de course portail fermé.\n Retourne True si le portail est fermé.\n
@ -115,8 +114,7 @@ card_firmata_text=""" Firmata est le protocole de communication \n entre les deu
Lors du jumelage, il faut récupérer l'objet \n "carte" avec carte = jumeau(brochage). \n
broche = carte.get_pin('type:numéro:mode') \n -> Créer une entrée/sortie (broche) : \n - type : a (analogique) ou d (numérique), \n - mode : i (entrée) , o (sortie) ou p (pwm). \n
valeur = broche.read() -> Lit la broche.\n
broche.write(valeur) -> Écrire sur la broche.
"""
broche.write(valeur) -> Écrire sur la broche."""
card_firmata_url=[["Protocole Firmata : pyFirmata","https://github.com/tino/pyFirmata"]]
system_card_description.update({"firmata-card" : [card_firmata_title, card_firmata_text, card_firmata_url]})

View File

@ -102,8 +102,8 @@ def bp_int ():
# Mode de jumelage (règles d'activation)
def jumeau_mode (input_real=True, input_digital=True, output_real=True, output_digital=True):
input_objs= ['Microrupteur fdc ouvert', 'Microrupteur fdc ferme', 'Bp cote cour','Bp cote rue', 'Recepteur IR']
output_objs= ['Led', 'Moteur', 'Emetteur IR']
input_objs = ['Microrupteur fdc ouvert', 'Microrupteur fdc ferme', 'Bp cote cour','Bp cote rue', 'Recepteur IR']
output_objs = ['Led', 'Moteur', 'Emetteur IR']
jumeau_mode_system (input_objs, output_objs, input_real, input_digital, output_real, output_digital)
###############################################################################

View File

@ -1,7 +1,7 @@
<data>
<screen>
<width>1609</width>
<height>905</height>
<width>1590</width>
<height>894</height>
<quality>1</quality>
</screen>
<plot>

View File

@ -126,7 +126,7 @@ def plot_config_generate(data_groups):
xml_color.text=daq_config[var][2][2]
xml_size = ET.SubElement(xml_var, 'linewidth')
xml_size.text=str(daq_config[var][2][3])
xml_type = ET.SubElement(xml_var, 'type')
xml_type = ET.SubElement(xml_var, 'type') # Binaire, analogique ou numérique
xml_type.text=str(daq_config[var][0][2])
# Détection de groupe de graphique

View File

@ -176,7 +176,7 @@ class MainWindow(QtWidgets.QMainWindow):
self.setCentralWidget(widget)
# print (self.getContentsMargins())
# Création des graphive à partir du fichier CSV
# Remplissage des graphiques à partir du fichier CSV
fields, xdata, ydata = csv_read(sys.argv[1])
plots_static(self.canvas.plt, fields, xdata, ydata, plot_config, sys.argv[1])
self.show()

View File

@ -20,116 +20,6 @@ from matplotlib.backends.backend_wxagg import (FigureCanvasWxAgg as FigureCanvas
plot_config={}
###############################################################################
# Création des graphiques
###############################################################################
def plot_draw(plt):
twin_config = ET.parse('twin_config.xml').getroot()
# Lecture fichier CSV
fields = []
rows = []
with open(sys.argv[1], newline='') as csv_buff:
csv_reader = csv.reader(csv_buff, delimiter=';')
fields = next(csv_reader)
for row in csv_reader:
rows.append(row)
# 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
# Groupe de plots : si group = 0 -> nouveau groupe, plot solitaire
# si group = -1 -> pas de plot
# si group > 0 -> numéro du groupe
plt_i=0 # Compteur de plot
plt_grp=[] # Groupe de plot [[numéro du plot, groupe du fichier CSV]]
for i in range(len(fields)):
var = fields[i]
plt_current=-1 # Numéro du plot à créer
if ('group' in plot_config[var]): # Pas de Plot
if int(plot_config[var]['group']) !=-1: # Pas de Plot
# Plot solitaire
if int(plot_config[var]['group']) ==0:
plt_current = plt_i
plt_grp.append([plt_i, 0])
plt_i +=1
# Plot groupé
else:
plt_new = True # Flag d'un nouveau groupe
for j in range(len(plt_grp)):
if plt_grp[j][1] == int(plot_config[var]['group']): # Groupe déjà existant
plt_current = plt_grp[j][0]
plt_new = False
break
# Nouveau groupe
if plt_new:
plt_current = plt_i
plt_grp.append([plt_i, int(plot_config[var]['group'])])
plt_i +=1
# Création du plot unique
if plot_nb(plot_config) ==1:
if twin_config[1][0].text == "True": # Configuration des plots activée
plt.plot(xdata[i], ydata[i], label=var, color=plot_config_get(plot_config, var, 'color'), linewidth=plot_config_get(plot_config, var, 'linewidth'),
linestyle=plot_config_get(plot_config, var, 'linestyle'), marker=plot_config_get(plot_config, var, 'marker'))
else:
plt.plot(xdata[i], ydata[i], '.-', label=var) # Configuration matplotlib par défaut
# Légende ou titre d'axe y
if plt_grp[plt_current][1]==0:
plt.set_ylabel(var)
else:
plt.legend()
# Création des subplots
if plot_nb(plot_config) >1:
if twin_config[1][0].text == "True": # Configuration des plots activée
plt[plt_current].plot(xdata[i], ydata[i], label=var, color=plot_config_get(plot_config, var, 'color'), linewidth=plot_config_get(plot_config, var, 'linewidth'),
linestyle=plot_config_get(plot_config, var, 'linestyle'), marker=plot_config_get(plot_config, var, 'marker'))
else:
plt[plt_current].plot(xdata[i], ydata[i], '.-', label=var) # Configuration matplotlib par défaut
# Légende ou titre d'axe y
if plt_grp[plt_current][1]==0:
plt[plt_current].set_ylabel(var)
else:
plt[plt_current].legend()
# Décoration
if plot_nb(plot_config) ==1: # 1 plot
plt.set_xlabel("Temps (s)")
# self.canvas.plt[0].set_ylabel("Valeurs")
plt.set_title(sys.argv[1])
plt.axhline(linewidth=1, color='k')
plt.grid(True, linestyle='--')
# self.canvas.plt.legend()
else: # Plusieurs plots
plt[plt_i-1].set_xlabel("Temps (s)")
# self.canvas.plt[0].set_ylabel("Valeurs")
plt[0].set_title(sys.argv[1])
for i in range (plt_i):
plt[i].axhline(linewidth=1, color='k')
plt[i].grid(True, linestyle='--')
# self.canvas.plt[i].legend()
###############################################################################
# Zone de dessin
###############################################################################
@ -147,7 +37,7 @@ class CanvasFrame(wx.Frame):
plt = self.figure.subplots(plot_nb(plot_config), 1, sharex=True) # plot_nb() : nombre de graphiques
self.canvas = FigureCanvas(self, -1, self.figure)
# Création des graphive à partir du fichier CSV
# Remplissage des graphiques à partir du fichier CSV
fields, xdata, ydata = csv_read(sys.argv[1])
plots_static(plt, fields, xdata, ydata, plot_config, sys.argv[1])
self.canvas.draw()
@ -159,6 +49,7 @@ class CanvasFrame(wx.Frame):
self.SetSizer(self.sizer)
self.Fit()
# Barre d'outils
def add_toolbar(self):
self.toolbar = NavigationToolbar(self.canvas)
self.toolbar.Realize()

Binary file not shown.

View File

@ -19,12 +19,13 @@ scene = bge.logic.getCurrentScene()
# Configuration des variables publiques
# 'nom_variable' :
# - Objet 3D : [nom de l'objet 3D, propriété associée à la valeur (activate ou activated_real), type de la valeur ('d' (digital, binary), 'a', (analog) ou 'n' (numeric)), échelle (1 si ommis)]
# - Configuration de la broche : [nom de la propriété stockant l'object broche (pyfirmata), type de broche par défaut('d','a' ou 'p'), 'mode de la broche par défaut ('i' ou 'o')]
# - Configuration du graphique : ['marque', 'type de ligne', 'couleur', linewidth]] (matplotlib)
# - Configuration de la broche : [nom de la propriété stockant l'object broche (pyfirmata),
# type de broche par défaut : 'd' (digital), 'a' (analog) ou 'p' (pwm)), mode de la broche par défaut : 'i' (input) ou 'o' (output)]
# - Configuration du graphique : ['marque', 'type de ligne', 'couleur', linewidth]] (Codification de Matplotlib)
#
# 'nom_variable_r' est la valeur réelle de la variable (valeur numérique) 'nom_variable' issue du jumelage numérique.
# Dans ce cas, il n'y a pas configuration de broche car elle est présente sur la variable 'nom_variable'.
# Ce distinguo ne concerne que les entrées, car il n'y pas de lecture des "sorties réelles".
# Ce distinguo ne concerne que les entrées, car les sorties sont pilotées par le numérique.
public_vars = {
't' : [['System','time','a'], [], []],
@ -46,7 +47,7 @@ public_vars = {
'bp_auto' : [['Bp auto','activated','d'], ['pin', 'd','i'], []],
'bp_auto_r' : [['Bp auto','activated_real','d'], [], []],
'voy_auto' : [['Led auto','activated','d'], ['pin', 'd','o'], []],
'lum' : [['Recepteur LDR','activated','a'], ['pin', 'd','i'], []], # Basculer en analogique
'lum' : [['Recepteur LDR','activated','a'], ['pin', 'd','i'], []], # FIXME : Basculer en analogique
'lum_r' : [['Recepteur LDR','activated_real','a'], [], []]}
# Couleurs
@ -119,6 +120,9 @@ def mot (cont):
# Monter
if obj['up']:
# Physique du modèle 3D
if obj['prior']:
# Physique (sens horaire -> négatif)
obj['step'] = abs(scene.objects['Axe enrouleur'].worldOrientation.to_euler().x - scene.objects['Axe enrouleur']['last_alpha'])
obj['alpha']=obj['last_alpha'] - obj['step']
@ -197,7 +201,7 @@ def mot (cont):
obj['last_alpha'] = obj['alpha']
# Modele 3D -> Arduino
if scene.objects['System']['twins']:
if scene.objects['System']['twins'] and obj['prior_real']:
if scene.objects['Moteur']['pin_m'] is not None:
if scene.objects['Moteur']['pin_d'] is not None:
scene.objects['Moteur']['pin_d'].write(0)
@ -206,6 +210,9 @@ def mot (cont):
# Descendre
if obj['down']:
# Physique du modèle 3D
if obj['prior']:
# Physique (sens trigo -> positif)
obj['step'] = abs(scene.objects['Axe enrouleur'].worldOrientation.to_euler().x - scene.objects['Axe enrouleur']['last_alpha'])
obj['alpha']=obj['last_alpha'] + obj['step']
@ -289,7 +296,7 @@ def mot (cont):
obj['last_alpha'] = obj['alpha']
# Modele 3D -> Arduino
if scene.objects['System']['twins']:
if scene.objects['System']['twins'] and obj['prior_real']:
if scene.objects['Moteur']['pin_d'] is not None:
if scene.objects['Moteur']['pin_m'] is not None:
scene.objects['Moteur']['pin_m'].write(0)
@ -298,7 +305,8 @@ def mot (cont):
# Arrêt
if obj['up'] == False and obj['down'] == False:
# Physique
# Physique du modèle 3D
if obj['prior']:
obj['speed']= 0
scene.objects['Axe enrouleur']['last_alpha'] = scene.objects['Axe enrouleur'].worldOrientation.to_euler().x
obj['last_time'] = scene.objects['System']['time']
@ -323,7 +331,7 @@ def mot (cont):
scene.objects['Lame volet 13'].stopAction(layer)
# Modele 3D -> Arduino
if scene.objects['System']['twins']:
if scene.objects['System']['twins'] and obj['prior_real']:
if scene.objects['Moteur']['pin_d'] is not None:
if scene.objects['Moteur']['pin_m'] is not None:
scene.objects['Moteur']['pin_m'].write(0)
@ -342,7 +350,7 @@ def fdc_h (cont):
obj = cont.owner
# Arduino -> Modele 3D
if scene.objects['System']['twins']:
if scene.objects['System']['twins'] and obj['prior_real']:
if obj['pin'] is not None:
if obj['pin'].read()==True and obj['activated_real'] == False :
obj['activated_real'] = True
@ -351,13 +359,13 @@ def fdc_h (cont):
# Etat capteur en fonction du volet
scene.objects['Axe fdc']['rx']= scene.objects['Axe fdc'].localOrientation.to_euler().x *(180/math.pi)
if scene.objects['Axe fdc']['rx'] >= -175 and scene.objects['Axe fdc']['rx'] <= -155 and obj['activated'] == False :
if scene.objects['Axe fdc']['rx'] >= -175 and scene.objects['Axe fdc']['rx'] <= -155 and obj['activated'] == False and obj['prior']:
obj['activated'] = True
if scene.objects['Axe fdc']['rx'] < -175 or scene.objects['Axe fdc']['rx'] > -155 and obj['activated'] == True :
if scene.objects['Axe fdc']['rx'] < -175 or scene.objects['Axe fdc']['rx'] > -155 and obj['activated'] == True and obj['prior']:
obj['activated'] = False
# Forçage par clic
if obj['click'] == True:
if obj['click'] == True and obj['prior']:
obj['activated'] = True
# Couleurs
@ -372,7 +380,7 @@ def fdc_b (cont):
obj = cont.owner
# Arduino -> Modele 3D
if scene.objects['System']['twins']:
if scene.objects['System']['twins'] and obj['prior_real']:
if obj['pin'] is not None:
if obj['pin'].read()==True and obj['activated_real'] == False :
obj['activated_real'] = True
@ -380,13 +388,13 @@ def fdc_b (cont):
obj['activated_real'] = False
# Etat capteur en fonction du volet
if scene.objects['Axe fdc']['rx'] >= -10 and scene.objects['Axe fdc']['rx'] <= 10 and obj['activated'] == False :
if scene.objects['Axe fdc']['rx'] >= -10 and scene.objects['Axe fdc']['rx'] <= 10 and obj['activated'] == False and obj['prior']:
obj['activated'] = True
if scene.objects['Axe fdc']['rx'] < -10 or scene.objects['Axe fdc']['rx'] > 10 and obj['activated'] == True :
if scene.objects['Axe fdc']['rx'] < -10 or scene.objects['Axe fdc']['rx'] > 10 and obj['activated'] == True and obj['prior']:
obj['activated'] = False
# Forçage par clic
if obj['click'] == True:
if obj['click'] == True and obj['prior']:
obj['activated'] = True
# Couleurs
@ -418,11 +426,26 @@ def system_init ():
def system_reset ():
# Entrées à l'état initial
objs= ['Bp monter', 'Bp arret', 'Bp descendre', 'Bp auto', 'Microrupteur haut','Microrupteur bas', 'Recepteur LDR']
for obj in objs:
scene.objects[obj]['activated']=False
scene.objects[obj]['activated_real']=False
# Voyants aux états initiaux
scene.objects['Led auto']['activated']=False
scene.objects['Led auto'].setVisible(True,False)
scene.objects['Led auto-on'].setVisible(False,False)
# Volet
# Volet et moteur
scene.objects['Moteur']['up']=False
scene.objects['Moteur']['down']=False
scene.objects['Moteur']['alpha']=0
scene.objects['Moteur']['last_alpha']=0
scene.objects['Moteur']['speed']=0
scene.objects['Moteur']['speed_setting']=125.6 # Vitesse du moteur numérique : 125.6 rad /s ( 20 tr / s )
scene.objects['Moteur']['step']=0
scene.objects['Axe enrouleur']['last_alpha']=scene.objects['Axe enrouleur'].worldOrientation.to_euler().x
obj = scene.objects['Moteur']
start = 49
end = 50
@ -448,30 +471,13 @@ def system_reset ():
scene.objects['Lame volet 11'].playAction('Lame volet 11-Up', start, end, layer, priority, blendin, mode, layerWeight, ipoFlags, speed)
scene.objects['Lame volet 12'].playAction('Lame volet 12-Up', start, end, layer, priority, blendin, mode, layerWeight, ipoFlags, speed)
scene.objects['Lame volet 13'].playAction('Lame volet 13-Up', start, end, layer, priority, blendin, mode, layerWeight, ipoFlags, speed)
# print ("reset")
obj['frame_up'] = scene.objects['Axe enrouleur'].getActionFrame(layer)
obj['frame_down']= 100-obj['frame_up']
# I/O à l'état initial
scene.objects['Led auto']['activated']=False
scene.objects['Bp monter']['activated']=False
scene.objects['Bp monter']['activated_real']=False
scene.objects['Bp arret']['activated']=False
scene.objects['Bp arret']['activated_real']=False
scene.objects['Bp descendre']['activated']=False
scene.objects['Bp descendre']['activated_real']=False
scene.objects['Bp auto']['activated']=False
scene.objects['Bp auto']['activated_real']=False
scene.objects['Microrupteur haut']['activated']=False
scene.objects['Microrupteur haut']['activated_real']=False
scene.objects['Microrupteur bas']['activated']=False
scene.objects['Microrupteur bas']['activated_real']=False
scene.objects['Moteur']['up']=False
scene.objects['Moteur']['down']=False
scene.objects['Moteur']['alpha']=0
scene.objects['Moteur']['last_alpha']=0
scene.objects['Moteur']['speed']=0
scene.objects['Moteur']['speed_setting']=125.6 # Vitesse du moteur numérique : 125.6 rad /s ( 20 tr / s )
scene.objects['Moteur']['step']=0
scene.objects['Axe enrouleur']['last_alpha']=scene.objects['Axe enrouleur'].worldOrientation.to_euler().x
scene.objects['Recepteur LDR']['activated']=False
# Priorités activées
objs= ['Bp monter', 'Bp arret', 'Bp descendre', 'Bp auto', 'Microrupteur haut','Microrupteur bas', 'Recepteur LDR',
'Moteur', 'Led auto']
for obj in objs:
scene.objects[obj]['prior']=True
scene.objects[obj]['prior_real']=True

View File

@ -42,6 +42,9 @@ from volrou_lib import * # Bibliothèque utilisateur du volet roulant
def commandes():
daq(['mot_angle', 'mot_vitesse'])
plot (['mot_angle', 'mot_vitesse'])
# plot ([['mot_angle', 'mot_vitesse']])
# jumeau_mode(True,True, True, False)
# Init -> Descendre
while fdc_b() ==False :
@ -85,8 +88,6 @@ def commandes():
print ("Descendre : "+str(round(t1-t0, 3)) +" s - angle : " +str(round(a1-a0, 3)) + " rad - moteur_vitesse : " +str(round(mot_vitesse, 3))+
" rad/s - moteur_pas : " +str(round(mot_pas, 3))+" rad/impulsion")
# plot ([['mot_angle', 'mot_vitesse']])
plot (['mot_angle', 'mot_vitesse'])
fin() # A garder

View File

@ -17,10 +17,12 @@ system_card_description ={}
# Jumeau numérique
card_twins_title="Jumeau numérique"
card_twins_text=""" jumeau(brochage) \n -> Active le jumeau réel.\n
'brochage' permet de faire le lien entre les \n deux jumeaux (plus de précision sur la \n page "Brochage").\n
jumeau_stop() \n -> Désactive le jumeau réel.\n
Avec "carte=jumeau(brochage)", on peut \n utiliser l'objet 'carte' pour communiquer \n directement avec le protocole Firmata."""
card_twins_text=""" jumeau(brochage) -> Démarrer le jumelage.\n
"brochage" permet de faire le lien entre les \n deux jumeaux (voir la page "Brochage").\n
jumeau_stop() -> Arrêter le jumelage.\n
jumeau_mode(entrées réelles, entrées \n numériques, sorties réelles, sorties \n numériques) -> Définit les modes
d'activation des entrées/sorties : \n - True pour activer (par défaut), \n - False pour désactiver."""
# Avec "carte=jumeau(brochage)", on peut \n utiliser l'objet 'carte' pour communiquer \n directement avec le protocole Firmata.
# jumeau_config(port, vitesse) \n -> Définit la configuration de la liaison \n série.\n
# Si le port n'est pas spécifié, il sera \n recherché automatiquement (carte \n Arduino Uno ou Mega). \n
# La vitesse par défaut est 115200 baud."""
@ -35,7 +37,7 @@ card_pin_text=""" Le brochage est un dictionnaire qui permet \n d'associer les o
- type : a (analogique) ou d (numérique),
- broche : numéro de la broche de carte,
- mode : i (entrée), o (sortie) ou p (pwm).
Par exemple : brochage = { 'led':['d', 3, 'o'] }.\n
Par exemple : brochage = { 'bp_m':['d',2,'i'] }.\n
Les objets numériques du jumeau sont : \n 'bp_m', 'bp_a', 'bp_d', 'mot_m', 'mot_d', \n 'fdc_h', 'fdc_b', 'bp_auto', 'voy_auto' et 'lum'."""
card_pin_url=[]
system_card_description.update({"pin-card" : [card_pin_title, card_pin_text, card_pin_url]})
@ -99,10 +101,11 @@ system_card_description.update({"model-card" : [card_model_title, card_model_tex
# Firmata
card_firmata_title="Protocole Firmata"
card_firmata_text=""" Firmata est le protocole de \n communication entre les deux jumeaux.\n
broche = carte.get_pin('type:numéro:mode') \n -> Créer une entrée/sortie (broche) \n - type : a (analogique) ou d (numérique) \n - mode : i (entrée) , o (sortie) ou p (pwm). \n
broche.read() \n -> Retourne la valeur de la broche.\n
broche.write(valeur) \n -> Écrire la valeur sur la broche."""
card_firmata_text=""" Firmata est le protocole de communication \n entre les deux jumeaux via la liaison série.
Lors du jumelage, il faut récupérer l'objet \n "carte" avec carte = jumeau(brochage). \n
broche = carte.get_pin('type:numéro:mode') \n -> Créer une entrée/sortie (broche) : \n - type : a (analogique) ou d (numérique), \n - mode : i (entrée) , o (sortie) ou p (pwm). \n
valeur = broche.read() -> Lit la broche.\n
broche.write(valeur) -> Écrire sur la broche."""
card_firmata_url=[["Protocole Firmata : pyFirmata","https://github.com/tino/pyFirmata"]]
system_card_description.update({"firmata-card" : [card_firmata_title, card_firmata_text, card_firmata_url]})

View File

@ -1,6 +1,6 @@
import bge # Bibliothèque Blender Game Engine (UPBGE)
import twin_threading # Multithreading (multitâches)
from twin_serial import jumeau, jumeau_stop, serial_close # Liaison série
from twin_serial import jumeau, jumeau_stop, serial_close, jumeau_mode_system, jumeau_mode_object # Liaison série
from twin_daq import get, daq, csv_generate, plot, plot_generate # Acquisition des données
import time
@ -108,6 +108,16 @@ def bp_d ():
def bp_auto ():
return scene.objects['Bp auto']['activated']
###############################################################################
# Jumelage
###############################################################################
# Mode de jumelage (règles d'activation)
def jumeau_mode (input_real=True, input_digital=True, output_real=True, output_digital=True):
input_objs = ['Bp monter', 'Bp arret', 'Bp descendre', 'Bp auto', 'Microrupteur haut', 'Microrupteur bas', 'Recepteur LDR']
output_objs = ['Moteur', 'Led auto']
jumeau_mode_system (input_objs, output_objs, input_real, input_digital, output_real, output_digital)
###############################################################################
# Cycle
###############################################################################