61-B) 27/02/2018 : Liberté artistique, le pinceau informatique (MJD 58178)

Réunion de tous les personnels en salle S7 qui resemble à une galerie d’exposition. Plusieurs tableaux présentent des logos étudiés par des artistes spécialistes en infographie. Les conversations vont bon train. Le Directeur est présent, et participe à l’ambiance joyeuse. C’est même lui qui a servi un verre de champagne à la serveuse présente pour cette petite fête. L’entreprise va choisir un LOGO pour symboliser sa dynamique, un petit dessin étant toujours préférable pour le grand public qu’un sigle NDRMSE difficile à retenir. Ce sont les personnels qui vont choisir le dessin qui emporte leur préférence. Autant dire que la bonne humeur embelli cette journée 58178 …

Dessiner n’est pas jouer !

Quand le destin s’acharne, arrive le moment où il faut savoir lâcher prise. La version 21N du démonstrateur s’achemine vers l’aboutissement ultime du logiciel. Tout est écrit et mis à part quelques petites misères à corriger, le programme commence à ressembler au « produit fini ». Rien à faire, on titille à peine les 83% d’occupation de la zone réservée dans l’ATmega328. La seule possibilité qui nous reste, c’est de dilapider des octets à tout va ! Traduisez … on va se faire un petit plaisir qui informatiquement est boulimique en code et qui fonctionnellement n’apporte strictement rien : La page d’écran d’accueil du pupitre affichera un LOGO.

La version P : Le dernier des démonstrateurs.

Téléversez P21P_Démonstrateur_Raquette.ino qui continue de fonctionner avec la version P22N du logiciel esclave. Il n’y aura plus de descendance mis à part la version ultime du programme, on commence à distinguer nettement le bout du tunnel. Suite à la version N on s’attendrait à la version O. Cette lettre a été écartée de la liste, car elle peut se confondre avec zéro. Donc ne cherchez pas un P21O hypothétique. En fin d’écriture du code dans le microcontrôleur, l’écran d’accueil de la Fig.330 s’affiche et la LED verte du clavier clignote rapidement nous invitant à cliquer sur une touche pour passer à la suite. Avouons que les personnels de la NDRMSE ont bien choisi en sélectionnant cette image qui présente la petite machine avec ses deux gros yeux ultrasons. Dans le cadre jaune est précisée la version du logiciel qui fonctionne actuellement sur le pupitre. Avant d’aborder les techniques pour créer un tel dessin et le faire afficher, nous allons passer en revue un certain nombre de petits perfectionnements qui accompagnent cette version du logiciel.

Les petits détails font les bons programmes.

Bien que P21P_Démonstrateur_Raquette.ino nous réserve encore pas mal de bonnes surprises, quelques évolutions visant à améliorer la convivialité émaillent ce démonstrateur. Il suffit souvent de peu de chose pour « changer la vie ». Quelques octets de plus pour beaucoup d’agacements en moins, l’investissement est bien plus que rentable. Les innombrables manipulations inhérentes au développement logiciel ont souvent conduit à un effet nul. Erreur de programme ou mauvaise touche cliquée ? Difficile de répondre. On utilise à nouveau le clavier et cette fois ça fonctionne. Le doute subsiste. Aussi, à partir de ce démonstrateur, toute touche qui n’a pas d’effet dans un menu engendrera un BIP sonore d’avertissement. L’opérateur sera ainsi averti qu’il a sollicité un bouton poussoir qui dans le contexte actuel n’est pas valide. Rien de révolutionnaire certes, mais pour un coût de 46 octets je vous assure qu’à l’usage c’est très utile. Autre petit détail presque insignifiant, SÉCURITÉ est dorénavant imposée pour pouvoir enregistrer un balayage télémétrique ou un spectre colorimétrique. Pour 42 octets investis, nous ne risquons plus d’écraser un enregistrement précédent auquel nous tenions car caractéristique pour une démonstration publique. La SÉCURITÉ doit également être allumée pour SAV POSTURE et Test UHF dont il sera question plus avant. Pour un coût totalement exagéré de 360 octets, des détails de présentation dont certains sont montrés sur la Fig.331 ajoutent un fifrelin de rigueur aux affichages. Regardez bien. Vous ne voyez pas ce qui a changé ?
Ben … chez Môamôa c’est maladif. Je ne supporte pas la vision de textes sur lesquels il manque les accentués. Alors pour envoyer un texto sur mon téléphone portable bas de gamme, je dois cheminer dans six écrans pour arriver à placer l’accent sur mon ‘é’. C’est ainsi. Ajouter un accent sur l’écran OLED revient à tracer un petit segment de deux pixels exactement au bon endroit. C’est calamiteux en temps de programmation et dramatique en augmentation de taille de programme. Tant pis, dilapidons, bouliminons et l’écran contiendra de merveilleux petits détails qui passeront totalement inaperçus. Donc si un jour vous voulez gagner de la place vous saurez où trouver 360 octets !

La genèse d’un dessin informatique.

Griffonner un dessin sur une feuille de papier s’apprend quand nous sommes tout petits. Puis certains génies s’affirment et sont capables de vous croquer un visage en quelques coups de crayon. Sans prétendre à posséder ce talent, on peut se débrouiller, et ce d’autant plus que la définition de notre portrait sera dérisoire, n’imposant pas à l’artiste une grande finesse. Il importe toutefois de s’y prendre avec méthode pour ne pas engloutir un nombre d’heures déraisonnable. Pour illustrer ce propos, commencez par téléverser Test_affiche_le_LOGO.ino ce qui revient à pratiquer :

Plagiat éhonté vont hurler ceux qui ont remarqué que le texte de l’encadré qui précède est un Copié / Collé d’un chapitre déjà abordé quand on a voulu mettre au point la visualisation à l’écran du listage d’un programme enregistré. Seul le nom du démonstrateur spécifique a été corrigé. L’histoire se répète, la méthodologie ne change pas. Chaque fois que se présente à vous un cas épineux, il sera toujours avantageux de consommer un peu de temps pour créer un petit module qui ensuite rendra le développement bien plus facile. N’oubliez jamais cette affirmation péremptoire.
La fin du téléversement du code dans l’ATmega328 s’achève par la visualisation d’un écran analogue à celui de la Fig.330 mis à part la date du logiciel. Ce qui impressionne, c’est la table des codes placée en tête de listage quand on consulte le programme source. Construite cette matrice de nombres binaires n’a rien d’élémentaire. Les chapitres qui suivent vont nous expliquer comment s’y prendre.

Première étape : « Scibouiller » une caricature.

Préalable à la cuisine informatique qui va suivre, commençons par dessiner ce que l’on désire. Si nous n’avons pas les facilités d’un illustre peintre, rien n’interdit de faire une photographie numérique de ce que l’on désire représenter. Puis, à l’aide d’un quelconque logiciel de dessin, la triturer pour en faire un croquis initial. Ensuite on imprime ce dernier. Gomme et crayons en renfort, on réalise une épure avec des traits volontairement épais. Quand vu de loin l’ensemble semble satisfaisant, avec un feutre noir on surligne pour, comme sur la Fig.332 améliorer le contraste.

Deuxième étape : Évaluer la définition du petit dessin.

Approche assez semblable à celle qui a conduit à la conception du petit tableau de bord virtuel, on doit disperser sur l’écran d’accueil les informations qui y figureront, définir leurs tailles respectives, et leurs positions précises. La Fig.333 représente grossièrement la page écran souhaitée. Dans le rectangle jaune 1 sera affichée la version du logiciel du pupitre à la plus petite police de caractères disponible dans la bibliothèque OLED. En 2 la ligne grise met en évidence la discontinuité de la matrice totale non pourvue de diodes électroluminescentes. En bleu clair la zone 3, correspondant aux luminophores bleus, est encadrée par souci esthétique. En 4 le mot SONDE est en taille minimale, contrairement en 5 au nom JEKERT affiché en double taille. Surtout en 6 nous avons « glissé » le dessin du LOGO avec sa plus grande taille possible en hauteur. Notez que sous la Griffe avant gauche il n’y a pas de tracé, le mot JEKERT est donc centré latéralement entre le dessin et le bord droit du cadre. Il importe maintenant de « numériser » la mosaïque du minuscule dessin.

 

Troisième étape : Transformer le dessin en une matrice de points.

Depuis l’abandon des tubes cathodiques qui généraient leurs images avec des lignes horizontales juxtaposées verticalement, les systèmes d’affichages actuels procèdent pratiquement tous par activation de points lumineux répartis sur des « grilles » généralement rectangulaires. Le nombre de points horizontaux et verticaux caractérisent la définition de ces écrans électroniques. Pour « numériser » l’esquisse représentée en 6 la technique consiste à imprimer une grille correspondant à la zone réservée au LOGO. Sur cette grille on trace au crayon le dessin désiré. Puis, soigneusement on noirci au feutre chaque petit carré qui se trouve sous une zone grisée initialement. Compte tenu de la surface affectée pour 6 on aboutit au résultat de la Fig.334 sur laquelle les carrés noirs correspondent en réalité aux pixels qui sur l’écran devront s’allumer. Dans la pratique, le résulta sera plus proche de la représentation Fig.335 sur laquelle les points allumés sont représentés en bleu clair. Le dessin a été épuré et ne représente plus les servomoteurs, les membres de l’insecte mécanique sont ainsi plus fins. Conserver leur présence conduisait à un ensemble confus les jambes ne se détachant pas assez du corps de la sonde. Maintenant que le chef-d’œuvre est abouti, il reste à le « binariser ».

Quatrième étape : Numériser la matrice de points.

Lorsque la grille artistique souhaitée est déterminée, il faut la faire correspondre aux luminophores physiques de la mosaïque électronique, trouver un moyen de l’y inscrire et si possible optimiser le code binaire qui sera chargé de ce traitement. Technique banale et incontournable, on utilise des OCTETs dont chaque BIT sera représentatif d’un point lumineux. État « 1 » le point sera allumé, état « 0 » il restera noir. Puis les octets seront balayés point par point pour être transportés dans la mémoire de l’afficheur OLED avec l’instruction display.drawPixel(). Il nous faut déterminer la structure du dessin « binaire » et la façon dont il sera balayé. Comme toujours se présente diverses possibilités, à nous de choisir le plus adaptée. (Optimiser !)

L’image binaire sera donc architecturée sous la forme d’un tableau d’OCTETs. Ces OCTETs seront rangés les uns à la suite des autres dans la mémoire dynamique de l’ATmega328, car pour le langage C++ les tableaux ne sont pas des constantes et peuvent évoluer au cours du temps. L’image à numériser doit donc être compartimentée en OCTETs, c’est à dire considérée comme des regroupements de huit points les uns contre les autres. En observant la Fig.336 on a mis en évidence deux possibilités strictement équivalentes en théorie. En A on regroupe les carrelages de la mosaïque horizontalement, contrairement au cas B où les OCTETS sont construits verticalement. Dans les deux cas, le nombre d’OCTETs horizontalement ou verticalement n’est pas entier. L’image retenue sur la Fig.333 fait 43 lignes x 52 colonnes. Latéralement nous avons la relation 52 = 6 x 8 + 4. Verticalement, la répartition fait 43 = 5 x 8 + 3. L’optimisation consiste à remplir l’image avec des OCTETs « entiers », puis à tracer ce qui se trouve en dehors par construction élémentaire de segments. Comme j’avais adopté la solution A sur d’autres programmes, par paresse mentale j’ai opté pour cette approche. Ici B serait plus logique car il n’y a que trois lignes à tracer au lieu de quatre. Comme le bénéfice escompté par B est faible, alors profiter d’une séquence déjà au point reste un choix raisonnable. Nous allons donc construire le dessin de la zone jaune sur la Fig.337 par exploitation d’une table de pixels rangés en OCTETs dans un tableau de bytes. La Griffe contenue dans la zone rouge sera construite à l’aide de quatre segments de droite verticaux.

Principe du balayage de construction d’une image.

Balayer, c’est déposer carrelage par carrelage et au bon endroit les divers éléments sur une surface qui représentera notre « fresque ». Dans notre cas, chaque carrelage est informatiquement un petit rectangle allongé de huit petits carrés « jaunes » ou noirs nommés PIXELs. Chaque élément allongé est nommé OCTET. Tous les carrelages qui vont composer notre œuvre d’art sont emballés dans un long paquet nommé byte Image_48x43[258]. (Tableau « linéaire » de 6 x 43 = 258 Octets.)
Informatiquement, le dessin du LOGO est préservé en mémoire sous forme d’un tableau d’OCTETs dans lesquels chaque PIXEL est matérialisé par un BIT. Si le BIT est à « 1 » il faudra allumer le point image correspondant, s’il est à « 0 » il faudra l’éteindre. Avec la bibliothèque Adafruit_ssd1306syp.h l’instruction display.drawPixel(X, Y, État); permet d’initialiser indépendamment chaque BIT de la matrice électronique de l’afficheur OLED. On indique ses coordonnées et l’état désiré.
Dans le programme codé en C++, l’image complète est une suite d’OCTETs dans lesquels nous avons imposé manuellement un « 0 » où un « 1 » pour que le total soit représentatif de la fresque que l’on veut transposer dans la mémoire de l’écran électronique.
Comme on peut le visualiser sur la Fig.338, traiter un OCTET du tableau informatique (Constitué de 258 OCTETs successifs dans la RAM.) consiste à « plaquer » les huit bits de ce dernier au bon endroit dans la grande matrice de RAM de 128 x 64 luminophores de l’afficheur OLED.

Le BALAYAGE consiste à prendre un à un et dans l’ordre les OCTETS dans le tableau byte Image_48x43[258] et à en déposer les huit BITs dans la mémoire RAM de l’afficheur.
Revenons au principe du BALAYAGE. Encore un mot issu de notre quotidien. Balayer une surface consiste à en « traiter » la totalité en procédant par éléments dont les dimensions sont fonction de notre allonge et de la largeur du balais. C’est exactement ce que l’on fait informatiquement pour une image. Dans ce but, il nous faut plusieurs INDEX. Un premier INDEX va être initialisé sur le tout premier élément du tableau byte Image_48x43[258]. Comme pour notre mental une image est à deux dimensions, autant raisonner comme des humains. La mémoire image devient alors une « macro matrice » de 6 COLONNEs et de 24 lignes. La Fig.336 met en évidence le fait qu’une COLONNE est constituée de macroéléments pour le balayage, et constituée d’OCTETs. Donc, chaque COLONNE sera en réalité pour l’image un groupe de huit « colonnes pixels ».
Pour effectuer un balayage simultané de la source (C’est à dire du tableau d’octets.) et de la destination, (La mémoire de l’afficheur OLED.) il nous faut concrètement trois INDEX. Le premier va explorer le tableau en ligne de l’élément 0 à l’élément 257. Le deuxième va balayer horizontalement les 6 COLONNEs de la gauche vers la droite. Puis, arrivé tout à droite de la « macro matrice », il sera ramené à gauche en reprenant la valeur zéro. L’INDEX pour les lignes sera incrémenté, et l’on traitera alors la ligne suivante. Notez que l’on effectue l’exploration de la gauche vers la droite, et du haut vers le bas. C’est purement arbitraire, il serait totalement équivalent de faire du bas vers le haut, de la droite vers la gauche. Toutes les variantes sont autorisées. L’auteur de ces lignes est très influencé par la télévision de Papa, celle où les écrans étaient des tubes cathodiques. Le balayage image était effectué comme choisi arbitrairement dans ce programme. Quand on prend de l’âge …

À ce stade de l’exposé, vous avez compris que chaque OCTET du tableau Image_48x43 représente huit PIXELs qui dans l’image seront successifs. L’OCTET devient une sorte de fenêtre qui va se déplacer d’élément en élément dans Image_48x43, et balayer COLONNEs/ligne dans la mémoire de l’afficheur. (Pour l’écriture, ligne est en lettres minuscules car elles désignent réellement des lignes de PIXELs dans l’image. Alors que COLONNEs est en majuscule car ce sont des groupements de huit « colonnes pixels ».) Ainsi vous pourrez faire plus facilement la distinction.
Quand on va imbriquer dans deux boucles de type for(….) on imagine assez bien la « fenêtre jumelle » constituée d’un OCTET qui puise dans l’ordre des paquets de huit BITs dans le tableau, et qui par balayage ligne/COLONNE les dépose dans la RAM de la grille électronique de luminophores. C’est ici que l’on rencontre une petite difficulté informatique. Les trois INDEX étant conditionnés, le plus simple consisterait à lire l’OCTET dans le tableau, puis à l’écrire directement dans la RAM de l’afficheur. Sauf … que la bibliothèque Adafruit_ssd1306syp.h ne nous fournit pas d’instruction pour lire et écrire des OCTETS. On peut soit utiliser des caractères, mais leurs empreintes nous sont imposées, soit déposer un à un des PIXELs en précisant leurs coordonnées.

Déposer des OCTETs dans l’afficheur OLED.

Abusons une fois de plus d’un petit dessin, toujours plus facile à cerner qu’un long verbiage. La Fig.339 suppose que l’identificateur OCTET contient les huit « PIXELs » puisés dans le tableau par lecture de l’un de ses éléments. Ce schéma suppose également que les index COLONNE et ligne pointent les coordonnées du premier point image à placer dans la RAM de l’afficheur. Pour « déposer l’OCTET » dans l’image, il faut extraire BIT par BIT l’état du PIXEL, puis avec l’instruction display.drawPixel(…); le placer dans la RAM image. On passe ensuite au BIT suivant et l’on recommence huit fois. Inutile de préciser que l’on va encore employer un index qui cette fois va varier entre 0 et 7. Il reste à « isoler » l’état de chaque BIT. Le plus rationnel dans ce type de traitement consiste à utiliser l’opération logiques de décalage. (Revoir les informations sur le décalage logique SHIFT abordé en Fig.141 du TOME 3.)

Les opérateurs LOGIQUES travaillant sur des BITs.

Désolé, mais dans la séquence qui construit le dessin sur la mosaïque de l’afficheur graphique, nous allons avoir besoin de faire appel à la notion de masque logique et d’opérateurs binaires travaillant BIT à BIT. Nous n’y consacrerons pas une thèse, toutefois un minimum d’informations sont indispensables pour pouvoir analyser le fonctionnement du programme. Le langage C++, comme tout système d’exploitation orienté microprocesseur du reste, met à notre disposition des opérateurs logiques qui permettent d’agir BIT à BIT dans un OCTET. Savoir les utiliser me semble absolument incontournable pour qui veut s’engager un tant sois peu en robotique.

La Fig.340 présente quelques exemples. Comme un exposé complet sur le sujet sortirait largement du cadre de ce document, nous allons restreindre notre réflexion au ET logique.

Pour isoler la valeur d’un BIT dans un OCTET, il suffit de mettre à « 0 » tous les autres dans le masque logique. L’exemple de la Fig.341 focalisant sur le cinquième octet de Image_48x43 montre que le résultat de l’opération donne bien un « 1 » si le bit examiné est à l’état haut, et un « 0 » s’il est à l’état bas.

L’état du PIXEL étant connu, il suffit alors de le confier à l’instruction de décalage SHIFT qui le « déposera au bon endroit » dans la RAM de l’afficheur graphique. Nous avons tous les éléments en main pour analyser la séquence qui écrit le petit dessin dans la mémoire de l’afficheur.

La variable PTR sera chargée de pointer l’octet à saisir dans le tableau Image_48x43[258]. En ligne (1) il est placé au tout premier élément du tableau. En ligne (2) on crée la variable locale Ligne qui va assurer le balayage vertical sur OLED. L’identificateur Colonne en variable globale sera chargé d’effectuer le balayage horizontal. En ligne (3) il pointe complètement à gauche sur l’afficheur. En ligne (4) on organise le balayage des six COLONNES avec la variable locale Tranche. L’instruction (5) recopie dans OCTET l’élément pointé par PTR dans Image_48x43[258]. En (6) on incrémente PTR pour pointer le prochain élément qui sera puisé dans le tableau. C’est l’instruction (7) qui va extraire BIT à BIT les huit PIXELs contenus dans OCTET et les inscrire dans la mémoire de l’afficheur OLED. La ligne (8) déroule toute une séquence d’instructions. En premier la fonction OCTET & B10000000 isole le BIT le plus à gauche contenu dans OCTET. Cette fonction ne fait que retourner une valeur et n’affecte pas le contenu d’OCTET. Dans cette écriture, le masque logique est B10000000, B précisant que la valeur est exprimée en binaire. La valeur « 0 » ou « 1 » retournée par l’opérateur & est alors déposée aux coordonnées convenables dans l’afficheur. Les constantes 5 et 19 décalent à notre convenance le dessin en largeur et en hauteur. En (9) on décale à gauche OCTET d’une position pour faire passer en poids fort le BIT suivant à l’aide de l’instruction de décalage <<.

La suite est ici.

 

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *