Appuyer sur "Entrer" pour passer
✨ 🎓Workspace - Continuité pédagogique - Lycée Roumanille 🎓 ✨
📢 Pas de reprise en présentiel avant juin.
😷 🦠 La science et la connaissance, excellents atouts contre la COVID-19.

Traitement temps réel de données en Python de données acquises avec Arduino (photorésistance)

Je mets en ligne, quelques réflexions, quelques lignes de code glanées 🤔 et deux programmes (C +🐍) permettant le traitement en temps réel ⌚ de données acquises depuis un capteur lumineux 💡 monté sur Arduino.

Le montage utilisé

Le capteur utilisé est une photorésistance LDR. La résistance de ce composant évolue comme l’inverse de l’éclairement. Cette relation peut être modélisée par la relation suivante :

    \[R(L) = R_0 L ^{-K}\]

LDR – Photorésistance

Avantages :

  • Faible coût
  • Larges gammes spectrales
  • Facilité de mise en œuvre
  • Rapport de transfert statique
  • Sensibilité élevée

Inconvénients :

  • Non linéarité de la réponse en fonction du flux
  • La vitesse de variation de R avec l’éclairement est faible et non symétrique
  • Sensibilité thermique
  • Refroidissement nécessaire dans certains cas (capteurs thermiques)
  • Temps de réponse élevé (0,1 us à 100 ms)
  • Bande passante limitée
  • Instabilité dans le temps (vieillissement dû aux échauffements)

La photorésistance n’a pas une réponse linéaire en fonction de la longueur d’onde du rayonnement incident. Cela veut dire que sa résistance pour un même éclairement varie pour deux “couleurs” différentes.

Evolution relative de la résistance en fonction de la longueur d’onde du rayonnement incident

La résistance n’évolue malheureusement pas non plus linéairement avec l’éclairement comme le montre le schéma ci-dessous.

Evolution de la résistance en fonction de l’éclairement

Montage de l’arduino

Matériel :

  • Un Arduino
  • Une photorésistance ayant une résistance dans l’obscurité de 1 MΩ
  • Une résistance de 10 kΩ
Schéma électronique du montage à réaliser

Il s’agit d’un pont diviseur de tension classique dont on prend la tension en A0. L’écriture de la loi d’Ohm à R1 et R2 donne :

    \[U = R \times I \implies I = \frac{U}{R}\]

    \[5 - A0 = R1 \times I \implies I = \frac{5 - A0}{R1}\]

    \[A0 - 0 = R2 \times I \implies I = \frac{A0}{R2}\]

    \[\implies \frac{5 - A0}{R1} = \frac{A0}{R2}\]

 

    \[\implies \frac{5 }{R1} = A0 \left( \frac{R1 + R2}{R1 \times R2} \right) \]

(1)   \begin{equation*}\implies  \large\boxed{A0 = \frac{R2}{R1+R2}\times 5}\end{equation*}

L’Arduino mesure la tension en A0, connaissant la résistance R2 (10 kΩ), on peut obtenir une information sur R1 qui dépend de l’éclairement. 

  • Plus l’éclairement augmente, plus la résistance R1 de la photorésistance diminue et donc plus A0 se rapproche de 5V et réciproquement si l’éclairement diminue.
  • On remarque que l’on peut faire évoluer la sensibilité du montage en changeant la valeur de la résistance R2.

Programme de l’Arduino

Le programme est plutôt simple :

  • Arduino démarre une connexion série
  • Il envoie un signal de départ START pour prévenir Python qu’il démarre le travail
  • Il mesure NBR_MESURE fois la tension A0
  • Il fait la moyenne et l’envoie sur le port série
  • Il réitère cette opération NBR_ACQUISITION fois
  • Il envoie un signal de fin END pour prévenir Python que c’est terminé
// -----------------------------------------------------------
// FICHIER   : photoresistance.py
// NOM       : Récupération d'une tension d'une photorésistance
// AUTEUR    : Rémi MEVAERE
// DATE      : 20/09/2019
// DESC      : - Lecture de la tension sur ANALOG_PIN A0
//             - +5V --- PHOTORESISTANCE --- A0 --- R10 kOhm --- o GND
//             - NBR_ACQUISITION Series de NBR_MESURE acquisitions
//             - Envoi sur le port série pour traitement Python
// LICENCE   : Creative Commons CC0
// -----------------------------------------------------------

// Declaration des constantes du programme
int NBR_ACQUISITION = 100;
// Nombre de mesure par acquisition
int NBR_MESURE = 5;
// On mesure la tension sur la broche A0
int ANALOG_PIN = A0;
int DELAIS_START = 100;
int DELAIS_SERIE = 50;

void setup() {
  // Fixe le débit de communication en bits par secondes
  Serial.begin(9600);
}

void loop() {

  // Attendre DELAIS_START ms 
  delay(DELAIS_START);
  // Envoyer le signal de départ au programme PYTHON
  Serial.println("START");

  // Pour NBR_ACQUISITION on execute le bloc suivant
  for(int compteur = 0 ; compteur < NBR_ACQUISITION ; compteur++)
  {
    int  somme = 0;

    // On mesure NBR_MESURE fois et on moyenne
    for(int donnees = 0 ; donnees < NBR_MESURE ; donnees++)
    {
        int valeur = analogRead(ANALOG_PIN);
        somme = somme + valeur;
        delay(DELAIS_SERIE);
    }
    int  moyenne = somme / NBR_MESURE;

    // On envoie le message sour la forme (N°ACQUISITION + ESPACE + MOYENNE)
    EnvoiDonnees(compteur, moyenne);
  }

  // Fin de l'expérience, on l'indique au programme PYTHON
  Serial.println("END");
}

// Procedure pour envoyer les données
void EnvoiDonnees(int compteur, int moyenne)
{
  Serial.print(compteur);
  Serial.print(" ");
  Serial.println(moyenne);
}

Programme commenté Python pour le suivi des données

Le programme ci-dessous est plus compliqué mais il est commenté. L’idée générale de celui-ci est plutôt élémentaire :

  • On démarre une connexion avec l’Arduino en utilise le package PySerial
  • On fait un reset de l’Arduino en utilisant TDR
  • On attend le signal START
  • On reçoit et on traite les données
  • Au signal END c’est terminé !
# -----------------------------------------------------------
# FICHIER   : Traceur.py
# NOM       : Récupération des données d'un arduino par port Serie
#               et traçage du graphique en temps réel
# AUTEUR    : Rémi MEVAERE
# DATE      : 13/05/2020
# DESC      : - On récupérer les donnés avec le paquet Serial
#             - On trace avec Matplotlib
# LICENCE   : Creative Commons CC0
# -----------------------------------------------------------

# Chargement des paquets, modules
import serial
import time
import sys
import matplotlib.pyplot as plt
import matplotlib.animation as animation

# Déclaration des constantes du programme
PORT = 'COM4'  # Port pour communiquer avec l'Arduino
DEBIT = 9600  # Doit-être identique à ce qui a été décidé dans le programme de l'Arduino
DELAY = 250  # Délais entre deux images pour l'animation
ATTENTE_MAX = 5000  # Attente maximum en centaine de ms
NBR_POINTS = 100  # Nombre d'acquisitions attendues (nombre d'image pour l'animation)

# Ouvrir le port de communication avec l'arduino
try:
    print("Ouverture : " + PORT)
    serial_port = serial.Serial(PORT, DEBIT, timeout=1000)
except Exception as ex:
    print("Impossible d'ouvrir le port : " + PORT)
    sys.exit(1)

# Utilisation de la broche contrôle de flux DTR (Data Terminal Ready) pour faire un reset de l'arduino
try:
    print("Redémarrage de l'Arduino pour synchronisation")
    serial_port.setDTR(False)
    time.sleep(2)
    serial_port.setDTR(True)
    serial_port.flushInput()
except Exception as ex:
    print("Impossible de redémarrer l'Arduino")
    sys.exit(2)

# On attend le signal de départ (START) de l'arduino
RECEPTION = False
try:
    serial_port.flushInput()
    print("En attente du signal de départ")
    for i in range(ATTENTE_MAX):
        time.sleep(0.100)
        val = serial_port.readline().split()
        if len(val) > 0:
            # Conversion bytes en string
            DECODE = val[0].decode("utf-8")
            if DECODE == "START":
                RECEPTION = True
                break
except:
    print("Le signal de départ n'a pas été récupéré")
    sys.exit(3)

# Si le signal de départ a été reçu alors on reçoit les données
if RECEPTION:
    print("Récupération des données")
    # Création d'un graphique
    fig, ax1 = plt.subplots()
    plt.axis([0, NBR_POINTS, 0, 5])
    # Deux listes
    mesure = []
    temps = []

    # Préparation du graphique
    ax1.title.set_text('Tension aux bornes de la résistance')
    ax1.set_xlabel("N° de l'acquisition")
    ax1.set_ylabel("Tension moyenne en V")
    points = ax1.plot(temps, mesure)

    # Fonction appelée pour l'animation
    def animate(i):
        try:
        # Lecture du port série, on place les données dans une liste
           val = serial_port.readline().split()
        except:
            print("Erreur de lecture")
            sys.exit(4)

        if len(val) > 0:
            # On veut savoir si c'est la fin de la transmission
            DECODE = val[0].decode("utf-8")
            if DECODE == "END":
                print("Fin de transmission")
                # On ferme le port
                try:
                    serial_port.close()
                except:
                    pass
                ani.event_source.stop()
            else:
                try:
                    # Sinon c'est une donnée
                    t = int(val[0])
                    m = float(val[1]) * 5 / float(1023)
                    # On ajoute tout cela aux deux listes
                    temps.append(t)
                    mesure.append(m)
                except:
                    pass
        points[0].set_data(temps, mesure)

    # Fonction d'animation intégré à Matplotlib
    ani = animation.FuncAnimation(fig, animate, frames=NBR_POINTS, interval=DELAY, repeat=False)
    fig.suptitle("Capteur : Photorésistance", fontsize=16)
    plt.show()
else:
    print("Le signal de départ n'a pas été récupéré")
    sys.exit(3)

Ce programme permet d’afficher et de tracer la courbe d’évolution de la tension aux bornes de la résistance.