- 1943 views
Dans ce projet, nous utiliserons des modules d'extension Digilent Pmods ainsi qu'une platine Raspberry Pi 4 pour mesurer la température, contrôler la vitesse d'un moteur à courant continu, afficher les données et contrôler l'appareil.
Une platine Digilent Pmod HAT est utilisée pour connecter les modules Pmods à la platine Raspberry Pi 4. Le contrôleur de moteur aura deux modes: un dans lequel la vitesse du moteur change en fonction de la température (dans ce mode, les limites de température pour 0% et 100% de la vitesse du moteur peuvent être réglées sur l'interface utilisateur) et un deuxième mode, dans lequel le moteur tourne à vitesse constante pendant un temps défini, puis il est arrêté pour le même temps (dans ce mode, la vitesse du moteur et le temps sont les paramètres contrôlables par l'utilisateur) . L'interface utilisateur sera utilisée pour changer de mode.
Inventaire nécessaire pour réaliser cette application:
1. Matériel
- Platine Raspberry Pi 4 Model B
- Platine Pmod HAT Adapter
- Module Pmod TC1
- Module Pmod HB3
- Module Pmod KYPD
- Module Pmod OLEDrgb
- Module Pmod TPH2
- Module un moteur 5V DC
- Des câbles MTE
- un petit tournevis (pour fixer les boulons dans les borniers)
2. Logiciel sur Raspberry Pi
- Python 3 - il est préinstallé sur le système d'exploitation Raspberry Pi par défaut
- Visual Studio Code - ou tout autre éditeur de texte de votre choix
Description du matériel utilisé:
Platine Pmod HAT: Cette platine possède 5 connecteurs principaux et trois cavaliers. En haut, le connecteur standard Raspberry Pi HAT peut être trouvé. L'adaptateur dispose de trois connecteurs 2x6 Digilent Pmod (JA, JB et JC) et chacun d'eux peut également être utilisé comme deux connecteurs 1x6 Pmod séparés (par exemple, JA peut être séparé en JAA et JAB). Tous les ports Pmod contiennent une masse et une broche 3,3 V pour alimenter le module Pmod qui y sera connecté. En plus de la fonction GPIO (General Purpose Input / Output), vous pouvez utiliser JAA et JBA comme interface SPI, JBB comme interface I2C et JCA comme interface UART. La carte Pmod HAT dispose également d'une prise DC d'entrée 5 V, de cavaliers permettant des résistances de pull-up sur les lignes I2C et d'un cavalier qui permet d'écrire dans la mémoire interne des Pmods. |
Module Pmod OLEDgrb: Le Pmod OLEDrgb est un écran LED RVB organique de 96 x 64 pixels avec une résolution couleur de 16 bits. Le module contient un pilote d'affichage qui communique avec les cartes ou systèmes hôtes via des liaisons SPI et GPIO. Pour ce projet, nous connecterons le module Pmod OLEDrgb aux ports JA ou JB sur l'adaptateur Pmod HAT qui prend en charge la communication SPI. |
Module Pmod KYPD: Le module Pmod KYPD dispose de 16 boutons poussoirs fugitifs, disposés en 4 lignes et 4 colonnes. En pilotant les lignes des colonnes à une basse tension de niveau logique une à la fois, les utilisateurs peuvent lire la tension de niveau logique correspondante sur chacune des lignes pour déterminer quel bouton, le cas échéant, est actuellement enfoncé (principe de lecture d'un clavier matricé). L'appareil communique avec Raspberry Pi via GPIO. Nous pouvons le connecter à n'importe quel port du Pmod HAT. |
Module Pmod TC1: Le Pmod TC1 contient un fil de thermocouple de type K et un convertisseur thermocouple-numérique à jonction froide. Le fil de thermocouple peut mesurer des températures de -73 ° C à 482 ° C avec une précision de ± 2 ° C et le module renvoie une valeur numérique signée de 14 bits. Le module Pmod TC1 doit être connecté aux ports JAA ou JBA (la partie supérieure des ports JA ou JB) sur le Pmod HAT pour la communication SPI . . |
Module Pmod HB3: Le Pmod HB3 est un driver de moteur CC à pont en H, avec une sortie allant jusqu'à 12 V et 2 A. Le module communique avec la carte Raspberry Pi via les GPIO. Il peut être connecté à n'importe quel port de l'adaptateur Pmod HAT. Si un moteur 5 V est utilisé, l'alimentation du moteur peut être fournie par l'une des broches 5 V PW du Raspberry Pi, qui sont capables de produire environ 2 A, lorsque le microcontrôleur a une alimentation appropriée. . |
Module Pmod TPH2: Le Pmod TPH2 est un connecteur de test à 12 points. Dans ce projet, il peut être utilisé pour diviser l'un des ports 2x6 Pmod de l' adaptateur Pmod HAT afin que plusieurs Pmods puissent être connectés au même port (à l'aide de câbles MTE). . |
Platine Raspberry Pi 4: Une carte Raspberry Pi 4 Model B sera utilisée en tant que "cerveau" dans cette application avec le système d'exploitation Raspberry Pi recommandé. Vous pouvez utiliser d'autres modèles et systèmes d'exploitation Raspberry Pi capables d'exécuter Python 3. La présentation détaillée de l'installation et de la configuration du système d'exploitation ne sera détaillée dans notre note d'application . . |
Configuration matérielle:
Les modules Pmod OLEDrgb et Pmod TC1 (avec interface SPI) ne peuvent être connectés qu'à des ports spécifiques sur la platine Pmod HAT. le module Pmod OLEDrgb est connecté au port JA tandis que le module Pmod TC1 ne peut être connecté qu'au port JBA. Le module Pmod KYPD est connecté au port JC et le module Pmod HB3 au port JBB. Le module Pmod TPH2 peut être utilisé pour briser le port JB afin que les deux modules Pmod (TC1 et HB3) puissent être connectés au même port. Connectez le fil du thermocouple et le moteur aux borniers respectifs. Comme mentionné ci-dessous, vous pouvez alimenter le moteur directement à partir de la platine Raspberry Pi. Le fichier Fritzing™ joint montre les connexions à réaliser.
Configuration du logiciel:
Tout d'abord, vous devez activer le port SPI et le port série sur la carte Raspberry Pi. Ouvrez un terminal, puis tapez: sudo raspi-config
Dans le menu, sélectionnez 3. Options d'interface, puis sélectionnez P4 SPI et activez-le. Sélectionnez à nouveau les options d'interface , puis sélectionnez P6 Serial Port . La première chose qui apparaît, le shell de connexion , peut être laissée désactivée. Il vous suffit d'activer le matériel du port série dans la deuxième invite.
Ensuite, vous changez la version par défaut de Python en Python 3. Le système d'exploitation Raspberry Pi recommandé est livré avec Python 2 et Python 3 préinstallés. Vérifiez la version Python avec les commandes suivantes:
python --version
python3 --version
Si Python 3 3.6 est préinstallé ou une version antérieur, vous devez installer une version plus récente via les commandes:
sudo apt-get installer python3.x
où x est le numéro de version. Par exemple, nous utilisons Python 3.7 dans ce projet (car il s'agit de la version préinstallée sur le système d'exploitation Raspberry Pi recommandé). Donc, vous allez taper sudo apt-get install python 3.7
Pour changer la version python par défaut en Python 3, exécutez la commande suivante:
sudo update-alternatives --install / usr / bin / python python / usr / bin / pythonn3 1
Maintenant, Python 3 devrait apparaître comme l'interpréteur par défaut.
La dernière étape consiste à installer les modules requis. Pour cela, tapez simplement les commandes suivantes dans le terminal:
sudo pip installer designspark.pmod
Code:
1. fan_controller.py
Le script Python se compose de trois modules: fan_controller.py, keypad.py et display.py. Le fan_controller.py est le module principal. Dans ce module, tout d'abord, nous importons toutes les bibliothèques et modules requis, créons une classe et définissons des variables:
- #!/usr/bin/env python
- """
- The controller sets the speed of a fan according to temperature (mode 1),
- or lets the fan run with a constant speed for a given time (mode 2).
- Temperature is measured with Pmod TC1.
- The motor is driven by Pmod HB3.
- The user interface is realized with Pmod OLEDrgb and Pmod KYPD.
- """
- # import necessary modules
- from DesignSpark.Pmod.HAT import createPmod
- from luma.core.render import canvas
- from datetime import datetime, timedelta
- import time
- # import own modules
- import display
- import keypad
- # create objects for each pmod
- TC1 = createPmod('TC1', 'JBA')
- HB3 = createPmod('HB3', 'JBB')
- keypad.KYPD = createPmod('KYPD', 'JC') # Pmod KYPD and Pmod OLEDrgb are
- display.OLED = createPmod('OLEDrgb', 'JA') # used in separate modules
- class settings:
- """ this class contains "global variables" """
- TEMP_AVG = 500 # number of temperature measurements to average
- TEMP_MIN = 22.0 # temperature for 0% fan speed
- TEMP_MAX = 35.0 # temperature for 100% fan speed
- TIME_RUN = 15 # number of minutes to run (mode 2)
- CONST_SPEED = 75 # speed in mode 2
- MOTOR_REV = False # reverse the rotation of the motor
- MODE = 1 # starting mode
Ensuite, les fonctions sont définies. Les quatre fonctions sont action_M1 () , qui règle la vitesse du moteur en fonction de la température mesurée et moyenne, action_M2 () , dont la vitesse du moteur est définie, puis la fonction attend le temps défini (les pressions sur les touches terminent la fonction). La fonction set_param () définit un paramètre et la fonction decode_key () décide quel menu ou sous-menu afficher en appuyant sur une touche.
- def action_M1():
- """ this is done in mode 1 """
- # get average temperature
- average_temp = 0.0
- for _ in range(settings.TEMP_AVG):
- average_temp = average_temp + TC1.readCelcius()
- average_temp = average_temp / settings.TEMP_AVG
- # calculate the speed from the temperature
- average_temp = average_temp - settings.TEMP_MIN
- max_temp = settings.TEMP_MAX - settings.TEMP_MIN
- if max_temp <= 0:
- max_temp = 1
- speed = 0
- if average_temp > 0:
- speed = average_temp * 100 / max_temp
- # limit the speed
- if speed > 100:
- speed = 100
- elif speed < 0:
- speed = 0
- # set the speed of the motor
- if settings.MOTOR_REV:
- HB3.reverse(speed)
- else:
- HB3.forward(speed)
- # display data
- display.data_M1(average_temp, speed, settings.TEMP_MIN,
- settings.MODE)
- return
- def action_M2():
- """ this is done in mode 2 """
- # calculate stop time
- stop_time = datetime.now() + timedelta(minutes=settings.TIME_RUN)
- # set motor speed
- if settings.MOTOR_REV:
- HB3.reverse(settings.CONST_SPEED)
- else:
- HB3.forward(settings.CONST_SPEED)
- # wait but check buttons
- try:
- # if the time didn't expire, continue
- while datetime.now() < stop_time:
- # display data in every iteration (the time will change)
- display.data_M2(settings.CONST_SPEED, stop_time -
- datetime.now(), settings.MODE)
- # check for keypress
- if keypad.KYPD.getKey() != None:
- raise keypad.KeyPressed
- pass
- # on keypress, stop the motor and exit
- except keypad.KeyPressed:
- HB3.forward(0)
- return
- # calculate stop time
- stop_time = datetime.now() + timedelta(minutes=settings.TIME_RUN)
- # stop motor
- HB3.reverse(0)
- # wait but check buttons
- try:
- # if the time didn't expire, continue
- while datetime.now() < stop_time:
- # display data in every iteration (the time will change)
- display.data_M2(0, stop_time - datetime.now(), settings.MODE)
- # check for keypress
- if keypad.KYPD.getKey() != None:
- raise keypad.KeyPressed
- pass
- # on keypress, stop the motor and exit
- except keypad.KeyPressed:
- HB3.forward(0)
- return
- return
- def set_param(text, unit):
- """ get a parameter and display it """
- # display a text to ask for the parameter
- display.require(text)
- # read the parameter
- parameter = keypad.get_param()
- # display the parameter
- display.parameter(text, parameter, unit)
- # wait for a button to exit
- keypad.wait_for_key()
- return parameter
- def decode_key(stage, key=None):
- """ this is done, when a key is pressed """
- # skip the main menu, if the key was pressed,
- # when a submenu was displayed
- if stage == 0:
- # display the main menu
- display.menu()
- # wait for a keypress
- key = keypad.wait_for_key()
- # if "A" is pressed in the main menu, or mode 1 submenu
- # was requested
- if key == "A" or stage == 1:
- # set mode to 1
- settings.MODE = 1
- # display submenu for mode 1
- display.menu_M1()
- # wait for a keypress
- key = keypad.wait_for_key()
- # if "C" is pressed in the submenu
- if key == "C":
- # request and set the minimum temperature
- settings.TEMP_MIN = set_param("low temperature limit", "\xb0C")
- # go back to the mode 1 submenu
- decode_key(1)
- # if "D" is pressed in the submenu
- elif key == "D":
- # request and set the minimum temperature
- settings.TEMP_MAX = set_param("high temperature limit", "\xb0C")
- # go back to the mode 1 submenu
- decode_key(1)
- else:
- # go back to the main menu
- decode_key(0)
- # if "B" is pressed in the main menu, or mode 2 submenu
- # was requested
- elif key == "B" or stage == 2:
- # set mode to 2
- settings.MODE = 2
- # display submenu for mode 2
- display.menu_M2()
- # wait for keypress
- key = keypad.wait_for_key()
- # if "C" is pressed in the submenu
- if key == "C":
- # request and set the speed
- settings.CONST_SPEED = set_param("speed", "%")
- # go back to the mode 2 submenu
- decode_key(2)
- # if "D" is pressed in the submenu
- elif key == "D":
- # request and set the runtime
- settings.TIME_RUN = set_param("nr. of minutes", "min")
- # go back to the mode 2 submenu
- decode_key(2)
- else:
- # go back to the main menu
- decode_key(0)
- return
Maintenant, nous créons le "châssis" du script. Il contient la boucle principale, dans laquelle les pressions sur les touches sont vérifiées. Si aucune touche n'est enfoncée, l'action du mode actuel est exécutée. Si une touche est enfoncée, le moteur est arrêté et la clé est décodée, le menu correspondant est affiché. Lorsque vous quittez le script, un nettoyage approprié est nécessaire.
- # main program
- try:
- # setup
- keypad.KYPD.setKeyMapDefault() # set default key map
- time.sleep(1) # wait a second
- # main loop
- while True:
- # if no key was pressed
- if keypad.get_key() == None:
- # if the mode variable is 1
- if settings.MODE == 1:
- # call function for mode 1
- action_M1()
- # if the mode variable is 2
- elif settings.MODE == 2:
- # call function for mode 2
- action_M2()
- # if a key was pressed
- else:
- # stop the motor
- HB3.forward(0)
- # decode the key
- decode_key(0)
- except KeyboardInterrupt:
- # exit on ctrl+c
- pass
- finally:
- # close opened connections
- TC1.cleanup()
- HB3.cleanup()
- keypad.KYPD.cleanup()
- display.OLED.cleanup()
2. keypad.py
Le module est constitué d'un objet vide ( KYPD ) qui est initialisé dans le fan_controller.py, un type d'exception lorsqu'une touche est enfoncée (en mode 2). Il y a 4 fonctions: get_param () définit un nouveau keymap et mappe les lettres à 0 et lit un nombre à deux chiffres sur le clavier; wait_for_key () est la fonction de lecture de clé de blocage et de blocage; get_key () est le lecteur de clé non-bloquant et non-bloquant; debounce () ne renvoie chaque pression qu'une seule fois. Pour renvoyer une pression sur une touche, la touche doit être relâchée et est vérifiée en validant 1000 états consécutifs «Aucun» du clavier.
- """
- This is the module containing keypad control functions
- """
- # import necessary modules
- from DesignSpark.Pmod.HAT import createPmod
- # the KYPD object is needed in this module,
- # but is initialized in the main program
- KYPD = None
- class KeyPressed(Exception):
- """This exception is raised when a key is pressed"""
- pass
- def get_param():
- """ this function returns a two digit number
- entered on the Pmod KYPD """
- # set a new keymap: letters are mapped to 0
- keyMap = [['1', '2', '3', '0'], ['4', '5', '6', '0'],
- ['7', '8', '9', '0'], ['0', '0', '0', '0']]
- KYPD.setKeyMap(keyMap)
- # wait for a keypress
- key = wait_for_key()
- # save the first digit
- parameter = int(key) * 10
- # wait for a keypress
- key = wait_for_key()
- # save the second digit
- parameter = parameter + int(key)
- # restore default keymap
- KYPD.setKeyMapDefault()
- return parameter
- def wait_for_key():
- """ this function wait until a key is pressed,
- then returns that key"""
- # read keypresses
- key = KYPD.getKey()
- # read keypresses until a key is pressed
- while key == None:
- key = KYPD.getKey()
- # debounce the keypad
- debounce()
- return key
- def get_key():
- """ this function returns the debounced keypresses
- non-blocking: returns None if nothing was pressed """
- # get keypress
- key = KYPD.getKey()
- # debounce it
- debounce()
- return key
- def debounce():
- """ this function debounces the keypad
- if 1000 consecutive states of the keypad
- are "None", the keyes are released """
- # enter in a loop
- flag = True
- while flag:
- # set the flag to False
- flag = False
- # inspect 1000 consecutive states of the keypad
- for _ in range(1000):
- # if a key is pressed
- if KYPD.getKey() != None:
- # restart the debouncing process
- flag = True
- break
- return
3. display.py
Le module d'affichage a un objet vide ( OLED ) qui est initialisé dans le fan_controller.py, et 7 fonctions pour afficher diverses données. Ces fonctions commencent par une ligne, effacent l'écran et dessinent plusieurs lignes de texte.
- """
- This is the module containing display control functions
- """
- # import necessary modules
- from DesignSpark.Pmod.HAT import createPmod
- from luma.core.render import canvas
- # the OLED object is needed in this module,
- # but is initialized in the main program
- OLED = None
- def require(text):
- """ display a text to require a parameter """
- with canvas(OLED.getDevice()) as draw:
- # clear the screen
- draw.rectangle(OLED.getDevice().bounding_box,
- outline="black", fill="black")
- # display some text
- draw.text((20, 10), "Enter the", fill="white")
- draw.text((0, 30), text, fill="red")
- return
- def parameter(text, number, unit):
- """ display a parameter with unit """
- with canvas(OLED.getDevice()) as draw:
- # clear the screen
- draw.rectangle(OLED.getDevice().bounding_box,
- outline="black", fill="black")
- # display some text
- draw.text((0, 10), text, fill="white")
- draw.text((30, 30), str(number), fill="green")
- draw.text((45, 30), unit, fill="white")
- draw.text((25, 45), "Exit", fill="yellow")
- draw.text((5, 52), "press any key", fill="yellow")
- return
- def data_M1(average_temp, speed, min_temp, mode):
- """ display data in mode 1: temperature and speed """
- with canvas(OLED.getDevice()) as draw:
- # clear the screen
- draw.rectangle(OLED.getDevice().bounding_box,
- outline="black", fill="black")
- # dislpay the temperature
- draw.text((5, 0), "Temperature: ", fill="white")
- draw.text((15, 10), "%.2f" % (average_temp + min_temp), fill="green")
- draw.text((50, 10), "\xb0" + "C", fill="white")
- # display the speed
- draw.text((5, 20), "Fan speed: ", fill="white")
- draw.text((15, 30), "%.2f" % speed, fill="green")
- draw.text((50, 30), "%", fill="white")
- # display current mode
- draw.text((80, 38), "M" + str(mode), fill="red")
- # display some text
- draw.text((25, 45), "Menu", fill="yellow")
- draw.text((5, 52), "press any key", fill="yellow")
- return
- def data_M2(speed, time, mode):
- """ display data in mode 2: speed and remaining time left """
- with canvas(OLED.getDevice()) as draw:
- # clear the screen
- draw.rectangle(OLED.getDevice().bounding_box,
- outline="black", fill="black")
- # display the speed
- draw.text((5, 0), "Speed: ", fill="white")
- draw.text((15, 10), str(speed), fill="green")
- draw.text((50, 10), "%", fill="white")
- # display the time left
- draw.text((5, 20), "Time left: ", fill="white")
- _, remainder = divmod(time.seconds, 3600)
- minutes, seconds = divmod(remainder, 60)
- draw.text((15, 30), str(minutes) + ":" + str(seconds), fill="green")
- draw.text((50, 30), "min:s", fill="white")
- # display the mode
- draw.text((80, 38), "M" + str(mode), fill="red")
- # display some text
- draw.text((25, 45), "Menu", fill="yellow")
- draw.text((5, 52), "press any key", fill="yellow")
- return
- def menu():
- """ display the main menu """
- with canvas(OLED.getDevice()) as draw:
- # clear the screen
- draw.rectangle(OLED.getDevice().bounding_box,
- outline="black", fill="black")
- # display option for key "A"
- draw.text((5, 0), "Press ", fill="white")
- draw.text((40, 0), "A", fill="green")
- draw.text((20, 10), "for mode ", fill="white")
- draw.text((75, 10), "1", fill="red")
- # display option for key "B"
- draw.text((5, 25), "Press", fill="white")
- draw.text((40, 25), "B", fill="green")
- draw.text((20, 35), "for mode", fill="white")
- draw.text((75, 35), "2", fill="red")
- # display some text
- draw.text((25, 45), "Exit", fill="yellow")
- draw.text((5, 52), "press any key", fill="yellow")
- return
- def menu_M1():
- "display submenu for mode 1"
- with canvas(OLED.getDevice()) as draw:
- # clear the screen
- draw.rectangle(OLED.getDevice().bounding_box,
- outline="black", fill="black")
- # display option for key "C"
- draw.text((5, 0), "Press ", fill="white")
- draw.text((40, 0), "C", fill="green")
- draw.text((50, 0), "to set", fill="white")
- draw.text((0, 10), "low temp. limt", fill="red")
- # display option for key "D"
- draw.text((5, 25), "Press", fill="white")
- draw.text((40, 25), "D", fill="green")
- draw.text((50, 25), "to set", fill="white")
- draw.text((0, 35), "high temp. limt", fill="red")
- # display some text
- draw.text((25, 45), "Exit", fill="yellow")
- draw.text((5, 52), "press any key", fill="yellow")
- return
- def menu_M2():
- "display submenu for mode 2"
- with canvas(OLED.getDevice()) as draw:
- # clear the screen
- draw.rectangle(OLED.getDevice().bounding_box,
- outline="black", fill="black")
- # display option for key "C"
- draw.text((5, 0), "Press ", fill="white")
- draw.text((40, 0), "C", fill="green")
- draw.text((50, 0), "to set", fill="white")
- draw.text((0, 10), "constant speed", fill="red")
- # display option for key "D"
- draw.text((5, 25), "Press", fill="white")
- draw.text((40, 25), "D", fill="green")
- draw.text((50, 25), "to set", fill="white")
- draw.text((0, 35), "run time", fill="red")
- # display some text
- draw.text((25, 45), "Exit", fill="yellow")
- draw.text((5, 52), "press any key", fill="yellow")
- return
Exécutez le script
Pour exécuter le script, entrez la ligne suivante dans le terminal:
- python /home/pi/path_to_script/fan_controller.py
où path_to_script est le chemin vers le script Python. Assurez-vous que le Raspberry Pi est allumé. Vous pouvez également ajouter la ligne ci-dessus suivie d'une esperluette dans le fichier /etc/rc.local (voir l'image à droite) afin que Python s'exécute lorsque le Raspberry Pi 4 démarre
Essai:
Allumez la carte Raspberry Pi. Si le script ne démarre pas au démarrage, exécutez le script.
Initialement, la vitesse du moteur est réglée en fonction de la température. Appuyez sur n'importe quelle touche pour accéder au menu principal. Dans le menu principal, choisissez le mode 1 (appuyez sur A) ou 2 (appuyez sur B). Lorsque vous êtes dans l'un des modes, vous pouvez régler les paramètres en appuyant sur C ou D. Vous pouvez quitter les menus en appuyant sur n'importe quelle touche (qui n'est pas répertoriée dans le menu ou le sous-menu).
En mode 1, la vitesse du moteur dépend de la température. Les utilisateurs peuvent définir les limites de température pour une vitesse de 0% et 100% à partir du sous-menu.
En mode 2, la vitesse du moteur est constante pendant un temps prédéfini (initialement 15 minutes). Ensuite, le moteur s'arrête pendant le même laps de temps. Les utilisateurs peuvent régler la vitesse du moteur et l'heure en mode 2.
Ressources:
- Cliquez ci pour télécharger les programmes sources de cette application
- Cliquez ci pour télécharger les schémas de cette application
Crédit: @ Digilent Inc - Alex wong