Mesure la vitesse d'un hand spinner avec la photo resistance (LDR); utilise le Timer, la console et la LDR.

Dependencies:   mbed

Ca tourne vite ! et une photoresistance (LDR) est lente !

La boucle du programme:

  1. Calibration du capteur
  2. Mesures
  3. Affichage sur la console

Le code utilise un Timer pour mesurer le temps écoulé, des fonctions et des structures.

Console

La vitesse de la communication USB est configurée à 115.200 baud (par défaut elle est de 9600.) A cette vitesse on peut se permettre d'envoyer chaque mesure sur la console et on reste dans les 1ms par boucle.

Au début, a 9600 bauds, on a regroupé les mesures par paquet de 1.000 pour les afficher d'un coup. Pendant la boucle on ne fait que remplir un tableau de float[1000] (il semble avoir du mal á aller au delá de 1000?) et apres les mesures on dump (affiche) le tableau.

Physique

La carte est assez rapide pour faire environs 30.000 mesures par seconde. Donc théoriquement mesurer des vitesses de rotation jusqu'a 15.000 tours/s ! La premiere limite qu'on atteindra est la latence de la photoresistance. A priori entre 10 et 500 ms et ce n'est pas linéaire. Elle met plus de temps (j'ai lu jusqu'à une seconde !?) pour augmenter sa résistance après avoir été éclairée.

Premières visu

Après avoir visualisé les mesures par paquets de 1.000. Il semble y avoir un autre phénomène. On observe une sorte de peigne, comme si une mesure sur deux ne rencontrait pas de résistance (valeur a 1). Mais ce n'est pas systématique non plus. https://docs.google.com/spreadsheets/d/1bWVamwfsqNKRFRfbD6L3g7Slo4lBYWXPn2ICLtPI5HI/edit?usp=sharing

Avec capa

Avec la capa de 10µF on a une courbe plus lisse.

Avec sortie des valeurs

afficher chaque valeur ralenti un peu la boucle, mais on reste à 1 ms par mesure, ce qui est suffisant.

On constate mieux le problème de saturation. Si la LDR est bien éclairé elle reste à 1.0, elle met du temps à re-descendre, mais montre des oscillations dès qu'on ne sature plus (pas besoin d'attendre 500ms!). On voit du 3 à 20 Hz environs, avec 25 points d'amplitude.

Sur une oscillation on pourra faire environs 50 mesures et voir un écart de 25 points. Ca reste largement suffisant.

A suivre ...

Next

  • Il faut juste indiquer les conditions d'éclairage:
    • LED rouge si on a trop de lumiere (on sature á 1)
    • LED bleu si on a pas assez de lumiere (a determiner)
    • LED orange si on a pas assez d'amplitude
  • Passer le AnalogIn de float (32b) à unsigned short (16b) https://developer.mbed.org/handbook/C-Data-Types
  • FFT https://developer.mbed.org/questions/tag/FFT/?sort=votes
  • Faire clignoter une LED a la vitesse du HandSpinner pour faire un effet stroboscopique et "arrêter" l'image.
  • Accélérer le HandSpinner avec un électro-aimant. (principe du moteur électrique).

Reference

main.cpp

Committer:
BrnVrn
Date:
2017-06-11
Revision:
11:ba42369ffdc0
Parent:
10:49bc07cc747d

File content as of revision 11:ba42369ffdc0:

#include "mbed.h"


DigitalOut myled(LED2);     // Pas encore utilisé
AnalogIn   phototo(A1);    // Renvoie un float entre [1.0 ; 0.0]
                   // Light => no resistance
                   // Dark => high resistance

Serial     pc(USBTX, USBRX);

const int changements_par_tour = 3*2;   // HandSpinner avec 3 branches
const int tours_par_mesure = 2;
const int timeout_ms = 4 * 1000;    // 4 secondes
const int TAILLE_RECORD = 1000;

struct Seuil {
    float haut;
    float bas;
};

Timer t;        // https://developer.mbed.org/handbook/Timer
                    // https://developer.mbed.org/questions/61002/Equivalent-to-Arduino-millis/
                    
Seuil calibration() {
    float  v, v_max, v_min, delta;
    Seuil s;
    
    v = phototo.read();
    v_max = v;
    v_min = v;
    
    t.reset();
    t.start();
    for (int i=0; i<200 ; i++) {
            v = phototo.read();         // float entre [1.0 ; 0.0]
            //phototo.read_u16();       // @TODO  renvoie un entier [65535 ; 0]  (plus rapide)
            if      (v > v_max)  v_max = v;
            else if (v < v_min)  v_min = v;
            wait_ms(5); 
    }
    t.stop();
    delta = (v_max - v_min) / 3.0;
    s.haut = v_max - delta;
    s.bas  = v_min + delta;
    pc.printf("Calibration [%.3f ; %.3f] [%.3f; %.3f] sur %d ms.\t", v_max, s.haut, s.bas, v_min, t.read_ms());
    return s;
}


void affiche_mesures(float mesures[], int nb_mesures)  {
    if ( nb_mesures > TAILLE_RECORD )  nb_mesures = TAILLE_RECORD;
    pc.printf("\r\n---------------------------------\r\n");
    for (int i=0; i < nb_mesures ; i++)  pc.printf("%f;", mesures[i]);
    pc.printf("\r\n---------------------------------\r\n");
}
    

int main() {
    pc.baud( 115200 ); // 9600 14400 57600 115200
    //pc.format(8, SerialBase::None, 1);  // Optional (default)
    
    pc.printf("Demarrage ! \r\n");
    
    bool jour_ou_nuit, precedent;
    int changements, mesures;
    int temps_par_tour_ms;
    Seuil seuil;      
    float value, valpre, moy;
    float record[TAILLE_RECORD];
    
    
    while(true) {

        seuil = calibration();
        valpre = seuil.haut;     // initialise la valeur "precedente"
        
        changements = 0; mesures = 0;
        t.reset();                
        t.start();
        while ( ( changements < ( changements_par_tour * tours_par_mesure ) )
                && ( t.read_ms() < timeout_ms ) )  {
            
            value = phototo.read();
            //printf("v %f\r\n", value);  // debug, mais bien trop lent!
            if (mesures < TAILLE_RECORD)  record[mesures] = value;
            mesures++;  // Attention de ne pas depasser!
    
            moy = (value + valpre) / 2.0;       // on lisse 
            valpre = value;
            if      (moy > seuil.haut)  jour_ou_nuit = true;
            else if (moy < seuil.bas)   jour_ou_nuit = false;
            else continue;
            
             if ( jour_ou_nuit != precedent )  {
                precedent = jour_ou_nuit;
                changements = changements + 1;
            }
         }
         t.stop();
         
        pc.printf(" %d mesures et %d changements \t", mesures, changements);
        
        if ( t.read_ms() >= timeout_ms ) {
            pc.printf("Timeout  ... \r\n");
            continue;
        }
            
        temps_par_tour_ms = t.read_ms() / tours_par_mesure;
        if (temps_par_tour_ms != 0)
            pc.printf("Un tour en %d ms ;\t %d tours/seconde \r\n",  temps_par_tour_ms, 1000/temps_par_tour_ms); 
        else
            pc.printf("Etrange ! le temps mesure est nul !?\r\n");
        affiche_mesures(record, mesures);
        wait_ms(100);       
    }
}