0% ont trouvé ce document utile (0 vote)
7 vues9 pages

Contrôler Arduino avec Python

Ce document explique comment contrôler un Arduino via un script Python en utilisant la communication série avec le module pyserial. Il détaille les commandes standard d'Arduino pouvant être exécutées depuis Python, ainsi que des exemples de programmes pour Arduino et Python. De plus, il aborde l'échange de tableaux de données entre Arduino et Python, en fournissant des prototypes de programmes pour illustrer ces échanges.

Transféré par

hospiceatchade229
Copyright
© All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd
0% ont trouvé ce document utile (0 vote)
7 vues9 pages

Contrôler Arduino avec Python

Ce document explique comment contrôler un Arduino via un script Python en utilisant la communication série avec le module pyserial. Il détaille les commandes standard d'Arduino pouvant être exécutées depuis Python, ainsi que des exemples de programmes pour Arduino et Python. De plus, il aborde l'échange de tableaux de données entre Arduino et Python, en fournissant des prototypes de programmes pour illustrer ces échanges.

Transféré par

hospiceatchade229
Copyright
© All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd

Frédéric Legrand Licence Creative Commons 1

Commande d'un Arduino en Python

1. Introduction

Ce document montre comment commander un Arduino depuis un script Python


tournant sur un ordinateur. La communication entre l'Arduino et l'ordinateur se fait
par la liaison série (câble USB). Pour la partie Python, le module pyserial est nécessaire
(ce module est inclus dans pythonxy).
On considère dans un premier temps un exemple simple de communication, où des
commandes standard de l'Arduino sont envoyées par le script Python.
On verra ensuite comment échanger des tableaux de données entre l'Arduino et
Python.

2. Exécution de commandes Arduino depuis Python

2.a. Principe

Le protocole Firmata permet de commander un Arduino depuis un programme tour-


nant sur un ordinateur (en langage Python, Java, etc). Le programme tournant sur l'ar-
duino reçoit des ordres correspondant aux commandes standard (par exemple digitalWrite)
de la part du programme de l'ordinateur.
Ce type d'interface est intéressant pour eectuer des tâches simples ne nécessitant
pas de réaction en temps réel de la part de l'Arduino. Il peut aussi servir pour vérier le
fonctionnement d'un circuit électronique relié à l'Arduino, avant de mettre en place une
solution en temps réel complète.
On propose ici une mise en ÷uvre de ce principe, avec un protocole élémentaire, qui
permet de comprendre comment se fait la communication série. Le programme Arduino
exécute sur demande l'une des commandes suivantes :
. pinMode
. digitalWrite
. digitalRead
. analogWrite
. analogRead
Les programmes présentés pourront être facilement complétés pour accomplir des tâches
plus spéciques (par exemple des lectures ou écritures séquentielles).

2.b. Programme Arduino

Voyons tout d'abord le programme tournant sur l'Arduino, écrit en C.


On commence par dénir les codes des diérentes commandes, qui doivent être des
caractères, c'est-à-dire des entiers 8 bits.
[Link]
#define PIN_MODE 100
#define DIGITAL_WRITE 101
#define DIGITAL_READ 102
#define ANALOG_WRITE 103
Frédéric Legrand Licence Creative Commons 2

#define ANALOG_READ 104

Dans la fonction setup, on initialise la liaison série et on envoit la série de caractères


(0,255,0) pour informer le correspondant que l'Arduino est prêt.

void setup() {
char c;
[Link](500000);
[Link]();
c = 0;
[Link](c);
c = 255;
[Link](c);
c = 0;
[Link](c);
}

Dans la fonction loop, on teste la présence d'une commande envoyée par l'ordinateur
(sous forme d'un caractère). Si un caractère de commande est présent, on appelle la
fonction de traitement correspondant à la commande. La fonction loop pourra bien sûr
être complétée par d'autres actions à faire, soit en tâche de fond, soit en réaction à une
commande de l'ordinateur.

void loop() {
char commande;
if ([Link]()>0) {
commande = [Link]();
if (commande==PIN_MODE) commande_pin_mode();
else if (commande==DIGITAL_WRITE) commande_digital_write();
else if (commande==DIGITAL_READ) commande_digital_read();
else if (commande==ANALOG_WRITE) commande_analog_write();
else if (commande==ANALOG_READ) commande_analog_read();
}
// autres actions à placer ici
}

On remarque que la commande [Link]() n'est pas bloquante, c'est-à-dire


qu'elle n'attend pas qu'un caractère soit présent sur le port série en lecture pour re-
tourner. C'est pour cette raison qu'il faut utiliser la fonction [Link](). Ce
mode de fonctionnement permet de tester la présence d'un caractère de commande sans
bloquer le fonctionnement de l'Arduino.
Voici la fonction de traitement de la commande pinMode. La boucle while permet
d'attendre que le numéro de la borne et le mode soient envoyés par l'ordinateur, tous
deux sous forme de caractère (entier 8 bits).

void commande_pin_mode() {
Frédéric Legrand Licence Creative Commons 3

char pin,mode;
while ([Link]()<2);
pin = [Link](); // pin number
mode = [Link](); // 0 = INPUT, 1 = OUTPUT
pinMode(pin,mode);
}

Voici la fonction de traitement de la commande digitalWrite :

void commande_digital_write() {
char pin,output;
while ([Link]()<2);
pin = [Link](); // pin number
output = [Link](); // 0 = LOW, 1 = HIGH
digitalWrite(pin,output);
}

Pour la commande digitalRead, il faut renvoyer à l'ordinateur la valeur lue, sous


forme d'un caractère :

void commande_digital_read() {
char pin,input;
while ([Link]()<1);
pin = [Link](); // pin number
input = digitalRead(pin);
[Link](input);
}

Voici le traitement de la fonction analogWrite (qui envoit un signal PWM) :

void commande_analog_write() {
char pin,output;
while ([Link]()<2);
pin = [Link](); // pin number
output = [Link](); // PWM value between 0 and 255
analogWrite(pin,output);
}

Pour la fonction analogRead, qui utilise le convertisseur analogique-numérique, il faut


envoyer à l'ordinateur la valeur lue, sous forme d'un entier 10 bits. En envoit en fait un
entier 16 bits sous forme de deux caractères, le premier correspondant aux 8 premiers
bits (poids fort), le seconde aux 8 derniers bits.

void commande_analog_read() {
char pin;
Frédéric Legrand Licence Creative Commons 4

int value;
while ([Link]()<1);
pin = [Link](); // pin number
value = analogRead(pin);
[Link]((value>>8)&0xFF); // 8 bits de poids fort
[Link](value & 0xFF); // 8 bits de poids faible
}

2.c. Programme Python

Voici le programme Python, qui utilise le module pyserial. Toutes les fonctions sont
incluses dans une classe Arduino.
[Link]
# -*- coding: utf-8 -*-
import serial

class Arduino():
def __init__(self,port):
[Link] = [Link](port,baudrate=500000)
c_recu = [Link](1)
while ord(c_recu)!=0:
c_recu = [Link](1)
c_recu = [Link](1)
while ord(c_recu)!=255:
c_recu = [Link](1)
c_recu = [Link](1)
while ord(c_recu)!=0:
c_recu = [Link](1)
self.PIN_MODE = 100
self.DIGITAL_WRITE = 101
self.DIGITAL_READ = 102
self.ANALOG_WRITE = 103
self.ANALOG_READ = 104
[Link] = 0
[Link] = 1
[Link] = 0
[Link] = 1

def close(self):
[Link]()

def pinMode(self,pin,mode):
[Link](chr(self.PIN_MODE))
[Link](chr(pin))
[Link](chr(mode))

def digitalWrite(self,pin,output):
Frédéric Legrand Licence Creative Commons 5

[Link](chr(self.DIGITAL_WRITE))
[Link](chr(pin))
[Link](chr(output))

def digitalRead(self,pin):
[Link](chr(self.DIGITAL_READ))
[Link](chr(pin))
x = [Link](1)
return ord(x)

def analogWrite(self,pin,output):
[Link](chr(self.ANALOG_WRITE))
[Link](chr(pin))
[Link](chr(output))

def analogRead(self,pin):
[Link](chr(self.ANALOG_READ))
[Link](chr(pin))
c1 = ord([Link](1))
c2 = ord([Link](1))
return c1*0x100+c2

On remarque que la fonction [Link] est bloquante : elle ne retourne que lorsque
le nombre de caractères demandé est présent sur la liaison série. Dans le cas présent, la
réponse de l'arduino est immédiate et ce blocage ne pose pas de problème. Si l'on souhaite
mettre en place un traitement asynchrone (pour des commandes plus longues), il faudra
le faire au moyen de threads. Le traitement asynchrone est nécessaire dans le cas d'un
programme avec interface graphique, pour des commandes dont la durée d'exécution
excède la seconde. Pour un programme en mode console, cela n'est pas nécessaire.
Le constructeur de la classe nécessite le numéro du port série sur lequel se trouve
relié l'Arduino. Celui-ci est facilement accessible dans l'interface de programmation de
l'arduino. Si le port est COM5, il faudra fournir le numéro de port 4.
Voici un exemple d'utilisation. Le chier [Link] doit se trouver dans le même
répertoire que le script.
import time
from commandesPython import Arduino

port = 4
ard = Arduino(port)

[Link](2,[Link])
[Link](3,[Link])
[Link](4,[Link])
for i in range(10):
print([Link](0))
[Link](1)
Frédéric Legrand Licence Creative Commons 6

[Link](5,100) # utiliser une sortie PWM pour cela


for i in range(10):
[Link](2,[Link])
[Link](1)
[Link](2,[Link])
[Link](1)
print([Link](3))
[Link]()

3. Échanges de tableaux entre Arduino et Python

3.a. Programme Arduino

Il peut être nécessaire d'échanger des données sous forme de tableaux d'entiers 8 bits.
On propose ci-dessous un prototype pour eectuer ce type d'échanges, avec un tableau
tampon de 256 octets. Le même principe peut être utilisé pour transmettre des entiers
16 bits : il sura de convertir chaque paire d'entiers de 8 bits en un entier 16 bits.
Le programme suivant répond à deux commandes :
. SEND_BUFFER : envoi d'un tableau contenant les entiers 0,1,2, etc.
. READ_SEND_BUFFER : lecture d'un tableau puis renvoi de ce tableau.
[Link]
#define SEND_BUFFER 100
#define READ_SEND_BUFFER 101
#define N 256
uint8_t buffer[N];

void setup() {
char c;
[Link](500000);
[Link]();
[Link](0);
c = 0;
[Link](c);
c = 255;
[Link](c);
c = 0;
[Link](c);
}

void loop() {
char c1;
int n;
int count;
for (n=0; n<N; n++) buffer[n] = n;
Frédéric Legrand Licence Creative Commons 7

if ([Link]()>0) {
c1 = [Link]();
if (c1==SEND_BUFFER) {
[Link](buffer,N);
}
else if (c1==READ_SEND_BUFFER) {
count = 0;
while (count < N) {
n = [Link](buffer+count, N-count);
count = count + n;
}
[Link](buffer,N);
}
}
}

La fonction [Link](0) permet de rendre la fonction [Link]


non bloquante. Celle-ci est appelée tant que le tableau de 256 éléments n'est pas com-
plètement lu.

3.b. Programme Python

Voici le programme Python :


[Link]
# -*- coding: utf-8 -*-
import serial

class Arduino():
def __init__(self,port):
[Link] = [Link](port,baudrate=500000)
c_recu = [Link](1)
while ord(c_recu)!=0:
c_recu = [Link](1)
c_recu = [Link](1)
while ord(c_recu)!=255:
c_recu = [Link](1)
c_recu = [Link](1)
while ord(c_recu)!=0:
c_recu = [Link](1)
self.SEND_BUFFER = 100
self.READ_SEND_BUFFER = 101
self.N = 256 # taille des tableaux

def close(self):
[Link]()
Frédéric Legrand Licence Creative Commons 8

La fonction suivante eectue n fois l'appel de la commande SEND_BUFFER et calcule


le débit de transfert des données.
def test_debit_lecture(self,n):
t = [Link]()
liste_recus = []
N = self.N
for k in range(n):
[Link](chr(self.SEND_BUFFER))
liste_recus = [Link](N)
t = [Link]()-t
baud = int(n*8*N/t)
print ("%d bits/s"%baud)
print ("%d octets/s"%(int(n*N/t)))
liste = []
for k in range(len(liste_recus)):
[Link](ord(liste_recus[k]))
print(liste)

La fonction suivante eectue n fois l'appel de la commande READ_SEND_BUFFER et


calcule le débit de transfert des données.
def test_debit_ecriture_lecture(self,n):
N = self.N
liste_emis = []
for n in range(N):
liste_emis.append(chr(n))
liste_recus = []
t = [Link]()
for k in range(n):
[Link](chr(self.READ_SEND_BUFFER))
[Link](liste_emis)
liste_recus = [Link](N)
t = [Link]()-t
baud = int(n*8*N*2/t)
print ("%d bits/s"%baud)
print ("%d octets/s"%(int(n*N*2/t)))
liste = []
for k in range(len(liste_recus)):
[Link](ord(liste_recus[k]))
print(liste)

Voici un exemple, pour un Arduino connecté sur le port COM5 :


from transmissionTableaux import Arduino
port = 4
Frédéric Legrand Licence Creative Commons 9

ard = Arduino(port)
ard.test_debit_lecture(1000)
[Link]()

Pour un arduino Duemilanove (ATmega328), le débit obtenu est d'environ 97000 bits
par seconde, soit 12000 octets par seconde. Pour un arduino Mega (ATmega2560), le
débit est d'environ 254000 bits par seconde, soit 32000 octets par seconde.
Pour un Arduino Due (SAM3X8E) , avec le port USB natif, il faut utiliser la fonction
SerialUSB. Le débit obtenu est d'environ 540000 bits par seconde, soit 680000 octets
par seconde.
Lorsque la taille du tampon (ici 256) est réduite, le débit est réduit. Pour échanger
une grande quantité de données avec un débit maximal, il faut donc utiliser un tampon
de manière à échanger les données par bloc. Une taille de tampon de 256 donne de bons
résultats.

Vous aimerez peut-être aussi