I. Introduction▲
Le sujet a déjà été abordé dans simulation de process industrielsimulation de process industriel. J'avais utilisé à l'époque des requêtes complexes pour réaliser l'application et on ne pouvait pas vraiment suivre le process en temps réel.
Dans ce nouvel article, je décris toujours ce type de simulateur pour une gamme de fabrication, mais cette fois-ci j'utilise le timer du formulaire, pour suivre en temps réel le processus.
II. Rappel du contexte▲
Dans l'industrie, les machines peuvent être regroupées en ensembles autonomes de production spécialisés par type de produits qui utilisent les mêmes machines : ces ensembles s'appellent des îlots. Les flux de produits (matières) peuvent utiliser les postes de travail de l'îlot dans un ordre différent suivant leur gamme de fabrication, alors que dans une ligne de fabrication l'ordre est impératif.
Pour simplifier, on va ici considérer une gamme de fabrication composée de m machines placées en série.
III. Description du processus▲
Détaillons les différentes étapes du processus se déroulant sur une machine :
Étapes du processus
- Si la machine est prête et s'il y a des pièces en attente, alors on lance l'opération sur la machine.
- Sinon on attend, jusqu'à ce que ces deux conditions soient réunies.
- Une fois l'opération terminée, la pièce est transférée vers la machine suivante.
IV. État d'avancement du process▲
L'objectif est d'obtenir, à partir de formules mathématiques, une estimation du nombre total de pièces déjà usinées à un instant donné, de la date et l'heure de fin du process, et de l'avancement du process. Nous utiliserons ces fonctions traduites en VBA pour afficher ces indicateurs sur le formulaire principal.
IV-A. Formules mathématiques de base▲
duree_fabrication = (n-1)*duree_max + duree_total- duree_max : durée de l'opération la plus longue de la gamme de fabrication ;
- duree_total : somme totale des durées de toutes les opérations de la gamme de fabrication.
On en déduit :
nbre_fabrique = ((d - duree_total) \ duree_max) + 1La durée de fabrication doit toujours être supérieure ou égale à la somme totale des durées de toutes les opérations.
IV-B. Formules employées▲
date_fin = DateAdd("s",duree_fabrication, date_debut)- duree_fabrication : durée de fabrication des n pièces suivant la 1re formule ;
- date_debut : date de début du process.
nbre_fabrique = ((d - duree_total) \ duree_max) + 1- duree_max : durée de l'opération la plus longue de la gamme de fabrication ;
- duree_total : somme totale des durées de toutes les opérations de la gamme de fabrication.
Cette dernière formule va nous permettre de connaître, à un instant donné, le nombre total de pièces déjà terminées en bout de gamme.
avancement_reel = nbre_fabrique/nbre_total- nbre_fabrique : quantité de pièces fabriquées après une durée d ;
- nbre_total : nombre total de pièces à fabriquer.
avancement_estime = nbre_estime/nbre_total- nbre_estime : quantité estimée de pièces fabriquées après une durée d ;
- nbre_total : nombre total de pièces à fabriquer.
V. Rendu final du simulateur de process▲
Voici le rendu du formulaire qui présente, pour chaque machine, le nombre de pièces en attente et la progression de l'opération.
On constate que le simulateur permet de visualiser l'avancement des opérations sur les différentes machines grâce à des barres de progression.
Démonstration du simulateur en vidéosimulateur de process
Voici les objets nécessaires pour aboutir à ce résultat.
VI. Tables nécessaires▲
Pour sauvegarder les informations concernant la gamme de fabrication et ses machines on a besoin de deux tables.
VI-A. T_Gamme▲
Cette table contient les informations concernant la gamme de fabrication.
|
Nom du champ |
Type de données |
Description |
|---|---|---|
|
IdGamme |
Entier long |
Identifiant de la gamme de fabrication |
|
NomGamme |
Texte |
Nom de la gamme de fabrication |
|
EtatProcess |
Texte |
État du process en cours sur la gamme de fabrication (Arrêt ; Progression) |
|
NbreMachines |
Entier long |
Nombre de machines composant la gamme de fabrication |
|
IntervalleTimer |
Entier long |
Intervalle de temps en millisecondes entre deux exécutions de la procédure sur Timer |
|
DebutProcess |
Date/Heure |
Début du process en cours sur la gamme de fabrication |
|
QtePieces |
Entier long |
Quantité totale de pièces à fabriquer |
|
QteFab |
Entier long |
Quantité de pièces déjà fabriquées |
VI-B. T_MachineGamme▲
Cette table permet de sauvegarder les informations relatives aux machines de la gamme de fabrication, telles que l'opération, l'état de la machine, la durée de l'opération et du transfert de la pièce.
|
Nom du champ |
Type de données |
Description |
|---|---|---|
|
IdMachine |
Texte |
Identifiant de la machine |
|
IdGamme |
Entier long |
Identifiant de la gamme contenant la machine |
|
Operation |
Texte |
Nom de l'opération réalisée sur la machine |
|
DureeOperation |
Réel simple |
Durée en secondes de l'opération sur la machine |
|
DureeTransfert |
Réel simple |
Durée de transfert de la pièce vers la machine suivante |
|
QteMachine |
Entier long |
Quantité de pièces en attente sur la machine |
|
EtatMachine |
Texte |
État de la machine : (R : Ready ; P : Progression) |
|
ProgressionOperation |
Réel simple |
Valeur indiquant la progression de la pièce sur la machine |
|
ProgressionTransfert |
Réel simple |
Valeur indiquant la progression du transfert de la pièce vers la machine suivante. |
VII. Formulaire F_SimulateurProcess▲
Il est relié à la table T_Gamme. Nous allons décrire les différents éléments du formulaire.
Le simulateur permet de visualiser la progression des pièces sur les différentes machines.
VII-A. Contrôles constituant le tableau des machines▲
Contrôles constituant le tableau
- Zones de texte txtIdMachine1..14 : affichent les indices ou numéros d'ordre des machines ;
- Zones de texte txtOperation1..14 : affichent les noms des opérations ;
- Zones de texte txtDureeOperation1..14 : les durées en secondes des opérations effectuées sur les différentes machines ;
- Zones de texte txtDureeTransfert1..14 : les durées en secondes de transfert sur les machines suivantes ;
- Zones de texte txtQteMachine1..14 : le nombre de pièces en attente sur les différentes machines ;
- Zones de texte txtEtatMachine1..14 : affichent l'état des machines (R : Ready ; P : Progression) ;
- Etiquettes lnlProgressionOperationMax1..14 : utilisées pour afficher les barres de largeur maximale ;
- Etiquettes lnlProgressionOperationPrg1..14 : utilisées pour afficher les barres de progression de largeur proportionnelle à l'avancement des opérations ;
- Etiquettes lnlProgressionOperationPct1..14 : utilisées pour afficher les pourcentages d'avancement des opérations ;
- Etiquettes lnlProgressionTransfertMax1..14 : utilisées pour afficher les barres de largeur maximale ;
- Etiquettes lnlProgressionTransfertPrg1..14 : utilisées pour afficher les barres de progression de largeur proportionnelle à l'avancement des transferts ;
- Etiquettes lnlProgressionTransfertPct1..14 : utilisées pour afficher les pourcentages d'avancement des transferts.
VII-A-1. Note sur les objets barres de progression▲
Ils indiquent la progression de l'usinage et du transfert des pièces grâce aux propriétés max, donnant la durée totale de l'opération, et value indiquant l'avancement de l'opération.
Il s'agit d'objets créés à partir du module de classe clsLblProg, réalisé par Adam Waller, et nécessitant d'être inséré dans votre projet Access.
Les deux tableaux des objets Barre de progression sont définis en haut du module du formulaire :
Option Compare Database
Option Explicit
' Tableaux des objets Barre de progression basés sur la classe clsLblProg
Dim prgProgressionOperation(1 To 14) As clsLblProg
Dim prgProgressionTransfert(1 To 14) As clsLblProg
...On initialise les deux tableaux des objets Barre de progression sur ouverture du formulaire :
Private Sub Form_Open(Cancel As Integer)
' On crée les objets Barre de progression à partir du module de classe clsLblProg
CreerBarresProgression
End SubPublic Sub CreerBarresProgression()
' Création des objets Barre de progression
Dim i As Long ' Indice des barres de progression dans les tableaux
For i = 1 To 14 ' Parcours des indices des barres de progression
Set prgProgressionOperation(i) = New clsLblProg ' Création de l'instance de l'objet Barre de progression pour l'opération
prgProgressionOperation(i).Initialize Me("lblProgressionOperationMax" & i), _
Me("lblProgressionOperationPrg" & i), _
Me("lblProgressionOperationPct" & i)
Set prgProgressionTransfert(i) = New clsLblProg ' Création de l'instance de l'objet Barre de progression pour le transfert
prgProgressionTransfert(i).Initialize Me("lblProgressionTransfertMax" & i), _
Me("lblProgressionTransfertPrg" & i), _
Me("lblProgressionTransfertPct" & i)
Next i
End SubOn libère les objets Barre de progression des deux tableaux sur fermeture du formulaire :
Private Sub Form_Close()
' On libère les objets Barre de progression
LibererBarresProgression
End SubPublic Sub LibererBarresProgression()
' Libération des objets Barre de progression
Dim i As Long ' Indice des barres de progression dans les tableaux
For i = 1 To 14 ' Parcours des indices des barres de progression
' libération des objets liés aux barres de progression de l'opération et du transfert
Set prgProgressionOperation(i) = Nothing
Set prgProgressionTransfert(i) = Nothing
Next i
End SubVII-B. Zones de texte pour paramétrer le process▲
VII-B-1. Zone de texte txtIntervalleTimer▲
On y renseigne l'intervalle du timer, c'est-à-dire le temps qui s'écoule en millisecondes entre deux exécutions de la procédure sur Timer.
VII-B-2. Zone de texte txtEtatProcess▲
Indique l'état du processus : Arrêt ; Progression. Elle est simplement mise à jour en cliquant respectivement sur les boutons cmdArreter et cmdDemarrer.
VII-B-3. Zone de texte txtNbreMachines▲
Affiche le nombre de machines composant la gamme de fabrication.
Private Sub txtNbreMachines_AfterUpdate()
' Procédure d'affichage des lignes du tableau en fonction de la valeur saisie dans la zone de texte
Dim i As Long, n As Long ' Indice et nombre de machines
i = 1
n = Nz(Me.txtNbreMachines.Value, 0) ' On copie dans la variable n le nombre maximum de machines.
If n > 14 Then
Me.txtNbreMachines.Value = 14 ' On définit la valeur maximale de saisie à 14.
n = 14
End If
For i = 1 To n ' On parcourt les lignes du tableau pour les afficher
' On affiche les zones de texte du tableau
Me("txtIdMachine" & i).Visible = True
Me("txtOperation" & i).Visible = True
Me("txtDureeOperation" & i).Visible = True
Me("txtDureeTransfert" & i).Visible = True
Me("txtQteMachine" & i).Visible = True
Me("txtEtatMachine" & i).Visible = True
' On affiche les barres de progression
Me("prgProgressionOperation" & i).Visible = True
Me("prgTransfertMachine" & i).Visible = True
Next i
While i <= 14 ' On parcourt les lignes restantes pour les masquer
' On masque les zones de texte du tableau
Me("txtidMachine" & i).Visible = False
Me("txtOperation" & i).Visible = False
Me("txtDureeOperation" & i).Visible = False
Me("txtDureeTransfert" & i).Visible = False
Me("txtQteMachine" & i).Visible = False
Me("txtEtatMachine" & i).Visible = False
' On masque les barres de progression
Me("prgProgressionOperation" & i).Visible = False
Me("prgTransfertMachine" & i).Visible = False
i = i + 1 ' Indice suivant
Wend
End SubVII-C. Contrôles Indicateurs d'avancement du process▲
Zones de texte indicateurs d'avancement
- txtDebutProcess : date et heure de début du process ;
- txtFinProcess : date et heure estimées de la fin du process ;
- txtQteFab : quantité de pièces déjà fabriquées ;
- txtQteEstimee : quantité estimée de pièces déjà fabriquées ;
- txtAvancementReel : indicateur d'avancement réel du process ;
- txtAvancementEstime : indicateur de l'avancement théorique du process.
VII-D. Boutons de commande pour le contrôle du process▲
VII-D-1. Bouton de commande cmdSauvegarder▲
Bouton permettant de sauvegarder l'état des machines dans la table T_MachineGamme.
Déroulé de la procédure
- Vidage de la table T_MachineGamme.
- Ouverture du Recordset lié à la table T_MachineGamme.
- Parcours ligne par ligne du tableau de contrôles représentant les machines, et création pour chaque ligne d'un enregistrement dans la table T_MachineGamme.
- Fermeture et libération des variables.
VII-D-2. Bouton de commande cmdDemarrer▲
Bouton permettant de démarrer le process.
Private Sub CmdDemarrer_Click()
' Procédure de lancement du process
If Not LignesOK Then ' Si une ligne est incomplète
MsgBox ("Une ligne comporte une case vide !")
Exit Sub ' Sortie
End If
If Me.EtatProcess = "Progression" Then ' Si le process est déjà en cours
MsgBox ("Process déjà en cours !")
Exit Sub ' Sortie
End If
If MsgBox("Souhaitez-vous démarrer le process ?", vbYesNo) = vbYes Then ' Si on accepte
Me.txtEtatProcess.Value = "Progression" ' On met l'état du process sur "Progression"
If Nz(Me.txtDebutProcess) = "" Then
' Mise à jour de la date de début du process
Me.txtDebutProcess = Now()
End If
Me.TimerInterval = Me.txtIntervalleTimer ' On active le timer avec l'intervalle d'exécution défini sur le formulaire
VerrouillageTableau (True) ' Verrouillage du tableau des machines
End If
End SubVII-D-3. Bouton de commande cmdArreter▲
Bouton permettant d'arrêter le processus.
Private Sub CmdArreter_Click()
' Procédure d'arrêt du process
If Me.EtatProcess = "Arrêt" Then ' Si le process est déjà arrêté
MsgBox ("Process déjà arrêté !")
Exit Sub ' Sortie
End If
If MsgBox("Souhaitez-vous arrêter le process ?", vbYesNo) = vbYes Then ' Si on accepte
Me.txtEtatProcess.Value = "Arrêt en cours" ' On met l'état du process à "Arrêt en cours"
VerrouillageTableau (False) ' déverrouillage du tableau des machines
End If
End SubVII-D-4. Bouton de commande cmdInitialiser▲
Bouton permettant d'initialiser le process en repartant avec le nombre total de pièces en attente sur la 1re machine.
Déroulé de la procédure
- Détermination du nombre total de pièces en attente, en fabrication et fabriquées.
- Parcours du tableau des machines.
- Pour chaque machine, initialisation des quantités en attente, de l'état de la machine et des barres de progression.
VII-E. Événement sur Activation▲
Procédure événementielle s'exécutant sur l'activation d'un enregistrement.
VII-E-1. Procédure événementielle sur Activation▲
Déroulé de la procédure
- Ouverture du Recordset lié à la table T_MachineGamme.
- Parcours du jeu enregistrements avec mise à jour des contrôles du tableau des machines situés sur le formulaire.
- Masquage des lignes en trop dans le tableau des machines.
- Mise à jour des indicateurs.
VII-E-2. Procédure de mise à jour des indicateurs▲
À la fin de la procédure principale, on met à jour les indicateurs de date de fin du process, de quantité fabriquée et estimée, d'avancement réel et estimé, en utilisant les formules mathématiques vues en section IV.
Public Sub MajIndicateursAvancement()
' On met à jour les indicateurs d'avancement
Dim dm As Long, dt As Long ' Variables indiquant la durée maximum et total des opérations sur les machines
Dim dp As Long, dr As Long ' Variables indiquant la durée estimée et restante du process
dm = Nz(DMax("[DureeOperation]", "T_MachineGamme", "IdGamme=" & Nz(Me.IdGamme, 0)), 0) ' Durée maximum entre les opérations de la gamme
dt = Nz(DSum("[DureeOperation] + [DureeTransfert]", "T_MachineGamme", "IdGamme=" & Nz(Me.IdGamme, 0)), 0) ' Somme des durées des opérations transfert compris
dr = (Nz([QtePieces], 0) - Nz([QteFab], 0) - 1) * dm + dt ' Durée restante selon la formule duree_restante = (nbre_restant - 1)*duree_max + duree_totale
If Not IsNull([DebutProcess]) Then ' Si date de début du process non nulle
' Durée écoulée depuis le lancement du process
dp = DateDiff("s", CDate([DebutProcess]), Now())
End If
If Not IsNull([DebutProcess]) Then ' Si date de début du process non nulle
' Date et heure estimées de fin du process
Me.txtFinProcess = DateAdd("s", dr, [DebutProcess])
Else
Me.txtFinProcess = Null
End If
If (dm <> 0) And (dp >= dt) Then ' On évite la division par 0 et le cas où aucune pièce n'a encore été fabriquée
' Qté estimée de pièces déjà fabriquées
Me.txtQteEstimee = ((dp - dt) \ dm) + 1
Else
Me.txtQteEstimee = Null
End If
If (Nz([QtePieces], 0) <> 0) And (Not IsNull([QteFab])) Then ' On évite la division par 0
' Indicateur d'avancement réel du process
Me.txtAvancementReel = Nz([QteFab], 0) / [QtePieces]
Else
Me.txtAvancementReel = Null
End If
If (Nz([QtePieces], 0) <> 0) And (Not IsNull([txtQteEstimee])) Then ' On évite la division par 0
' Indicateur de l'avancement théorique du process
Me.txtAvancementEstime = CLng(Nz([txtQteEstimee], 0)) / [QtePieces]
Else
Me.txtAvancementEstime = Null
End If
If Nz(Me.txtQtePieces, 0) = Nz(txtQteFab, 0) Then ' Si toutes les pièces ont été fabriquées
Me.IntervalleTimer = 0 ' On désactive le timer, ce qui interrompt le processus.
Me.txtFinProcess = Now() ' On met à jour le champ FinProcess de la table T_Gamme avec la date et l'heure actuelles
End If
End SubVII-F. Événement sur Timer▲
Description de la procédure événementielle form_timer qui s'exécute à intervalle régulier. On pourra prendre comme intervalle 1000 ms soit 1 seconde :
On constate que la propriété Intervalle minuterie (IntervalleTimer) est réglée à zéro, elle indique que le timer est par défaut inactif. La mise à jour de cette propriété avec une valeur entière X entraine automatiquement l'exécution de la procédure sur minuterie toutes les X millisecondes.
VII-F-1. Procédure événementielle sur Timer▲
Déroulé de la procédure
- Pour chaque machine, on teste si elle est prête (R : Ready) et s'il y a des pièces en attente.
- Si c'est le cas, on met la machine à l'état de progression (P : Progress) et on décrémente le nombre de pièces en attente.
- Sinon, s'il y a déjà une pièce, on incrémente l'indicateur de progression de la pièce sur la machine.
- Pour chaque machine, on teste si la machine est à l'état de progression et si l'indicateur de progression est au maximum.
- Si c'est le cas, on initialise l'indicateur de progression, on met la machine à l'état prête (R) et on transfère la pièce sur la machine suivante.
- Sinon, on incrémente l'indicateur de progression de la pièce sur la machine.
Private Sub Form_Timer()
On Error GoTo err_Form_Timer
Dim i As Long ' Variable d'indice de la machine
Dim p As Single ' Variable indiquant le pas de progression en secondes
Dim dm As Long, dt As Long ' Variables indiquant la durée maximum et total des opérations sur les machines
Dim dp As Long, dr As Long ' Variables indiquant la durée estimée et restante du process
Dim ar As Boolean ' Variable indiquant si le process est arrêté
p = CLng(Me.txtIntervalleTimer.Value) / 1000 ' Définition du pas de progression en secondes
i = 1 ' Initialisation de l'indice des machines
ar = True ' Initialisation de la variable indiquant si le process est à l'arrêt
Do While (i <= 14) ' On parcourt les machines
If (Me("txtEtatMachine" & i).Value = "R") And (Me.txtEtatProcess.Value = "Progression") Then ' si la machine est prête et si le process est en cours
If (CLng(Nz(Me("txtQteMachine" & i).Value, 0)) > 0) Then ' s'il y a encore des pièces en attente
Me("txtQteMachine" & i).Value = CLng(Me("txtQteMachine" & i).Value) - 1 ' on décompte le nombre de pièces en attente
Me("txtEtatMachine" & i).Value = "P" ' On met la machine en progression
ar = False ' Processus en cours
End If
Else
If (Me("txtEtatMachine" & i).Value = "P") Then ' si la machine est en progression
ar = False ' Processus en cours
If (prgProgressionOperation(i).Value < prgProgressionOperation(i).Max) Then ' Si la pièce n'est pas terminée
' Durée de fabrication pas encore atteinte
prgProgressionOperation(i).Value = prgProgressionOperation(i).Value + p ' On incrémente d'une seconde la progression
Else
Me("txtEtatMachine" & i).Value = "R" ' On met la machine dans l'état 'Prête' (R: 'Ready')
prgProgressionOperation(i).Value = 0
prgProgressionTransfert(i).Value = 0
prgProgressionTransfert(i).Tag = "P"
End If
End If
End If
...
End SubDéroulé de la procédure — partie n°2
- On teste pour chaque machine, si le transfert est terminé.
- Si c'est le cas, on incrémente le nombre de pièces en attente sur la machine suivante.
- Sinon, on incrémente l'indicateur de progression du transfert.
- À la fin, on met à jour les indicateurs d'avancement du process.
...
If (prgProgressionTransfert(i).Tag = "P") Then ' Si la Transfert est en cours
If (prgProgressionTransfert(i).Value < prgProgressionTransfert(i).Max) Then ' Si la Transfert n'est pas terminée
prgProgressionTransfert(i).Value = prgProgressionTransfert(i).Value + p ' On incrémente d'une seconde la progression
ar = False ' Processus en cours
Else
prgProgressionTransfert(i).Value = 0 ' On remet à 0 l'indicateur de progression du Transfert
prgProgressionTransfert(i).Tag = ""
If i < 14 Then ' Si on a pas dépassé la dernière machine
If Nz(Me("txtIdMachine" & (i + 1)).Value) <> "" Then ' si on est pas sur la dernière machine
' on incrémente le nombre de pièces en attente sur la machine suivante
Me("txtQteMachine" & (i + 1)).Value = CLng(Me("txtQteMachine" & (i + 1)).Value) + 1
Else ' Sinon
' on incrémente le nombre total de pièces fabriquées
Me.txtQteFab.Value = Nz(Me.txtQteFab.Value, 0) + 1
MajIndicateursAvancement ' Mise à jour des indicateurs d'avancement
End If
Else ' Sinon
' on incrémente le nombre total de pièces fabriquées
Me.txtQteFab.Value = Nz(Me.txtQteFab.Value, 0) + 1
MajIndicateursAvancement ' Mise à jour des indicateurs d'avancement
End If
End If
End If
i = i + 1 ' on passe à l'indice suivant
If Nz(Me("txtIdMachine" & i).Value) = "" Then ' Si plus d'indice de machine on sort
Exit Do
End If
Loop
If ar Then ' Processus arrêté
Me.txtEtatProcess.Value = "Arrêt" ' Mise à jour de l'état du process
Me.TimerInterval = 0 ' Interruption du timer
End If
err_Form_Timer:
If Err.Number <> 0 Then ' Gestion d'erreur
MsgBox (Err.Description) ' Affichage du message d'erreur
End If
End SubVIII. Téléchargement▲
Pour faciliter les tests et assurer leur portabilité, les bases exemples n'utiliseront pas de composants externes à Access (ActiveX ou autres).
Les bases exemplessimulateur-process.zip sont au format mdb et accdb.
IX. Remerciements▲
Un grand Merci à toute l'équipe de Dvp et plus particulièrement à :
Pour leurs remarques et conseils avisés :
. arkham46
. Laurent Ott
Pour sa relecture :
. f-leb













