Je mets en ligne, quelques réflexions, quelques lignes de code glanées 🤔 et deux programmes (C + Python) permettant le traitement en temps réel ⌚ de données acquises depuis un capteur lumineux 💡 monté sur Arduino.
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 :
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.
La résistance n’évolue malheureusement pas non plus linéairement avec l’éclairement comme le montre le schéma ci-dessous.
Montage de l’arduino
- Un Arduino
- Une photorésistance ayant une résistance dans l’obscurité de 1 MΩ
- Une résistance de 10 kΩ
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 :
L’Arduino mesure la tension en , connaissant la résistance (10 kΩ), on peut obtenir une information sur qui dépend de l’éclairement.
- Plus l’éclairement augmente, plus la résistance de la photorésistance diminue et donc plus 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 .
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.C
// NOM : Récupération d'une tension aux bornes d'une photorésistance
// AUTEUR : Rémi MEVAERE
// DATE : 20/09/2019
// DESC : - Lecture de la tension sur ANALOG_PIN A0
// - +5V o --- o PHOTORESISTANCE o --- A0 --- o 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ées avec la bibliothèque 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.