mercredi 27 novembre 2019

pyserial: communiquer en python avec un Arduino

Aujourd'hui, nous allons programmer un script en Python qui communiquera avec une carte Arduino branchée à un port USB de l'ordinateur.

Ce programme sera utile, par exemple, pour consulter à partir de l'ordinateur des mesures prises par des capteurs branchés à l'Arduino,  pour contrôler à partir de l'ordinateur un bras robotisé branché à l'Arduino, etc.

Bien entendu, tout ça peut se faire à partir du moniteur série de l'IDE Arduino, mais l'écriture de notre propre programme nous offrira la flexibilité nécessaire pour mieux répondre à nos besoins spécifiques.

Avant d'aller plus loin, j'aimerais attirer votre attention sur la série d'articles que j'ai rédigée sur l'utilisation de pyFirmata: on y atteint le même objectif d'une façon différente. Firmata est un protocole de communication entre un ordinateur hôte et un microcontrôleur. À mon avis, l'utilisation de Firmata est particulièrement appropriée si vous êtes très à l'aise avec la programmation en Python, mais moins à l'aise avec la programmation d'un Arduino: vous pouvez télécharger dans l'Arduino un sketch générique déjà tout fait, et concentrer tous vos efforts du côté du script en Python qui s'exécutera sur l'ordinateur.

La méthode que nous allons employer aujourd'hui (sans Firmata) suppose que vous maîtrisez à la fois le Python (côté ordinateur) et le C (côté Arduino).

Installation de pyserial

Côté ordinateur, nous aurons besoin de la bibliothèque pyserial qui, comme son nom l'indique, permet d'établir une communication série dans un programme en Python. Pour ce faire, j'ai utilisé pip:

pip install pyserial


Exemple 1: Communication de l'Arduino vers l'ordinateur

Dans ce premier exemple, l'Arduino va envoyer un message à chaque demi seconde. Le script en Python affichera chaque message reçu.

Commençons par le sketch à télécharger dans l'Arduino. Rien de bien compliqué ici: après avoir activé la communication série et choisi la vitesse de transmission au début du programme (Serial.begin(9600)), chaque émission d'un message s'accomplit grâce à un Serial.println().

-
-

Du côté ordinateur, la réception des messages s'accomplit au moyen de l'instruction readline(). Mais auparavant, en plus d'avoir défini la vitesse de transmission (baud rate), il faut indiquer quel port série est utilisé par l'Arduino.

La plupart des tutos proposent d'écrire le nom du port série directement dans le programme, comme par exemple, sur Linux:

serial.Serial('/dev/ttyACM0', 9600, timeout=.1)

... ou sur Windows:

serial.Serial('COM4', 9600, timeout=.1)

Cette approche me semble assez peu pratique, surtout qu'une même carte Arduino peut se voir attribuer des ports différents d'une utilisation à l'autre. Pour cette raison, mon script est un tout petit peu plus compliqué, car il effectue un scan des ports série actifs et demande à l'utilisateur de choisir celui qu'il désire. Il demande aussi à l'utilisateur de choisir la vitesse de transmission.

-
-

L'image ci-dessous montre l'exécution du programme: 2 cartes Arduino étaient simultanément branchées à l'ordinateur, une sur le port ttyUSB1 et l'autre sur le port ttyACM5.  J'ai choisi la deuxième carte, avec une vitesse de transmission de 9600 bauds, et les données en provenance de la carte choisie ont commencé à s'afficher.



Exemple 2: Communication de l'ordinateur vers l'Arduino

Essayons maintenant une communication de l'ordinateur hôte vers l'Arduino. Le script en Python enverra à l'Arduino le nombre de clignotements que devra effectuer sa LED intégrée.

Voici d'abord le sketch de l'Arduino: sur réception d'un message UART, il vérifie s'il s'agit d'un nombre situé 1 et 9 et, si c'est le cas, il fait clignoter sa LED. Notez que le message reçu est codé en ASCII, d'où la soustraction du nombre 48 (puisque le code ASCII du chiffre zéro est 48).

-
-

Du côté de l'ordinateur, le script en Python envoie, par l'instruction write(), le nombre choisi par l'utilisateur. Tout le début du script est similaire à celui de l'exemple 1: on effectue d'abord un scan des ports série actifs, et on demande à l'utilisateur de faire son choix.

-
-

L'image ci-dessous montre l'exécution du programme alors qu'un seul Arduino était connecté à l'ordinateur (dans le port ttyACM2). La LED intégrée à la carte Arduino se met à clignoter chaque fois que je choisis un nombre entre 1 et 9.



Yves Pelletier   (TwitterFacebook)

samedi 23 novembre 2019

Écran couleur SPI ST7735 et Raspberry Pi

Cet article a été mis à jour le 30 décembre 2020 (compatibilité Python 3).

Je vous explique aujourd'hui comment j'ai procédé pour contrôler un petit écran couleur SPI ST7735 ("KMR-1.8 SPI") de 128 * 160 pixels, branché à un Raspberry Pi, grâce à un script en Python.


Connexions

Il existe plusieurs modèles d'écrans couleurs basés sur le contrôleur ST7735, et le nom des broches peut varier d'un modèle à l'autre.  Le modèle que j'ai utilisé comporte 16 connecteurs (mais 9 d'entre eux suffisent à faire fonctionner l'écran).




J'ai branché l'écran à mon Raspberry Pi 2 de la façon suivante:
  • Broche GND de l'écran - Une des broches GND du Raspberry Pi
  • Broche VCC de l'écran - Une des broches 5V du Raspberry Pi
  • Broches NC de l'écran - Pas branchées
  • Broche RESET de l'écran - Broche GPIO25 du Raspberry Pi
  • Broche AO (ou DC/RS) de l'écran - Broche GPIO24 du Raspberry Pi
  • Broche SDA de l'écran - Broche GPIO10 du Raspberry Pi
  • Broche SCL de l'écran - Broche GPIO11 du Raspberry Pi
  • Broche CS de l'écran - Broche GPIO8 du Raspberry Pi
  • Broches SCK/MISO/MOSI/SD_CS de l'écran - Pas branchées (pour carte SD)
  • Broche LED+ de l'écran - Une des broches 3,3 V du Raspberry Pi
  • Broche LED- de l'écran - Une des broches GND du Raspberry Pi


Activation de SPI

Si ce n'est pas déjà fait, il est important d'activer le protocole SPI sur votre Raspberry Pi.  Pour ce faire, on ouvre "Configuration du Raspberry Pi" dans le menu "Préférences" de Raspbian.


Dans l'onglet, on coche "Activé" sur la ligne "SPI".



Installation de la bibliothèque

J'ai utilisée la bibliothèque Python ST7735, adaptée par Clement Skau à partir d'une bibliothèque qu'Adafruit avait conçue pour un autre modèle d'écran.

Pour installer la bibliothèque, les lignes de commande suivantes ne sont probablement pas nécessaires si vous utilisez une version récente de Raspberry Pi OS (dans mon cas, tout était déjà installé). Mais ça ne coûte rien de vérifier:

sudo apt-get update
sudo apt-get install build-essential python3-dev python3-smbus python3-pip python3-pil python3-numpy
sudo pip3 install RPi.GPIO

Les 4 lignes suivantes, par contre, sont essentielles:

sudo pip3 install Adafruit_GPIO
git clone https://github.com/cskau/Python_ST7735
cd Python_ST7735
sudo python3 setup.py install

Le répertoire Python_ST7735 comporte un dossier "Examples". Le script "image.py" qui s'y trouve constitue une façon simple et rapide de vérifier le fonctionnement correct de l'écran (ça affiche à l'écran l'image contenue dans le fichier "cat.jpeg").



Vous pouvez facilement modifier ce script afin d'afficher une image de votre choix.



Le script "shapes.py", toutefois, n'est pas tout à fait au point: il a visiblement été conçu pour un écran ayant une résolution différente, et on ne voit à l'écran qu'une partie de l'image construite.

Exemple de script en python

Puisque la bibliothèque utilise la Python Imaging Library (PIL), c'est assez facile de trouver de la documentation pour apprendre à construire des images pouvant être affichées à l'écran.

Les coordonnées sont définies selon l'orientation en mode portrait; la bibliothèque ne semble pas comporter une façon simple de définir une orientation en mode paysage.

Dans le script ci-dessous, j'affiche quelques formes géométriques, puis j'écris l'adresse IP du Raspberry Pi (utile pour travailler en mode "headless") ainsi que la date et l'heure.





-

-

Inversion du bleu et du rouge!

Sur certains modèles d'écran ST7735, les couleurs seront incorrectes: ce qui devrait être rouge apparaît en bleu, et ce qui devrait être bleu apparaît en rouge!  (C'est un écran "bgr" plutôt que "rgb"). Si vous constatez ce phénomène sur votre écran, la solution consiste à modifier la bibliothèque Python_ST7735:
  • Ouvrez le fichier /Python_ST7735/ST7735/ST7735.py avec un éditeur de texte.
  • À la ligne 241, remplacez self.data(0xC8) par self.data(0xC0) .
  • Retournez dans le répertoire Python_ST7735 et tapez à nouveau la commande "sudo python3 setup.py install"


À lire aussi

Cet écran couleur ST7735 peut également être contrôlé par un Raspberry Pi Pico , un Arduino, un STM32, un ESP8266 ou un ESP32.


Parmi les nombreux articles de ce blog portant sur le Raspberry Pi, certains décrivent l'utilisation d'autres modèles d'afficheurs: écran OLED SH1106, écran Nokia 5110,  afficheur LCD 16 X 2...

Yves Pelletier   (TwitterFacebook)

mercredi 20 novembre 2019

Raspberry Pi: présenter des mesures sous forme de graphique cartésien

Dans cet article, je vous présente comment j'ai pu présenter en temps réel, sous la forme d'un graphique cartésien, les mesures prises par un capteur branché aux broches GPIO du Rasbperry Pi.  Pour ce faire, j'ai utilisé un programme en langage Python, ainsi que la bibliothèque Matplotlib.



Installation de la bibliothèque Matplotlib

Matplotlib est une bibliothèque spécialement conçue pour représenter des données sous forme de graphique dans un programme en Python. Une façon simple de l'installer dans votre Raspberry Pi est d'écrire la commande suivante dans le terminal:

pip3 install matplotlib

J'ai aussi eu besoin d'installer gi cairo:

sudo apt-get install python3-gi-cairo

Un exemple de script (données calculées)

Voici un script qui fait apparaître un graphique qui se met à jour à toutes les 500 ms. Pour que tout le monde puisse en faire l'essai sans autre matériel qu'un Rasbperry Pi, les données qui s'affichent sur le graphique sont issues d'un calcul plutôt que d'une mesure effectuée par un capteur.

-
-

La variable temps_pause contient le nombre de millisecondes entre chaque mise à jour du graphique. Vous pouvez évidemment modifier cette valeur selon vos besoins (si ce temps est trop court pour la vitesse de votre Raspberry Pi, le graphique restera vide).

Les données à mettre en graphique s'accumulent dans les variables valeurs_x et valeurs_y.

Grâce à la fonction FuncAnimation de matplotlib, la routine animate s'exécute automatiquement, à intervalle régulier.

Le programme s'interrompt lorsque vous fermez la fenêtre du graphique.



Un deuxième exemple de script (données mesurées)

Pour afficher dans le graphique les données mesurées par un capteur, il s'agit de remplacer le calcul de la ligne 30 par une procédure qui ajoute à la variable valeurs_y la mesure issue du capteur. Évidemment, la syntaxe exacte dépend du capteur que vous utilisez.

Voici par exemple un script qui met en graphique les valeurs mesurées par un module PCF8591 (il s'agit en fait de la tension contrôlée par le potentiomètre intégré au module).

-
-

En tournant lentement le potentiomètre, j'ai obtenu ce graphique:


À lire aussi

Vous trouverez sur cette page la liste de tous les articles du blog portant sur le Raspberry Pi, et sur celle-ci les articles portant sur l'utilisation des microcontrôleurs dans un contexte scientifique.

Yves Pelletier   (TwitterFacebook)