Ce document est prévu comme support pour la formation Initiation à Linux et à la programmation sur Raspberry Pi donnée à la Patente. Il est amené à évoluer en fonction des questions et commentaires des participants!
Lors de cette formation, vous apprendrez à utiliser un Raspberry Pi pour monter une station de contrôle d’humidité pour plantes d’appartement. Ce sera l’occasion de configurer votre propre Raspberry Pi, de vous initier à Linux et aux bases de la programmation et de développer un petit circuit électronique.
Le Raspberry Pi est un nano-ordinateur (single-board computer, SBC) développé par l'Université de Cambridge pour démocratiser l'accès aux ordinateurs et à la robotique. Le premier modèle est sorti en 2012.
Il se démarque d'un ordinateur conventionnel sous plusieurs abords:
Depuis le premier modèle commercialisé en 2012, il existe plusieurs versions. Une liste complète des modèles est disponible sur le site officiel (en anglais). En voici un résumé.
En général, plus le numéro de modèle est élevé, plus l'ordinateur est rapide et plus ses besoins en énergie sont grands. Certains modèles diffèrent selon la quantité de mémoire vive fournie. Voir le lien ci-dessus pour plus de détails.
Quelques différences marquantes:
C'est ce type de modèle qui est utilisé dans le cadre de la formation donnée à la Patente.
Ce sont des modèles plus petits, moins chers, avec moins de connecteurs et qui consomment moins d'énergie. Ils sont donc particulièrement adaptés aux applications mobiles.
Le Pico n'est pas un ordinateur complet! Il s'agit d'un microcontrôleur (micro-controller unit, MCU), similaire au Arduino. On le programme au moyen d'un kit de développement (SDK).
Ces modèles sont intégrés dans un clavier. Le 400 est basé sur un modèle 4, le 500 sur un modèle 5.
Les modules compute ne comportent que le processeur et certains composants essentiels, ils sont prévus pour être insérés dans des châssis. Ils servent en général pour un usage industriel.
Voici un aperçu des connecteurs d'un Raspberry Pi modèle 5. Si vous avez un modèle plus ancien, il y aura quelques différences mais les principaux restent les mêmes:
Il est important de noter que même si la prise d'alimentation utilise un connecteur de type USB (USB-C sur les modèles 4 et 5, micro-USB sur les modèles plus anciens), on ne peut pas substituer le bloc d'alimentation fourni par n'importe quel chargeur USB comme p.ex. un chargeur de téléphone. En-effet, les besoins du Pi en énergie sont relativement importants: 3A jusqu'au modèle 4 et 5A pour le 5. La plupart des chargeurs bon marché ne peuvent pas fournir un tel courant.
Lorsque le Pi est sous-alimenté, il peut dysfonctionner et cela peut causer des erreurs d'écriture sur la carte SD pouvant mener à des fichiers corrompus. Les périphériques USB (souris, clavier) consomment aussi de l'énergie.
Voici un aperçu des composants d'un Raspberry Pi modèle 5. Les modèles antérieurs sont similaires.
Le premier pas avant d'utiliser un Raspberry Pi est d'y installer un système d'exploitation. La méthode la plus courante est d'utiliser l'imageur Raspberry Pi, une application gratuite qui permet d'installer rapidement le logiciel sur une carte SD. L'application Imager devrait déjà être présente sur les postes informatiques de l'atelier.
Depuis le modèle 5, il est aussi possible d'installer le système directement à partir d'une connexion internet par câble Ethernet (démarrer avec la touche majuscule enfoncée et suivre les indications).
Lorsqu'on démarre l'imageur, il suffit de choisir la génération du Pi (important de choisir la bonne pour s'assurer de la compatibilité du logiciel choisi), la variante du système d'exploitation désiré et la carte SD sur laquelle on souhaite installer le logiciel.
Attention de choisir la bonne carte SD car le logiciel va l'effacer entièrement!
Lors de l'étape suivante, il est possible de configurer l'installation en cliquant sur l'option "éditer la configuration". Les réglages suivants sont recommandés:
La première chose à faire une fois le système d'exploitation installé est de le mettre à jour.
Si on a installé une version de Linux avec interface graphique, les mises à jour disponibles s'affichent dans la barre des menus:
Sinon, on peut utiliser la ligne de commande (voir plus bas) avec l'utilitaire apt
(Advanced Package Tool).
On commence par mettre à jour le catalogue de logiciels maintenu par apt
:
sudo apt-get update
Noter l'usage de sudo
(Super User DO) pour appliquer les mises à jour en tant qu'administrateur.
Une fois que le catalogue est à jour, on peut tout mettre à jour les logiciels par la commande suivante:
sudo apt-get full-upgrade
apt
va nous demander de valider la liste de logiciels à mettre à jour. Taper sur retour pour accepter la mise à jour et attendre que ce soit terminé.
On peut utiliser Linux avec son interface graphique au moyen d'une souris et d'un clavier pour faire la plupart des opérations nécessaires. Cependant, il reste utile de savoir interagir avec l'ordinateur via la ligne de commande, qu'on appelle aussi "terminal".
Pour ouvrir un terminal, on peut cliquer sur cette icône dans la barre des menus, ou utiliser le raccourci Contrôle-Alt-T:
En deux mots, il s'agit d'une façon de transmettre des ordres à l'ordinateur en les tapant avec le clavier. Une fois qu'on a tapé la commande, on utilise la touche Entrée ou Retour pour l'effectuer. Lorsqu'on ouvre le terminal, on est présenté à une fenêtre qui attend les ordres. Celle-ci affiche en général un "prompt", soit une ligne qui contient quelques informations et se termine par le signe $
, par exemple
votrenom@nom-du-pi:~/chemin/dossier $
Le prompt affiche
$
qui indique que l'ordinateur attend un ordre pour continuerUne commande est en général constituée du nom du programme que l'on souhaite utiliser suivi éventuellement par un ou plusieurs paramètres séparés par des espaces. Par exemple, pour naviguer vers le dossier formations/raspberry-pi
, on utilise la commande cd
suivie du chemin vers lequel on veut se déplacer, puis la touche retour:
$ cd formations/raspberry-pi
Pour en savoir plus sur comment utiliser la ligne de commande, on peut se référer à ce tutoriel.
Commande | Fonction |
---|---|
pwd |
Afficher le chemin du dossier dans lequel on se trouve actuellement |
cd |
Naviguer vers un dossier: cd chemin/vers/dossier ou retourner dans le dossier d'origine avec juste cd . |
ls |
Afficher le contenu du dossier dans lequel on se trouve actuellement. |
cp |
Copier un fichier: cp source destination |
mv |
Renommer ou déplacer un fichier mv source destination |
rm |
Effacer un fichier. Attention cette opération est immédiate et irreversible, il n'y a pas de "corbeille". |
less |
Visualiser le contenu d'un fichier texte (sans l'éditer). Taper q pour quitter. |
nano |
Éditer un fichier texte. |
top |
Afficher les programmes en cours d'exécution et leur utilisation du processeur. Une alternative plus visuelle est btop mais elle n'est pas installée par défaut. |
Pour configurer le Raspberry Pi (ex. changer la langue, changer le type de clavier que l'on utilise, modifier son mot de passe, etc.) il y a un utilitaire visuel dans le menu "framboise"->Preferences->Raspberry Pi Configuration.
On peut accéder aux mêmes réglages par la ligne de commande en utilisant l'utilitaire raspi-config
:
sudo raspi-config
L'interface suivante s'affiche. On la navigue en utilisant les flèches du clavier et la touche Entrée/Retour pour effectuer une sélection.
L'installation de nouveaux logiciels sur Linux est un peu différente que sous Windows ou MacOS. En général, on utilise un gestionnaire de paquets pour installer un logiciel. Si on utilise l'interface graphique, on peut utiliser l'utilitaire d'installation de logiciels et rechercher celui que l'on veut avant de l'installer. On peut aussi utiliser apt
sur la ligne de commande.
Par exemple, on peut installer le logiciel de dessin vectoriel Inkscape, ou la suite LibreOffice (équivalente gratuite à la suite Microsoft Office). Pour installer Inkscape avec la ligne de commande, il suffit d'écrire
sudo apt-get install inkscape
et suivre les indications à l'écran.
Suivant les usages, il peut être parfois utile de configurer un Raspberry Pi sans écran ni clavier. On parle de configuration "sans tête" ou "headless". C'est notamment utile lorsqu'on a plusieurs Pi à configurer ou lorsqu'on veut installer une version minimale du système d'exploitation pour un usage qui ne nécessite pas d'interface graphique (p.ex serveur, robotique, etc.).
Pour ce faire, configurer le WiFi et activer SSH lors de l'écriture du système d'exploitation sur la carte SD (dans les configurations avancées de l'imageur). Ensuite, démarrer le Pi (pas besoin d'un écran, clavier ni souris) et s'y connecter par SSH.
Le protocole SSH (secure shell) est très utile pour se connecter à distance avec un ordinateur sous Linux/Unix ou un serveur. Il s'agit d'une interface par ligne de commande uniquement.
Pour se connecter à un Pi sur lequel on a activé SSH, le plus simple si on utilise MacOS ou Linux sur son ordinateur est d'ouvrir un terminal et taper les commandes ci-dessous. Sous Windows, on peut utiliser le logiciel PuTTY.
En principe il est possible d'atteindre le Pi en utilisant son nom (remplacer nom-utilisateur
et nom-du-pi
par ceux que vous avez choisi lors de la config):
ssh nom-utilisateur@nom-du-pi
ou
ssh nom-utilisateur@nom-du-pi.local
Si ça ne marche pas, utiliser un sniffeur réseau ou l'utilitaire de configuration du routeur WiFi pour trouver l'adresse IP du Pi que l'on cherche à atteindre, par exemple:
ssh nom-utilisateur@128.132.1.5
On a ensuite accès à la ligne de commande du Raspberry Pi, que l'on peut configurer avec sudo raspi-config
etc.
Une alternative à SSH qui peut être intéressante est d'utiliser le service Raspberry Pi Connect. Celui-ci nécessite de se créer un compte (gratuit) sur le site de Raspberry Pi puis d'activer la fonction Raspberry Pi Connect. On est ensuite en mesure de se connecter soit via l'interface graphique (un peu comme Remote Desktop) soit via la ligne de commande directement depuis un navigateur web n'importe où dans le monde.
Dans cette section, nous allons commencer à utiliser les broches GPIO qui vont nous permettre de connecter des composants au Raspberry Pi (GPIO = General Purpose Input and Output).
Les graphiques suivants indiquent la fonction de chaque broche sur un Raspberry Pi:
Prendre note en particulier des broches suivantes:
On trouvera plus d'informations sur l'interface GPIO sur pinout.xyz ou dans la documentation officielle (en anglais).
On peut contrôler et lire les signaux reçus sur les broches GPIO directement depuis la ligne de commande. Cela est très utile lors du développement d'un circuit ou pour résoudre les erreurs.
Les commandes suivantes sont utiles:
Commande | Fonction |
---|---|
pinout |
Affiche un schéma avec la numérotation des broches |
pinctrl -p |
Liste le statut de chaque broche GPIO. |
pinctrl get X |
Lit le statut de la broche X. |
pinctrl set X op |
Définit la broche X comme une sortie (output). |
pinctrl set X ip |
Définit la broche X comme une entrée (input). |
pinctrl set X dh |
Envoie le signal "ALLUMÉ" (3.3 V) sur la broche X (drive high). |
pinctrl set X dl |
Envoie le signal "ÉTEINT" (0 V) sur la broche X (drive low). |
Il est possible de combiner plusieurs commandes, par exemple pinctrl set 23 op dh
définit la broche 23 comme une sortie et la met en mode "ALLUMÉ".
À noter que dans la plupart des cas, les attributs get
et set
sont optionnels.
Pour les versions antérieures au Raspberry Pi 5, utiliser
raspi-gpio
au lieu depinctrl
(fonctionne de manière similaire).
Pour tester la fonction d'écriture sur les ports GPIO, on utilise le montage suivant.
Quelques détails
On peut maintenant jouer à allumer et éteindre les dels en utilisant
pinctrl set 23 op # Définit la broche 23 comme une sortie.
pinctrl set 24 op # Définit la broche 24 comme une sortie.
pinctrl set 23 dh # Envoie le signal "ALLUMÉ" (3.3 V) sur la broche 23 (drive high).
pinctlr set 24 dh # Envoie le signal "ALLUMÉ" (3.3 V) sur la broche 24 (drive high).
pinctlr set 23 dl # Envoie le signal "ÉTEINT" (0 V) sur la broche 23 (drive low).
pinctrl set 24 dl # Envoie le signal "ÉTEINT" (0 V) sur la broche 24 (drive low).
Pour les versions antérieures au Raspberry Pi 5, utiliser
raspi-gpio
au lieu depinctrl
(fonctionne de manière similaire).
Le Raspberry Pi ne peut lire que des valeurs numériques (1 ou 0) sur le GPIO. Pour recevoir des valeur analogiques (variations de tension), il faut utiliser un convertisseur.
Dans cette section nous allons voir comment connecter un convertisseur analogique-digital en utilisant l'interface I2C (Inter-Integrated Circuit). Il s'agit d'une interface sérielle permettant de dialoguer entre plusieurs circuits. Le protocole I2C a besoin de deux lignes:
Sur le Raspberry Pi, l'interface I2C n'est pas activée par défaut. Pour l'activer, il faut retourner dans l'interface de configuration
sudo raspi-config
En navigant vers 3 Interface Options puis I5 I2C on peut activer cette interface.
Les connecteurs suivants sont présents sur ce circuit.
Nom | Fonction | À brancher sur |
---|---|---|
G (GND) | Mise à la terre | Une des broches GND du Pi |
V (VCC) | Source de tension entre 2 et 5.5V | On utilise ici le voltage 3.3V fourni par le Pi sur la broche 1 |
SCL | Port SCL de l'interface I2C | Port SCL du Pi (broche 3) |
SDA | Port SDA de l'interface I2C | Port SDA du Pi (broche 5) |
ADDR | Permet de définir l'adresse du convertisseur, utile lorsqu'on en utilise plusieurs. | (non utilisé ici) |
ALERT | Peut servir pour indiquer qu'une des valeurs mesurée dépasse une valeur prédeterminée, utile pour un usage asynchrone. | (non utilisé ici) |
A0 | Entrée analogique, canal 0 | Sortie AOUT du capteur d'humidité |
A1 | Entrée analogique, canal 1 | (non utilisé, disponible pour un autre senseur) |
A2 | Entrée analogique, canal 2 | (non utilisé, disponible pour un autre senseur) |
A3 | Entrée analogique, canal 3 | (non utilisé, disponible pour un autre senseur) |
Pour vérifier que le convertisseur est correctement branché et alimenté, on peut utiliser l'outil i2cdetect
dans la ligne de commande:
i2cdetect -y 1
Celui-ci imprime une matrice de tous les circuits opérationnels sur le bus I2C. Si tout va bien, on devrait voir apparaître le convertisseur à son adresse par défaut 0x48
(notation hexadécimale):
. 0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- 48 -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
Les connecteurs suivants sont présents sur ce circuit.
Nom | Fonction | À brancher sur |
---|---|---|
GND | Mise à la terre | Une des broches GND du Pi |
VCC | Source de tension entre 3.3 et 5.5V | On utilise ici le voltage 3.3V fourni par le Pi sur la broche 1 |
AOUT | Sortie du signal mesuré entre 0 et 3V | Entrée analogique A0 du convertisseur ADS1115 |
Voici un schéma du montage complet
La communication par interface sérielle est assez compliquée à faire à la main, il est préférable d'utiliser une librairie pour nous aider.
Dans les versions récentes de Raspberry OS, il est nécessaire d'opérer au sein d'un environnement virtuel lorsqu'on utilise Python. Il faut donc commencer par le créer et ensuite l'activer. Lors de la création, on peut utiliser l'option --system-site-packages
pour remprendre toutes les librairies par défaut (sinon on part de zéro):
python -m venv --system-site-packages mesure-humidite
source mesure-humidite/bin/activate
Lorsque notre environnement est activé, son nom devrait apparaître dans le prompt entre parenthèses.
On peut maintenant installer la librairie qui nous permet de communiquer avec le convertisseur:
pip install adafruit-circuitpython-ads1x15
Si on a une erreur pip3: command not found
, il peut être nécessaire de l'installer avec
sudo apt-get install python3-pip
Un petit programme tout simple a été développé dans le cadre de cette formation pour afficher les valeurs mesurées par le convertisseur. Pour l'installer il suffit de faire
git clone https://github.com/timtomch/formation-raspi.git
Celui-ci lit les valeurs relevées sur les 4 canaux du convertisseur analogique-digital et les imprime (1x par seconde):
cd formation-raspi
python adctest.py
On devrait voir l'affichage suivant:
A0 A1 A2 A3
0.260 0.928 0.928 0.922
0.260 0.924 0.928 0.926
0.260 0.930 0.920 0.928
0.258 0.922 0.926 0.926
...
(les valeurs affichées vont varier). Taper Contrôle-C pour interrompre le programme.
Noter maintenant le voltage mesuré lorsque le capteur est à sec, immergé dans l'eau, ou planté dans la terre humide.
En principe, plus la terre est sèche, plus la tension de sortie sera élevée. La valeur exacte va aussi dépendre de la profondeur du capteur, etc.
Le capteur d'humidité utilisé dans ce projet est de type capacitif. Dans un condensateur classique, deux plaques (les électrodes) sont séparées par de l'air ou du papier (milieu diélectrique). Lorsqu'on applique un courant électrique entre les deux électrodes, une charge électrique va progressivement se former et le voltage va augmenter jusqu'à un certain maximum. Lorsqu'on retire le courant, cette charge électrique va à son tour se "vider" et générer un courant. La vitesse de chargement et déchargement d'un condensateur dépend du milieu diélectrique (ce qu'il y a entre les électrodes).
Dans un capteur d'humidité, le milieu diélectrique est constitué de la terre qui se trouve à proximité du senseur, et la quantité d'eau qu'il contient va donc influencer la vitesse de chargement et de déchargement du "condensateur" formé entre les électrodes (situées dans la partie pointue du capteur). C'est cet effet qui est mesuré. On trouve quelques explications supplémentaires ici et là (en anglais).
Voici quelques principes de base de programmation en utilisant le language Python.
On trouvera beaucoup de ressources sur Internet pour aller plus loin, par exemple le tutoriel "Bases de Python" et le livre en ligne "Apprendre à programmer avec Python3".
On peut utiliser Python de deux manières:
En principe, on peut utiliser n'importe quel éditeur de texte pour écrire un programme Python. En pratique, l'idéal est d'utiliser un éditeur spécialisé qui va nous aider à rédiger notre programme en vérifiant les fautes de frappe et en utilisant la couleur pour améliorer la lisibilité.
Un tel éditeur est Thonny, qui est installé par défaut sur Raspberry Pi OS. Celui-ci offre à la fois une console Python et un éditeur de fichiers de programme:
Attention à utiliser le bon environnement virtuel lorsqu'on utilise Thonny. Ce sera particulièrement important lorsqu'on commencera à utiliser des librairies. Utiliser le menu en bas de l'écran à droite pour passer de l'environnement par défaut (
/usr/bin/python3
) à celui qu'on souhaite utiliser. Ici, il s'agit demesure-humidite
qu'on a créé plus haut.
Pour faire des opérations arithmétiques simples:
3 + 5 * 4
On peut utiliser des variables pour stocker temporairement une valeur ou le résultat d'une opération:
var1 = 3
var2 = 5
var1 + var2
var3 = var1 * var2
On peut définir des listes comportant plusieurs éléments de la manière suivante:
maliste = [1, 3, 5, 7, 9]
maliste[0]
maliste[1]
Noter que Python utilise un index de base zéro: le premier élément d'une liste a l'index 0, le second l'index 1, etc.
On peut faire appel à des fonctions en leur fournissant un ou plusieurs paramètres entre parenthèses:
print(var3)
print('Le résultat du calcul est ', var3)
len(maliste)
On peut utiliser les comparateurs suivants pour comparer deux valeurs:
Symbole | Comparaison |
---|---|
> |
Plus grand que |
< |
Plus petit que |
== |
Est égal à |
!= |
Est différent de |
>= |
Est plus grand ou égal à |
<= |
Est plus petit ou égal à |
if(var3 > 10):
print('Valeur importante')
else:
print('Valeur faible')
Noter que les blocs logiques commencent par
:
et doivent être indentés (avec des espaces ou des tabulations).
On peut combiner plusieurs tests logiques avec les opérateurs ET (and
) et OU (or
):
2 < 3 and 3 < 4
True
2 < 3 and 3 > 4
False
2 < 3 or 3 < 4
True
2 < 3 or 3 > 4
True
Lorsqu'on souhaite faire une opération iterative pour chaque élément d'une liste, on utilise l'opérateur for
:
for i in [0, 1, 2]:
print("valeur :", i)
print("Fin")
Lorsqu'on ne sait pas encore combien d'itérations seront nécessaires, on peut utiliser l'opérateur while
à la place. Celui ci continue la boucle tant que la condition indiquée est vraie.
x = 1
while x < 10:
print("x a pour valeur", x)
x = x * 2
print("Fin")
Les mots-clefs suivants permettent en outre de sortir d'une boucle en tous temps:
break
: pour sortir immédiatement de la bouclecontinue
: pour passer au tour de boucle suivantOn peut définir ses propres fonctions avec le mot-clef def
:
Sans paramètre:
def compteur():
i = 0
while i < 3:
print(i)
i = i + 1
compteur()
Avec paramètre:
def compteur(stop):
i = 0
while i < stop:
print(i)
i = i + 1
On peut avoir plusieurs paramètres
def compteur_complet(start, stop, step):
i = start
while i < stop:
print(i)
i = i + step
compteur_complet(1, 7, 2)
En pratique, on veut souvent pouvoir utiliser le résultat d'une fonction dans une autre opération. On utilise pour ça le mot-clef return
pour définir la valeur "retournée" par une fonction:
def verif_temperature(temp, limite)
if temp > limite:
return False
else: return True
Cela permet alors d'utiliser la fonction dans une autre opération, par exemple:
if verif_temperature(14,20):
print('Il ne fait pas trop chaud')
C'est une bonne idée d'ajouter des commentaires dans son code pour expliquer ce qu'on fait. Cela permet de s'y retrouver par la suite. Les commentaires sont précédés du caractère #
que l'on peut utiliser sur une ligne seule, ou après une opération:
# Fonction pour vérifier si la température est dans la limite indiquée.
def verif_temperature(temp, limite)
if temp > limite:
return False # La limite est atteinte
else: return True # La limite n'est pas atteinte
L'une des forces du language Python est la grande diversité de librairies à disposition. Une librairie Python (parfois aussi appelé bibliothèque, "library" en anglais) permet d'étendre les fonctionnalités de Python et rend plus aisé de travailler sur un certain domaine. Par exemple, il existe des librairies pour les calculs mathématiques (pandas, numpy), la visualisation de données (matplotlib), la communication avec des services sur internet (requests), l'intelligence artificielle (pytorch), etc.
Il en existe aussi plusieurs qui simplifient le développement de circuits personnalisés sur Raspberry Pi. Nous en avons du reste déjà utilisé une lorsque nous avons communiqué avec le convertisseur analogique digital dans la section précédente.
Certaines de ces librairies sont installées par défaut dans Raspberry Pi OS. Lorsqu'on crée un environnement virtuel avec l'option --system-site-packages
, on peut immédiatement en bénéficier. Sinon, il suffit de les installer avec pip
.
Librairie | Description | Installée par défaut? |
---|---|---|
gpiozero | Simplifie le contrôle des broches GPIO, fournit des fonctions permettant de faire clignoter une DEL, contrôler des boutons, relais, moteurs, écrans, etc. | Oui |
time | Permet de compter le temps écoulé ou d'interrompre un programme pendant un temps donné. | Oui |
picamera | Permet de contrôler une caméra. | Non |
adafruit-circuitpython-ads1x15 | Permet de contrôler les convertisseurs analogique-digital ADS1015 et ADS1115. Nous l'avons utilisée plus haut. | Non |
board | Permet d'obtenir rapidement les numéros de broches correspondant à un usage précis. Par exemple, au lieu de devoir se rappeler que le port SCL de l'interface I2C est sur la broche 3, on peut utiliser board.SCL . |
Non. |
busio | Permet d'utiliser les protocoles de communication I2C et série (SPI et UART). On s'en sert ici pour communiquer avec le convertisseur analogique-digital. | Non. |
Pour utiliser une librairie dans Python, il faut commencer par l'importer:
import gpiozero
Il est aussi possible de n'importer qu'un module particulier d'une librairie:
from gpiozero import LED
Une fois que la librairie est importée, on a accès à ses fonctions. Par exemple, on peut maintenant utiliser le module LED de la librairie gpiozero
pour contrôler les DELs de notre circuit.
On commence par leur assigner chacune une variable en utilisant le module LED
et les numéros de broche GPIO correspondants:
rouge = LED(23)
verte = LED(24)
On peut ensuite utiliser les fonctions suivantes pour allumer, éteindre, ou faire clignoter nos DELs:
rouge.on()
rouge.off()
verte.blink() # Par défaut, s'allume et s'éteint toutes les secondes
verte.blink(2) # Change l'intervalle à 2 secondes
rouge.blink(0.2,2) # Allume la DEL pendant 0.2 secondes toutes les 2 secondes
L'autre librairie qui sera utile pour notre projet est celle qui nous permet de communiquer avec le convertisseur analogique-digital via le port I2C. Le plus simple pour observer comment elle fonctionne est d'ouvrir le programme formation-raspi/adctest.py
téléchargé plus tôt. Le revoici:
# Importation des librairies utiles
import time # Permet de temporiser l'affichage des valeurs
import board # Pour accéder rapidement aux broches du port I2C
import busio # Pour implémenter le protocole de communication I2C
import adafruit_ads1x15.ads1015 as ADS # Pour contrôler le convertisseur.
from adafruit_ads1x15.analog_in import AnalogIn # Pour lire les valeurs analogiques.
# Ouverture du bus I2C sur les broches SCL et SDA
i2c = busio.I2C(board.SCL, board.SDA)
# Initialisation d'un objet ADS via le bus I2C
ads = ADS.ADS1015(i2c)
# Initialisation des canaux
canal0 = AnalogIn(ads, ADS.P0)
canal1 = AnalogIn(ads, ADS.P1)
canal2 = AnalogIn(ads, ADS.P2)
canal3 = AnalogIn(ads, ADS.P3)
# Impression de la première ligne avec les en-têtes de colonnes.
# Chaque colonne est séparée de 5 tabulations.
print("{:>5}\t{:>5}\t{:>5}\t{:>5}".format('A0', 'A1', 'A2', 'A3'))
# Boucle principale. L'instruction while True fait en sorte que la boucle tourne indéfiniment
# jusqu'à ce qu'on interrompe le programme.
while True:
print("{:>5.3f}\t{:>5.3f}\t{:>5.3f}\t{:>5.3f}".format(canal0.voltage,canal1.voltage,canal2.voltage,canal3.voltage))
time.sleep(0.5)
Si on obtient une erreur du style ModuleNotFoundError: No module named 'gpiozero'
lorsqu'on tente d'utiliser une librairie, cela signifie qu'elle n'a pas encore été installée.
Pour installer une librairie, le plus simple est d'utiliser l'utilitaire pip
dans l'environnement qu'on souhaite utiliser:
pip install gpiozero
Lorsqu'on installe une librairie avec
pip
, celui-ci s'occupe également d'installer d'autres librairies si celle qu'on veut installer en dépend. Par exemple, lorsqu'on a installéadafruit-circuitpython-ads1x15
, d'autres librairies nécessaires à son fonctionnement commeboard
etbusio
ont aussi été installées.
En utilisant toutes les informations ci-dessus, il est maintenant temps d'écrire un programme selon les indications suivantes:
Un exemple de solution est fourni dans le programme formation-raspi/mesure.py
On peut ensuite utiliser la librarie logging pour ajouter une fonction permettant d'enregistrer la valeur mesurée à intervalle régulier, par exemple de la manière suivante:
import logging
# Définition du fichier de log
# Celui-ci est configuré pour enregistrer la date et l'heure avant le message fourni.
logging.basicConfig(filename='humidite.log',level=logging.INFO,format='%(asctime)s %(message)s')
# Ajout d'une ligne dans le fichier de log
logging.info("Message à enregistrer")
On peut voir cette approche à l'oeuvre dans le programme formation-raspi/mesure_log.py
On utilise ici un simple fichier de log pour enregistrer les données mesurées au fil du temps car c'est très simple à utiliser. Dans un projet plus complexe, il serait préférable d'utiliser une base de données comme SQLite à la place.
Une fois qu'on est content avec notre programme, on peut retirer les messages de déboggage et l'invoquer avec le caractère (&
) à la fin, ce qui permet de le faire tourner en arrière plan:
python mesure-humidite.py &
Cependant, avec cette approche, le programme ne démarrera pas automatiquement à chaque redémarrage du Raspberry Pi. Pour que ce soit le cas, on peut par exemple modifier le crontab
, qui permet de faire tourner des programmes automatiquement au démarrage, ou à intervalles réguliers.
Pour éditer le crontab
sur la ligne de commande:
crontab -e
On ajoute ensuite la ligne suivante à ce fichier
@reboot /home/thomas/mesure-humidite/bin/python /home/thomas/formation-raspi/mesure_log.py &
Remplacer le premier chemin par celui vers l'environnement virtuel python que l'on souhaite utiliser et le second chemin par celui vers le programme à démarrer.
La dernière étape de ce projet consiste à écrire une petite application web permettant en tous temps de voir quelle est la mesure du taux d'humidité de notre plante.
On utilise pour ça la librairie Flask, qui permet de déployer un serveur web écrit en langage Python. En principe, Flask est installé par défaut sur Raspberry Pi OS.
On peut très rapidement écrire une première application avec ces quelques lignes:
from flask import Flask
app = Flask(__name__)
@app.route('/')
def index():
return 'Bonjour!'
if __name__ == '__main__':
app.run(debug=True, host='0.0.0.0')
Pour faire démarrer le serveur web il suffit de démarrer ce programme:
python mon-application.py
On verra alors apparaître les informations suivantes:
* Serving Flask app 'app'
* Debug mode: on
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
* Running on all addresses (0.0.0.0)
* Running on http://127.0.0.1:5000
* Running on http://192.168.68.115:5000
Press CTRL+C to quit
Les adresses auxquelles l'application est disponible s'affichent et on peut les ouvrir dans un navigateur pour voir le résultat. La première adresse (127.0.0.1
) n'est valable que depuis le Raspberry Pi lui-même, il s'agit d'une adresse spéciale qui pointe vers la machine elle-même (localhost). L'autre adresse est ouverte au réseau local et on peut s'y connecter depuis un autre ordinateur sur le même réseau. On remarquera que l'application est exposée par défaut sur le port 5000.
Plutôt que d'envoyer directement le contenu de la page web que l'on souhaite afficher au travers de la fonction return
, l'approche habituelle est d'utiliser un système de gabarits HTML dans lesquels on viendra remplacer certains éléments.
Pour cela, on commence par créer quelques dossiers pour organiser notre application et on y ajoute un fichier de gabarit HTML, ainsi qu'un fichier CSS pour les styles, comme ceci:
webapp
- application.py
static
- style.css
templates
- index.html
Le fichier de gabarit index.html
contient la structure HTML de notre page. Là où on souhaite afficher des données dynamiques provenant de notre application, on utilise la syntaxe {{ nom-de-variable }}
, par exemple
<!DOCTYPE html>
<html lang="fr">
<head>
<title>Comment va ma plante verte?</title>
<link rel="stylesheet" href='../static/style.css'/>
</head>
<body>
<div class="message">{{ message }}</div>
<div class="donnees">Humidité actuelle: {{ humidite_actuelle }}</div>
</body>
</html>
On modifie maintenant le programme de notre application pour utiliser ce gabarit et y envoyer les valeurs message
et humidite_actuelle
:
from flask import Flask, render_template
app = Flask(__name__)
@app.route('/')
def index():
return render_template('index.html', message='Test de message', humidite_actuelle='Test de valeur')
if __name__ == '__main__':
app.run(debug=True, host='0.0.0.0')
On peut modifier l'apparence de notre application dans le fichier CSS, par exemple
body {
text-align: center;
font-family: sans-serif;
}
.message {
font-size: 2em;
}
.donnees {
margin-top: 20px;
}
On peut maintenant commencer à lire les données enregistrée par notre application précédente pour les afficher dans notre application web:
from flask import Flask, render_template
app = Flask(__name__)
# Cette fonction lit les données provenant du fichier de log.
def lire_donnees():
fichier = '/home/thomas/humidite.log'
with open(fichier, 'rb') as donnees:
# On initialise une série de listes vides qui serviront à contenir les données extraites
temps = []
humidite = []
statut = []
# On passe au travers de chaque ligne du fichier et on extrait les données
for ligne in donnees:
# La fonction decode() sert à convertir les données binaires en texte
ligne = ligne.decode()
# On sépare chaque ligne en utilisant la tabulation
valeurs = ligne.split('\t')
# Puis on ajoute à chacune des listes les données qu'on a extraites
temps.append(valeurs[0])
humidite.append(valeurs[1])
statut.append(valeurs[2])
return temps, humidite, statut
@app.route('/')
def index():
# Appel de la fonction pour lire les données.
temps, humidite, statut = lire_donnees()
# On calcule la longueur des listes que l'on a obtenu.
nombre_donnees = len(temps)
# On utilise cette longueur pour obtenir la dernière valeur de chaque liste.
# Attention au -1 car Python utilise l'index en base zéro.
# Le dernier élément d'une liste de n éléments est à l'index liste[n-1].
humidite_actuelle = humidite[nombre_donnees-1]
# On utilise la fonction strip() pour ôter d'éventuels espaces superflus.
statut_actuel = statut[nombre_donnees-1].strip()
# On construit un objet contenant les données à envoyer au gabarit.
pour_affichage = {
'humidite_actuelle': humidite_actuelle,
'message': statut_actuel
}
# Appel du gabarit. Noter les deux étoiles pour "déballer" l'objet de données.
return render_template('index.html', **pour_affichage)
if __name__ == '__main__':
app.run(debug=True, host='0.0.0.0')
Si on le souhaite, on peut ajouter des éléments visuels à l'application, par exemple changer la couleur de fond en fonction du statut, ajouter des images, etc. En utilisant des librairies JavaScript comme ChartJS, GaugeJS ou Canvas Gauges, on peut afficher les données de manière visuelle et interactive. Les possibilités sont infinies!
Un exemple d'application web qui affiche le statut actuel de la plante et les 100 derniers relevés d'humidité de manière visuelle est disponible dans formation-raspi/webapp
.
Il nous est maintenant possible de nous connecter au Rasbperry Pi et voir l'état de notre plante verte via un navigateur internet. Cependant, cela est seulement possible au sein de notre propre réseau, car l'adresse IP assignée au Raspberry Pi par notre routeur est uniquement valable localement. De plus, un pare-feu empêche les connexions provenant de l'extérieur à notre réseau, pour des raisons de sécurité.
Il est cependant possible d'utiliser un service comme PiTunnel pour mettre en place une passerelle sécurisée entre le Raspberry Pi et le monde entier. Pour cela, il suffit de se créer un compte (gratuit) sur PiTunnel et suivre les instructions pour installer ce service.
Une fois que c'est fait, il est possible d'ouvrir un nouveau tunnel vers notre application de la manière suivante
pitunnel --port=5000 --http --name=maplante --persist
Se reporter au tableau de bord de PiTunnel pour voir l'URL qui sera assigné à notre Rasbperry Pi.
Composant | Mode d'emploi | Note |
---|---|---|
Raspberry Pi 5 4GB | Documentation | Il est possible d'utiliser un modèle plus ancien pour les exemples proposés ici. |
Capteur d'humidité Hacbop V1.2 | Spécifications et mode d'emploi | Plusieurs versions de ce composant circulent, de qualité variable. Cette vidéo (en anglais) indique comment les départager et comment réparer certains composants défectueux. |
Convertisseur analogique digital ADS1115 | Librairie Python Mode d'emploi Datasheets (IC uniquement) |
Il existe plusieurs modules basés sur le TI ADS1115, celui que nous utilisons est similaire à ce module Adafruit. |
Cet aide-mémoire, la formation Initiation à Linux et à la programmation sur Raspberry Pi et les exemples de programmes qui y sont associés ont été développés par Thomas Guignard pour le compte de l'Atelier la Patente.
Ce document est distribué sous license Creative Commons CC-BY 4.0 et peut être librement réutilisé sous ces conditions!