Le multitâche est devenu l’un des sujets les plus importants dans les systèmes à base de µC, notamment dans les automatismes. Avec l’accroissement de leur complexité, on attend plus des projets, ce qui, sur le même système, impose l’utilisation de plusieurs tâches interdépendantes et partageant l’unité centrale (ou de multiples UC) pour effectuer les opérations. D’où l’importance croissante du fonctionnement multitâche dans les applications à base de µC. Beaucoup de projets d’automatisme complexes font appel à un noyau multitâche. Dans le livre, on utilise le langage Python avec le Raspberry Pi (RPI). On peut aussi utiliser différents modèles de RPi sans rien changer au code.

Voici un exemple de projet extrait d’un ouvrage publié récemment par Elektor. Intitulé "Multitasking with RPi". Ce livre est destiné aux étudiants, aux ingénieurs et aux amateurs intéressés par les projets multitâches utilisant le langage Python3 sur l’ordinateur Raspberry Pi (RPI).

Le livre repose sur des projets. Son objectif principal est d’enseigner les principes de base du multitâche avec Python sur RPi. Il présente de nombreux projets dûment testés avec les modules multitâches de Python. Chaque projet est décrit et commenté en détail. Les listages complets des programmes sont fournis pour chaque projet. Les lecteurs devraient pouvoir les utiliser tels quels, ou les adapter à leurs propres besoins.

Savoir-faire : commande de feux de circulation

Ce projet consiste à concevoir une commande simple des feux de circulation d’un carrefour, à l’intersection de deux routes : East Street et North Street. Il y a des feux à chaque branche du carrefour. Des boutons d’appel pour piétons se trouvent près des feux sur North Street. L’appui sur un bouton d’appel provoque le passage au rouge de tous les feux à la fin de leurs cycles. Un signal sonore est alors déclenché pour indiquer aux piétons qu’ils peuvent traverser sans danger. Un afficheur LCD indique le cycle piétons ou circulation en cours. La figure 9.12 montre la disposition au carrefour.

Figure 9.12. Signalisation au carrefour.

Pour ce projet, les durées fixes suivantes sont affectées à chaque feu, ainsi que la durée du signal sonore pour piétons. Pour simplifier, on suppose que les deux routes du carrefour ont les mêmes durées (en secondes) :

  • rouge : 19 s
  • orange : 2 s
  • vert : 15 s
  • orange + rouge : 2 s
  • piétons : 10 s

La durée totale du cycle des feux est fixée à 38 s.

La séquence adoptée pour ces feux de circulation est la suivante (qui n'est peut-être pas celle dont vous êtes familier dans votre pays, mais c'est le même principe partout) :

Rouge - Orange+Rouge - Vert - Orange…

Vert - Orange - Rouge - Orange+Rouge…

La figure 9.13 montre le diagramme du projet, la figure 9.14 le schéma. Les LED rouge (R), orange (O) et verte (V) sont utilisées pour représenter les vrais feux de circulation.

Figure 9.13. Diagramme du projet.
Figure 9.14. Schéma du circuit.

Les connexions suivantes sont réalisées entre le RPi et les éléments de signalisation routière :

La figure 9.15 montre le listage complet (nom du programme : traffic.py ; téléchargement [1]). En début de programme, on importe les modules nommés RPi, time, I2C LCD driver et multiprocessing et on crée deux files nommées pedq et lcdq.


#--------------------------------------------------------------------
#                     TRAFFIC LIGHTS CONTROLLER
#                     =========================
#
# This is a traffic lights controller project controlling lights
# at a junction. 6 LEDS are used to represent the traffic lights.
# Additionally a button is used for pedestrian crossing, and an
# LCD shows the state of the traffic lights at any time
#
# Author: Dogan Ibrahim
# File  : traffic.py
# Date  : May 2020
#----------------------------------------------------------------------
import RPi.GPIO as GPIO                      # Import RPi
import multiprocessing                       # Import multiprocessing
import time                                  # Import time
import RPi_I2C_driver                        # I2C library
LCD = RPi_I2C_driver.lcd()                   # Import LCD
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)                       # GPIO mode BCM
pedq = multiprocessing.Queue()               # Create queue
lcdq = multiprocessing.Queue()               # Create queue
 
#
# This function sends data 'state (0 or 1)' to specified port
#
def ONOF(port, state):
   GPIO.output(port, state)
 
#
# This function configures the specified port as output
#
def CONF_OUT(port):
   GPIO.setup(port, GPIO.OUT)
 
#
# Process to control the lights
#
def Lights():                                 # Process Lights
   R1=21; A1=20; G1=16                        # LED connections
   R2=12; A2=7;  G2=8                         # LED conenctions
   Buzzer=25                                  # Buzzer connection
   CONF_OUT(R1); CONF_OUT(A1); CONF_OUT(G1)   # Configure
   CONF_OUT(R2); CONF_OUT(A2); CONF_OUT(G2)   # Configure
   CONF_OUT(Buzzer)                           # Configure
   ONOF(R1,0); ONOF(A1,0); ONOF(G1,0); ONOF(R2,0); ONOF(A2,0); ONOF(G2,0)
   ONOF(Buzzer, 0)
 
   RedDuration = 15
   GreenDuration = 15
   AmberDuration = 2
 
#
# Control the traffic light sequence
#
   while True:                                # Do forever
      ONOF(R1,0); ONOF(A1,0); ONOF(G1,1); ONOF(R2,1); ONOF(A2,0); ONOF(G2,0)
      time.sleep(RedDuration)
      ONOF(G1,0); ONOF(A1,1)
      time.sleep(AmberDuration)
      ONOF(A1,0); ONOF(R1,1); ONOF(A2,1)
      time.sleep(AmberDuration)
      ONOF(A2,0); ONOF(R2,0); ONOF(G2,1)
      time.sleep(GreenDuration)
      ONOF(G2,0); ONOF(A2,1)
      time.sleep(AmberDuration)
      ONOF(A2,0); ONOF(A1,1); ONOF(R2,1)
      time.sleep(AmberDuration)
 
      while not pedq.empty():                  # If ped request
         lcdq.put(1)
         ONOF(G1,0); ONOF(R1,1); ONOF(A1,0)    # Only RED ON
         ONOF(G2,0); ONOF(R2,1); ONOF(A2,0)    # Only RED ON
         d = pedq.get()                        # Clear ledq
         ONOF(Buzzer, 1)                       # Buzzer ON
         time.sleep(10)                        # Wait 10 secs
         ONOF(Buzzer, 0)                       # Buzzer OFF
         d = lcdq.get()                        # Clear lcdq
     
 
def Pedestrian():                              # Process Pedestrian
   PB1 = 24
   GPIO.setup(PB1, GPIO.IN)                    # PB1 is input
 
   while True:                                 # Do forever
      while GPIO.input(PB1) == 1:              # PB1 not pressed
         pass
      pedq.put(1)                              # Send to Ped queue
      while GPIO.input(PB1) == 0:              # PB1 not released
         pass
 
#
# Create the processes
#
p = multiprocessing.Process(target = Lights, args = ())
q = multiprocessing.Process(target = Pedestrian, args = ())
p.start()
q.start()
 
#
# LCD Display control. Display 'Ped Cycle' or 'Traffic Cycle'
#
LCD.lcd_clear()                                # Clear LCD
LCD.lcd_display_string("TRAFFIC CONTROL", 1)   # Heading
 
while True:                                    # DO forever
   if not lcdq.empty():
      LCD.lcd_display_string("Ped Cycle    ", 2)
   else:
      LCD.lcd_display_string("Traffic Cycle", 2)
   time.sleep(1)


Deux fonctions nommées ONOF et CONF_OUT sont définies dans le programme. La fonction ONOF a deux arguments : port et state. Cette fonction envoie l’état (0 ou 1) au port GPIO spécifié. La fonction CONF_OUT a un paramètre nommé port. Cette fonction configure le port GPIO spécifié en mode sortie.

Il y a deux processus dans le programme : Lights (= feux) et Pedestrian.(= piéton) Au début du processus Lights, on définit les connexions entre le RPi, les LED (feux de circulation) et le buzzer puis ces ports sont configurés en sorties. De plus, tous ces ports sont mis à zéro pour éteindre toutes les LED et le buzzer. Enfin, les LED sont séquencées dans le bon ordre avec les bonnes durées. Vers la fin de la fonction, on vérifie si le bouton piétons a été pressé. Si c’est le cas, la file pedq n’est pas vide. Pendant le cycle piétons, les feux rouges des deux rues sont allumés pour arrêter la circulation et céder le passage aux piétons.

Le buzzer est également activé pendant 10 s pendant le cycle piétons pour les avertir qu’ils peuvent traverser sans danger.

Le processus Pedestrian surveille en permanence le bouton PB1. Si le bouton est pressé, un « 1 » est envoyé à la file pedq pour que le processus Lights puisse facilement détecter cette action et commencer le cycle piétons.

Le programme principal commande l’afficheur LCD. Au démarrage, le message « TRAFFIC CONTROL » est affiché sur la première ligne. La seconde vérifie en permanence la file lcdq et affiche soit « Ped Cycle » (cycle piétons) soit « Traffic Cycle » (cycle circulation).

La figure 9.16 montre un exemple d’affichage sur l’afficheur.

Figure 9.16. Exemple d’affichage.

(200381-01)


► Elektor est réputé pour la qualité de son contenu. En voulez-vous davantage ?

Abonnez-vous maintenant au magazine Elektor et ne manquez plus jamais ni aucun de ces articles précieux ni aucun de ces projets géniaux.