Recettes sur Vijeo-designer.

Partie du forum pour tout ce qui concerne les interfaces homme machine ou IHM. Forum, conseil, astuce et entraide sur les interface homme machine ou IHM tels que les magelis, KEP, proface, XBT, .
Avatar du membre
itasoft
Mi homme - Mi automate
Mi homme - Mi automate
Messages : 7152
Enregistré le : 20 oct. 2015, 10:15
Localisation : Lyon
Contact :

Recettes sur Vijeo-designer.

Message par itasoft »

Recettes sur Vijeo-designer.
La question avait été posée sur ce forum à une époque, sans réponse.
Via une communication on reçois le code de la recette à charger.
La question était de comment trouver le n° de la recette d’après son code (étiquette) .
Une des solutions consisterait à copier toutes les étiquettes des recette dans un tableau de String dans l’ordre des n°
puis parcourir ce tableau pour chercher l’étiquette (le code) demandé et le rang nous donnera son n°
L’autre solution consisterait à charger les recettes une par une jusqu’a ce que l’on trouve celle que l’on cherche,
mais c’est beaucoup plus long surtout si c’est la dernière de la liste.
Qu’en pensez vous ?
Automaticien privé (de tout)
itasoft@free.fr
steph68
Codeur fou
Codeur fou
Messages : 269
Enregistré le : 21 oct. 2015, 08:23

Re: Recettes sur Vijeo-designer.

Message par steph68 »

hello,

le problème c'est que tu n'as pas accès aux données des recettes sans impacter les champs d'affichage / d'édition.

il faut construire un mapping "numéro (indice) <=> nom" en parallèle et faire la recherche sur cette table (avec mise à jour de la table à chaque modif de nom de recette).

pour comparer les chaînes de caractères rapidement, il faut calculer un code de hachage par chaîne (hashing) --> https://fr.wikipedia.org/wiki/Fonction_de_hachage

c'est jouable, mais ça devient (très) lourd à faire juste avec le java "light" de Vijeo.

@+
Avatar du membre
skip74
Créateur de langage
Créateur de langage
Messages : 643
Enregistré le : 13 oct. 2015, 06:34

Re: Recettes sur Vijeo-designer.

Message par skip74 »

Salut Antoine

J'ai eu ce genre de truc à faire sur un afficheur automate Proface série lt300 ou un truc du genre.

Ce qui a été programmé :
Au démarrage de l'afficheur, une fonction qui lit les 500 recettes pour sauvegarder les noms en zone ls.
Cette manip prenait environ 15 secondes.

Sur saisie code barre, on testait la chaîne saisie avec le tableau de noms sans algorithme spécifique.
Ça allait suffisamment vite


Toutes ces phases de prog était programmées dans le code automate intégré......

Pour ton cas, si tu as de la latitude du client:
Je stockerais les recettes en data automate.
Je pense que les fonctions de recherche iraient beaucoup plus vite.
C'est sur qu'il faut un vrai automate.....
Avatar du membre
itasoft
Mi homme - Mi automate
Mi homme - Mi automate
Messages : 7152
Enregistré le : 20 oct. 2015, 10:15
Localisation : Lyon
Contact :

Re: Recettes sur Vijeo-designer.

Message par itasoft »

slts,
une des solutions testée:

1) Copier en permanence les noms des étiquettes dans un tableau de DINT (le hashCode)
2) Faire une recherche du code à trouver dans ce tableau, le rang donne le n° de la recette

exemple de script:

//=== Nombre de recettes dans le Groupe de Recettes ====
int RMax=100;
//==Copie des labels dans la table TAB_LABELS==
_RecipeControlDefault.RecipeGroupNumber.write(1);
String label=_RecipeControlDefault.RecipeLabel.getStringValue();
int X=INDEX.getIntValue();INDEX.add(1);
TAB_LABELS[X].write(label.hashCode());
if(X>=RMax){X=0;INDEX.write(0);OKCopy.write(1);}
_RecipeControlDefault.RecipeNumber.write(X+1);
//==Nom de l'Etiquette à chercher dans la table==
label=WLabel.getStringValue();
//== hashCode de l'Etiquette à chercher==
int HCode=label.hashCode();
//==n°recette==
int nr=0;
//==boucle de recherche dans la table des labels==
for (X = 1; X <=RMax; X++)
if (TAB_LABELS[X].getIntValue()==HCode) nr=X;
//== n° de la recette trouvée ou 0 si trouve pas==
NUM_RECETTE.write(nr);
Automaticien privé (de tout)
itasoft@free.fr
steph68
Codeur fou
Codeur fou
Messages : 269
Enregistré le : 21 oct. 2015, 08:23

Re: Recettes sur Vijeo-designer.

Message par steph68 »

attention, il y a le risque de collision du hashcode qui n'est pas géré dans ton programme.

2 chaines de caractères différentes peuvent donner le même hashcode (collision) --> oui je sais, 1 chance sur 4 milliards, mais ça arrive plus souvent qu'on le croit 8-)
donc il faut comparer dans un premier temps le hashcode (rapide) puis les chaines de caractères (lent) en cas d'égalité du hashcode.

c'est dommage que le java de Vijeo ne gère pas les HashMap ou HashTable (c'est ce que tu es en train de recréer, plus ou moins).

le principe d'une hashtable, au lieu de faire une recherche linéaire sur un tableau de 100, est de tomber directement sur les bons candidats (pour une taille de 100, seulement 2 ou 3 candidats à tester).

il y a plusieurs façon de faire, mais la plus simple est :

suppose une liste chaînée ou un tableau dynamique (array en java) que tu appelles "bucket" (seau).
suppose un tableau de "bucket" dont la taille de ce tableau est un nombre premier bien choisi (qui se calcule en fonction du volume de données et d'un facteur de charge, mais pour une constante de 100, pourquoi pas 43 ou 89 ou même 101).

au remplissage de ta hashmap, tu ranges le numéro de la recette (opération "push") dans le bucket à l'indice "HashCode" modulo (%) "taille de la map = nombre premier". Sur un bucket donné, il peut y avoir plusieurs recettes (d'où le tableau dynamique ou la liste chaînée), mais rarement bcp.

A la recherche d'une recette, c'est le même principe : tu as le hashcode, donc l'indice du bucket. Le bucket te donnera les 2 / 3 candidats à tester (il n'y en a rarement bcp parce que le choix d'un nombre premier fait que les recettes seront généralement bien réparties).

si ton hashcode est de bonne qualité, tu peux même utiliser un poids binaire (64 ou 128 pour un tableau de 100 valeurs par ex) au lieu d'un nombre premier et calculer l'indice du bucket par un simple masquage (AND 63 ou AND 127).

ceci dit, à faire ça avec Vijeo est impossible (à mon avis) :mrgreen: ... et c'est plus de l'informatique que de l'automatisme ...

simplement pour que tu vois l'utilité / l'usage réel du "hashcode" (et une hashmap est très utilisée en info et est très rapide pour une recherche de données - c'est de cette façon que les bases de données gèrent les "index")

@+
steph68
Codeur fou
Codeur fou
Messages : 269
Enregistré le : 21 oct. 2015, 08:23

Re: Recettes sur Vijeo-designer.

Message par steph68 »

une idée que je vais essayer de développer (pas trop le temps, donc en plusieurs parties) :

* mettre en place un "écouteur" sur la variable "_RecipeControlDefault.Status", ainsi un script peut être déclenché dès qu'une opération est effectuée sur les recettes (chargement / sauvegarde ...)
recettes-1.GIF
je viens de tester, ça fonctionne bien ; exemple pour un chargement de recettes, le script est appelé avec "Status" à 1025 (bit 10 + bit 0) puis est appelé à nouveau avec "Status" à 0.

pour info, voici la description de la variable "Status" :
recettes-2.GIF
recettes-2.GIF (9.11 Kio) Vu 9349 fois
ce script servira à actualiser notre propre table d'étiquettes (un tableau de STRING) et le hashcode correspondant qui sera enregistré.

* pour initialiser notre table d'étiquettes, il faut un script au démarrage de l'IHM

celui-ci va lancer le chargement de la première recette (amorçage)

le script à l'écoute de la variable "Status" va stocker l'étiquette et lancer le chargement de la recette suivante (relance) jusqu'à ce qu'il y ait une erreur (on sera arrivé au bout de toutes les recettes, on aura déterminé le nombre total de recettes)


c'est un peu "tordu" comme fonctionnement, mais il n'y a pas le choix vu que la gestion des recettes se programme par "contrat" (ordre puis résultat).

pour le stockage des hashcodes, au lieu d'un tableau de int, j'opterai plutôt pour un STRING (qui est en fait un tableau de CHAR) puis les recherches avec la fonction "indexOf" (quoique le type STRING est limité à 100 caractères ...)
le hashcode sera réduit à une valeur 8 bits (un CHAR).

voilà le programme, affaire à suivre :mrgreen:
Avatar du membre
itasoft
Mi homme - Mi automate
Mi homme - Mi automate
Messages : 7152
Enregistré le : 20 oct. 2015, 10:15
Localisation : Lyon
Contact :

Re: Recettes sur Vijeo-designer.

Message par itasoft »

slts,
la fonction indexOf() donne la première occurrence trouvée, si on cherche le texte "ABCD" il va aussi trouver le texte "ABCDEFGH"
Automaticien privé (de tout)
itasoft@free.fr
steph68
Codeur fou
Codeur fou
Messages : 269
Enregistré le : 21 oct. 2015, 08:23

Re: Recettes sur Vijeo-designer.

Message par steph68 »

posons les bases:

* une étiquette est une chaine de 32 caractères maxi
* on ne travaille que sur un seul groupe de recettes
* il n'y a que 100 recettes maxi (la limite de Vijeo est 256 par groupe, mais comme les chaines de caractères ne peuvent faire que 100 caractères de longueur ...)

les variables à déclarer:

* un tableau "Etiquettes" de 100 * STRING de 32 caractères, en stockage interne, non persistant
* un STRING "HashCodes" de 100 caractères, en stockage interne, non persistant

détails sur le hashcode:

pour chaque étiquette de recette un code de hachage est calculé (java fait tout le boulot via la méthode "hashCode")
pour des raisons pratiques, ce code sera stocké dans une chaine de caractères, la chaine "HashCodes".
un caractère correspondra à une recette (donc 5ème caractère = code de hachage de la recette 5 ...)

ce code de hachage est initialement un entier (int), il faut le convertir en caractère (char)

Code : Tout sélectionner

char hash = (char)(etiquette.hashCode() % 127 + 127);
la valeur "hash" sera entre 1 et 253.

127 est un nombre premier, ce qui répartira bien la plage initiale.

je me réserve la valeur 0 pour indiquer une recette pas encore initialisée.

le script à exécuter au démarrage de l'IHM:

Code : Tout sélectionner

StringBuffer buffer = new StringBuffer();
buffer.setLength(100); // remplissage par '\u0000'
HashCodes.write(buffer.toString());

_RecipeControlDefault.RecipeNumber.write(1); // recette n° 1
_RecipeControlDefault.Operation.write(4); // commande "charger"
le script au changement de la variable "Status" (cf post précédent) :

Code : Tout sélectionner

int status = _RecipeControlDefault.Status.getIntValue();

if ((status & 1) == 0) // opération terminée
{
	if ((status & 2) == 0) // pas d'erreur
	{
		int index = _RecipeControlDefault.RecipeNumber.getIntValue() - 1;

		String etiquette = _RecipeControlDefault.RecipeLabel.getStringValue();
		Etiquettes[index].write(etiquette); // mise à jour de notre table

		char hash = (char)(etiquette.hashCode() % 127 + 127); // calcul du code de hachage

		StringBuffer buffer = new StringBuffer(HashCodes.getStringValue());
		buffer.setCharAt(index, hash); // enregistrement du code de hachage
		HashCodes.write(buffer.toString());
	}
	else if (_RecipeControlDefault.Error.getIntValue() == 4) // indice erroné
	{
		int index = _RecipeControlDefault.RecipeNumber.getIntValue() - 1;
		String str = HashCodes.getStringValue();
		if (str.length() > index)
		{
			// raccourcissement de la chaine
			StringBuffer buffer = new StringBuffer(str);
			buffer.setLength(index);
			HashCodes.write(buffer.toString());
		}
	}

	// encore une recette à initialiser ?

	int index = HashCodes.getStringValue().indexOf(0);
	if (index >= 0)
	{
		_RecipeControlDefault.RecipeNumber.write(index + 1); // recette à charger
		_RecipeControlDefault.Operation.write(4); // opération chargement
	}
}
bon, il reste à débugger, tester, simplifier ... à suivre
steph68
Codeur fou
Codeur fou
Messages : 269
Enregistré le : 21 oct. 2015, 08:23

Re: Recettes sur Vijeo-designer.

Message par steph68 »

la fonction indexOf() donne la première occurrence trouvée, si on cherche le texte "ABCD" il va aussi trouver le texte "ABCDEFGH"
c'est pour ça qu'il y a sa petite soeur :
indexOf(String str,int fromIndex)
Retourne la position de l'index dans cette chaîne de la première occurrence de la sous chaîne en commençant par la position d'index définie.

paramètre1 : Chaîne
paramètre2 : entier
retour : entier
et on l'utilise comme ceci :

Code : Tout sélectionner

int index = -1;
while ((index = str.indexOf(32, index + 1)) >= 0)
{
  // ici index est positionné à chaque caractère "espace" (code 32)
}
et pour le problème actuel, ça donnerait ceci:

Code : Tout sélectionner

char hash = (char)(etiquette.hashCode() % 127 + 127); // etiquette est le nom de la recette qu'on cherche

int index = -1;
String str = HashCodes.getStringValue();

while ((index = str.indexOf(hash, index + 1)) >= 0 && !Etiquettes[index].getStringValue().equals(etiquette));

// ici index = -1 si recette pas trouvée, sinon index = (n° de recette - 1)
@+
Modifié en dernier par steph68 le 24 nov. 2015, 23:56, modifié 3 fois.
steph68
Codeur fou
Codeur fou
Messages : 269
Enregistré le : 21 oct. 2015, 08:23

Re: Recettes sur Vijeo-designer.

Message par steph68 »

aux premiers essais:
* l'amorce ne fonctionne pas (le script est bien exécuté mais pour une raison obscure, Vijeo ne charge pas la 1ère recette ou il n'appelle pas le script "écouteur")
* si je fais une amorce manuelle, je vois bien les recettes défiler à toute allure et le tableau se remplir correctement (étiquette + hashcode)
* le hic, c'est que de temps en temps, ça s'arrête en plein milieu (le gestionnaire de recettes doit retourner une erreur ou je ne sais quoi ...) - un coup c'est nickel, un coup ça plante au bout de X recettes traitées ...

donc ce n'est pas encore au point ... :evil: et ça sent les "évènements" de Vijeo pas super fiable (c'est déjà du vécu)... à creuser

@+
Répondre