MPU6050 détection de mouvement

Bonjour,

J’aimerais que le MPU6050 commence à relever les valeurs gyroscopique seulement lors du premier mouvement sur un rotor. Pour le moment j’avais retiré l’interruption pour prendre des valeurs en continue dés l’alimentation et le téléversement du programme. Cependant, pour mon projet ceci n’est pas idéal car le gyroscope sera toujours alimenté et je ne veux pas qu’il relève les valeurs tous le temps.
De plus, l’interruption doit pouvoir s’effectuer sans intervention humaine d’ou la nécessite d’imposer le relevage des mesures seulement à partir d’un mouvement.
J’ai déjà passé quelques heures sur ce problème mais tous mes essais reste des échecs.
Auriez vous une idée de comment faire ?

Merci à vous !

voici mon programme :

#include "I2Cdev.h"
#include "MPU6050_6Axis_MotionApps20.h"
#include "Wire.h"
// ---------------------------------------------------------------------------
#define YAW      0
#define PITCH    1
#define ROLL     2
// --------------------- MPU650 variables ------------------------------------
// class default I2C address is 0x68
// specific I2C addresses may be passed as a parameter here
// AD0 low = 0x68 (default for SparkFun breakout and InvenSense evaluation board)
// AD0 high = 0x69
MPU6050 mpu;
// MPU control/status vars
bool dmpReady = false;  // set true if DMP init was successful
uint8_t mpuIntStatus;   // holds actual interrupt status byte from MPU
uint8_t devStatus;      // return status after each device operation (0 = success, !0 = error)
uint16_t packetSize;    // expected DMP packet size (default is 42 bytes)
uint16_t fifoCount;     // count of all bytes currently in FIFO
uint8_t fifoBuffer[64]; // FIFO storage buffer

// Orientation/motion vars
Quaternion q;        // [w, x, y, z]         quaternion container
VectorFloat gravity; // [x, y, z]            gravity vector
float ypr[3];        // [yaw, pitch, roll]   yaw/pitch/roll container and gravity vector

volatile bool mpuInterrupt = false;     // Indicates whether MPU interrupt pin has gone high
// ---------------------------------------------------------------------------

/**
 * Interrup détection routine
 */
void dmpDataReady() {
    mpuInterrupt = true;
}

/**
 * Setup configuration
 */
void setup() {
    Wire.begin();
    TWBR = 24; // 400kHz I2C clock (200kHz if CPU is 8MHz)

    Serial.begin(57600);

    Serial.println(F("Initializing I2C devices..."));
    mpu.initialize();

    // Verify connection
    Serial.println(F("Testing device connections..."));
    Serial.println(mpu.testConnection() ? F("MPU6050 connection successful") : F("MPU6050 connection failed"));

    // Load and configure the DMP
    Serial.println(F("Initializing DMP..."));
    devStatus = mpu.dmpInitialize();

    // MPU calibration: set YOUR offsets here.
    mpu.setXAccelOffset(365);
    mpu.setYAccelOffset(-4046);
    mpu.setZAccelOffset(1554);
    mpu.setXGyroOffset(105);
    mpu.setYGyroOffset(96);
    mpu.setZGyroOffset(26);

    // Returns 0 if it worked
    if (devStatus == 0) {
        // Turn on the DMP, now that it's ready
        Serial.println(F("Enabling DMP..."));
        mpu.setDMPEnabled(true);

        // Enable Arduino interrupt detection
        Serial.println(F("Enabling interrupt detection (Arduino external interrupt 0 : #pin2)..."));
        attachInterrupt(0, dmpDataReady, RISING);
        mpuIntStatus = mpu.getIntStatus();

        // Set our DMP Ready flag so the main loop() function knows it's okay to use it
        Serial.println(F("DMP ready! Waiting for first interrupt..."));
        dmpReady = true;

        // Get expected DMP packet size for later comparison
        packetSize = mpu.dmpGetFIFOPacketSize();
    } else {
        // ERROR!
        // 1 = initial memory load failed
        // 2 = DMP configuration updates failed
        // (if it's going to break, usually the code will be 1)
        Serial.print(F("DMP Initialization failed (code "));
        Serial.print(devStatus);
        Serial.println(F(")"));
    }
}

/**
 * Main program loop
 */
void loop() {
    // If programming failed, don't try to do anything
    if (!dmpReady) {
        return;
    }

    // Wait for MPU interrupt or extra packet(s) available
    while (!mpuInterrupt && fifoCount < packetSize) {
        // Do nothing...
    }

    // Reset interrupt flag and get INT_STATUS byte
    mpuInterrupt = false;
    mpuIntStatus = mpu.getIntStatus();

    // Get current FIFO count
    fifoCount = mpu.getFIFOCount();

    // Check for overflow (this should never happen unless our code is too inefficient)
    if ((mpuIntStatus & 0x10) || fifoCount == 1024) {
        // reset so we can continue cleanly
        mpu.resetFIFO();
        Serial.println(F("FIFO overflow!"));

        // Otherwise, check for DMP data ready interrupt (this should happen frequently)
    } else if (mpuIntStatus & 0x02) {
        // Wait for correct available data length, should be a VERY short wait
        while (fifoCount < packetSize) {
            fifoCount = mpu.getFIFOCount();
        }

        // Read a packet from FIFO
        mpu.getFIFOBytes(fifoBuffer, packetSize);

        // Track FIFO count here in case there is > 1 packet available
        // (this lets us immediately read more without waiting for an interrupt)
        fifoCount -= packetSize;

        // Convert Euler angles in degrees
        mpu.dmpGetQuaternion(&q, fifoBuffer);
        mpu.dmpGetGravity(&gravity, &q);
        mpu.dmpGetYawPitchRoll(ypr, &q, &gravity);

        // Print angle values in degrees.
        Serial.print(ypr[YAW] * (180 / M_PI));
        Serial.print("\t");
        Serial.print(ypr[PITCH] * (180 / M_PI));
        Serial.print("\t");
        Serial.println(ypr[ROLL] * (180 / M_PI));
    }
}

J'aimerais que le MPU6050 commence à relever les valeurs gyroscopique seulement lors du premier mouvement sur un rotor.

La première idée qui me vient serait d'alimenter le module MPU non sur la broche 5V mais sur une pin digitale que tu mets à HIGH uniquement lorsque tu en as besoin.

... Mais je ne sais pas si c'est une bonne idée...

J'ai peur que ceci endommage le module vu qu'il sera alimenté continuellement sur une grande période. Cependant, je peux vérifier si cela est possible. J'avais plutôt opté pour tenter de faire en sorte d'obtenir un écart de 1° et lorsque cette écart est obtenu alors on affiche les valeurs.

J'ai peut-être mal compris ton besoin : si tu veux détecter un mouvement, tu peux utiliser les interruptions. Ce composant génère une interruption lorsqu'un mouvement est appliqué. Je m'en sers pour réveiller un ESP32 en sommeil par exemple. Voir ici par exemple

Noyha: Cependant, pour mon projet ceci n'est pas idéal car le gyroscope sera toujours alimenté et je ne veux pas qu'il relève les valeurs tous le temps. De plus, l'interruption doit pouvoir s'effectuer sans intervention humaine d'ou la nécessite d'imposer le relevage des mesures seulement à partir d'un mouvement.

Tu n'explique pas vraiment tes contraintes et je ne comprends pas bien le besoin. Tu as un problème de consommation? Sinon rien n'empêche de faire tourner le MPU tout le temps mais que l'arduino ne garde les informations que sous certaines conditions.

Mon besoin est exactement celui que @lesept à exprimer. Je n'ai pas de problème de consommation je souhaite seulement pouvoir commencer à relever des valeurs lorsque un mouvement de rotation à lieu alors que le MPU relève des valeurs continuellement sans avoir forcément besoins de mouvement.

lesept: J'ai peut-être mal compris ton besoin : si tu veux détecter un mouvement, tu peux utiliser les interruptions. Ce composant génère une interruption lorsqu'un mouvement est appliqué. Je m'en sers pour réveiller un ESP32 en sommeil par exemple. Voir ici par exemple

L'interruption fonctionne automatiquement il n'y a pas besoins de la déclenché manuellement ?

Non, c’est automatique par défaut. Mais tu peux spécifier par programme que tu autorise ou inhibes les interruptions. Voir ici et

La fonction sei() permet d’autoriser les interruptions alors que la fonction cli() permet de les ignorer ; on peut aussi utiliser les fonctions interrupts() et noInterrupts() du langage Arduino.

Cela est similaire à mon programme ou je place les interruptions en True ou False. Sauf que le problème que je rencontre en utilisant celles ci est que soit cela ne prend aucune valeurs soit une fois que je fais une interrupt cela me prend toute les valeurs.

C'est pour ça que j'avais abandonné l'idée de l'interruption et me dire que peut être il serait plus intéressant d'imposer une condition signifiant que :

si il y a un écart entre la dernière valeur et la nouvelle valeur de 0.1° alors on affiche les valeurs sinon non .

Ton programme est trop complexe, j'ai beaucoup de mal à le décrypter. Tu devrais faire un truc plus simple, à base d'interruption si tu veux, pour gérer l'interruption et les données mesurées. Une fois que ça fonctionne, tu l'insères dans ton programme complet.

Pars de ton cahier des charges :

J'aimerais que le MPU6050 commence à relever les valeurs gyroscopique seulement lors du premier mouvement sur un rotor.

Comment est détecté le premier mouvement du rotor ? Par la commande du moteur associé ? Si oui, tu inhibes les interruptions jusqu'au lancement du moteur, puis tu les autorises au moment du lancement du moteur et tu fais tes mesures à partir de là.

Ou bien, encore plus simple : tu mesures tout le temps, sans utiliser d'interruption, mais tu ne prends les valeurs en compte qu'à partir du moment où le moteur est en marche. Pas besoin de se compliquer la vie plus que nécessaire...

Comme disait fdufnews :

Sinon rien n'empêche de faire tourner le MPU tout le temps mais que l'arduino ne garde les informations que sous certaines conditions.

si il y a un écart entre la dernière valeur et la nouvelle valeur de 0.1° alors on affiche les valeurs sinon non .

Je traduirais celà en: si il y a un écart entre la dernière valeur et la nouvelle valeur de 0.1° alors on affiche les valeurs deniere valeur = valeur_en_cours sinon on ne fait rien (ou presque) .

De plus, les valeurs sortant d'un gyroscope 3 D sont un tableau de 3 valeurs (un vecteur). L'écart n'est pas une simple valeur absolue de differences (la somme ou le max. de valeurs absolues font l'affaire)

Noyha: J'ai peur que ceci endommage le module vu qu'il sera alimenté continuellement sur une grande période. Cependant, je peux vérifier si cela est possible. J'avais plutôt opté pour tenter de faire en sorte d'obtenir un écart de 1° et lorsque cette écart est obtenu alors on affiche les valeurs.

le mpu6050 retourne une vitesse et une accélération pas un angle. Donc il faut bien que ce soit l'arduino qui calcule l'angle. Ou alors il y a quelque chose qui m'échappe.

lesept: Ton programme est trop complexe, j'ai beaucoup de mal à le décrypter. Tu devrais faire un truc plus simple, à base d'interruption si tu veux, pour gérer l'interruption et les données mesurées. Une fois que ça fonctionne, tu l'insères dans ton programme complet.

Pars de ton cahier des charges :Comment est détecté le premier mouvement du rotor ? Par la commande du moteur associé ? Si oui, tu inhibes les interruptions jusqu'au lancement du moteur, puis tu les autorises au moment du lancement du moteur et tu fais tes mesures à partir de là.

Ou bien, encore plus simple : tu mesures tout le temps, sans utiliser d'interruption, mais tu ne prends les valeurs en compte qu'à partir du moment où le moteur est en marche. Pas besoin de se compliquer la vie plus que nécessaire...

Comme disait fdufnews :

Justement , tu as parfaitement compris ce que je voulais faire avec la solution encore plus simple ! En effet, plutôt qu'utiliser une interruptions il est plus simple de prendre les valeurs en compte seulement lorsque le moteur marche. Cependant, je ne vois pas comment mis prendre. Il faut que cela respecte certaines conditions et pour cela j'avais pensé à un écart de 0.1°. Mais il y a peut être plus simple je ne sais vraiment pas.

Mais il est où le moteur dans ton code ? Je pensais que tu le commandais avec l'arduino. Sinon, comment veux-tu savoir qu'il est ou non en marche ?

lesept: Mais il est où le moteur dans ton code ? Je pensais que tu le commandais avec l'arduino. Sinon, comment veux-tu savoir qu'il est ou non en marche ?

Le problème est que le moteur n'est pas présent dans le code car c'est un moteur physique je travaille sur une centrale. Ce que je réalise avec le gyro est un complément qui sera embarqué donc il n'y a pas de code de moteur. C'est pour cela que j'ai du mal à savoir comment m'y prendre.

Il te faut un capteur qui te permette de savoir quand le moteur est en marche, par exemple un capteur de courant, si tu as accès à son alimentation (ou celui-ci). Voir ici par exemple et aussi ça

Sinon, écouter le bruit ...?

Si tu expliquais un peu mieux la configuration de la manip, avec ses contraintes, ce serait quand même plus simple pour t'aider.

Noyha:
… je travaille sur une centrale…

Si les centrales nucléaires sont contrôlées par des Arduino, on est mal…