Bugfix capteur barrage du portail, documentation avec plusieurs textes suivante la variante de la maquette

This commit is contained in:
Philippe Roy 2024-01-18 01:49:39 +01:00
parent e113cb8dff
commit 38d41d9b69
11 changed files with 180 additions and 241 deletions

107
README.md
View File

@ -1,107 +0,0 @@
# Jumeaux numériques
<!-- # Digital Twin -->
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
<table>
<tr>
<td> <div> <a href="https://forge.aeif.fr"> <img src="img/la_forge-brigit_et_komit.svg" alt="Brigit et Komit"> </a> </div> </td>
<td> <div> Les fichiers sources sont dans le projet <b>Blender-Edutech / Jumeaux numériques</b> de La Forge des Communs Numériques Éducatifs :
https://forge.aeif.fr/blender-edutech/jumeau-numerique . </div> <div> &nbsp; </div> <div> 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). </div> <div> &nbsp; </div> <div> La version de Blender/UPBGE utilisée pour le développement est la version 0.36.1 (20 août
2023).</td>
</tr>
</table>
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)
<!-- - [**whell**](https://pyfirmata.readthedocs.io) : format de paquet Python -->
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
<!-- - Installer Pylint : $ ./pip install pylint -t ~/UPBGE-0.30-linux-x86_64/3.0/python/lib/python3.9/site-packages -->
<!-- - Installer pySerial : $ ./pip install pyserial -t ~/UPBGE-0.30-linux-x86_64/3.0/python/lib/python3.9/site-packages -->
<!-- - Installer pyFirmata : $ ./pip install pyfirmata -t ~/UPBGE-0.30-linux-x86_64/3.0/python/lib/python3.9/site-packages -->
<!-- - Installer Matplotlib : $ ./pip install matplotlib -t ~/UPBGE-0.30-linux-x86_64/3.0/python/lib/python3.9/site-packages -->
<!-- - Installer PyQt6 : $ ./pip install PyQt6 -t ~/UPBGE-0.30-linux-x86_64/3.0/python/lib/python3.9/site-packages -->
- **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
<!-- - **Windows** : La configuration ici présente est UPBGE installé sur le bureau utilisateur (prenom.nom) avec la distribution Anaconda installée : -->
<!-- - Avec Anaconda Navigator ouvrir un terminal Powershell -->
<!-- - Installer Pylint : pip install pylint -t C:\Users\prenom.nom\Desktop\UPBGE-0.30-windows-x86_64\3.0\python\lib\site-packages -->
<!-- - Installer pySerial : pip install pyserial -t C:\Users\prenom.nom\Desktop\UPBGE-0.30-windows-x86_64\3.0\python\lib\site-packages -->
<!-- - Installer pyFirmata : pip install pyfirmata -t C:\Users\prenom.nom\Desktop\UPBGE-0.30-windows-x86_64\3.0\python\lib\site-packages -->
<!-- - Installer Matplotlib : pip install matplotlib -t C:\Users\prenom.nom\Desktop\UPBGE-0.30-windows-x86_64\3.0\python\lib\site-packages -->
<!-- - Installer wxPython : pip install wxpython -t C:\Users\prenom.nom\Desktop\UPBGE-0.30-windows-x86_64\3.0\python\lib\site-packages -->

View File

@ -315,64 +315,53 @@ def fdc_f (cont):
def ir_emet (cont): def ir_emet (cont):
if scene.objects['System']['run'] : if scene.objects['System']['run'] :
obj = cont.owner 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 # Mouse over
if obj['mo'] == True and obj['click'] == False and obj.color !=color_hl: if obj['mo'] == True and obj['click'] == False and obj.color !=color_hl:
obj.color =color_hl obj.color =color_hl
return return
# Passif # Activation
if obj['active'] == False and obj.color !=color_passive: if obj['activated']:
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 # Modele 3D -> Arduino
if scene.objects['System']['twins'] and obj['prior_real']: if scene.objects['System']['twins'] and obj['prior_real']:
if scene.objects['Emetteur IR']['pin'] is not None: if obj['pin'] is not None:
scene.objects['Emetteur IR']['pin'].write(0) obj['pin'].write(1)
return
# Active # Désactivation
if obj['active']: if obj['activated']==False:
# Allumage # Modele 3D -> Arduino
if scene.objects['Emetteur IR Led-on'].visible == False: if scene.objects['System']['twins'] and obj['prior_real']:
if obj['pin'] is not None:
obj['pin'].write(0)
# Physique du modèle 3D # Forçage par clic
if obj['prior']: if obj['click'] == True and obj['prior']:
scene.objects['Emetteur IR Led-on'].setVisible(True,False) obj['activated'] = True
scene.objects['Emetteur IR Led'].setVisible(False,False)
obj.color = color_active
scene.objects['Recepteur IR']['active'] = True
# Modele 3D -> Arduino # Couleurs
if scene.objects['System']['twins'] and obj['prior_real']: # twin.cycle_sensitive_color(obj)
if scene.objects['Emetteur IR']['pin'] is not None: if obj['activated'] == True and obj.color !=color_activated:
scene.objects['Emetteur IR']['pin'].write(1) obj.color =color_activated
elif obj['activated'] == False and obj.color !=color_active:
# Forçage par clic obj.color =color_active
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
## ##
# Récepteur IR # Récepteur IR
# FIXME : Modele 3D -> Arduino à faire
## ##
def ir_recep (cont): def ir_recep (cont):
@ -384,36 +373,34 @@ def ir_recep (cont):
obj.color =color_hl obj.color =color_hl
return 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 # Passif
if obj['active'] == False and obj.color !=color_passive: if obj['active'] == False and obj.color !=color_passive:
obj.color =color_passive obj.color =color_passive
return return
# Active # Arduino -> Modele 3D
if obj['active']: 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 # Forçage par clic
if scene.objects['System']['twins'] and obj['prior_real']: if obj['click'] == True and obj['prior']:
if obj['pin'] is not None : obj['activated'] = False
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
# Couleurs # Couleurs
# FIXME : à faire twin.cycle_sensitive_color(obj)
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
############################################################################### ###############################################################################
# Système # Système
@ -440,9 +427,6 @@ def system_reset ():
for obj in objs: for obj in objs:
scene.objects[obj]['activated']=False scene.objects[obj]['activated']=False
scene.objects[obj]['activated_real']=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 # Grille à l'état initial
scene.objects['Portail']['x']=0 scene.objects['Portail']['x']=0
@ -474,12 +458,14 @@ def system_reset ():
scene.objects['Led-on'].setVisible(False,False) scene.objects['Led-on'].setVisible(False,False)
# Capteur barrage IR # Capteur barrage IR
scene.objects['Emetteur IR'].color = color_active
scene.objects['Emetteur IR']['activated'] =False 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'].setVisible(True,False)
scene.objects['Emetteur IR Led-on'].setVisible(False,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'].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 # Priorités activées
objs= ['Led', 'Moteur', 'Microrupteur fdc ouvert', 'Microrupteur fdc ferme', objs= ['Led', 'Moteur', 'Microrupteur fdc ouvert', 'Microrupteur fdc ferme',

View File

@ -13,7 +13,7 @@ from porcou_lib import * # Bibliothèque utilisateur du portail coulissant
# - Ouvrir le portail (moteur sens trigo) : mot_o(True | False) # - Ouvrir le portail (moteur sens trigo) : mot_o(True | False)
# - Fermer le portail (moteur sens horaire) : mot_f(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 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) # - Emetteur pour le capteur barrage IR : ir_emet(True | False)
# #
# Capteurs (valeur retournée = True ou False) : # Capteurs (valeur retournée = True ou False) :
@ -54,9 +54,11 @@ brochage={
'bp_ext' : ['d',6,'i'],'bp_int' : ['d',5,'i'], 'bp_ext' : ['d',6,'i'],'bp_int' : ['d',5,'i'],
'fdc_o' : ['a',1,'i'],'fdc_f' : ['a',0,'i'], 'fdc_o' : ['a',1,'i'],'fdc_f' : ['a',0,'i'],
'mot_v' : ['d',3,'p'], 'mot_s' : ['d',4,'o'], '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']} 'ir_emet' : ['d',7,'o'],'ir_recep' : ['d',8,'i']}
# 'gyr' : ['d',2,'o'],
# Motor Direction(Forward/Backward) Speed Speed range # Motor Direction(Forward/Backward) Speed Speed range
# M1 4 LOW HIGH 3 0-255 # M1 4 LOW HIGH 3 0-255
# M2 12 HIGH LOW 11 0-255 # M2 12 HIGH LOW 11 0-255
@ -75,30 +77,27 @@ def fermer():
gyr(True) gyr(True)
mot_o(False) mot_o(False)
mot_f(True) 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 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
ouvrir() ouvrir()
print ("Temporisation") ir_emet(True)
tempo(2) # Temporisation 2s
tempo(0.1) # Donne du temps à communication avec le jumeau réel tempo(0.1) # Donne du temps à communication avec le jumeau réel
gyr(False) gyr(False)
mot_f(False) mot_f(False)
ir_emet(False) ir_emet(False)
tempo(0.1) # Donne du temps à communication avec le jumeau réel
# Ouvrir le portail # Ouvrir le portail
def ouvrir(): def ouvrir():
print ("Ouverture") print ("Ouverture")
mot_f(False)
ir_emet(False)
while fdc_o() ==False: while fdc_o() ==False:
gyr(True) gyr(True)
mot_o(True) mot_o(True)
tempo(0.1) # Donne du temps à communication avec le jumeau réel tempo(0.1) # Donne du temps à communication avec le jumeau réel
gyr(False) gyr(False)
mot_o(False) mot_o(False)
tempo(0.1) # Donne du temps à communication avec le jumeau réel print ("Temporisation")
tempo(2) # Temporisation 2s
############################################################################### ###############################################################################
# Commandes # Commandes
@ -113,23 +112,27 @@ def commandes():
mot_vitesse_r(100) mot_vitesse_r(100)
fermer() 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 # Jumelage
print ("Attente") print ("Attente")
jumeau(brochage) # jumeau(brochage)
# Fonctionnement normal # Fonctionnement normal
while True : while True :
tempo(0.1) # Donne du temps à communication avec le jumeau réel tempo(0.1) # Donne du temps à communication avec le jumeau réel
# Ouverture # Ouverture + Tempo
if bp_int() or bp_ext() : if bp_int() or bp_ext() :
mot_vitesse(1000)
mot_vitesse_r(200) mot_vitesse_r(200)
ouvrir() ouvrir()
print ("Temporisation")
tempo(2) # Temporisation 2s
# Fermeture # Fermeture
mot_vitesse(100)
mot_vitesse_r(100) mot_vitesse_r(100)
fermer() fermer()
print ("Attente") print ("Attente")
@ -138,8 +141,8 @@ def commandes():
# En: External call << DONT CHANGE THIS SECTION >> # En: External call << DONT CHANGE THIS SECTION >>
# Fr: Appel externe << NE PAS MODIFIER CETTE 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 1 (par défaut) : Maquette 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 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': if __name__=='stop':
stop() stop()
if __name__=='init': if __name__=='init':
variant(1) # Variante Grove variant(1) # Variante maquette Grove

View File

@ -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) """ Pour le moteur (maquette AutoProg) : \n 'mot_o' (ouvrir) et 'mot_f' (fermer) """
card_pin_url=[] 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 # Données
card_data_title="Accès aux données" card_data_title="Accès aux données"

View File

@ -55,14 +55,14 @@ def mot_f (order):
def mot_vitesse (speed=125.6): def mot_vitesse (speed=125.6):
scene.objects['Moteur']['speed_setting']=speed # Vitesse du moteur numérique : 125.6 rad /s ( 20 tr / s ) 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 # Valeur par défaut est 255
def mot_vitesse_r (speed=255): def mot_vitesse_r (speed=255):
scene.objects['Moteur']['speed_real_setting']=speed scene.objects['Moteur']['speed_real_setting']=speed
# Ordre pour le capteur barrage IR # Ordre pour le capteur barrage IR
def ir_emet(order): def ir_emet(order):
scene.objects['Emetteur IR']['active']=order scene.objects['Emetteur IR']['activated']=order
############################################################################### ###############################################################################
# Capteurs # Capteurs
@ -81,11 +81,11 @@ def fdc_f ():
return False return False
# Compte-rendu du capteur barrage IR # 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 (): def ir_recep ():
if scene.objects['Recepteur IR']['activated'] or scene.objects['Recepteur IR']['activated_real']: if scene.objects['Recepteur IR']['activated'] == False or scene.objects['Recepteur IR']['activated_real'] == False:
return True return False
return False return True
############################################################################### ###############################################################################
# Boutons poussoirs # Boutons poussoirs
@ -162,31 +162,8 @@ def start(fct):
def variant(variant_num): def variant(variant_num):
if variant_num != scene.objects['System']['variant']: 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 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 # FIXME : Affichage de la maquette Grove -> plus tards
# variant_dict = {'Bp auto':[1], 'Bg auto':[2], 'Bg auto-on':[2]} # variant_dict = {'Bp auto':[1], 'Bg auto':[2], 'Bg auto-on':[2]}

72
twin.py
View File

@ -641,7 +641,7 @@ def cycle_hl(cont):
obj.color = color_active 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): def cycle_click(cont):
@ -662,7 +662,7 @@ def cycle_click(cont):
obj['click'] = True obj['click'] = True
# Désactivation # 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['activated'] = False
obj['click'] = False obj['click'] = False
if cont.sensors['MO'].positive: if cont.sensors['MO'].positive:
@ -670,6 +670,72 @@ def cycle_click(cont):
else: else:
obj.color = color_active 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) # 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 # 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) # obj_on : objet numérique à l'état activé (si différent)
## ##

View File

@ -1,8 +1,8 @@
<data> <data>
<screen> <screen>
<width>1609</width> <width>1341</width>
<height>905</height> <height>754</height>
<quality>0</quality> <quality>4</quality>
</screen> </screen>
<plot> <plot>
<config>True</config> <config>True</config>

View File

@ -578,7 +578,13 @@ def text_dynamic_load():
# Création des objets 3D # Création des objets 3D
for card in card_description: 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): for i in range (13):
doc_text= scene.addObject('Doc_text-l'+str(i+1), None, 0.00, True) doc_text= scene.addObject('Doc_text-l'+str(i+1), None, 0.00, True)
doc_text.setParent(scene.objects['Doc']) doc_text.setParent(scene.objects['Doc'])

View File

@ -99,12 +99,14 @@ def serial_open():
if device is None: if device is None:
scene.objects['System']['twins'] = False scene.objects['System']['twins'] = False
scene.objects['Twins-text']['Text'] = "Aucune connection disponible : jumeau réel débranché." 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) board = board_init(device)
if board is None: if board is None:
scene.objects['System']['twins'] = False scene.objects['System']['twins'] = False
scene.objects['Twins-text']['Text'] = "Aucune connection disponible : port "+device+" pas prêt." 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 scene.objects['System']['twins'] = True
board_it = pyfirmata.util.Iterator(board) # Itérateur pour les entrées board_it = pyfirmata.util.Iterator(board) # Itérateur pour les entrées
board_it.start() board_it.start()
@ -115,7 +117,7 @@ def serial_open():
else: else:
scene.objects['Twins-text']['Text'] = "Connection ouverte : "+board_name+" sur "+device+" à "+str(speed)+" baud." scene.objects['Twins-text']['Text'] = "Connection ouverte : "+board_name+" sur "+device+" à "+str(speed)+" baud."
time.sleep(0.1) time.sleep(0.1)
return (board) return board, True
## ##
# Fermeture de la communication série # Fermeture de la communication série
@ -127,6 +129,7 @@ def serial_close(board):
board.exit() # Fermer proprement la communication avec la carte board.exit() # Fermer proprement la communication avec la carte
time.sleep(0.1) time.sleep(0.1)
scene.objects['System']['twins'] = False scene.objects['System']['twins'] = False
print ("Jumelage : connection fermée.")
# Configuration manuelle du port # Configuration manuelle du port
# FIXME : plus tard # FIXME : plus tard
@ -161,7 +164,10 @@ def config(port, speed):
def jumeau_get_pin(board, name, brochage): def jumeau_get_pin(board, name, brochage):
for pin in brochage : for pin in brochage :
if pin ==name: 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 return None
## ##
@ -171,9 +177,11 @@ def jumeau_get_pin(board, name, brochage):
def jumeau (brochage=None): def jumeau (brochage=None):
# Carte # Carte
board =serial_open() board, board_ok =serial_open()
if board_ok == False:
return None
scene.objects['System']['board']=board scene.objects['System']['board']=board
# print ("jumeau : ", scene.objects['System']['board']) print ("Jumelage :", scene.objects['System']['board'])
# Brochage # Brochage
if brochage is not None: if brochage is not None:

Binary file not shown.