Objectifs et enjeux
Mesurer une vitesse avec un capteur de vitesse de rotation avec fourche optique et roue codeuse type FC-03 ou LM393
Capteur de vitesse
Le capteur de vitesse utilisé ici est le FC-03, module avec circuit intégré LM293. Le principe de mesure de vitesse repose sur un capteur optique à fourche qui va détecter un signal. Ce signal sera régulièrement « coupé » par une roue perforée en rotation. Il sera alors possible de remonter à la vitesse de rotation de la roue en mesurant le nombre d’interruptions par secondes et en tenant compte du nombre de trous de la roue codeuse.
Dispositif expérimental pour l’acquisition
La roue codeuse est fixée sur l’axe d’un moteur à courant continu qui est contrôlé par une alimentation stabilisée dont on peut faire varier la tension.
Branchement sur la carte Arduino
Il existe deux branchements possibles : on peut détecter le signal avec la broche D0 ou la broche A0. Voici ci dessous le schéma de branchement pour ces deux possibilités :
Téléversement du programme Arduino
Voici les deux programmes Arduino à téléverser pour chacune de ces deux possibilités
Code avec le branchement sur A0
int sensor = A0; // broche pour détection du capteur
int etatSensor ; // état du capteur (haut ou bas)
unsigned long start_time=0; //temps de début d'un comptage
unsigned long end_time =0; //temps de fin d'un comptage
int nb_trous =20 ; // nombre de trous de la roue codeuse
bool etat_old= false ; //
bool etat_new = false; // les états vont changer à chaque chaque modiication de la valeu lue par le capteur (haut/5V ou bas/0V)
int compt=0; // comptage initialisé à 0
float rps=0; // vitesse intialisée à 0
long temps; //mesure du temps pour l'acquisition
void setup()
{
pinMode(sensor,INPUT); // la broche A0 est déclarée comme entrée
Serial.begin(9600); // pour le moniteur série
temps = millis(); // mesure du temps
}
void loop()
{
compt = 0;
start_time=millis(); //on mesure le temps
end_time=start_time+1000; // pour un comptage toutes les secondes
temps = millis(); //mesure du temps pour l'acquisition
while(millis()<end_time){ // comptage sur une seconde
if (analogRead(sensor)< 50){
etat_new = true;
}
else {
etat_new =false;
}
if (etat_old != etat_new) {
etat_old = etat_new;
compt = compt + 1;
}
}
rps = float(compt)/(2*nb_trous) ; // il faut diviser par 2 car pour chaque trou , deux changements d'état vont être détectés
Serial.print("temps ");
Serial.print(temps);
Serial.print(" rps ");
Serial.println(rps);
}
Code avec le branchement sur D0
int sensor = 3; // broche pour détection du capteur
int etatSensor ; // état du capteur (haut ou bas)
unsigned long start_time=0; //temps de début d'un comptage
unsigned long end_time =0; //temps de fin d'un comptage
int nb_trous =20 ; // nombre de trous de la roue codeuse
int etat_old= 1 ; //
int etat_new = 1; // les états vont changer à chaque chaque modiication de la valeu lue par le capteur (haut/5V ou bas/0V)
int compt=0; // comptage initialisé à 0
float rps=0; // vitesse intialisée à 0
long temps; //mesure du temps pour l'acquisition
void setup()
{
pinMode(sensor,INPUT); // la broche 3 est déclarée comme entrée
Serial.begin(9600); // pour le moniteur série
temps = millis(); // mesure du temps
}
void loop()
{
compt = 0;
start_time=millis(); //on mesure le temps
end_time=start_time+1000; // pour un comptage toutes les secondes
temps = millis(); //mesure du temps pour l'acquisition
while(millis()<end_time){ // comptage sur une seconde
etat_new = digitalRead(sensor);
if (etat_old != etat_new) { // petite boucle pour incrémenter le compteur à chaque changement d'état lu par le capteur
etat_old = etat_new;
compt = compt+1;
}
}
rps = float(compt)/(2*nb_trous) ; // il faut diviser par 2 car pour chaque trou , deux changements d'état vont être détectés
Serial.print("temps ");
Serial.print(temps);
Serial.print(" rps ");
Serial.println(rps);
}
Mais quel branchement choisir ???
Et ben … ça dépend !!!
On pourrait privilégier l’utilisation de la sortie numérique D0 pour des mesures plus précises mais cela ne fonctionnera plus pour des vitesses trop élevées. Pour les mesures élevées, il faudrait choisir la méthode avec la sortie analogique A0.
Explications ci-dessous …
Explication du code Arduino et choix de la sortie du capteur de vitesse
La sortie numérique D0 va renvoyer la valeur True (5V) lorqu’un signal est détecté et la valeur False quand le signal sera occulté par la roue.
Voici le signal observé à l’oscilloscope
Le code Arduino va compter chaque passage d’une valeur à une autre , donc le comptage se fera deux fois pour un trou. (voir animation ci contre)
C’est pour cela qu’on demande au code de calculer le nombre de tours par secondes ainsi :
Nombre de comptages pour 1s /nombre de trous … divisé par deux !
Cette méthode est assez précise mais montre ses limites à vitesse élevée car le capteur n’arrive plus à suivre … ce problème est sans doute lié au temps de réponse du capteur :
Il faudrait donc privilégier la mesure avec la sortie analogique A0, qui est certes beaucoup moins propre … mais pour laquelle nous pouvons observer un signal même à vitesse élevée.
Nous voyons bien à l’oscilloscope que, bien qu’il y ait un certain temps de réponse du capteur, il est quand même possible de récupérer la vitesse de la roue :
L’idée est alors de « ruser » dans le code avec A0 en définissant un seuil pour lequel on bascule d’un état à un autre
Ce comtage est illustré par cette animation, le comptage se fera à chaque passage du seuil , donc toujours deux fois pour un trou !
Donc, on demande encore au code de calculer le nombre de tours par secondes ainsi :
Nombre de comptages pour 1s /nombre de trous … divisé par deux !
Donc pour résumer …
- Utiliser le branchement avec D0 et le code Arduino associé pour les mesures de faible vitesse
- Utiliser le branchement avec A0 et le code Arduino associé pour les mesures élevées de vitesse
Récupération des données avec Python
Une fois ce code Arduino téléversé, nous pouvons récupérer les valeurs avec Python (par le biais d’un IDE comme Pyzo, Spyder, IDLE, Sublime Text,..). Il est alors possible de tracer un graphe en temps réel, traiter les données, modéliser les courbes etc…
Dans cet article , je ne rentrerai pas dans les détails pour les étapes de récupération de données. Pour cela, je vous invite à consulter l’article qui explique ces différentes étapes sur ce lien :
Récupération des données d’une carte Arduino avec Python
Voici le script Python à exécuter :
#importation des modules
import serial
import serial.tools.list_ports # pour la communication avec le port série
import matplotlib.pyplot as plt # pour le tracé de graphe
from matplotlib import animation # pour la figure animée
import time # gestion du temps
#initialisation des listes
liste_temps=[] # liste pour stocker les valeurs de temps en partant de t=0
liste_rps = [] # liste pour stocker les valeurs de vitesse
t_acquisition = 10.0
rpsmax= 150 # en mm
#pour le graphe en temps réel
def animate(i):
line1 = Data.readline()
print (line1)
# on retire les caractères d'espacement en début et fin de chaîne
listeDonnees = line1.strip()
# on sépare les informations reçues séparées par les espaces et on stocke ces informations dans une liste pour chacune de lignes
listeDonnees = line1.split()
print (listeDonnees)
if len(listeDonnees)!= 0 : # parfois des lignes de données vides peuvent être envoyées, il faut les "écarter"
rps = float(listeDonnees[3].decode()) # après consulation des données, nous choisissons le 4ème élément de listeDonnees
temps = (float(listeDonnees[1].decode()))/1000.0 # après consulation des données, nous choisissons le 2ème élément de listeDonnees
while temps <= t_acquisition:
liste_rps.append(rps)
print("rps = %f"%(rps)) # affichage de la valeur de la vitesse
liste_temps.append(temps)
print("temps mesuré = %f"%(temps), " s") # affichage de la valeur du temps absolu
line.set_data(liste_temps,liste_rps)
return line,
# Fonction pour la récupération des données série venant de la carte Arduino
def recup_port_Arduino() :
ports = list(serial.tools.list_ports.comports())
for p in ports:
if 'Arduino' in p.description :
mData = serial.Serial(p.device,9600)
print(mData.is_open) # Affiche et vérifie que le port est ouvert
print(mData.name) # Affiche le nom du port
return mData
Data =recup_port_Arduino() #récupération des données
# Création figure
fig=plt.figure()
line, = plt.plot([],[])
plt.xlim(0, t_acquisition)
plt.ylim(0,rpsmax)
plt.xlabel('temps en s')
plt.ylabel('rps')
plt.grid()
#Animation
ani = animation.FuncAnimation(fig, animate, frames=200, interval=20,repeat=False)
plt.show()
plt.close(fig)
Data.close() # pour arrêter la lecture des données série
plt.title('rps=f(t)') # titre du graphique
plt.scatter(liste_temps,liste_rps, color ='r', marker = 'o') # On affiche les points de coordonnées (t,rps) avec des points rouges
plt.xlabel('temps en s')
plt.ylabel('rps')
plt.xlim (min(liste_temps),max(liste_temps)) #limtes pour les axes avec les valeurs extrêmes de t et de rps
plt.ylim(min(liste_rps),max(liste_rps))
plt.show() #afficher le graphique (ne rien mettre dans la parenthèse)
#Ecriture dans un fichier txt
lines=['t\trps\n'] #première ligne du fichier txt
for i in range (len (liste_rps)):
line = str(liste_temps[i]) +'\t'+ str(liste_rps[i])+'\n'
lines.append(line)
fichier = open('data_arduino.txt', 'w')
fichier.writelines(lines) #création d'un nouveau fichier texte, penser à spécifier le chemin d'accés
Lien Github des scripts Python et Arduino :
https://github.com/jonasforlot/python-arduino/tree/main/Donnees%20serie%20mesure%20vitesse