IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Arduino Discussion :

Communication port série lente HC-SR04


Sujet :

Arduino

  1. #1
    Nouveau Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    mars 2020
    Messages
    8
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Somme (Picardie)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : mars 2020
    Messages : 8
    Points : 1
    Points
    1
    Par défaut Communication port série lente HC-SR04
    bonjour,

    Je réalise actuellement un projet et j'ai un petit problème avec la vitesse de communication de mon capteur HC-SR04. Le capteur prend des mesures toutes les ms (en théorie) et les envoie sur le port série, je récupère ensuite ces valeurs sur python sauf que en 1 seconde je n'ai que 1000 valeurs environ au lieu des ~10 000 théoriques. Mon code arduino :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    const byte TRIGGER_PIN = 12; 
    const byte ECHO_PIN = 13;    
    const float SOUND_SPEED = 340.29 / 1000;
     
    void setup() {
      Serial.begin(115200);
      pinMode(TRIGGER_PIN, OUTPUT);
      digitalWrite(TRIGGER_PIN, LOW); 
      pinMode(ECHO_PIN, INPUT);
    }
     
    void loop() {
      digitalWrite(TRIGGER_PIN, HIGH);
      delayMicroseconds(10);
      digitalWrite(TRIGGER_PIN, LOW);
      long measure = pulseIn(ECHO_PIN, HIGH);
      float distance_mm = measure / 2.0 * SOUND_SPEED;
      Serial.println(distance_mm);
      delay(10);
    }
    J'ai vraiment besoin que la fréquence de réception des mesures soit celle d'arduino pour des soucis de filtrage après..
    Merci !

  2. #2
    Membre émérite

    Homme Profil pro
    mad scientist :)
    Inscrit en
    septembre 2019
    Messages
    1 566
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : septembre 2019
    Messages : 1 566
    Points : 2 818
    Points
    2 818
    Par défaut
    Citation Envoyé par SosoManess Voir le message
    Le capteur prend des mesures toutes les ms (en théorie) et les envoie sur le port série, je récupère ensuite ces valeurs sur python sauf que en 1 seconde je n'ai que 1000 valeurs environ au lieu des ~10 000 théoriques,
    vous avez à la fin de votre loop() la commande donc vous demandez une distance toute les 10ms ==> 100 fois par seconde.
    donc je ne vois pas trop pourquoi vous en recevez 1000 par seconde ou en espérez 10,000

    pour en avoir 1000 par seconde, il faudrait une lecture toutes les millisecondes
    pour en avoir 10,000 par seconde, il faudrait une lecture toutes les 100 microsecondes...

    Mais votre communication série ne se fait qu'à 115200 bauds. ça veut dire environ 11520 caractères par seconde. Vous pensez afficher la distance en mm suivie de CR/LF puisque vous faites un println(), sous forme d'un float avec 2 chiffre après la virgule. pour un distance moyenne de l'ordre du mètre ça fait 9 caractères par affichage, donc à 115200 bauds vous ne pourrez pas envoyer plus de 1 280 lectures... et comme il faut un peu de temps pour les calculs ce sera sans doute moins que cela.

    --> si vous parlez à un PC de l'autre côté, mettez le débit à 500,000 ou 1 million de bauds ça sera toujours mieux si vraiment vous avez bcp de données à envoyer (si le buffer d'émission est plein et que vous appelez print, la fonction devient bloquante en attendant que le buffer ait de la place)

    il faut aussi regarder votre formule.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    float distance_mm = measure / 2.0 * SOUND_SPEED;
    vérifiez la priorité des opérateurs (il serait sans doute bon de prendre l'habitude de mettre des parenthèses si vous ne savez pas)

    Enfin quand vous envoyez vos ultra-sons une partie revient au capteur et c'est ce que vous mesurez mais les autres vont continuer à rebondir sur les murs (faire de l'echo) et si vous re-balancez un train d'onde tout va finir pas se mélanger... ==> On recommande généralement d'attendre environ 60ms avant de lancer une nouvelle lecture de distance, le temps que les ondes précédentes et l'echo se soient atténués

    donc en pratique vous pourrez faire environ 16 lecture par seconde avec ce composant.

    -----

    il existe d'autres composants, comme le VL53L0X de ST Microelectronics, c'est un module laser dit de "temps de vol" (Time of Flight) qui utilise un petit laser VCSEL (Vertical Cavity Surface Emitting Laser) à 940 nm et qui fonctionne jusqu'à 2m max. il a un grand frère, le VL53L1X permet de mesurer de 40mm à 4m. il existe aussi le VL6180 si vous travaillez avec des distances de l'ordre de 10/15 cm

    On lit les données en I2C qui devrait permettre d'échantillonner sans trop de souci toutes les 20ms voire en travaillant la spec et en utilisant le mode continu peut-être descendre vers 8ms entre 2 échantillons.

    enfin en mettant plus de budget (plus de 150€) il existe le "LIDAR-Lite v3HP" qui mesure de 1m à 40m et est capable d'échantillonner à 1KHz. (il y a aussi le "TF03 Long-Distance LiDAR" qui mesure de 10cm à 180m (lire la notice) mais qui ne fait que 100Hz)

    certains de ces modules ont une version directement avec une interface série donc si votre arduino ne fait rien d'autre que copier la distance pour l'envoyer sur le port série, avec ce genre de module vous n'auriez plus besoin de l'arduino

  3. #3
    Nouveau Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    mars 2020
    Messages
    8
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Somme (Picardie)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : mars 2020
    Messages : 8
    Points : 1
    Points
    1
    Par défaut
    Merci beaucoup pour votre réponse détaillée. En effet grosse bourde !!! Je ne sais pas où j'avais la tête pour écrire une telle ânerie...
    En réalité j'avais fixé la fréquence d’échantillonnage à 1ms mais je ne récupère que 500-600 mesures par seconde ( toujours à 115200 baud ) or vous me dites que ce baudrate permet l'envoi de 1260 lectures par seconde donc je ne comprends pas pourquoi je n'en récupère que la moitié, et ce, même avec le VL53L0X.
    Maintenant que vous le mentionnez, je possède aussi un VL53L0X ainsi qu'un Sharp GP2Y0A02YK. Le but de mon projet étant de mesurer différentes hauteurs d'eau à l'aide de ces 3 capteurs. Pour le VL53 je peux descendre jusque 20ms mais concernant le sharp vous auriez une idée aussi ?
    Merci d'avance

  4. #4
    Membre émérite

    Homme Profil pro
    mad scientist :)
    Inscrit en
    septembre 2019
    Messages
    1 566
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : septembre 2019
    Messages : 1 566
    Points : 2 818
    Points
    2 818
    Par défaut
    En réalité j'avais fixé la fréquence d’échantillonnage à 1ms mais je ne récupère que 500-600 mesures par seconde ( toujours à 115200 baud )
    je ne sais pas comment vous fixez à 1ms, ce n’est généralement pas possible avec un capteur HC-SR04 en faisant des mesures justes à cause de l’écho

    Votre port série s’il tourne à fond peut envoyer 11520 caractères en 1s. Si une mesure s’écrit sur 10 caractères ça fait 1152 mesures envoyables par seconde, mais pour cela il faudrait réussir à lire les distances aussi à cette vitesse...

    Du temps est aussi perdu dans les calculs, la mesure etc....

    Passez à 500,000 bauds pour que ce débit ne soit plus un facteur bloquant dans votre programme

    Pour votre Sharp GP2Y0A02YK, il suffit de lire la doc technique. Vous verrez page 4, figure 1 que il faut 38.3ms±9.6ms pour la lecture, puis attendre 5ms pour que la sortie soit stabilisée avant de lire donc on est à 43.3ms±9.6ms par lecture, disons donc 50ms ça vous donne aussi du 20Hz Max


    Sinon l’eau a une inertie, dans quelles conditions êtes vous pour penser avoir une grosse variation de niveau en un millième de seconde ?? C’est peu probable dans la nature...

  5. #5
    Nouveau Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    mars 2020
    Messages
    8
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Somme (Picardie)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : mars 2020
    Messages : 8
    Points : 1
    Points
    1
    Par défaut
    Je ne pensais pas qu'on trouvait ce genre d'information dans la doc, c'est bon à savoir. Pour le 1ms, je l'ai fixé pour avoir au moins deux décades de différence avec la fréquence d'oscillation de l'eau afin de filtrer efficacement les mesures mais au vu de ce que vous me dites je n'aurai pas ce luxe, je vais donc devoir augmenter l'ordre de mon filtre..
    Merci encore, vous m'avez bien débloqué ^^

  6. #6
    Nouveau Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    mars 2020
    Messages
    8
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Somme (Picardie)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : mars 2020
    Messages : 8
    Points : 1
    Points
    1
    Par défaut
    Bon, j'ai fixé le baudrate a 500 000, la fréquence d'échantillonnage à 50Hz ( soit tous les 20ms ) et pourtant je n'arrive qu'à avoir 80 valeurs en 5 secondes.. soit à peine 16Hz. Je précise que je récupère les mesures du port série depuis python ( où j'ai aussi fixé le baudrate à 500k ). Une idée d'où pourrait venir le problème ?

  7. #7
    Membre émérite

    Homme Profil pro
    mad scientist :)
    Inscrit en
    septembre 2019
    Messages
    1 566
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : septembre 2019
    Messages : 1 566
    Points : 2 818
    Points
    2 818
    Par défaut
    Postez votre code

  8. #8
    Nouveau Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    mars 2020
    Messages
    8
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Somme (Picardie)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : mars 2020
    Messages : 8
    Points : 1
    Points
    1
    Par défaut
    Voilà ma fonction et l'initialisation du port série :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
     
    port_serie = sr.Serial(port = "COM4", baudrate = "500000")
     
    def prise_mesure2(tps,fichier_txt):
        data=[]
        fichier=open(fichier_txt,'w')
        a=time.time()
        b=0
        while b-a<tps:
            data.append(port_serie.read())
            b=time.time()
     
        data=[i.decode('utf-8') for i in data]
        authorized=[str(i) for i in range(10)]+['.']
     
        for k in range(len(data)):
            filtered=''
            for elements in data[k]:
                if elements in authorized:filtered+=elements
            data[k]=filtered+","
            fichier.write(data[k])
     
        fichier.close()
    merci

  9. #9
    Responsable Modération

    Homme Profil pro
    Ingénieur électricien
    Inscrit en
    septembre 2008
    Messages
    1 035
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : Suisse

    Informations professionnelles :
    Activité : Ingénieur électricien

    Informations forums :
    Inscription : septembre 2008
    Messages : 1 035
    Points : 3 681
    Points
    3 681
    Par défaut
    Bonsoir à tous

    Il y a aussi un "problème" avec ces lignes:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
      float distance_mm = measure / 2.0 * SOUND_SPEED;
      Serial.println(distance_mm);
    Car l'AVR qui équipe l'Uno a un coeur 8 bits à virgule fixe. Demander de faire un calcul en float prend énormément de temps (quelques centaines de cycles pour une multiplication, encore plus pour une division, la conversion en string également). Travailler en virgule fixe sera un gain énorme, voir envoyer la mesure par le port série et faire le calcul sur le PC (qui en x86 ou ARM a un coeur 32 ou 64 bits à vigule flottante bien plus efficace).
    Mettre deux micros() ou millis(), un avant le calcul et l'autre après et envoyer la différence entre les deux permet de chiffrer cela (bon cela ajoute un peu de calcul donc c'est pour le débogage).

    Ensuite la période c'est 20ms plus le temps du calcul. Si on veut être précis il faut utiliser une temporisation à millis(). On peut aussi ajouter une petite vérification pour vérifier que le calcul a pris moins de temps que la période choisie lors du débogage. Voir cette discussion à partir de ce message, pour avoir une période précise.

    Finalement si on veut être très précis, il faut configurer l'un des Timer de l'AVR et utiliser les interruptions. (Mais cela casse les fonctions temporelles de l'Arduino, il faut bien choisir celles le Timer correspondant à celles que l'on utilisent pas et c'est d'un niveau avancé). Rechercher Timer Arduino Uno donne suffisamment de tutos. Le point très délicat avec cette méthode c'est de vérifier que le calcul est plus rapide que la période d’interruption.

    Bonne suite

    Delias

  10. #10
    Nouveau Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    mars 2020
    Messages
    8
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Somme (Picardie)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : mars 2020
    Messages : 8
    Points : 1
    Points
    1
    Par défaut
    Merci pour la remarque et bonne idée pour le calcul, je vais creuser ça avec ce que j'ai compris. Par contre j'ai le même problème avec le capteur VL53L0X, le code arduino étant le suivant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
     
    #include "Adafruit_VL53L0X.h"
     
    Adafruit_VL53L0X lox = Adafruit_VL53L0X();
     
    void setup() {
      Serial.begin(500000);
      while (! Serial) {
        delay(1);
      }
      if (!lox.begin()) {
        Serial.println(F("Failed to boot VL53L0X"));
        while(1);
      }
    }
    void loop() {
      VL53L0X_RangingMeasurementData_t measure;
      lox.rangingTest(&measure, false);
     
      Serial.print(measure.RangeMilliMeter); 
      delay(20);
    }
    Merci

  11. #11
    Membre émérite

    Homme Profil pro
    mad scientist :)
    Inscrit en
    septembre 2019
    Messages
    1 566
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : septembre 2019
    Messages : 1 566
    Points : 2 818
    Points
    2 818
    Par défaut
    Citation Envoyé par SosoManess Voir le message
    Voilà ma fonction et l'initialisation du port série :
    C’est plus le code Arduino qui compte.

    pas top de modifier votre ancien post, on s'y perd...

  12. #12
    Membre émérite

    Homme Profil pro
    mad scientist :)
    Inscrit en
    septembre 2019
    Messages
    1 566
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : septembre 2019
    Messages : 1 566
    Points : 2 818
    Points
    2 818
    Par défaut
    OK, donc vous avez pris le code d'exemple standard et simplifié le test de validité
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
      if (measure.RangeStatus != 4) {  // phase failures have incorrect data
        Serial.print("Distance (mm): "); Serial.println(measure.RangeMilliMeter);
      } else {
        Serial.println(" out of range ");
      }
    et modifié l'attente entre 2 mesures en remplaçant leur delay(100); par delay(20);

    il faudrait voir combien de temps prends leur fonction
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     lox.rangingTest(&measure, false);
    si elle est bloquante ce n'est pas la peine d'attendre 20ms ensuite. généralement on met ça dans un test avec millis()

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    #include "Adafruit_VL53L0X.h" // https://github.com/adafruit/Adafruit_VL53L0X
    Adafruit_VL53L0X lox = Adafruit_VL53L0X();
     
    void setup()
    {
      Serial.begin(500000);
      while (! Serial);
      if (!lox.begin()) {
        Serial.println(F("Failed to boot VL53L0X"));
        while (1);
      }
    }
     
    void loop()
    {
      static unsigned long chrono = 0;
      if (millis() - chrono >= 20) {
        VL53L0X_RangingMeasurementData_t measure;
        lox.rangingTest(&measure, false);
        Serial.print(measure.RangeMilliMeter);
        chrono += 20; // à préférer à chrono = millis(); comme ça si une mesure a pris plus de 20ms avec cette approche on se recale sur un top toutes les 20ms
      }
    }

  13. #13
    Nouveau Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    mars 2020
    Messages
    8
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Somme (Picardie)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : mars 2020
    Messages : 8
    Points : 1
    Points
    1
    Par défaut
    Bonjour,

    Je viens d'exécuter le code et j'ai bien un affichage dans le port série, j'en déduis donc que le delay est inutile car une mesure + affichage prend plus de 20ms ?

    EDIT : Je viens de faire pas mal de tests sur python et j'ai trouvé une fonction qui lit un certain nombre de byte dans le port série.Si le nombre de byte demandé dépasse celui présent dans le buffer arduino il attend que les mesures se fassent, sinon il prend celles en mémoire. Je pense que ça règle mon problème , car ma problématique était que le temps entre chaque mesure devait être celui indiqué dans le delay() arduino et j'avais peur que python prenne les valeurs mais pas dans l'ordre chronologique, ce qui changerait évidemment le temps entre 2 mesures, le rendant même aléatoire. Le dernier problème est qu'il faut s'assurer que la prise de mesure respecte le delay mais si je ne m'abuse vous m'avez déjà fourni une fonction faisant le job. J'attends tout de même votre confirmation.

  14. #14
    Membre émérite

    Homme Profil pro
    mad scientist :)
    Inscrit en
    septembre 2019
    Messages
    1 566
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : septembre 2019
    Messages : 1 566
    Points : 2 818
    Points
    2 818
    Par défaut
    Citation Envoyé par SosoManess Voir le message
    j'avais peur que python prenne les valeurs mais pas dans l'ordre chronologique
    le port série est asynchrone mais les données arrivent dans l'ordre d'émission => donc vous n'avez aucune raison de vous inquiéter votre programme python les reçoit forcément dans l'ordre.

    si vous voulez avoir le même timing pour comparer tous vos capteurs de distance, utilisez l'approche que j'ai mentionnée dans mon post précédent, vous ne faites pas de delay() mals utilisez millis() et prenez la période la plus longue, par exemple 60ms pour chacun des capteurs même si le VL53L0X pourrait aller un peu plus vite

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    ...
     
    const unsigned int periodeEchantillonnage  = 60; // un échantillon toutes les 60ms 
     
    unsigned long lireMesure()  // à adapter en fonction du capteur
    {
      unsigned long distance = .... ; // faire une lecture
      return distance;
    }
     
    void initCapteur()  // à adapter en fonction du capteur
    {
      ...
    }
     
    ...
     
    void setup()
    {
      Serial.begin(500000);
      initCapteur();
    }
     
    void loop()
    {
      static unsigned long chrono = 0;
      if (millis() - chrono >= periodeEchantillonnage) {
        Serial.println(lireMesure());
        chrono += periodeEchantillonnage; 
      }
    }

  15. #15
    Nouveau Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    mars 2020
    Messages
    8
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Somme (Picardie)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : mars 2020
    Messages : 8
    Points : 1
    Points
    1
    Par défaut
    D'accord, super !
    Je vais tester tout ça et déterminer la meilleure fréquence d’échantillonnage commune. Merci encore pour votre aide précieuse !

Discussions similaires

  1. Communication port série (RS232) avec VC++
    Par sanatou dans le forum Visual C++
    Réponses: 2
    Dernier message: 30/10/2006, 13h49
  2. Communication Port Série Internet
    Par psyckey dans le forum Hardware
    Réponses: 3
    Dernier message: 29/09/2006, 19h37
  3. [VB6] Probleme communication Port série
    Par Renard-fou dans le forum VB 6 et antérieur
    Réponses: 8
    Dernier message: 15/05/2006, 00h01
  4. Communication port série W2000/W98
    Par Fabsou dans le forum MFC
    Réponses: 4
    Dernier message: 24/10/2005, 19h57
  5. probleme de communication port série
    Par ben23 dans le forum MFC
    Réponses: 8
    Dernier message: 06/02/2004, 15h12

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo