Outils pour utilisateurs

Outils du site


publish:hide:inforep:1819:python-arduino

Python et Arduino

Python est un langage interprété. Il fonctionnera donc sur n'importe quelle plate-forme qui dispose d'un interpréteur. Un interpréteur est un programme relativement complexe qui ne peut pas fonctionner avec de trop faibles ressources. C'est la raison pour laquelle on ne peut pas faire fonctionner Python sur du matériel qui possède trop peu de ressources.

Les interpréteurs Python les moins gourmands sont MicroPython et CircuitPython, qui sont des interpréteurs écrits pour des microcontrôleurs. Toutefois, les microcontrôleurs disposant de trop peu de ressources ne permettront pas de les faire fonctionner.

Actuellement, ni MicroPython, ni CircruitPython ne peuvent fonctionner sur un Arduino Uno. En revanche, MicroPython pourra fonctionner sur un Arduino Due, certains ESP, un micro:bit… CircuitPython est supporté par les cartes Adafruit (il est dérivé de MicroPython).

Ce document traite de l'utilisation de Python avec un arduino Uno, c'est à dire du moyen de faire communiquer un programme Python, qui tourne sur un ordinateur de bureau, avec un programme qui tourne sur un Arduino Uno (donc écrit en ≈ C).

Communication

La communication entre l'ordinateur de bureau et l'Arduino sera réalisée par le port série. L'Arduino possède une liaison série (broches RX, TX), et est capable d'émuler d'autres liaisons séries de manière logicielle sur d'autres broches (avec la bibliothèque SoftwareSerial).

Côté Python, on utilise généralement le module pySerial pour utiliser une liaison série.

L'idée générale est la suivante :

  • Le programme Arduino scrute la liaison série, et exécute les commandes qu'on lui envoie via cette liaison série selon un protocole qu'on aura défini.
  • Le programme Python fait son travail, et lorsqu'il veut agir sur l'Arduino, lui envoie une commande via la liaison série.

Pour utiliser Python et Arduino, il faut donc développer 2 programmes :

  • celui écrit en Python qui tourne sur le PC de bureau
  • celui écrit en ≈ C qui tourne sur l'Arduino

Programmes Arduino Custom

Outils

Module Python utilisé dans la suite :

outils_arduino.py
"""
Utilitaires pour l'utilisation d'une carte Arduino avec Python
"""
 
import time
import serial.tools.list_ports
 
 
def get_serial_ports():
    """ Renvoie la liste des ports série sur lesquels
        il semble qu'une Arte Arduino soit branchée
    """
    ports = list(serial.tools.list_ports.comports())
    arduino_ports = []
    for port_no, description, address in ports:
        # print(port_no, description, address)
        if 'Arduino' in description:
            arduino_ports.append(port_no)
    return arduino_ports
 
def restart(ser):
    """ Redémarre le programme de l'Arduino connecté
        par la liaison série ser
    """
    ser.setDTR(False)
    time.sleep(0.1)
    ser.setDTR(True)

L'arduino envoie des valeurs lues par le programme Python

Programme pour l'Arduino :

send_compteur.ino
int compteur;
 
void setup () {
  Serial.begin(9600);
  pinMode(13, OUTPUT);
  compteur = 0;
}
 
void loop () {
Serial.println(compteur);
compteur += 1;
digitalWrite(13, HIGH);
delay (200);
digitalWrite(13, LOW);
delay(1800);
}

Programme pour le PC :

read_values.py
import serial
import outils_arduino
 
ports = outils_arduino.get_serial_ports()
print(ports)
port = ports[0]
serial_port = serial.Serial(port=port, baudrate=9600)
 
for i in range(10):
    data = serial_port.readline()
    idata = int(data.strip())
    print("Read : ", data)
    print("iRead : ", idata)
 
serial_port.close()

Le PC pilote une LED RGB

Établit un protocole de communication assez rudimentaire : commande 'L' suivie de 3 octets pour l'intensité de rouge, de vert et de bleu.

Programme pour l'Arduino :

pilote_rgb_led.ino
const int redPin   = 3;        
const int greenPin = 5;
const int bluePin  = 6;
 
int R, G, B;  
int error = 0;
 
void setup()
{
  // Par défaut, donc facultatif...
  pinMode(redPin, OUTPUT);
  pinMode(greenPin, OUTPUT);
  pinMode(bluePin, OUTPUT);
  pinMode(13, OUTPUT);
  R = 0;
  G = 255;
  B = 0;
  Serial.begin(9600);
  analogWrite(redPin, 255-R);
  analogWrite(greenPin, 255-G);
  analogWrite(bluePin, 255-B );
 
}
 
void loop()
{
  char commande;
 
  if (Serial.available()) {
    commande = Serial.read();
    if (commande == 'L') {
      R = Serial.read();
      G = Serial.read();
      B = Serial.read();
      analogWrite(redPin, 255-R);
      analogWrite(greenPin, 255-G);
      analogWrite(bluePin, 255-B );
      error = 0;
    }
    else {
      error = 1;
    }
  }
 
  if (error) digitalWrite(13, HIGH);
  else digitalWrite(13, LOW);
 
  delay(100);
}

Programme pour le PC :

send_commandes.py
import serial
import outils_arduino
import time
 
def pilote_led(ser, r, g, b):
    n = ser.write(b'L' + bytes([r, g, b]))
 
ports = outils_arduino.get_serial_ports()
print(ports)
port = ports[0]
serial_port = serial.Serial(port=port, baudrate=9600)
 
time.sleep(3)
print("Go")
r, g, b = 255, 0, 0
 
for _ in range(200):
    pilote_led(serial_port, r, g, b)
    r, g, b = g, b, r
    time.sleep(1)
 
serial_port.close()

Programmes Arduino prévus pour le pilotage

Plutôt que de développer un programme Arduino spécifique pour chaque application, il existe des programmes génériques qui permettent d'activer les diverses fonctionnalités de l'Arduino.

Certains sont listés sur cette page Arduino and Python

Une des solutions les plus standard semble être l'utilisation du protocole Firmata. On le trouve sous forme d'une bibliothèque Arduino (Firmata, by Firmata, v 2.5.8). Une fois la bibliothèque installée, on dispose de plusieurs exemples (menu Fichier/Exemples/Firmata), dont : StandardFirmata. On peut par exemple installer ce croquis sur l'Arduino.

Coté PC, il existe plusieurs modules Python qui implémentent le module Firmata. J'ai testé pyFirmata (il y a une liste d'alternatives ici : firmata-client-libraries) :

test_firmata.py
from pyfirmata import Arduino, util
board = Arduino('/dev/ttyACM0')
import time
 
r, g, b = 0, 1, 1
pin3 = board.get_pin("d:3:p")
pin5 = board.get_pin("d:5:p")
pin6 = board.get_pin("d:6:p")
for i in range(10):
    pin3.write(r)
    pin5.write(g)
    pin6.write(b)
    r, g, b = g, b, r
    time.sleep(1)

Firmata et capteur de distance ultra-son (HC-SR04)

Ce type de capteur n'est pas supporté par le programme StandardFirmata. Il existe par contre de nombreuses variantes patchées. Nous testons ici FirmataExpress  + Ultrasonic (le premier utilise le second).

Le firmware `FirmataExpress` est téléversé sur un arduino Nano.

Côté PC Python, l'auteur de FirmataExpress MrYsLab (github) propose PyMata, et une version plus récente (python 3.7+) utilisant la programmation asynchrone (pymata-express).

Le test a été réalisé avec Pymata

sensor_dist_led.py
import time
import sys
import signal
 
from PyMata.pymata import PyMata
 
def signal_handler(sig, frame):
    print('You pressed Ctrl+C')
    if board is not None:
        board.reset()
        board.close()
    sys.exit(0)
 
 
def loupiote(board, distance):
    mini = 3
    maxi = 20
    if distance > maxi:
        distance = maxi
    if distance < mini:
        distance = mini
    frac = (distance - mini) / (maxi - mini)
    board.analog_write(3, 255)
    board.analog_write(5, int(255 * (1- frac)))
    board.analog_write(6, int(255 * frac))
 
 
board = PyMata("/dev/ttyUSB0", verbose=True, baud_rate=115200)
signal.signal(signal.SIGINT, signal_handler)
 
board.sonar_config(12, 12)
board.set_pin_mode(3, PyMata.PWM, PyMata.DIGITAL)
board.set_pin_mode(5, PyMata.PWM, PyMata.DIGITAL)
board.set_pin_mode(6, PyMata.PWM, PyMata.DIGITAL)
 
time.sleep(1)
 
while True:
    data = board.get_sonar_data()
    distance = data[12][1]
    print(distance)
    loupiote(board, distance)
    time.sleep(.2)

Références

publish/hide/inforep/1819/python-arduino.txt · Dernière modification: 2019/04/30 07:48 (modification externe)