 |
 |
LEADER MONDIAL
DEPUIS
PLUS DE 15 ANS !
|
|
-
- Cet exemple se contente de commander un
moteur raccordé à la sortie "io(MOTEUR_3)" à
partir d'un contact branché sur l'entrée "En(5)".
-
- Les appellations "MOTEUR_3" et
"5" sont librement choisies par le programmeur.
-
- L'analyse va donc aboutir au dessin du
graphe suivant :
 |
Actions
(initialisations):
io(MOTEUR_3)
= 0
étape suivante = 1 |
 |
conditions:
IF En(5) < > 1 THEN rien (attente) |
 |
- Actions
:
io(MOTEUR_3) = 1
étape suivante = 2
|
 |
conditions:
IF En(5) < > 0 THEN rien (attente) |
 |
- Actions
:
io(MOTEUR_3) = 0
étape suivante = 1
|
Or ce graphe sera directement transcrit en
programme, sans aucune étude intermédiaire !
Les connaisseurs apprécieront l'astuce qui
consiste à assurer une maîtrise totale de la synchronisation
par la variable "étape". Ce souci de synchronisation
est constant dans tout le système de programmation, ce qui
affranchit l'utilisateur des aléas de la programmation événementielle
non synchronisée.
Ainsi, entre autres, toutes les entrées sont
lues et toutes les sorties sont positionnées en même temps, évitant
complètement les aberrations de comportement du système !
Voici donc le programme correspondant :
SUB
Graphe1 ()
STATIC etape AS INTEGER
SELECT CASE etape:CASE 0:
io(MOTEUR_3)
= 0
etape = 1
CASE
1:
IF
En(5) < > 1 THEN EXIT SUB
- io(MOTEUR_3) = 1
- etape = 2
CASE
2:
IF
En(5) < > 0 THEN EXIT SUB
io(MOTEUR_3)
= 0
etape = 1
END
SELECT
END SUB
|
Qui dit mieux ?
Pour la lisibilité et la maintenance, nous
allons lui rajouter des commentaires:
SUB
Graphe1 ()
STATIC etape AS INTEGER ' = variable permanente
'===========================================================
' Principe du Multi-Tâche du système GRAPH-7:
' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
' - chaque graphe est un programme autonome
' - les tests sont toujours simples et rapides
' - ne jamais inclure de calculs dans une condition.
'===========================================================SELECT CASE
etape:
CASE
0:'------------- initialisation: --------------
io(MOTEUR_3)
= 0
etape = 1
CASE
1:'------------- attente condition: -----------
IF
En(5) < > 1 THEN EXIT SUB ' tester l'entrée
'--------------
actions de l'étape 1: ---------
io(MOTEUR_3)
= 1 ' sortie de commande du moteur
etape = 2 ' étape suivante
CASE
2:'-------------- attente condition: ------------
IF
En(5) < > 0 THEN EXIT SUB ' arrêt du moteur ?
'--------------- actions de l'étape 2: ---------
io(MOTEUR_3)
= 0 ' RAZ relais moteur
etape = 1 ' étape suivante
END
SELECT
END SUB
|
Et pourtant, il y a
encore plus spectaculaire :
Un cas de difficulté bien connu dans les
scieries est celui du trieur, qui consiste à devoir ranger dans
des "boxes", les billons (troncs découpés), en
fonction de leur longueur, de leur qualité ("choix")
etc.
Avec une programmation classique, une telle
mise en route s'éternise le plus souvent, au plus grand désespoir
du programmeur, de son employeur, et du Client !
Ici la difficulté de gérer des piles de
valeurs et des registres à décalage a été solutionnée par un
simple tableau dans lequel on range la valeur du codeur à
atteindre pour commander les éjecteurs, puis pour les désactiver
!
Cette simplicité est tellement spectaculaire
qu'elle peut sembler incroyable. Or ici c'est bien un exemple réel
qui est proposé (chaque fonction est un programme totalement
autonome, qui s'exécute de façon isolée) :
- SUB
Nouveau_Billon (Numero_Box, longueur)
'================================================================
' Ceci est la Procédure qui est appelée lors de
la lecture
' de la cellule d'entrée du trieur
'
' - elle reçoit le numéro de box de destination
et la
- '
longueur du billon
'
' - elle mémorise à quelle position future du
codeur il y aura
' l'action d'éjecter, et ensuite celle de RAZ du
vérin.
'
' NOTA: c'est le Graphe_Commande_Ejecteurs qui
- '
exécutera ces actions
'================================================================
' On utilise les indices 0 et 1 du tableau, car
le début du
' tableau ne sera jamais utilisé par la suite.
' C'est pourquoi il faut sur-dimensionner le
tableau de
' au moins 2 emplacements.
' Ainsi, ce tableau remplace à la fois une pile
et un
- '
registre à décalage.
- '
1. calculer le centrage de l'éjecteur, selon la
longueur:
- '
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
CALL Centrer_Billon(Numero_Box, longueur, action&,
repos&)
' 2. définir quand il faudra actionner l'éjecteur:
'
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Tableau_Boxes(0, 0) = action& ' val. codeur
"actionner éjecteur"
Tableau_Boxes(0, 1) = Numero_Box
Tableau_Boxes(0, 2) = 1 ' 1 = sortie vérin à 1
(activé)
' 3. définir quand il faudra relâcher l'éjecteur:
' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Tableau_Boxes(1, 0) = repos& ' val. codeur
"relâcher éjecteur"
Tableau_Boxes(1, 1) = Numero_Box
Tableau_Boxes(1, 2) = 0 ' 0 = sortie vérin à 0
' 3. ranger ces valeurs dans l'ordre croissant du
codeur:
'
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
CALL Misajour_Trieur(Tableau_Boxes())
END SUB
|
- SUB
Graphe_Commande_Ejecteurs ()
STATIC etape AS INTEGER, Fin_du_Tableau
'==========================================================
' - actionne le vérin de l'éjecteur lorsque le
codeur est à
- '
la bonne valeur
' - mise à zéro (RAZ) du vérin apràs éjection
' - enlève la tâche exécutée de la pile
'==========================================================
SELECT CASE etape:
CASE 0:'---------------- initialisation:
---------------
Fin_du_Tableau
= UBOUND(Tableau_Boxes)
etape = 1
CASE
1:'---------------- test condition: ---------------
'
tester si une action reste à exécuter:
IF Tableau_Boxes(Fin_du_Tableau, 0) = 0 THEN EXIT SUB
- ' tester position du
codeur :
- IF Counter(1) < Tableau_Boxes(Fin_du_Tableau,
0) THEN
- EXIT SUB
' rien à faire pour le moment !
END
IF
'---------------------
actions: ------------------
verin = Tableau_Boxes(Fin_du_Tableau, 1) ' quel vérin
?
action = Tableau_Boxes(Fin_du_Tableau, 2) ' q. action
?
io(verin) = action ' positionner sortie de l'automate
Tableau_Boxes(Fin_du_Tableau, 0) = 0 ' effacer
consigne
'
puis mise à jour tableau pour la consigne suivante:
CALL Misajour_Trieur(Tableau_Boxes())
etape = 1
END
SELECT
END SUB
|
- SUB
Centrer_Billon (Numero_Box, longueur, action&,
repos&)
' lire la position actuelle du codeur du trieur:
actuel&
= Counter(1)
- '
puis:
- '
lire offset (position Numero_Box) - (cellule de zéro)
' calculer position suivante action
' calculer position suivante repos (selon
installation)
END SUB
|
Mise en route du programme sans déplacement
sur le site !
Combien de semaines passe votre technicien chez le client pour
faire la même chose ?
C'est incroyable, mais bien réel !
| Non destiné au public.Toutes
les marques citées sont des marques déposées. Les
images sont propriétaires de leurs ayants-droits
respectifs. Le Système Graph-7 et ses composants sont déposés
et/ou brevetés. |