
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().
-
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Communication série par USB entre Arduino et PC. | |
electroniqueamateur.blogspot.com | |
http://electroniqueamateur.blogspot.com/2014/11/utiliser-le-moniteur-serie-de-lide.html | |
*/ | |
int compteur = 0; | |
void setup() { | |
Serial.begin(9600); | |
} | |
void loop() { | |
compteur++; | |
Serial.print("Valeur du compteur: "); | |
Serial.println(compteur); | |
delay(500); | |
} | |
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.
-
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
# -*- coding: utf-8 -*- | |
''' | |
Reception des données émise par un Arduino branché | |
à un port USB. | |
''' | |
import serial | |
import serial.tools.list_ports | |
print("Recherche d'un port serie...") | |
ports = serial.tools.list_ports.comports(include_links=False) | |
if (len(ports) != 0): # on a trouvé au moins un port actif | |
if (len(ports) > 1): # affichage du nombre de ports trouvés | |
print (str(len(ports)) + " ports actifs ont ete trouves:") | |
else: | |
print ("1 port actif a ete trouve:") | |
ligne = 1 | |
for port in ports : # affichage du nom de chaque port | |
print(str(ligne) + ' : ' + port.device) | |
ligne = ligne + 1 | |
portChoisi = input('Ecrivez le numero du port desire:') | |
print('1: 9600 2: 38400 3: 115200') | |
baud = input('Ecrivez le baud rate desire:') | |
if (baud == 1): | |
baud = 9600 | |
if (baud == 2): | |
baud = 38400 | |
if (baud == 3): | |
baud = 115200 | |
# on établit la communication série | |
arduino = serial.Serial(ports[portChoisi - 1].device, baud, timeout=1) | |
print('Connexion a ' + arduino.name + ' a un baud rate de ' + str(baud)) | |
# si on reçoit un message, on l'affiche | |
while True: | |
data = arduino.readline()[:-2] | |
if data: | |
print data | |
else: # on n'a pas trouvé de port actif | |
print("Aucun port actif n'a ete trouve") | |
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
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).
-
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Si le message série reçu est un nombre entre 1 et 9, | |
on fait clignoter la LED intégrée à la carte. | |
*/ | |
void setup() { | |
Serial.begin(9600); | |
pinMode(LED_BUILTIN, OUTPUT); | |
} | |
void loop() { | |
int messageRecu = 0, clignotements = 0; | |
if (Serial.available() > 0) { | |
messageRecu = Serial.read(); | |
clignotements = messageRecu - 48; // car 0 = ASCII 48 | |
if ((clignotements > 0) && (clignotements < 10)) { | |
for (int i = 0; i < clignotements; i++) { | |
digitalWrite(LED_BUILTIN, HIGH); | |
delay(500); | |
digitalWrite(LED_BUILTIN, LOW); | |
delay(500); | |
} | |
} | |
} | |
} |
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.
-
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
# -*- coding: utf-8 -*- | |
''' | |
Envoi de données vers l'Arduino (série) | |
''' | |
import serial | |
import serial.tools.list_ports | |
print("Recherche d'un port serie...") | |
ports = serial.tools.list_ports.comports(include_links=False) | |
if (len(ports) != 0): # on a trouvé au moins un port actif | |
if (len(ports) > 1): # affichage du nombre de ports trouvés | |
print (str(len(ports)) + " ports actifs ont ete trouves:") | |
else: | |
print ("1 port actif a ete trouve:") | |
ligne = 1 | |
for port in ports : # affichage du nom de chaque port | |
print(str(ligne) + ' : ' + port.device) | |
ligne = ligne + 1 | |
portChoisi = input('Ecrivez le numero du port desire:') | |
print('1: 9600 2: 38400 3: 115200') | |
baud = input('Ecrivez le baud rate desire:') | |
if (baud == 1): | |
baud = 9600 | |
if (baud == 2): | |
baud = 38400 | |
if (baud == 3): | |
baud = 115200 | |
# on établit la communication série | |
arduino = serial.Serial(ports[portChoisi - 1].device, baud, timeout=1) | |
print('Connexion a ' + arduino.name + ' a un baud rate de ' + str(baud)) | |
while True: | |
message = input('Ecrivez le nombre de clignotements desire (1-9)') | |
arduino.write(str(message)) # envoi du message série | |
else: # on n'a pas trouvé de port actif | |
print("Aucun port actif n'a ete trouve") |
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 (Twitter, Facebook)