Conseils de pro
Définir des fonctions et des procédures
Depuis l’apparition des premiers langages informatiques et dès lors qu’ils ont permis l’écriture de programmes de plus en plus longs, la facilité de compréhension du code lors du codage et de sa relecture ainsi que le besoin de réutiliser des parties de code ont conduit à les regrouper en fonctions et en procédures. C’est l’origine d’une pratique professionnelle de la programmation qui permet de gérer des ensembles de code de plus en plus grands. Gérer, c’est créer son propre code, assembler des parties existantes avec de nouvelles productions, et bien évidemment faire en sorte que le code puisse évoluer facilement et à un coût réduit.
La version 5 de mBlock se rapproche d’un environnement de développement professionnel pour la part qui concerne le développement d’extensions, mais ces conseils sont bien évidemment applicables au codage de l’Arduino.
1. Les fonctions
Au sens mathématique du terme, une fonction attribue une valeur à une ou plusieurs variables qui lui sont communiquées en entrée. Ainsi, la fonction qui à tout x associe une valeur y=f(x) telle que y = 2x en est un exemple très simple. Mais une fonction surfaceDuRectangle() peut aussi attribuer une valeur correspondant au produit deux variables, l’une contenant la longueur et l’autre la largeur, qui lui seraient passées en paramètre. La notion de fonction est très utilisée en algorithmique dans la mesure où elle permet de décomposer un programme en éléments plus simples que l’on détaillera plus tard, l’essentiel étant de connaître sa syntaxe d’appel.
Utiliser la fonction surfaceDuRectangle(longueur, largeur) par exemple permet de se concentrer sur la gestion de son résultat en oubliant son calcul, celui-ci étant relégué à un niveau d’abstraction inférieur. L’approche descendante, héritée de la décomposition analytique chère à Descartes, permet d’écrire un programme à partir d’une idée générale et de décomposer l’algorithme...
Adopter une règle de nommage des variables et des objets (et s’y tenir !)
Règles de nommage : voir ce qui est préconisé dans les guides de programmation et ce qui se fait en général sur l’Arduino et sous mBlock.
Gérer les versions de code
La gestion de version de code est primordiale pour tout programmeur soucieux de la qualité de son travail et surtout de son efficacité. Dans le feu de l’action, l’esprit est concentré sur le « quoi », la raison d’être du programme, et sur les algorithmes qui permettent de l’implémenter et de le faire vivre.
Les considérations bassement matérielles comme le nommage du script ou du programme, ce qui le distingue de la version précédente, le repérage ou la trace de ses évolutions ou encore l’endroit où il sera stocké passent en second plan face à l’élan créatif du programmeur.
Et pourtant, elles sont essentielles à la réussite de cette activité et au succès du programme, dans le sens où il répond au besoin initial avec un niveau de qualité, de fiabilité et de coût conforme à ce qui était prévu avant son développement.
1. Les outils de gestion de version
Il existe des environnements de développement, hérités des techniques du génie logiciel et des usines de développement (software factories) qui permettent de gérer facilement des versions et leur historique. L’utilisation d’une extension (plug-in) de l’environnement Eclipse dédiée...
L’assemblage et l’intégration
Ces principes peuvent paraître un peu compliqués pour le débutant, mais ils deviennent essentiels lorsque la taille globale du code à développer est importante. Comment l’évaluer ? Traditionnellement, le nombre de lignes de code était un indicateur fiable lorsque les langages de programmation étaient bien connus. Avec la génération de code, c’est plutôt le nombre de fonctionnalités qui serait l’indicateur de taille et avec les projets robotiques ou domotiques il faudrait ajouter le nombre d’interactions avec l’environnement et la gestion des liaisons distantes entre composants.
C’est toute la problématique de l’assemblage et de l’intégration qui est posée et dont une part de la résolution s’appuiera sur la gestion de version.
Prenons un exemple assez simple et concret : une association à but scientifique et pédagogique lance le déploiement d’un réseau de stations de mesures environnementales à l’échelle d’une région, l’Île-de-France, par exemple. Le nombre de stations variera entre une dizaine et plusieurs centaines, selon le rythme d’appropriation de la démarche. Il s’agit de proposer à des associations, clubs, établissements scolaires...
Tester et détecter les bugs avant l’exécution : une check-list avant le décollage
La qualité des réalisations est assurée par des tests au cours du développement et avant la mise en service :
-
La vérification de la programmation textuelle et visuelle, qui est simplifiée de façon très importante pour cette dernière avec un gain de temps substantiel.
-
Les tests de bon fonctionnement.
La check-list suivante pourra être enrichie de nouveaux points de contrôle.
A - Vérification de la programmation textuelle
-
La syntaxe
-
Les lignes d’instructions se terminent par ;.
-
Les commentaires sont bien signalés (pas de commentaire sans // ou sans /* … */).
-
Les déclarations
-
La déclaration des PIN de l’Arduino correspond au câblage.
-
Les valeurs des constantes sont correctes.
-
Le nom des variables est cohérent avec leur utilisation dans le setup et dans la boucle.
-
Les objets sont correctement déclarés (servo…).
-
Les fichiers include des librairies sont déclarés.
-
L’initialisation
-
Le mode d’utilisation des PIN (INPUT, OUTPUT) est déclaré par l’instruction pinMode(nom ou numéro du pin, INPUT ou OUTPUT).
-
Les résistances de pull-up sont activées par l’instruction digitalWrite(nom ou numéro du pin).
-
Les servomoteurs sont attachés à...
Tracer et commenter les algorithmes et le code
Il y a bien des années, quand la compilation d’un programme prenait une demi-journée et son exécution le reste du temps, le « temps machine » était une denrée très précieuse et les programmeurs relisaient et vérifiaient minutieusement leur code avant de le « faire passer ». Les erreurs de programmation étaient rares et pouvaient être très coûteuses en termes de temps machine facturé ou de papier mis au rebut. Il y avait une éthique du programmeur, qui devait non seulement produire un code de qualité, mais également s’assurer de sa capacité à évoluer facilement. La métrologie du logiciel est née à cette époque et avec, la construction puis la fusion de systèmes informatiques devenus des systèmes d’information.
Cette anecdote un peu « rétro » permet de mettre en lumière une activité qui est en même temps un paradoxe et une nécessité.
Le paradoxe tient au fait qu’un programme est une suite d’instructions écrite délibérément par un programmeur donc de façon complètement déterministe. Hors heuristique ou moteur d’intelligence artificielle, le programme suit le strict enchaînement des instructions dont le cours peut varier au gré de ses structures, séquentielles, conditionnelles ou répétitives, ou encore des appels de fonctions et de procédures, mais qui correspond forcément à un chemin prévu. Quoi qu’il en soit, le compilateur, avec le peu de marge de manœuvre dans la traduction du code en bits qui est la sienne, produit un objet physique et bien délimité qui sera exécuté par le microcontrôleur.
Alors, pour quelles raisons le programme ne se comporterait-il pas comme attendu ? Ou bien, dans le cas où tout semble se dérouler comme prévu, quelle assurance cela donne-t-il...
Ne jamais supposer que le microcontrôleur ou l’ordinateur sait quelque chose…
Dans son livre Proverbes de programmation, Henry Ledgard (Édition Bordas, 1978, publié dans la collection Dunod Informatique, traduit de l’anglais par Jacques Arsac) donne le conseil suivant : « ne supposez jamais que l’ordinateur suppose quelque chose ! »
Ce proverbe est le 17e d’une liste de 26 conseils qui concernent l’étude du programme à réaliser, sa réalisation et son exécution. Une quatrième catégorie mentionne le besoin de relire la documentation, de penser à un autre langage et de ne pas avoir peur de tout recommencer. Presque quarante ans après sa publication, il est frappant de constater que la plupart de ces 26 proverbes sont toujours d’actualité et ce, quel que soit le langage, car ce qui est visé c’est la pratique de la programmation, l’action de coder en train de se faire et non des éléments techniques.
Ne jamais supposer que le microcontrôleur suppose quelque chose se situe dans les fondements de la cybernétique et dans la notion même de programme. À moins qu’il ne s’agisse d’intelligence artificielle ou d’un raisonnement basé sur l’apprentissage, tout programme est déterministe et le comportement de la machine...
Penser au pire, développer pour le meilleur
L’expérience de la programmation confirme le caractère utile et même précieux du proverbe de la section précédente qui peut se décliner sous la forme « penser au pire, développer pour le meilleur ».
1. Penser au pire
Dans le fil de l’action de coder, que ce soit par le texte ou visuellement, l’esprit du développeur est accaparé par la logique du programme ou du script et par les algorithmes qu’elle sous-tend. Le niveau d’abstraction est plus élevé et se situe au niveau des grandes fonctions à assurer et des intitulés de procédures. Les détails seront vus plus tard… ou pas. Lorsqu’une variable est créée, elle correspond en général à une grandeur numérique, un texte ou une variable booléenne, pour les types de données les plus simples. Dans le cas d’une variable numérique, par exemple, celle-ci présente plusieurs caractéristiques et peut même être soumise à des contraintes :
-
Sa plage de valeurs peut être limitée, par exemple, pour une variable qui mémorise l’angle d’un servomoteur, elle ne peut varier qu’entre 0 et 180 degrés.
-
Au démarrage d’un programme, elle peut avoir une valeur quelconque. Par exemple, la variable reflétant l’état d’un port en entrée d’un microcontrôleur peut correspondre à la tension entre ce port et la masse et prendre n’importe quelle valeur entre 0 et cette tension de service, qui dépend du type de microcontrôleur utilisé. Compte tenu des fluctuations électrostatiques, il est même possible de considérer que sa valeur est aléatoire.
-
Lors de l’exécution d’un programme, la valeur de la variable peut subir différentes modifications selon la logique du code. Elle peut se voir affecter le résultat d’un...
Autres proverbes utiles d’Henry Ledgard
Parmi les 26 proverbes de l’édition originale, figurent également les suivants :
1 - « Définissez le problème complètement. »
2 - « Réfléchissez d’abord, vous programmerez plus tard. »
3 - « Utilisez l’analyse descendante. »
6 - « Utilisez des procédures. »
10 - « Choisissez bien vos identificateurs. »
12 - « Ne touchez pas aux paramètres d’une boucle. »
13 - « Ne recalculez pas de constantes dans une boucle. »
14 - « Évitez les particularités d’une implémentation. »
15 - « Évitez les astuces. »
18 - « Employez les commentaires. »
20 - « Fournissez une bonne documentation. »
21 - « Testez le programme à la main avant de l’exécuter. »
22 - « Ne vous préoccupez pas de la présentation des résultats avant que le programme soit correct. »
23 - « Quand le programme est correct, soignez la présentation des résultats. »
24 - « Relisez le manuel. »
…
26 - « N’ayez pas peur de tout recommencer . »
Un exemple de problème : le rebond des boutons poussoirs et des détecteurs de contact
1. Le problème
Le problème correspond à la situation suivante, qui est très courante dans le domaine de la robotique et de l’électronique de loisirs :
-
Un montage a été câblé avec soin, vérifié puis mis sous tension.
-
Ses composants choisis sont de premier choix et les essais unitaires (servomoteur, moteur, joystick…) étaient encourageants.
-
Tous les ports de l’Arduino sont initialisés en entrée ou en sortie comme il se doit.
-
La batterie est chargée et l’Arduino est alimenté par une pile 9V indépendante.
-
Toutes les masses sont connectées.
En synthèse, un montage qui a toutes les chances de remplir les espérances de son créateur.
Seulement, à l’appui sur le bouton censé déclencher une action, rien ne se passe. Pire, après plusieurs appuis, tout se bloque.
Le montage et son concepteur sont les victimes d’un mal très courant : le rebond du bouton poussoir.
Sans entrer dans les détails, les tolérances de fabrication des boutons poussoirs grand public sont à peu près proportionnelles à leur coût. Il en va bien évidemment différemment de composants utilisés dans l’industrie. Lors d’un...
Cent fois sur le métier remettre son ouvrage
Cette maxime est inspirée de la formule initiale de Nicolas Boileau qui au XVIIe siècle posait les fondements de la philosophie de tout développeur du monde moderne :
Avant donc que d’écrire, apprenez à penser. »
Ce que l’on conçoit bien s’énonce clairement,
Et les mots pour le dire arrivent aisément. »
Hâtez-vous lentement, et sans perdre courage,
Vingt fois sur le métier remettez votre ouvrage,
Polissez-le sans cesse, et le repolissez,
Ajoutez quelquefois, et souvent effacez. »
Tout ce qui est écrit là est rigoureusement juste et bien évidemment dans des domaines autres que celui du codage et des projets à base d’Arduino. Mais il faut reconnaître que la première maxime vise à tempérer un enthousiasme tout à fait naturel qui pousse à connecter une carte ou un module avant même d’avoir étudié dans le détail ce qu’il allait bien pouvoir faire. La seconde renvoie à la description de ce que le code devra faire, sa spécification, et l’exercice sur le calcul de la date de Pâques a pu illustrer le besoin de réfléchir avant de coder.
La dernière maxime, la plus longue et celle qui a peut-être le plus de sens mérite quelques aménagements....
Gérer les bibliothèques
Question fréquemment posée sur les forums, la gestion des bibliothèques dans l’environnement de l’Arduino doit être maîtrisée, car elle pose souvent des problèmes lors de la génération du code, en particulier à la compilation.
Parmi les difficultés qu’un programmeur débutant ou confirmé peut rencontrer, se trouvent :
-
les problèmes de compilation du fait d’une bibliothèque à inclure non trouvée par le compilateur,
-
des problèmes de fonctions non définies ou manquantes alors que le code ou une bibliothèque incluse les utilisent,
-
des problèmes de bibliothèques appelées par des bibliothèques incluses et qui ne peuvent être trouvées,
-
des problèmes d’incompatibilité entre une bibliothèque et le type de carte utilisé,
-
des problèmes de conflits de noms entre bibliothèques nommées de la même façon et a priori identiques, mais dont le contenu a pu être modifié par un développeur.
Il est gênant de constater que la logique de réutilisation du code, pensée par la mise à disposition de bibliothèques dont le contour est bien délimité et l’usage, soit spécifique à un matériel soit générique à une fonction, amène au final à passer du temps en mise au point lors de la compilation....