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 :

Mesurer une vitesse avec un MPU6050


Sujet :

Arduino

  1. #1
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Août 2021
    Messages
    52
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Août 2021
    Messages : 52
    Points : 41
    Points
    41
    Par défaut Mesurer une vitesse avec un MPU6050
    Bonjour;
    je cherche à faire un compteur vitesse à partir d'une centrale inertielle (en l’occurrence le mpu6050);
    Après du travail, j'ai fait le programme suivant.
    Mais ça marche pas... :
    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
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    #include <LiquidCrystal.h>
    #include <Wire.h>
    #include "fonctions.h"
     
    #define X     0     // X axis
    #define Y     1     // Y axis
    #define Z     2     // Z axis
     
    #define MPU_ADDRESS 0x68  // I2C address of the MPU-6050
    #define FREQ        260   // Sampling frequency
    #define SSF_GYRO    65.5  // Sensitivity Scale Factor of the gyro from datasheet
     
    const int rs = 12, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 2;
    LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
     
    int gyro_raw[3] = {0, 0, 0};
     
    // Average gyro offsets of each axis in that order: X, Y, Z
    long gyro_offset[3] = {0, 0, 0};
     
    // Calculated angles from gyro's values in that order: X, Y, Z
    float gyro_angle[3]  = {0, 0, 0};
     
    // The RAW values got from accelerometer (in m/sec²) in that order: X, Y, Z
    int acc_raw[3] = {0 , 0 , 0};
     
    // Calculated angles from accelerometer's values in that order: X, Y, Z
    float acc_angle[3] = {0, 0, 0};
     
    int moy;
     
    boolean initialise;
     
    int temperature;
     
    unsigned int  period; // Sampling period
    unsigned long loop_timer;
    float fspeed;
     
     
    void setup() {
      Serial.begin(9600);
      lcd.begin(16, 2);
      Wire.begin();
      TWBR = 12; // Set the I2C clock speed to 400kHz.
      period = (1000000 / FREQ);
      loop_timer = micros();
     
      setupMpu6050Registers();
      CalibrerMPU();
      Serial.print("moyenne : ");
      Serial.println(moy);
      Serial.print(period);
      initialise = true;
    }
     
    void loop() {
        fspeed += vitesse();
        lcd.setCursor(0, 0);
        lcd.print("vitesse: ");
        lcd.setCursor(8, 0);
        lcd.print(fspeed);
        lcd.setCursor(0, 1);
        lcd.print(fspeed*18/5);
     
        while (micros() - loop_timer < period);
        loop_timer = micros();
     
     
    }
     
    void setupMpu6050Registers() {
      // Configure power management
      Wire.beginTransmission(MPU_ADDRESS); // Start communication with MPU
      Wire.write(0x6B);                    // Request the PWR_MGMT_1 register
      Wire.write(0x00);                    // Apply the desired configuration to the register
      Wire.endTransmission();              // End the transmission
     
      // Configure the gyro's sensitivity
      Wire.beginTransmission(MPU_ADDRESS); // Start communication with MPU
      Wire.write(0x1B);                    // Request the GYRO_CONFIG register
      Wire.write(0x08);                    // Apply the desired configuration to the register : ±500°/s
      Wire.endTransmission();              // End the transmission
     
      // Configure the acceleromter's sensitivity
      Wire.beginTransmission(MPU_ADDRESS); // Start communication with MPU
      Wire.write(0x1C);                    // Request the ACCEL_CONFIG register
      Wire.write(0x10);                    // Apply the desired configuration to the register : ±8g
      Wire.endTransmission();              // End the transmission
     
      Wire.beginTransmission(MPU_ADDRESS); // Start communication with MPU
      Wire.write(0x1A);                    // Request the CONFIG register
      Wire.write(0x03);                    // Set Digital Low Pass Filter about ~43Hz
      Wire.endTransmission();              // End the transmission
    }
     
     
    void readSensor() {
      Wire.beginTransmission(MPU_ADDRESS); // Start communicating with the MPU-6050
      Wire.write(0x3B);                    // Send the requested starting register
      Wire.endTransmission();              // End the transmission
      Wire.requestFrom(MPU_ADDRESS, 14);   // Request 14 bytes from the MPU-6050
     
      // Wait until all the bytes are received
      while (Wire.available() < 14);
     
      acc_raw[X]  = Wire.read() << 8 | Wire.read(); // Add the low and high byte to the acc_raw[X] variable
      acc_raw[Y]  = Wire.read() << 8 | Wire.read(); // Add the low and high byte to the acc_raw[Y] variable
      acc_raw[Z]  = Wire.read() << 8 | Wire.read(); // Add the low and high byte to the acc_raw[Z] variable
      temperature = Wire.read() << 8 | Wire.read(); // Add the low and high byte to the temperature variable
      gyro_raw[X] = Wire.read() << 8 | Wire.read(); // Add the low and high byte to the gyro_raw[X] variable
      gyro_raw[Y] = Wire.read() << 8 | Wire.read(); // Add the low and high byte to the gyro_raw[Y] variable
      gyro_raw[Z] = Wire.read() << 8 | Wire.read(); // Add the low and high byte to the gyro_raw[Z] variable
    }
     
    float vitesse(){
     
        float vitesse;
        readSensor();
        /*acc_raw[X] = sqrt(pow(acc_raw[X],2)+pow(acc_raw[Y], 2)+ pow(acc_raw[Z], 2));*/
        vitesse = ((9.81*(acc_raw[X]))/4.096)*0.004; // 0.004 corespond à la période en secondes
        Serial.print("x: ");
        Serial.println(acc_raw[X]-104); 
        if (initialise){
          return round(vitesse-moy);
        }
        else{
          return vitesse;
        }
     
    }
     
    void CalibrerMPU(){
     
      int tours;
      float Vitesse;
     
      for(tours = 0 ; tours <= 300 ; tours ++){
        Vitesse += vitesse();
        delay(3);
      }
     
      moy = Vitesse/300;
     
    }
    les résultats sont absurdes et ne collent pas.
    de plus, je vois dans la datasheet :
    Nom : Capture d’écran 2021-11-01 150901.png
Affichages : 1106
Taille : 4,1 Ko
    donc le résultat retourné divisé par 4 dans mon cas est bien en G ? et pas en m/s ?

    Le principe de mon programme est donc de récupérer cette valeur, de la convertir en m/s², puis en m/s en multipliant par le temps écoulé.
    Ainsi j'obtiens la vitesse affichée sur un écran lcd. je la converti en km/h en multipliant par 3600/1000 soit 18/5.
    Mais ils y a un os...
    Quelqu'un peut-il m'aider ?
    Merci d'avance

  2. #2
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Août 2021
    Messages
    52
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Août 2021
    Messages : 52
    Points : 41
    Points
    41
    Par défaut
    Je répond moi-même à ma question.
    Voici un programme qui marche "mieux", mais les marges d'erreurs sont encore grosses.
    Alors si quelqu'un a des conseils...
    Prgm :
    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
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    #include <LiquidCrystal.h>
    #include <Wire.h>
    #include "fonctions.h"
     
    #define X     0     // X axis
    #define Y     1     // Y axis
    #define Z     2     // Z axis
     
    #define MPU_ADDRESS 0x68  // I2C address of the MPU-6050
     
    const int rs = 12, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 2;
    LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
     
    int gyro_raw[3] = {0, 0, 0};
     
    int acc_raw[3] = {0, 0, 0};
     
    int moy, temperature;
     
    float fspeed, acc, temps, Xx, Yy, Zz, deb, fin;
     
    void setup() {
      Serial.begin(9600);
      lcd.begin(16, 2);
      Wire.begin();
      TWBR = 12; // Set the I2C clock speed to 400kHz.
     
      setupMpu6050Registers();
    }
     
    void loop() {
     
      deb = micros();
      delay(5);
      readSensor();
      fin = micros();
      temps = (fin-deb)/1000000;
      Xx = ConvertData(acc_raw[X]);
      Yy = ConvertData(acc_raw[Y]);
      Zz = ConvertData(acc_raw[Z]);
     
      if(Xx-0.2 < 0){
        acc = -(sqrt(pow(Xx, 2)+pow(Yy, 2)+pow(Zz, 2))-9.37);
      }
      else{
        acc = sqrt(pow(Xx, 2)+pow(Yy, 2)+pow(Zz, 2))-9.37;
      }
     
      fspeed += acc * temps;  // v = v0 +a*t
      lcd.setCursor(0, 0);
      lcd.print("vitesse(km/h)");
      lcd.setCursor(0, 1);
      lcd.print(fspeed*18/5);
      Serial.println(fspeed*18/5);  // le *18/5 pour convertir m/s -> km/h
     
    }
     
    void setupMpu6050Registers() {
      // Configure power management
      Wire.beginTransmission(MPU_ADDRESS);
      Wire.write(0x6B);
      Wire.write(0x00);
      Wire.endTransmission();
     
      Wire.beginTransmission(MPU_ADDRESS);
      Wire.write(0x1B);                    // GYRO_CONFIG registre
      Wire.write(0x08);                    // ±500°/s
      Wire.endTransmission();
     
      Wire.beginTransmission(MPU_ADDRESS);
      Wire.write(0x1C);                    // ACCEL_CONFIG registre
      Wire.write(0x10);                    // ±8g
      Wire.endTransmission();
     
      Wire.beginTransmission(MPU_ADDRESS);
      Wire.write(0x1A);                    // CONFIG registre
      Wire.write(0x03);                    // Low Pass Filter ~43Hz
      Wire.endTransmission();
    }
     
     
    void readSensor() {
      Wire.beginTransmission(MPU_ADDRESS); // Commencer communication avec MPU-6050
      Wire.write(0x3B);                    // envoie requète
      Wire.endTransmission();
      Wire.requestFrom(MPU_ADDRESS, 14);   // Request 14 bytes from the MPU-6050
     
      // Wait until all the bytes are received
      while (Wire.available() < 14);
     
      acc_raw[X]  = Wire.read() << 8 | Wire.read(); 
      acc_raw[Y]  = Wire.read() << 8 | Wire.read();
      acc_raw[Z]  = Wire.read() << 8 | Wire.read();
      temperature = Wire.read() << 8 | Wire.read();
      gyro_raw[X] = Wire.read() << 8 | Wire.read();
      gyro_raw[Y] = Wire.read() << 8 | Wire.read();
      gyro_raw[Z] = Wire.read() << 8 | Wire.read();
    }
     
    float ConvertData(float data){
     
      data /= 4096;  //conversion données brutes
      data *= 9.81;  //conversion g en m/s²
      data -= 0.2;
      return data;
    }
    et le header :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    void setupMpu6050Registers();
    void readSensor();
    float ConvertData(float data);

  3. #3
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Août 2021
    Messages
    52
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Août 2021
    Messages : 52
    Points : 41
    Points
    41
    Par défaut Post scriptum
    En effet, les résultats son plus ou moins probants :
    voici le traceur série :
    Nom : Capture d’écran 2021-11-02 121005.png
Affichages : 1096
Taille : 8,4 Ko

    ce qui nous fait une vitesse de ~1.5 km/h soit 0.42 m/s durant ~25ms. (on prend la dernière mesure)
    Donc d = v*t
    d = 0.42 * 25*10^-3
    = 1cm
    Ce serait plutôt 10, mais comme je fais ça sur mon bureau, l'ordre de grandeur est bon, mais ça reste mauvais.
    Puis après un test grandeur nature (en courant), je vois que c'est carrément faut...
    Quelqu'un a des idées ?

  4. #4
    Responsable Arduino et Systèmes Embarqués


    Avatar de f-leb
    Homme Profil pro
    Enseignant
    Inscrit en
    Janvier 2009
    Messages
    12 621
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Sarthe (Pays de la Loire)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Janvier 2009
    Messages : 12 621
    Points : 56 867
    Points
    56 867
    Billets dans le blog
    40
    Par défaut
    Bonsoir,

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    acc = sqrt(pow(Xx, 2)+pow(Yy, 2)+pow(Zz, 2))-9.37;
    Il y a trop de valeurs "magiques" dans ton code. C'est quoi ce 9.37 ?

    En plus, tes valeurs Xx, Yy, Zz intègre l'accélération de la pesanteur. Donc même au repos, il y a un +/- 9.81m/s2 qui traine suivant un axe et qu'il faut neutraliser si tu veux une accélération nulle à l'arrêt.

    Je pense aussi qu'il faut améliorer ta méthode d'intégration, au moins faire un lissage avec une moyenne glissante.

  5. #5
    Modérateur

    Avatar de Vincent PETIT
    Homme Profil pro
    Consultant en Systèmes Embarqués
    Inscrit en
    Avril 2002
    Messages
    3 191
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Pas de Calais (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Consultant en Systèmes Embarqués
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Avril 2002
    Messages : 3 191
    Points : 11 577
    Points
    11 577
    Par défaut
    Bonjour,
    Que représente la variable float acc pour toi ? Ce n'est pas l'accélération, n'essayerais tu pas d'afficher une mauvaise donnée ? Et en effet, qu'est ce que c'est cette constante 9.37 qui créait un offset ?


    Au vu de la formule que tu utilises :

    Formule mathématique

    Tu calculs la norme d'un vecteur qui correspond à une position dans un espace euclidien; donc float acc c'est la longueur "P"

    Nom : text4801.png
Affichages : 1078
Taille : 60,8 Ko
    La science ne nous apprend rien : c'est l'expérience qui nous apprend quelque chose.
    Richard Feynman

  6. #6
    Responsable Arduino et Systèmes Embarqués


    Avatar de f-leb
    Homme Profil pro
    Enseignant
    Inscrit en
    Janvier 2009
    Messages
    12 621
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Sarthe (Pays de la Loire)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Janvier 2009
    Messages : 12 621
    Points : 56 867
    Points
    56 867
    Billets dans le blog
    40
    Par défaut
    Hello Vincent

    De toute façon, avant de regarder en 3D, il vaut mieux commencer par mettre au point en 1D.

    C'est-à-dire étudier l'accélération en translation rectiligne suivant un axe principal du capteur (par exemple X), l'accélération de la pesanteur étant suivant Y ou Z.
    L'accéléromètre embarqué sur les smartphones peut aider lors des essais

  7. #7
    Expert confirmé

    Homme Profil pro
    Directeur de projet
    Inscrit en
    Mai 2013
    Messages
    1 335
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Directeur de projet
    Secteur : Service public

    Informations forums :
    Inscription : Mai 2013
    Messages : 1 335
    Points : 4 158
    Points
    4 158
    Par défaut Intégrer dérive
    Bonjour,

    Je pense que mesurer une vitesse à partir d'une accélération n'est pas une très bonne idée car l'intégration donne de la surface aux erreurs. Par exemple, un véhicule arrêté et un véhicule en mouvement constant au même endroit ont la même accélération (0 une fois l'attraction corrigée). Cela signifie qu'une erreur ponctuelle reste et qu'une incertitude va générer une erreur croissante. Par ailleurs, lors d'une variation de pente la compensation de la pesanteur sera légèrement en défaut ce qui générera une accélération parasite pour apprécier une vitesse linéaire par rapport au sol.

    Sans capteur physique (comme une roue) la seule solution qui me vienne à l'esprit est le GPS (plutôt Galileo qui est le plus précis).

    Le besoin de moyenner les résultats reste présent. Il y a effectivement la technique du tampon de n valeurs (n étant généralement une puissance de 2 pour remplacer la division par un décalage). Mais il y a aussi les filtres récursifs dont le plus simple simule bien un réseau RC : Yn = Yn-1 + a*(Xn - Yn-1) avec a compris entre 0 et 1. Pour simplifier, on prend souvent a de la forme u/2v u et v étant des entiers. Ces derniers ont ma préférence car ils sont souples et ne nécessitent que 3 variables (mais une multiplication entière par u en plus).

    Salutations
    Ever tried. Ever failed. No matter. Try Again. Fail again. Fail better. (Samuel Beckett)

  8. #8
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Août 2021
    Messages
    52
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Août 2021
    Messages : 52
    Points : 41
    Points
    41
    Par défaut
    Merci à tous.
    Étant très occupé je n'ai pas le temps de lire ça en profondeur pour l'instant.
    pour le 9.37 c'est juste le 1g (9.81), mais avec les marges d'erreurs on obtient ça sur mon mpu

  9. #9
    Responsable Arduino et Systèmes Embarqués


    Avatar de f-leb
    Homme Profil pro
    Enseignant
    Inscrit en
    Janvier 2009
    Messages
    12 621
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Sarthe (Pays de la Loire)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Janvier 2009
    Messages : 12 621
    Points : 56 867
    Points
    56 867
    Billets dans le blog
    40
    Par défaut
    Bonsoir,

    Citation Envoyé par LSBTD
    pour le 9.37 c'est juste le 1g (9.81), mais avec les marges d'erreurs on obtient ça sur mon mpu
    moui, enfin... Avant de parler de "marges d'erreurs", il va falloir retrouver les cours de maths, le chapitre sur les vecteurs en particulier.

    Parce que cette formule :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    acc = sqrt(pow(Xx, 2)+pow(Yy, 2)+pow(Zz, 2))-9.37;
    est complètement fausse

  10. #10
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Août 2021
    Messages
    52
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Août 2021
    Messages : 52
    Points : 41
    Points
    41
    Par défaut
    Bonsoir;
    Quand je change l'inclinaison de mon mpu, la vitesse change aussi... Ce qui est du à l'accélération de la pesanteur qui se répartit sur les 3 axes.
    La formule qui pose problème (sqrt(x²+y²....)) a donc pour but de supprimer ce problème, en calculant la norme du vecteur total et en y soustrayant l'accélération de la pesanteur (~9.37).
    Mais après vos remarques je constate mon erreur : calculer ça est stupide. Alors que dois-je faire ?

    De toutes les manières, comme dit Guesset : "Je pense que mesurer une vitesse à partir d'une accélération n'est pas une très bonne idée car l'intégration donne de la surface aux erreurs."

    Donc je "gèle le projet" car j'en ai un autre mieux.
    cordialement.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Mesurer une évolution avec Excel
    Par villegente dans le forum Excel
    Réponses: 1
    Dernier message: 09/01/2019, 11h44
  2. Gérer une vitesse avec précision
    Par mazertys17 dans le forum Algorithmes et structures de données
    Réponses: 4
    Dernier message: 31/12/2018, 13h59
  3. Réponses: 4
    Dernier message: 11/08/2010, 14h33
  4. Réponses: 0
    Dernier message: 08/06/2010, 22h04
  5. Réponses: 0
    Dernier message: 10/06/2009, 14h10

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