ACTIVITÉ ARDUINO/PYTHON : Mesurer une vitesse à l’aide d’un module capteur de vitesse de rotation LM293 type FC-03 ou VMA347 (tracé de graphe en temps réel)

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 A0est 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

Signal D0 OK

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 :

Signal D0 pas OK !

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

Laisser un commentaire