Le chapitre 2 du livre précédemment cité sur l’Intelligence
Artificielle propose un exemple de logique floue. Cela m’a donnée l’idée de
l’appliquer au GPIO du Raspberry. Pour cela, je voudrais gérer la luminosité
d’une LED en fonction de la lumière reçue par 2 cellules photoélectriques.
C’est un projet complexe car outre l’adaptation de la
logique floue à l’assembleur, il faut aussi arriver à récupérer les intensités
lumineuses de chaque photo résistance puis moduler la luminosité de la LED au
travers des instructions du GPIO.
Donc je vais le décomposer en 3 parties : un programmepour tester la récupération de la luminosité et connaitre l’échelle de
variation possible. Un deuxième programme pour tester la variation de la
lumière émise par la LED et là aussi connaitre l’échelle des valeurs possibles
et enfin un 3ième programme pour gérer les ensembles et règlesflous.
Comme pour le programme sur le système expert, je vous
renvoie pour les concepts théoriques au livre en question.
En premier, recherche sur Internet du montage pour lire les
valeurs d’une photo résistance et d’un exemple de programme associé pour
comprendre le principe. Le montage est assez simple. J’adapte le programme déjà
écrit précédemment pour intégrer la lecture de l’état de la photo résistance.
Pour la Led, je recherche comment gérer sa luminosité. C’est
moins simple car il faut alternativement l’allumer et l’éteindre avec des
durées différentes. Et il va falloir donc trouver une solution pour garder la
luminosité constante pendant un laps de temps jusqu’au calcul suivant.
Enfin je traduis en assembleur les routines données en Java
dans le livre précédent. Pour simplifier la saisie, je développe toute une
partie pour récupérer les variables d’entrées, de sortie et les règles dans un
fichier de configuration. Les routines de gestion seront rassemblées dans un
fichier objet qui sera lié à un programme maitre. Seul celui-là sera à modifié
et à recompiler en fonction des valeurs d’entrées nécessaires à la résolution.
Les routines de gestion des ensembles floues sont assez
compliquées. En plus, j’ai choisi d’utiliser des listes chainées pour gérer
toutes les données nécessaires. Cela oblige d’utiliser un grand nombre de
pointeurs ce qui ne facilite pas la lecture du programme. Puis c’est du brut de
fonderie, je n’ai pas réfléchi à toutes les améliorations possibles.
Au début du programme, nous trouvons les descriptions des
structures nécessaires : une pour les points, une pour les ensembles
flous, une pour le contrôleur, une pour les variables et enfin la dernière pour
les valeurs. Vous remarquerez qu’en plus des données propres, des pointeurs
vers la structure suivante ont été ajoutés pour gérer les listes chainées.
Ensuite nous trouvons les descriptions des libellés
nécessaires puis les réservations de place des variables. Peu de variables sont
déclarées car toutes les données seront créées dans un tas et accessibles
seulement par des pointeurs.Dans ce programme nous utiliserons le tas du système
(heap) en récupérant l’adresse de début du tas par la fonction call system brk
de Linux. Nous ajouterons notre taille nécessaire et nous fixerons la nouvelle
taille du tas par le même call system brk. Cette solution permet de créer plusieurs
contrôleurs avec des configurations différentes dans le même programme ( cas de
figure non testé à ce jour).
La première routine FLOUcreationcontroleur concerne la
création du contrôleur à partir du nom du fichier de configuration passé en
paramètre dans le registre r0. Nous commençons par lire le fichier de
configuration pour vérifier s’il existe bien. Puis nous créons dans le tas, le contrôleur
à l’aide de la description de sa structure. Pour tout ce qui concerne les
pointeurs de débuts de liste chainées, nous les initialisons avec une adresse
du tas contenant une valeur sentinelle (cad que le pointeur contenant l’entité
suivante contient en fait sa propre adresse). Nous aurions pu nous contenter de
mettre une valeur nulle dans le pointeur mais cette solution permet de
s’assurer que les listes sont correctement alimentées et terminées par une
sentinelle de fin. Une valeur à zéro pouvant être aussi une erreur de
programmation.
Puis nous passons à une sous routine d’analyse du fichier de
configuration pour créer les variables d’entrées, et leurs valeurs associées,
la variable de sortie et ses valeurs associés, et les règles de détermination.
Cette programmation n’est pas le top et a été un peu améliorée par rapport au
programme sur le petit système expert (voir chapitre 21). J’ai écrit une sous
sous routine pour boucler sur les blancs présents dans le buffer de lecture et
une autre pour analyser chaque mot, mettre un 0 binaire de fin de chaine et
avancer jusqu’au prochain mot valide (ou la fin de fichier) en éliminant les
blancs, le caractère « : » et les caractères de fin de ligne
(soit 0D0A mais à vérifier suivant votre système et votre éditeur de texte
adoré). Chaque variable, valeur ou règle est stockée dans la liste chainée
adéquate du contrôleur.
Après mise à jour en mémoire du pointeur du tas, la routine
retourne l’adresse du contrôleur au programme appelant.
Une autre routine concerne l’ajout de valeurs déterminant le
problème à résoudre. Les paramètres en entree sont l’adresse du contrôleur, le
nom de la variable concernée et la valeur associée. Si la variable n’est pas
trouvée dans les variables d’entrée données par le fichier de configuration, un
libellé d’erreur est affiché.
Puis nous trouvons la sous routine résoudre qui est l’exact
reflet des routines décrites dans le livre de MME MATHIVET. Quelques petites
différences quand même : pour éviter des calculs en virgule flottante, la
valeur Y de chaque point est 100 et non pas 1. Ce qui entraine qu’un résultat
de 77 par exemple correspond à un résultat de 0,77 du livre. Les sous routines
semblent complexes, mais j’ai mis le maximum de commentaires pour expliquer les
calculs et opérations réalisées. A ce jour, j’ai testé ces routines avec les
données du livre, et il y a une petite différence dans les calculs pour un des
cas. Malgré mes recherches, je n’ai pas trouvé l’erreur et je suspecte qu’une
entrée du livre est incorrecte !!!
Enfin la dernière sous routine concerne la réinitialisation
des données du problème pour effectuer un nouveau calcul. Et pour éviter tout
accroissement du tas, cette routine remet l’adresse du tas à sa valeur après
l’analyse du fichier de configuration.
J’ai ajouté d’autres sous routines pour afficher les
variables d’entrées, de sortie et les règles, ce qui permet de vérifier la
bonne prise en compte du fichier de configuration.
Après compilation, le fichier objet sera linké avec le programme appelant ainsi que le fichier des sousroutines de gestion du gpio
Ici dans notre cas, le programme appelant va appeler la
routine de création du contrôleur en lui passant le nom du fichier de
configuration récupère dans la ligne de commande comme déjà vu dans des
chapitres précédents. Puis va appeler dans une boucle, la routine de lecture de
la photorésistance 1 la routine de lecture de la photo résistance 2, passer les
2 valeurs au contrôleur par la sous routine FLOUajoutervaleur,, appeler la
résolution, puis appeler la routine d’allumage de la LED avec le résultat
précèdent en paramètre. Puis attendre un certain temps avant de boucler à
nouveau après avoir réinitialiser l’état du contrôleur a son état après la
prise en compte des règles.
Le jour où j’écris ces lignes, je ne sais pas encore si tout
cela va fonctionner correctement !! Je pense que cela va nécessiter
plusieurs ajustements tant au niveau des valeurs qu’au niveau des règles. Bon
je vais déjà aller tester la partie GPIO avec les montages proposés.
Quelques jours après : après quelques erreurs de
montage, les 2 premiers programmes ont bien fonctionné. J’ai pu obtenir les
variations de la cellule photoélectrique ( de 5000 à 80000) et j’ai donc
appliqué un facteur de réduction de 1000 pour rester dans une plage de valeur
de 5 à 800. Pour le réglage de la luminosité de la LED, les réglages ont été
plus délicats et ne sont pas encore tout à fait satisfaisants. Mais cela suffit
pour effectuer un test final.
J’effectue soigneusement le montage des 2 cellules
photorésistantes (attention au sens des condensateurs) l’ajout de la led
(attention aussi à son sens), je modifie le programme principal pour que les
pins du GPIO correspondent bien à ceux du programme (18 pour la LED, 4 et 22
pour les cellules) J’adapte le fichier de configuration pour déterminer les
différentes valeurs et je crée quelques règles de génération de la luminosité
(voir plus bas la syntaxe du fichier de configuration à respecter). Et cela
fonctionne !!! En passant la main devant les cellules, la luminosité de la
LED varie (imparfaitement mais tout est dans le fignolage des réglages).
Pour lancer le programme il faut taper : pilotageLedFinal configFlGpio.txt
Et maintenant ?
restent à fignoler les règles et réglages, à réécrire les routines pour
améliorer l’utilisation des registres et la lisibilité.
Syntaxe du fichier de configuration (fichier texte) :
1ère ligne : nom du contrôleur ( ne sert à
rien !!!mais est obligatoire)
2ième ligne : libellé Entrées: indique le début de la liste des variables
d’entrées
Ligne Variable:nom_de_la variable:valeur mini:valeur maxi
Pour chaque variable plusieurs lignes valeurs
Valeur:nom_de_la
valeur :type_ensemble_flou :valeur1 :valeur2 :valeurn :
Avec type d’ensemble flou : EFTG : Ensemble Flou Trapèze Gauche suivi de 4
valeurs en ordre croissant dont la première est égale à la valeur mini et la
dernière à la valeur maxi
EFTD : Ensemble Flou Trapèze Droit suivi de 4
valeurs en ordre croissant dont la première est égale à la valeur mini et la
dernière à la valeur maxi
EFTRA : Ensemble Flou TRApèze suivi de 5 valeurs
en ordre croissant dont la première est égale à la valeur mini et la dernière à
la valeur maxi
EFTRI : Ensemble Flou TRIangle suivi de 5 valeurs
en ordre croissant dont la première est égale à la valeur mini et la dernière à
la valeur maxi
Puis le libellé Sortie : avec une seule variable et ses
valeurs comme une variable d’entrée.
Puis le libellé Règles :
Puis chaque règle codifiée comme suit
SI nom_variable_entrée EST nom_de la valeur [ET
nom_variable_entrée EST nom_de la valeur…] ALORS nom_variable_sortie EST
nom_d’une_valeur_de_sortie
Attention : les contrôles de cette syntaxe sont très
légers !!! et donc vérifier bien l’affichage lors de l’execution pour
contrôler la prise en compte.
Aucun commentaire:
Enregistrer un commentaire