diff --git a/README.md b/README.md deleted file mode 100644 index c23829f..0000000 --- a/README.md +++ /dev/null @@ -1,107 +0,0 @@ -# Jumeaux numériques - - -Un jumeau numérique d'un système technique permet de visualiser son comportement à travers une maquette numérique. Le principal intérêt est de valider un -modèle comportemental d'abords par la simulation (avant mise en oeuvre du jumeau réel) puis expérimentalement (mesure des écarts entre les deux jumeaux). - -Ici le jumeau numérique d'un système pluritechnologique va nous servir à programmer le système en simulant (hors ligne) son évolution. Nous pourrons alors -mettre en lien les deux jumeaux et appliquer les règles programmées sur le jumeau réel. - -Lors de l'exécution du cycle, tous écarts entre les deux jumeaux seront mesurés afin de corriger le modèle comportemental. Par aileurs, les évènements -numériques impacteront le jumeau réel et les évènements réels impacteront aussi le jumeau numérique. - -**Systèmes** : - -* [Monte-charge](https://forge.aeif.fr/blender-edutech/jumeau-numerique/-/tree/main/monte_charge) -* [Portail coulissant](https://forge.aeif.fr/blender-edutech/jumeau-numerique/-/tree/main/portail_coulissant) -* [Volet roulant](https://forge.aeif.fr/blender-edutech/jumeau-numerique/-/tree/main/volet_roulant) - -Systèmes dont le jumeau numérique est cours de développement : -* Labyrinthe à bille : [tutoriel à destination des enseignants souhaitant découvrir la plateforme UPBGE](https://forge.aeif.fr/blender-edutech/blender-edutech-tuto/-/tree/main/labyrinthe) -* Bras robotisé Poppy Ergo Jr ([Poppy](https://www.poppy-project.org/en/robots/poppy-ergo-jr/)) -* Robot haptique ([SET](https://setdidact.com/voie-generale-et-technologique/sciences-de-lingenieur/)) -* Cobot souple ([Dossier personnel](https://nuage03.apps.education.fr/index.php/s/PMFdMPWprEZoWiR?path=%2F2022)) - -[![Jumeaux numériques présentation](img/lien_video.png)](https://tube-sciences-technologies.apps.education.fr/w/7B1BtC92PTW5dmRfJPsKhk) - -## Jumelage numérique - -Le jumelage numérique est basé sur la liaison série entre l'ordinateur (port USB) et un microcontrôleur Arduino (Uno ou Mega). Suivant les jumeaux numériques, -le protocole de communication peut être le protocole générique Firmata ou un protocole spécifique. - -[![Vidéo du test de jumelage du portail coulissant](img/lien_video-2.png)](https://tube-sciences-technologies.apps.education.fr/w/sVSgBfGssESLBhHGMg98AR) - -## Téléchargement - -Les binaires (Game Engine Runtime) sont hébergés sur [phroy.org](https://www.phroy.org/twin.html). - -## Ressources pédagogiques - -Les applications pédagogique se trouvent dans le [dépôt des ressouces pédagogiques du projet Blender-EduTech](https://forge.aeif.fr/blender-edutech/blender-edutech-peda) : -- [Enseignements de la spécialité Sciences de l'Ingénieur](https://forge.aeif.fr/blender-edutech/blender-edutech-peda/-/tree/main/Lycee/programmation_python/si/jumeau_numerique). - -## Développement - - - - - - -
Brigit et Komit
Les fichiers sources sont dans le projet Blender-Edutech / Jumeaux numériques de La Forge des Communs Numériques Éducatifs : - https://forge.aeif.fr/blender-edutech/jumeau-numerique .
 
L'environnement de développement est basé sur : la plateforme de - modélisation et d'animation 3D [Blender](https://blender.org), le langage [Python](https://python.org) et le moteur de jeu 3D - [UPBGE](https://upbge.org).
 
La version de Blender/UPBGE utilisée pour le développement est la version 0.36.1 (20 août - 2023).
- -Les bibliothèques suivantes ne sont pas incluses par défaut dans l'environnement UPBGE : -- [**Pylint**](https://pylint.pycqa.org) : vérificateur de code Python -- [**pySerial**](https://pyserial.readthedocs.io) : communication sur le port série -- [**pyFirmata**](https://pyfirmata.readthedocs.io) : protocole Firmata (protocole générique de communication entre un logiciel et un microcontrôleur) -- [**Matplotlib**](https://matplotlib.org) : grapheur (visualisation de données) -- [**wxPython**](https://www.wxpython.org/) : interface graphique utilisateur (GUI, utilisé ici pour Windows) -- [**pyQt6**](https://www.riverbankcomputing.com/software/pyqt/) : interface graphique utilisateur (GUI, utilisé ici pour GNU/Linux) - - - -Il faut donc les installer localement (dans UPBGE), les étapes sont : -- **GNU/Linux** : La configuration ici présente est UPBGE installé sur ~ avec Python 3.10 : - - Aller dans le répertoire local de Python de UPBGE: $ cd ~/upbge-0.36.1-linux-x86_64/3.6/python/bin - - Télécharger le script ['get-pip.py'](https://bootstrap.pypa.io/get-pip.py) pour installer le gestionnaire de paquet [**Pip**](https://pip.pypa.io) - - Installer le gestionnaire de paquet Pip : $ ./python3.10 get-pip.py - - Installer Pylint : $ ./pip install pylint - - Installer pySerial : $ ./pip install pyserial - - Installer pyFirmata : $ ./pip install pyfirmata - - Installer Matplotlib : $ ./pip install matplotlib - - Installer PyQt6 : $ ./pip install PyQt6 - - - - - - - -- **Windows** : La configuration ici présente est UPBGE installé sur le bureau utilisateur (prenom.nom) : - - Ouvrir un terminal Powershell (éventuellement en passant par Anaconda Navigator) - - Aller dans le répertoire local de Python de UPBGE: cd C:\Users\prenom.nom\Desktop\upbge-0.36.1-windows-x86_64\3.6\python\bin - - Télécharger le script ['get-pip.py'](https://bootstrap.pypa.io/get-pip.py) pour installer le gestionnaire de paquet [**Pip**](https://pip.pypa.io) - - Installer le gestionnaire de paquet Pip : python.exe get-pip.py - - Aller dans le répertoire 'Scripts' : cd C:\Users\prenom.nom\Desktop\upbge-0.36.1-windows-x86_64\3.6\python\Scripts - - Installer Pylint : pip.exe install pylint - - Installer pySerial : pip.exe install pyserial - - Installer pyFirmata : pip.exe install pyfirmata - - Installer Matplotlib : pip.exe install matplotlib - - Installer wxPython : pip.exe install wxpython - -- Si l'installation des paquets Python ne se fait pas dans le bon répertoire ('site-packages' des bibliothèques du Python embarqué par UPBGE), il faut allors spécifier le répertoire cible avec - l'option '-t target' lors de la commande 'pip install'. Par exemple pour Pylint : - - **GNU/Linux** : $ ./pip install pylint -t ~/upbge-0.36.1-linux-x86_64/3.6/python/lib/python3.10/site-packages - - **Windows** : $ pip.exe install pylint -t C:\Users\prenom.nom\Desktop\upbge-0.36.1-windows-x86_64\3.6\python\lib\site-packages - - - - - - - - - diff --git a/portail_coulissant/porcou.py b/portail_coulissant/porcou.py index e84a651..3d4e930 100644 --- a/portail_coulissant/porcou.py +++ b/portail_coulissant/porcou.py @@ -315,64 +315,53 @@ def fdc_f (cont): def ir_emet (cont): if scene.objects['System']['run'] : obj = cont.owner + obj_off = scene.objects['Emetteur IR Led'] + obj_on = scene.objects['Emetteur IR Led-on'] + + # Gestion de la led (Physique du modèle 3D) + if obj['activated']: + if obj_on.visible == False and obj['prior']: + obj_on.setVisible(True,False) + obj_off.setVisible(False,False) + else: + if obj_on.visible == True and obj['prior']: + obj_on.setVisible(False,False) + obj_off.setVisible(True,False) # Mouse over if obj['mo'] == True and obj['click'] == False and obj.color !=color_hl: obj.color =color_hl return - - # 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 + + # Activation + if obj['activated']: # Modele 3D -> Arduino 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 + if obj['pin'] is not None: + obj['pin'].write(1) - # Active - if obj['active']: + # Désactivation + if obj['activated']==False: - # Allumage - if scene.objects['Emetteur IR Led-on'].visible == False: + # Modele 3D -> Arduino + if scene.objects['System']['twins'] and obj['prior_real']: + if obj['pin'] is not None: + obj['pin'].write(0) - # 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 + # Forçage par clic + if obj['click'] == True and obj['prior']: + obj['activated'] = True - # Modele 3D -> Arduino - 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 and obj['prior']: - obj['activated'] = True - scene.objects['Recepteur IR']['activated'] = True - - # Couleurs - # FIXME : à faire - if obj['activated'] == True and obj.color !=color_activated: - obj.color =color_activated - if obj['activated'] == False : - if obj['mo'] == True and obj.color !=color_hl: - obj.color =color_hl - if obj['mo'] == False and obj.color !=color_active: - obj.color =color_active + # Couleurs + # twin.cycle_sensitive_color(obj) + if obj['activated'] == True and obj.color !=color_activated: + obj.color =color_activated + elif obj['activated'] == False and obj.color !=color_active: + obj.color =color_active ## # Récepteur IR -# FIXME : Modele 3D -> Arduino à faire ## def ir_recep (cont): @@ -384,36 +373,34 @@ def ir_recep (cont): obj.color =color_hl return + # Lien avec l'émetteur + if obj['click'] == False: + if scene.objects['Emetteur IR']['activated'] == False and obj['active']: + obj['active'] = False + obj['actived'] = False + if scene.objects['Emetteur IR']['activated'] and obj['active'] == False: + obj['active'] = True + obj['actived'] = True + # Passif if obj['active'] == False and obj.color !=color_passive: obj.color =color_passive return - # Active - if obj['active']: + # Arduino -> Modele 3D + 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 + if obj['pin'].read()==False and obj['activated_real'] == True : + obj['activated_real'] = False - # 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 and obj['prior']: - obj['activated'] = True - scene.objects['Emetteur IR']['activated'] = True + # Forçage par clic + if obj['click'] == True and obj['prior']: + obj['activated'] = False - # Couleurs - # FIXME : à faire - if obj['activated'] == True and obj.color !=color_activated: - obj.color =color_activated - if obj['activated'] == False : - if obj['mo'] == True and obj.color !=color_hl: - obj.color =color_hl - if obj['mo'] == False and obj.color !=color_active: - obj.color =color_active + # Couleurs + twin.cycle_sensitive_color(obj) ############################################################################### # Système @@ -440,9 +427,6 @@ def system_reset (): for obj in objs: scene.objects[obj]['activated']=False scene.objects[obj]['activated_real']=False - scene.objects['Recepteur IR']['activated'] =False - scene.objects['Recepteur IR']['active'] =False - scene.objects['Recepteur IR']['activated_real'] =True # Absence d'obstacle -> True, présence d'obstacle -> False # Grille à l'état initial scene.objects['Portail']['x']=0 @@ -474,12 +458,14 @@ def system_reset (): scene.objects['Led-on'].setVisible(False,False) # Capteur barrage IR + scene.objects['Emetteur IR'].color = color_active scene.objects['Emetteur IR']['activated'] =False - scene.objects['Emetteur IR']['active'] =False scene.objects['Emetteur IR Led'].setVisible(True,False) scene.objects['Emetteur IR Led-on'].setVisible(False,False) - scene.objects['Emetteur IR'].color = color_passive scene.objects['Recepteur IR'].color = color_passive + scene.objects['Recepteur IR']['active'] =False + scene.objects['Recepteur IR']['activated'] =True # Absence d'obstacle -> True, présence d'obstacle -> False + scene.objects['Recepteur IR']['activated_real'] =True # Absence d'obstacle -> True, présence d'obstacle -> False # Priorités activées objs= ['Led', 'Moteur', 'Microrupteur fdc ouvert', 'Microrupteur fdc ferme', diff --git a/portail_coulissant/porcou_cmd.py b/portail_coulissant/porcou_cmd.py index 49bb6e2..dbe0d26 100644 --- a/portail_coulissant/porcou_cmd.py +++ b/portail_coulissant/porcou_cmd.py @@ -13,7 +13,7 @@ from porcou_lib import * # Bibliothèque utilisateur du portail coulissant # - Ouvrir le portail (moteur sens trigo) : mot_o(True | False) # - Fermer le portail (moteur sens horaire) : mot_f(True | False) # - Définir la vitesse du moteur jumeau numérique : mot_vitesse (vitesse) , vitesse en rad / s, si vitesse est omis la valeur par défaut est 125.6 rad /s ( 20 tr / s )) -# - Définir la vitesse du moteur jumeau réel : mot_vitesse_r (vitesse) , vitesse de 0 à 255, la valeur par défaut est 255 +# - Définir la vitesse du moteur jumeau réel : mot_vitesse_r (vitesse) , vitesse de 0 à 255, la valeur par défaut est 255 (uniquement sur la maquette Grove) # - Emetteur pour le capteur barrage IR : ir_emet(True | False) # # Capteurs (valeur retournée = True ou False) : @@ -54,9 +54,11 @@ brochage={ 'bp_ext' : ['d',6,'i'],'bp_int' : ['d',5,'i'], 'fdc_o' : ['a',1,'i'],'fdc_f' : ['a',0,'i'], 'mot_v' : ['d',3,'p'], 'mot_s' : ['d',4,'o'], - 'gyr' : ['d',2,'o'], + 'gyr' : [], 'ir_emet' : ['d',7,'o'],'ir_recep' : ['d',8,'i']} + # 'gyr' : ['d',2,'o'], + # Motor Direction(Forward/Backward) Speed Speed range # M1 4 LOW HIGH 3 0-255 # M2 12 HIGH LOW 11 0-255 @@ -75,30 +77,27 @@ def fermer(): gyr(True) mot_o(False) mot_f(True) - tempo(0.1) # Donne du temps à communication avec le jumeau réel - # if ir_recep()==False or bp_int() or bp_ext() : # Ouverture en cas présence d'obstacle ou boutons - if bp_int() or bp_ext() : # Ouverture en cas présence d'obstacle ou boutons - mot_f(False) - tempo(0.1) # Donne du temps à communication avec le jumeau réel + if ir_recep()==False or bp_int() or bp_ext() : #Ouverture en cas présence d'obstacle ou boutons ouvrir() - print ("Temporisation") - tempo(2) # Temporisation 2s + ir_emet(True) tempo(0.1) # Donne du temps à communication avec le jumeau réel gyr(False) mot_f(False) ir_emet(False) - tempo(0.1) # Donne du temps à communication avec le jumeau réel # Ouvrir le portail def ouvrir(): print ("Ouverture") + mot_f(False) + ir_emet(False) while fdc_o() ==False: gyr(True) mot_o(True) tempo(0.1) # Donne du temps à communication avec le jumeau réel gyr(False) mot_o(False) - tempo(0.1) # Donne du temps à communication avec le jumeau réel + print ("Temporisation") + tempo(2) # Temporisation 2s ############################################################################### # Commandes @@ -113,23 +112,27 @@ def commandes(): mot_vitesse_r(100) fermer() + # Données + # daq(['mot_angle', 'mot_vitesse', 'portail_x', 'portail_vitesse', 'mot_v', 'mot_s']) + # plot(['mot_angle', 'mot_vitesse', 'portail_x', 'portail_vitesse', 'mot_v', 'mot_s']) + # reset_t() + # Jumelage print ("Attente") - jumeau(brochage) + # jumeau(brochage) # Fonctionnement normal while True : tempo(0.1) # Donne du temps à communication avec le jumeau réel - # Ouverture + # Ouverture + Tempo if bp_int() or bp_ext() : + mot_vitesse(1000) mot_vitesse_r(200) ouvrir() - print ("Temporisation") - tempo(2) # Temporisation 2s - # Fermeture + mot_vitesse(100) mot_vitesse_r(100) fermer() print ("Attente") @@ -138,8 +141,8 @@ def commandes(): # En: External call << DONT CHANGE THIS SECTION >> # Fr: Appel externe << NE PAS MODIFIER CETTE SECTION >> # -# Variante 1 (par défaut) : version Grove : la carte moteur est le shield moteur Arduino CC 4 x 1,2 A DRI0039 (DFROBOT) -# Variante 2 : version AutoProg : la carte moteur est le module AutoProg K-AP-MMOT-KIT +# Variante 1 (par défaut) : Maquette Grove : la carte moteur est le shield moteur Arduino CC 4 x 1,2 A DRI0039 (DFROBOT) +# Variante 2 : Maquette AutoProg (A4 Technologie) : la carte moteur est le module AutoProg K-AP-MMOT-KIT # ############################################################################### @@ -152,4 +155,4 @@ if __name__=='start': if __name__=='stop': stop() if __name__=='init': - variant(1) # Variante Grove + variant(1) # Variante maquette Grove diff --git a/portail_coulissant/porcou_doc.py b/portail_coulissant/porcou_doc.py index 6976629..4730658 100644 --- a/portail_coulissant/porcou_doc.py +++ b/portail_coulissant/porcou_doc.py @@ -60,7 +60,7 @@ card_pin_text_autoprog=""" Le brochage est un dictionnaire d'association \n des Pour le moteur (maquette AutoProg) : \n 'mot_o' (ouvrir) et 'mot_f' (fermer) """ card_pin_url=[] -system_card_description.update({"pin-card" : [card_pin_title, card_pin_text_grove, card_pin_url, card_pin_text_autoprog]}) # Deux descriptions +system_card_description.update({"pin-card" : [card_pin_title, [card_pin_text_grove, card_pin_text_autoprog] , card_pin_url]}) # Deux descriptions # Données card_data_title="Accès aux données" diff --git a/portail_coulissant/porcou_lib.py b/portail_coulissant/porcou_lib.py index 991f2ed..ec21d06 100644 --- a/portail_coulissant/porcou_lib.py +++ b/portail_coulissant/porcou_lib.py @@ -55,14 +55,14 @@ def mot_f (order): def mot_vitesse (speed=125.6): scene.objects['Moteur']['speed_setting']=speed # Vitesse du moteur numérique : 125.6 rad /s ( 20 tr / s ) -# Réglage de la vitesse du moteur réel (uniquement sur la maquette Grove, de 0 à 255) +# Réglage de la vitesse du moteur réel (de 0 à 255, uniquement sur la maquette Grove) # Valeur par défaut est 255 def mot_vitesse_r (speed=255): scene.objects['Moteur']['speed_real_setting']=speed # Ordre pour le capteur barrage IR def ir_emet(order): - scene.objects['Emetteur IR']['active']=order + scene.objects['Emetteur IR']['activated']=order ############################################################################### # Capteurs @@ -81,11 +81,11 @@ def fdc_f (): return False # Compte-rendu du capteur barrage IR -# Absence d'obstacle -> True, présence d'obstacle -> False +# Absence d'obstacle -> True (par défaut), présence d'obstacle -> False def ir_recep (): - if scene.objects['Recepteur IR']['activated'] or scene.objects['Recepteur IR']['activated_real']: - return True - return False + if scene.objects['Recepteur IR']['activated'] == False or scene.objects['Recepteur IR']['activated_real'] == False: + return False + return True ############################################################################### # Boutons poussoirs @@ -162,31 +162,8 @@ def start(fct): def variant(variant_num): if variant_num != scene.objects['System']['variant']: - print ("Variante de la maquette numérique:", variant_num) + print ("Variante de la maquette numérique :", variant_num) scene.objects['System']['variant']=variant_num - - # FIXME : MaJ de la documentation dynamique -> plus tards - # if 'Doc_text-l1-pin-card' in scene.objects: - # card_description ={} - # system=importlib.import_module(scene.objects['System']['system']+'_doc') # Système - # card_description.update(system.get_system_card_description()) - # if variant_num == 1 : # Grove (par défaut) - # lines = card_description["pin-card"][1].split("\n") - # if variant_num == 2 : # Autoprog (par défaut) - # lines = card_description["pin-card"][3].split("\n") - - # print (lines) - # print (scene.objects) - - # for i in range (13): - # if i >= len(lines): - # scene.objects['Doc_text-l'+str(i+1)+'-pin-card']['Text']="" - # else: - # if len(lines[i]) ==0: - # scene.objects['Doc_text-l'+str(i+1)+'-pin-card']['Text']="" - # else: - # scene.objects['Doc_text-l'+str(i+1)+'-pin-card'].blenderObject.data.body=lines[i] # Bug de la propriétés 'Text' (UPBGE) -> passage par 'body' de bpy (Blender) - # FIXME : Affichage de la maquette Grove -> plus tards # variant_dict = {'Bp auto':[1], 'Bg auto':[2], 'Bg auto-on':[2]} diff --git a/portail_coulissant/portail_coulissant-18.blend b/portail_coulissant/portail_coulissant-18.blend index 8218937..17ef88e 100644 Binary files a/portail_coulissant/portail_coulissant-18.blend and b/portail_coulissant/portail_coulissant-18.blend differ diff --git a/twin.py b/twin.py index 86283d2..a04d257 100644 --- a/twin.py +++ b/twin.py @@ -641,7 +641,7 @@ def cycle_hl(cont): obj.color = color_active ## -# Click sur les éléments cliquables du système (activation numérique) +# Click sur les éléments cliquables normalement ouverts (NO) du système (activation numérique) ## def cycle_click(cont): @@ -662,7 +662,7 @@ def cycle_click(cont): obj['click'] = True # Désactivation - if cont.sensors['Click'].status == JUST_RELEASED and obj['prior']: + if cont.sensors['Click'].status == JUST_RELEASED and cont.sensors['MO'].positive and obj['prior']: obj['activated'] = False obj['click'] = False if cont.sensors['MO'].positive: @@ -670,6 +670,72 @@ def cycle_click(cont): else: obj.color = color_active +## +# Click sur les éléments cliquables normalement fermés (NC) +# Lors de l'activation la valeur est False +## + +def cycle_click_nc(cont): + obj = cont.owner + if scene.objects['System']['run'] ==False: + return + + # Passif + if "active" in obj.getPropertyNames(): + if obj['active'] == False: + obj.color = color_passive + return + + # Activation + if cont.sensors['Click'].status == JUST_ACTIVATED and cont.sensors['MO'].positive and scene.objects['System']['manip_mode']==0 and obj['prior']: + obj.color = color_active + obj['activated'] = False + obj['click'] = True + + # Désactivation + if cont.sensors['Click'].status == JUST_RELEASED and cont.sensors['MO'].positive and obj['prior']: + obj['activated'] = True + obj['click'] = False + if cont.sensors['MO'].positive: + obj.color = color_hl + else: + obj.color = color_activated + +## +# Click sur les éléments rémanents (activation numérique) +# Lors de la désactivation, activated reprend la valeur d'avant le click +## + +def cycle_click_persistent(cont): + obj = cont.owner + if scene.objects['System']['run'] ==False: + return + + # Passif + if "active" in obj.getPropertyNames(): + if obj['active'] == False: + obj.color = color_passive + return + + # Activation + if cont.sensors['Click'].status == JUST_ACTIVATED and cont.sensors['MO'].positive and scene.objects['System']['manip_mode']==0 and obj['prior']: + obj.color = color_activated + obj['activated_prev'] = obj['activated'] + obj['activated'] = True + obj['click'] = True + + # Désactivation + if cont.sensors['Click'].status == JUST_RELEASED and cont.sensors['MO'].positive and obj['prior']: + obj['activated'] = obj['activated_prev'] + obj['click'] = False + if cont.sensors['MO'].positive: + obj.color = color_hl + else: + if obj['activated_prev'] : + obj.color = color_activated + else: + obj.color = color_active + obj['activated_prev'] = False ## # Click sur les éléments commutables du système (activation numérique) @@ -716,7 +782,7 @@ def cycle_switch(cont): ## # Couleurs sur les éléments sensibles du système -# obj : objet numérique +# obj : objet numériquegb # obj_on : objet numérique à l'état activé (si différent) ## diff --git a/twin_config.xml b/twin_config.xml index b87016d..9fa47d7 100644 --- a/twin_config.xml +++ b/twin_config.xml @@ -1,8 +1,8 @@ - 1609 - 905 - 0 + 1341 + 754 + 4 True diff --git a/twin_doc.py b/twin_doc.py index c881278..9ce4447 100644 --- a/twin_doc.py +++ b/twin_doc.py @@ -578,7 +578,13 @@ def text_dynamic_load(): # Création des objets 3D for card in card_description: - lines = card_description[card][1].split("\n") + if len(card_description[card][1][0])>1: + if scene.objects['System']['variant']-1 >len(card_description[card][1]): + lines = card_description[card][1][scene.objects['System']['variant']-1].split("\n") # Plusieurs versions de la description (fonction de la variante) + else: + lines = card_description[card][1][0].split("\n") # Si le nombre de description est inférieur au numéro de variante -> la description 1 est prise par défaut + else: + lines = card_description[card][1].split("\n") for i in range (13): doc_text= scene.addObject('Doc_text-l'+str(i+1), None, 0.00, True) doc_text.setParent(scene.objects['Doc']) diff --git a/twin_serial.py b/twin_serial.py index 3adefa3..59d0c6e 100644 --- a/twin_serial.py +++ b/twin_serial.py @@ -99,12 +99,14 @@ def serial_open(): if device is None: scene.objects['System']['twins'] = False scene.objects['Twins-text']['Text'] = "Aucune connection disponible : jumeau réel débranché." - return False + print ("Jumelage : aucune connection disponible, jumeau réel débranché.") + return None, False board = board_init(device) if board is None: scene.objects['System']['twins'] = False scene.objects['Twins-text']['Text'] = "Aucune connection disponible : port "+device+" pas prêt." - return False + print ("Jumelage : aucune connection disponible : port "+device+" pas prêt.") + return None, False scene.objects['System']['twins'] = True board_it = pyfirmata.util.Iterator(board) # Itérateur pour les entrées board_it.start() @@ -115,7 +117,7 @@ def serial_open(): else: scene.objects['Twins-text']['Text'] = "Connection ouverte : "+board_name+" sur "+device+" à "+str(speed)+" baud." time.sleep(0.1) - return (board) + return board, True ## # Fermeture de la communication série @@ -127,6 +129,7 @@ def serial_close(board): board.exit() # Fermer proprement la communication avec la carte time.sleep(0.1) scene.objects['System']['twins'] = False + print ("Jumelage : connection fermée.") # Configuration manuelle du port # FIXME : plus tard @@ -161,7 +164,10 @@ def config(port, speed): def jumeau_get_pin(board, name, brochage): for pin in brochage : if pin ==name: - return board.get_pin(brochage[pin][0]+':'+str(brochage[pin][1])+':'+brochage[pin][2]) + if len (brochage[pin])==3: + return board.get_pin(brochage[pin][0]+':'+str(brochage[pin][1])+':'+brochage[pin][2]) + else: + print ("Jumelage : adressage incomplet de l'objet 3D :", pin) return None ## @@ -171,9 +177,11 @@ def jumeau_get_pin(board, name, brochage): def jumeau (brochage=None): # Carte - board =serial_open() + board, board_ok =serial_open() + if board_ok == False: + return None scene.objects['System']['board']=board - # print ("jumeau : ", scene.objects['System']['board']) + print ("Jumelage :", scene.objects['System']['board']) # Brochage if brochage is not None: diff --git a/volet_roulant/volet_roulant-18.blend b/volet_roulant/volet_roulant-18.blend index e8f404e..ae8ec0c 100644 Binary files a/volet_roulant/volet_roulant-18.blend and b/volet_roulant/volet_roulant-18.blend differ