Dans certains projets, il peut être intéressant d’établir une communication série entre Raspberry Pi et Arduino. Il est ainsi possible de coupler la puissance de calcul et les interface sans fil du Raspberry Pi avec les entrées-sorties et la collection de modules Arduino. Le premier exemple qui vient en tête est l’utilisation de ce système pour de la domotique dans lequel le Raspberry Pi va héberger l’interface de contrôle et l’intelligence et les Arduino vont servir d’automate programmable agissant sur les composants en bout de chaîne (lumière, radiateur, ventilateur, capteurs, etc.).
Nous allons voir dans ce tutoriel comment mettre en place une communication série entre Raspberry Pi et Arduino via le port USB. Dans cet article, nous utilisons la carte Arduino UNO mais il peut être adapté à d’autre type de carte avec une connexion série (Nano, Mega, Feather, EPS32, ESP8266 etc.)
Prérequis: Communication Série avec Arduino, Accès à distance du Raspberry Pi avec VNC
Matériel
- Ordinateur
- Arduino UNO
- Raspberry Pi 3B+
- USB A Mâle/USB B Mâle
Schéma de câblage
Pour établir la communication série entre Raspberry Pi et Arduino, il suffit des les relier grâce à un câble USB adapté. Dans notre cas, nous utilisons un Raspberry Pi 3B+ et un Arduino UNO. Il nous faut donc un cable USBA Mâle vers USB B Mâle.
Il est aussi possible de créer une communication série en utilisant les broches Rx/Tx des deux composants. Dans ce tutoriel, nous allons nous concentrer sur la connexion USB
- Tx GPIO14(RPI) <-> Rx 0(Arduino)
- Rx GPIO15(RPI) <-> Tx 1(Arduino)
- GND (RPI) <-> GND(Arduino)
Configuration du Raspberry Pi
Nous rappelons que pour pouvoir utiliser votre Raspberry Pi sans écran ni clavier, il faut que la connexion à distance VNC soit configurée.
Pour utiliser l’interface Série du Raspberry Pi, celle-ci doit être activée dans le menu de configuration. Pour cela entrez la commande suivante dans un terminal:
sudo raspi-config
Dans le menu, sélectionnez « 5 – Interfacing Options » puis « P6 Serial » et validez.
Un fois le branchement fait, vous pouvez vérifier les appareils branchés sur le port série en tapant dans le terminal la commande:
lsusb
Le Raspberry Pi retourne la liste des appareils branchés sur les ports USB.
pi@raspberrypi:~ $ lsusb
Bus 001 Device 002: ID 2341:0043 Arduino SA Uno R3 (CDC ACM)
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Pour trouver le nom du port sur lequel est branché l’Arduino, nous utilisons la commande:
dmesg | grep "tty"
Cette commande retourne les message système relatifs aux port séries. Vous deviez trouver le nom du port dans les derniers message. Dans notre cas le nom du port est ttyACM0.
pi@raspberrypi:~ $ dmesg | grep "tty"
[ 0.000000] Kernel command line: coherent_pool=1M 8250.nr_uarts=1 bcm2708_fb.fbwidth=1824 bcm2708_fb.fbheight=984 bcm2708_fb.fbswap=1 smsc95xx.macaddr=B8:27:EB:23:CF:07 vc_mem.mem_base=0x1ec00000 vc_mem.mem_size=0x20000000 console=ttyS0,115200 console=tty1 root=/dev/mmcblk0p7 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait quiet splash plymouth.ignore-serial-consoles
[ 0.000636] console [tty1] enabled
[ 0.951553] 20201000.serial: ttyAMA0 at MMIO 0x20201000 (irq = 81, base_baud = 0) is a PL011 rev2
[ 0.954393] console [ttyS0] disabled
[ 0.954466] 20215040.serial: ttyS0 at MMIO 0x0 (irq = 53, base_baud = 31250000) is a 16550
[ 0.954570] console [ttyS0] enabled
[ 5.378641] systemd[1]: Created slice system-serial\x2dgetty.slice.
[ 1455.402071] cdc_acm 1-1:1.0: ttyACM0: USB ACM device
[ 1581.980257] cdc_acm 1-1:1.0: ttyACM0: USB ACM device
Installation de l’IDE Arduino sur Raspberry Pi
Pour installer l’IDE Arduino sur Raspberry Pi, le mieux est de passer par le terminal. Il vous suffit de rentrer les lignes de code suivantes:
mkdir ~/Applications
cd ~/Applications
wget https://downloads.arduino.cc/arduino-1.8.9-linuxarm.tar.xz
tar xvJf arduino-1.8.9-linuxarm.tar.xz
cd arduino-1.8.9/
./install.sh
rm ../arduino-1.8.9-linuxarm.tar.xz
Ceci vous permettra, par la suite, de programmer l’Arduino directement à partir du Raspberry Pi.
Code
Code Arduino
La librairie utilisée pour la communication série côté Arduino est la même que pour communiquer avec le moniteur série, la librairie Serial.h que nous connaissons bien. Vérifiez bien que la vitesse de communication est la même pour les deux appareils (baudrate=9600) sinon la communication ne fonctionnera pas.
String nom = "Arduino"; String msg; void setup() { Serial.begin(9600); } void loop() { readSerialPort(); if (msg != "") { sendData(); } delay(500); } void readSerialPort() { msg = ""; if (Serial.available()) { delay(10); while (Serial.available() > 0) { msg += (char)Serial.read(); } Serial.flush(); } } void sendData() { //write data Serial.print(nom); Serial.print(" received : "); Serial.print(msg); }
Code Python
Dans ce tutoriel, nous allons utiliser le langage Python côté Raspberry Pi. La librairie utilisée pour la gestion de la communication série est la librairie serial.
#!/usr/bin/env python # -*- coding: utf-8 -*- # lsusb to check device name #dmesg | grep "tty" to find port name import serial,time if __name__ == '__main__': print('Running. Press CTRL-C to exit.') with serial.Serial("/dev/ttyACM0", 9600, timeout=1) as arduino: time.sleep(0.1) #wait for serial to open if arduino.isOpen(): print("{} connected!".format(arduino.port)) try: while True: cmd=input("Enter command : ") arduino.write(cmd.encode()) #time.sleep(0.1) #wait for arduino to answer while arduino.inWaiting()==0: pass if arduino.inWaiting()>0: answer=arduino.readline() print(answer) arduino.flushInput() #remove data after reading except KeyboardInterrupt: print("KeyboardInterrupt has been caught.")
Résultat
Le Raspberry Pi envoie la commande « Hello Arduino » à l’Arduino, et l’Arduino répond avec son nom et la commande reçu.
Exemple pratique
Une fois que la communication est établie entre Raspberry Pi et Arduino, ce qui est intéressant, c’est de piloter les entrées-sorties de l’Arduino et de récupérer les valeurs des capteurs. Dans cet exemple, nous allons définir différentes commandes:
- une pour récupérer les valeurs des capteurs
- une pour allumer et éteindre la LED sur la broche 13
Code Arduino
L’Arduino, renvoie des données lorsqu’elle reçoit la commande « data » et allume et éteint la LED branchée sur la broche 13 en fonction des commandes « led0 » et « led1 ».
const int ledPin=13; String nom = "Arduino"; String msg; void setup() { Serial.begin(9600); } void loop() { readSerialPort(); if (msg == "data") { sendData(); }else if(msg=="led0"){ digitalWrite(ledPin,LOW); Serial.print(" Arduino set led to LOW"); }else if(msg=="led1"){ digitalWrite(ledPin,HIGH); Serial.print(" Arduino set led to HIGH"); } delay(500); } void readSerialPort() { msg = ""; if (Serial.available()) { delay(10); while (Serial.available() > 0) { msg += (char)Serial.read(); } Serial.flush(); } } void sendData() { //write data ledState x sensor1 x sensor2 Serial.print(digitalRead(ledPin)); Serial.print("x"); Serial.print(analogRead(A0)); Serial.print("x"); Serial.print(analogRead(A1)); }
Code Python
#!/usr/bin/env python # -*- coding: utf-8 -*- # lsusb to check device name #dmesg | grep "tty" to find port name import serial,time if __name__ == '__main__': print('Running. Press CTRL-C to exit.') with serial.Serial("/dev/ttyACM0", 9600, timeout=1) as arduino: time.sleep(0.1) #wait for serial to open if arduino.isOpen(): print("{} connected!".format(arduino.port)) try: while True: cmd=input("Enter command (data,led0 or led1): ") arduino.write(cmd.encode()) #time.sleep(0.1) #wait for arduino to answer while arduino.inWaiting()==0: pass if arduino.inWaiting()>0: answer=str(arduino.readline()) print("---> {}".format(answer)) if cmd=="data": dataList=answer.split("x") print("led state : {}".format(dataList[0])) print("Analog input A0 : {}".format(dataList[1])) print("Analog input A1: {}".format(dataList[2])) arduino.flushInput() #remove data after reading except KeyboardInterrupt: print("KeyboardInterrupt has been caught.")
Une fois les deux codes téléversés et lancés, on observe que lorsqu’on entre la commande « data » dans le terminal, Arduino renvoie bien des bytes contenant les valeurs de capteurs. Il est possible de séparer cette réponse en liste à l’aide de la fonction split() et du caractère « x » et, ainsi, récupérer les valeurs des capteurs et l’état de la led. Grâce à ce code, il nous est possible de piloter l’état de la LED de la broche 13.
En modifiant ce code, il vous sera possible de piloter et d’observer n’importe quelle entrée-sortie de l’Arduino sur le Raspberry Pi.
Application
- Créer une interface graphique (GUI) sous Raspberry Pi pour piloter un Arduino et récupérer des valeurs de capteurs
Sources
Retrouvez nos tutoriels et d’autres exemples dans notre générateur automatique de code
La Programmerie
Merci 🙂
Je cherche simplement a envoyer un message à l’Arduino (comme « coucou ») mais je n’y arrive pas… comment dois-je modifier mon programme pour que celui-ci envoie un message sans que je lui entre des donné manuellement ?
Bonjour,
Dans le code Python, tu dois commenter la commande input() qui permet d’attendre une commande de l’utilisateur.
cmd= »Coucou » #cmd=input(« Enter command : « )
arduino.write(cmd.encode())
Si tu souhaites que la commande ne soit envoyée qu’une seule fois, il faut supprimer la boucle while
Mais justement, je ne veux rien attendre de l’utilisateur… je souhaite combiner ça à de la reconnaissance vocale. Actuellement, je dis un mot dans un micro, mon RPI le récupère dans une variable, et c’est cette variable que j’aimerais envoyer à l’Arduino… le déclencheur de tout ça est un bouton poussoir, j’appuis dessus, je parle et je peux allumer des relais grâce à mes commande vocales. je vous met le lien du tuto : https://www.youtube.com/watch?v=R1SFP3t7Gwo
J’ai bien compris.
il vous suffit de remplacer cmd=input(« Enter command : « ) par cmd= « votre commande »
Le mieux est d’appeler la fonction arduino.write(cmd.encode()) une fois que la reconnaissance vocale a été effectué pour ne pas envoyer constamment des messages à l’arduino.
try:
while True:
cmd= »coucou »
arduino.write(cmd.encode())
except KeyboardInterrupt:
print(« KeyboardInterrupt has been caught. »)
Tout ce qu’il me manque c’est de pouvoir ouvrir la communication une fois au démarrage du programme. je vous explique, j’ai réussi à faire ce que je voulais mais cela me demande d’ouvrir les port chaque fois que je veux transmettre quelque chose ( et donc cela redémarre mon programme Arduino)… n’est il pas possible de les ouvrir une fois seulement ? merci pour vos réponses.
merci beaucoup !
Bonjour,
Il est possible de configurer le port série pour que l’Arduino ne redémarre pas à chaque connexion
arduino.dtr=True
Bonjour, je n’ai pas compris ou je devais mettre la commande « arduino.dtr=True » ? =Merci pour vos réponse ! 🙂
Rajouter le paramètre dsrdtr dans l’appel de l’objet serial
serial.Serial(« /dev/ttyACM0 », 9600, timeout=1,dsrdtr=None)
salut , comment je peux afficher les valeurs dans une page html avec python?
Tu peux créer une page web avec python et récupérer les valeurs envoyées par l’Arduino
Bonjour,
bravo pour le tuto. voici ce que je désire :
– mon Arduino envoie +/- 8 messages /minutes de – de 30 caractères.
– cet envoi pourrait-il déclencher une interruption du côté Raspberry ?
Merci !
Bonjour,
Merci pour votre commentaire.
Qu’entendez-vous par interruption?
vous souhaitez que le Raspberry fasse une action en fonction du message reçu?
Bonjour, et déjà merci de m’avoir répondu !
Voilà la définition : https://fr.wikipedia.org/wiki/Interruption_(informatique)
Dans les faits, le programme tourne dans son train-train, mais est interrompu (et dévié) lorsque un message arrive, qui est alors traité, puis retourne à son train-train jusqu’à l’interruption suivante.
En fait, à l’origine, je cherchais une communication I2C où le Raspberry serait en mode SLAVE d’un Arduino MASTER, mais je n’ai pas trouvé d’exemple dans ce sens.
Bonjour,
Avec la communication série, c’est un peut se que fait la ligne if arduino.inWaiting()>0:. Si un message est présent il est traité. Ce n’est pas une interruption, à proprement parlé.
Trois possibilité:
-Il est possible de détecter un interrupt sur la broche de réception du RPi branchée à la broche Tx de l’Arduino
-Il est possible d’utiliser du multithreading afin que le raspberry écoute le port série constamment et traite un message lorsqu’il arrive.
-Il semble qu’il soit possible de configurer un Raspberry en Slave I2C avec la librairie pigpio
en espérant que cela soit utile
Bonjour,
Je viens de faire la première parti de tuto et je me retrouve avec ce message d’erreur :
« File « comunication_arduino.py », line 18, in
cmd=input(« Enter command : « )
File « », line 1
Hello Arduino
^
SyntaxError: unexpected EOF while parsing »
Avez vous une idée du problèmes
Merci
Bonjour,
essayez avec raw_input() ou avec python3
Bojour Meri pour le tuto
pour un système RFID basé sur le kit MFRC522 qui est câblé dans l’arduino uno, je souhaiterai récupérer les identifiant du tag et le message de celui-ce dans un code python exécuté dans le RPI 3B+
Merci
Bonjour,
il est possible de lire le module RC522 directement avec Raspberry Pi.
Pour récupérer le tag sur Raspberry, il suffit de l’envoyer dans la fonction sendData() de l’Arduino