f Système Graph-7

LEADER MONDIAL
DEPUIS PLUS DE 15 ANS !

 


Exemple d'un graphe:
 
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 :

Programme d'un trieur:

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.