Un thermostat allume le chauffage quand la pièce est trop froide. Un lampadaire s’éclaire à la tombée de la nuit. Un aspirateur robot change de direction avant de toucher un mur. Dans ces trois objets, un petit ordinateur mesure quelque chose dans le monde réel, décide quoi faire, puis agit sur le monde réel.
Dans le modèle de Von Neumann, vu au chapitre 09 - Architecture , ces échanges avec l’extérieur sont le rôle des entrées-sorties. Ce chapitre présente les composants qui les réalisent, les capteurs et les actionneurs, puis montre comment écrire un programme qui les relie, et comment programmer une interface homme-machine (IHM). La fiche d’exercices correspondante est 33 - Périphériques et IHM .
Définition. Un périphérique est un appareil relié à l’unité centrale, qui permet à l’ordinateur d’échanger des informations avec l’extérieur :
Certains périphériques font les deux. Un écran tactile affiche une image (sortie) et repère la position du doigt (entrée).
Un programme ne pilote pas directement le matériel : c’est le système d’exploitation, vu au chapitre 23 - Systèmes d’exploitation
, qui gère les entrées-sorties grâce à ses pilotes. Quand un programme Python appelle input(), il demande au système le texte tapé au clavier ; quand il appelle print(), il lui demande d’afficher un texte à l’écran.
Définition. Un capteur mesure une grandeur physique (température, lumière, distance, pression…) et la transforme en un signal électrique, que le système lit sous la forme d’un nombre.
Un capteur est donc un périphérique d’entrée. Quelques exemples :
| Grandeur mesurée | Capteur | Exemple d’utilisation |
|---|---|---|
| Température | Thermomètre électronique (sonde) | Thermostat, station météo |
| Lumière | Capteur de luminosité (photorésistance) | Éclairage public, réglage de l’écran d’un téléphone |
| Distance | Capteur à ultrasons ou à infrarouge | Robot, aide au stationnement d’une voiture |
| Grandeur mesurée | Capteur | Exemple d’utilisation |
|---|---|---|
| Présence, mouvement | Détecteur de mouvement infrarouge | Éclairage d’un couloir, alarme |
| Contact, appui | Bouton, interrupteur, touche de clavier | Clavier, sonnette, butée d’un robot |
| Position du doigt | Surface tactile | Écran de téléphone, borne de distributeur |
Le clavier et l’écran tactile sont eux aussi des capteurs : chaque touche est un petit interrupteur, et la surface tactile mesure l’endroit où le doigt la touche.
Pour le programme, une mesure n’est qu’un nombre : 21 pour 21 °C, 350 pour une luminosité de 350 sur une échelle propre au capteur, 1 ou 0 pour un bouton appuyé ou non. C’est au programmeur de savoir ce que ce nombre représente et dans quelle unité.
Définition. Un actionneur reçoit une commande du programme, sous forme de signal électrique, et la transforme en une action physique : mouvement, lumière, son, chaleur.
Un actionneur est donc un périphérique de sortie. Quelques exemples :
| Actionneur | Action produite | Exemple d’utilisation |
|---|---|---|
| Moteur | Mouvement de rotation | Roues d’un robot, ventilateur, store électrique |
| Lampe, diode électroluminescente (DEL) | Lumière | Éclairage, voyant d’un appareil |
| Haut-parleur, buzzer | Son | Alarme, signal sonore d’un four |
| Résistance chauffante | Chaleur | Radiateur électrique, bouilloire |
| Électrovanne | Ouverture ou fermeture d’un passage d’eau | Arrosage automatique, lave-linge |
L’écran est aussi un actionneur particulier : il transforme les données envoyées par le programme en lumière, point par point.
Un système qui réagit à son environnement fonctionne toujours en trois étapes :
L’action modifie la grandeur mesurée : le chauffage réchauffe la pièce, donc la température lue au tour suivant change. C’est pourquoi la chaîne se répète sans fin, tant que l’appareil est sous tension.
Le programme qui réalise la décision s’exécute sur un petit ordinateur intégré à l’objet :
| Système | Capteur | Décision | Actionneur |
|---|---|---|---|
| Thermostat | Sonde de température | température < consigne ? | Résistance chauffante |
| Éclairage automatique | Capteur de luminosité, détecteur de mouvement | luminosité < seuil et présence ? | Lampes |
| Robot aspirateur | Capteur de distance, capteur de contact | obstacle proche ? | Moteurs des roues |
Sur une carte programmable ou dans un robot, une bibliothèque fournit des fonctions qui lisent les capteurs et commandent les actionneurs. Ici, on n’a pas de matériel : on simule le capteur et l’actionneur par deux fonctions, ce qui permet d’écrire et de tester la partie la plus importante, la décision.
Le capteur simulé renvoie une température tirée au hasard ; l’actionneur simulé affiche l’état du chauffage au lieu d’allumer un vrai radiateur.
import random
def lire_temperature():
"""Capteur simulé : renvoie la température de la pièce, en degrés Celsius."""
return random.randint(15, 25)
def commander_chauffage(allumer):
"""Actionneur simulé : allume le chauffage si allumer vaut True, l'éteint sinon."""
if allumer:
print("chauffage allumé")
else:
print("chauffage éteint")
def decider(temperature, consigne):
"""Renvoie True s'il faut chauffer, c'est-à-dire si la pièce est plus froide que la consigne."""
return temperature < consigne
La fonction decider ne dépend d’aucun matériel : elle reçoit des nombres et renvoie un booléen. On peut donc la tester avec des valeurs choisies, sans attendre qu’il fasse froid :
assert decider(17, 19) == True # trop froid : on chauffe
assert decider(21, 19) == False # assez chaud : on ne chauffe pas
assert decider(19, 19) == False # exactement la consigne : on ne chauffe pas
print("Tous les tests passent")
Le programme principal répète la chaîne mesure, décision, action. Ici, on se limite à cinq mesures :
consigne = 19
for i in range(5):
temperature = lire_temperature() # mesure
chauffer = decider(temperature, consigne) # décision
print(f"Mesure {i + 1} : {temperature} °C,", end=" ")
commander_chauffage(chauffer) # action
Un affichage possible (les températures sont tirées au hasard) :
Mesure 1 : 17 °C, chauffage allumé
Mesure 2 : 22 °C, chauffage éteint
Mesure 3 : 19 °C, chauffage éteint
Mesure 4 : 15 °C, chauffage allumé
Mesure 5 : 24 °C, chauffage éteint
Dans un vrai thermostat, la boucle ne s’arrête jamais : on écrit while True, et le programme attend un moment, par exemple une minute, entre deux mesures.
# NE PAS EXÉCUTER : boucle sans fin, comme dans un vrai thermostat
consigne = 19
while True:
temperature = lire_temperature()
commander_chauffage(decider(temperature, consigne))
Remarque. Dans ce programme, chaque fonction a un seul rôle : lire_temperature pour la mesure, decider pour la décision, commander_chauffage pour l’action. Pour faire tourner le même programme sur un vrai thermostat, il suffit de réécrire les deux fonctions qui touchent au matériel ; la décision ne change pas.
Définition. L’interface homme-machine (IHM) est l’ensemble des moyens par lesquels un utilisateur et une machine échangent des informations : les périphériques (boutons, écran, écran tactile…) et le programme qui affiche des informations et réagit aux actions de l’utilisateur.
Le panneau d’un four (un afficheur et quelques boutons), l’écran tactile d’un distributeur de billets, la fenêtre d’une application ou une page web, étudiée au chapitre 13 - IHM Web , sont des IHM.
Avant de programmer une IHM, on écrit son cahier des charges : la liste de ce que l’interface doit afficher, des actions que l’utilisateur peut faire et de ce que le programme doit faire en réponse. Voici celui d’un thermostat :
Un programme avec une interface graphique ne s’exécute pas de haut en bas puis s’arrête. Il crée la fenêtre et ses composants, associe une fonction à chaque action possible de l’utilisateur, puis attend : c’est la boucle d’événements. Un clic sur un bouton est un événement ; le programme répond en appelant la fonction associée à ce bouton. Ce style de programmation s’appelle la programmation événementielle.
Le module tkinter, fourni avec Python, permet de créer des fenêtres. La page 16 - GUI
en donne d’autres exemples. Les composants (en anglais widgets) utilisés ici :
| Composant ou méthode | Rôle |
|---|---|
tk.Tk() |
crée la fenêtre principale |
tk.Label(fenetre, text="…") |
affiche un texte (sortie) |
tk.Button(fenetre, text="…", command=f) |
bouton : un clic appelle la fonction f (entrée) |
tk.Scale(fenetre, from_=a, to=b, orient="horizontal") |
curseur pour choisir un entier entre a et b (entrée) |
| Composant ou méthode | Rôle |
|---|---|
composant.pack() |
place le composant dans la fenêtre, sous le précédent |
curseur.get(), curseur.set(v) |
lit ou fixe la valeur du curseur |
etiquette.configure(text="…", fg="red") |
change le texte ou la couleur d’un Label |
etiquette.cget("text") |
renvoie le texte affiché par un Label |
fenetre.mainloop() |
lance la boucle d’événements |
Le programme ci-dessous répond au cahier des charges du thermostat. Il ne fonctionne pas dans le navigateur : l’exécuter dans Thonny.
import tkinter as tk
import random
def lire_temperature():
"""Capteur simulé : renvoie la température de la pièce, en degrés Celsius."""
return random.randint(15, 25)
def mesurer():
"""Lit le capteur, compare à la consigne, puis affiche la mesure et l'état du chauffage."""
temperature = lire_temperature()
texte_mesure.configure(text=f"Température mesurée : {temperature} °C")
if temperature < curseur.get():
texte_chauffage.configure(text="Chauffage allumé", fg="red")
else:
texte_chauffage.configure(text="Chauffage éteint", fg="blue")
fenetre = tk.Tk()
fenetre.title("Thermostat")
# Point 1 du cahier des charges : curseur de 15 à 25, réglé sur 19 au démarrage
curseur = tk.Scale(fenetre, label="Consigne (°C)", from_=15, to=25, orient="horizontal", length=250)
curseur.set(19)
curseur.pack()
# Point 2 : le bouton appelle la fonction mesurer
bouton = tk.Button(fenetre, text="Mesurer", command=mesurer)
bouton.pack()
# Points 3 et 4 : deux textes, modifiés par la fonction mesurer
texte_mesure = tk.Label(fenetre, text="Température mesurée : aucune mesure")
texte_mesure.pack()
texte_chauffage = tk.Label(fenetre, text="Chauffage éteint", fg="blue")
texte_chauffage.pack()
fenetre.mainloop()
On retrouve la chaîne mesure, décision, action, déclenchée cette fois par l’utilisateur :
mesurer ;mesurer lit le capteur (mesure), compare la température à la valeur du curseur (décision), puis modifie les deux textes (action sur l’interface).Dans command=mesurer, on écrit le nom de la fonction sans parenthèses : on indique au bouton quelle fonction appeler plus tard, au moment du clic. Avec command=mesurer(), la fonction serait appelée une seule fois, à la création du bouton.
assert.tkinter une IHM qui répond à un cahier des charges : composants d’entrée (bouton, curseur), composants de sortie (textes), fonctions appelées lors des événements, boucle d’événements.