Eclairage à led de vélo 3W+tracker (atmega, ESP32)

Fonctionnement du MPU6050 Le capteur MPU6050 est la combinaison d’un accéléromètre et d’un gyroscope. Il est aussi doté d’un capteur de température que nous ne servirons pas ici. L’objectif était d’éteindre la l’éclairage lorsque le vélo ne bougeait plus pendant au moins 2 minutes (je me suis aussi amusé à faire le cas inverse ou lorsque le vélo bouge on allume). Cela nous permet d’avoir une meilleure autonomie et une meilleure gestion des batteries. Pourquoi avoir choisis le MPU6050 ? Nous utilisons le matériel que nous avons dans notre université, nous essayons de « recycler » un maximum pour éviter de faire des dépenses alors que nous pouvons utiliser d’autres composants.

Voici le programme que j’ai fait :

|340x500

Nous utilisons seulement l’accéléromètre du MPU6050, j’ai commencé par trouver par quel coefficient il fallait diviser la mesure pour obtenir quelque chose de cohérent, sur internet et les différents tutos explicatifs que l’on peut trouver personne ne parle de ce coefficient, j’ai donc cherché dans la datasheet et en regardants les différents paramètres que j’avais sur mon MPU6050, il s’avère qu’il fallait que je choisisse 16384. Ensuite j’ai effectué une correction à chaque démarrage ou redémarrage du module pour que son accélération d’origine soit 0,0,0 lors de son démarrage car nous devions tenir compte de l’inclinaison du vélo et la force gravitationnelle de 1G vers le centre de la terre. Par la suite j’ai calculé le module de l’accélération et j’ai fais en sorte que lorsque que l’on marche normalement à une vitesse d’environs 6km/h le module est d’environs 12/13, alors dans le programme lorsque le module est supérieur a 10 il active une boucle qui fait clignoter une led (cette même boucle sera remplacée par l’extinction de là l’éclairage du vélo). Pour trouver le module de l’accélération lorsque l’on marche nous avons dû effectuer des test e utilisant un Arduino nano, un écran LCD, le MPU6050 et 2 batteries lithium 18650.

J'ai vérifié la mesure du courant du processeur de l'arduino PRO MINI ainsi que celui de l'arduino NANO, les deux possèdent un processeur ATMEGA 328.

Pour réaliser cette mesure sur nous allons mettre une résistance 100 Ohms brancher en série sur l'alimentation et de l'autre côté sur l'entrée Vcc (pour l'arduino PRO MINI) ou sur l'entrée Vin (pour l'arduino NANO) Ensuite nous allons mesurer la tension aux bornes de la résistance, puis nous allons appliquer la loi d'Ohms: I = U/R

Pour la PRO MINI nous allons réaliser les mesures en utilisant les deux entrées l'entrée VCC et l'entrée RAW.

Voici les entrées RAW et VCC représenter sur le schéma de la carte arduino PRO MINI

Voici les entrées RAW et VCC représenter sur le diagramme de la carte arduino PRO MINI |500x336

Pour l'arduino PRO MINI en 16MHz alimenter sur VCC avec la led d'alimentation qui demande :

  • avec une alimentation de 3.3V, la consommation est de 1.9 mA, sachant que la led alimentation consomme 0.15mA
  • avec une alimentation de 5V, la consommation est de 9.7 mA, sachant que la led alimentation consomme 0.32mA

Pour l'arduino PRO MINI avec l'alimentation utilisant le régulateur de tension brancher sur l'entrée RAW, ce port peut être alimenté de 7V à 12V.

avec une alimentation de 7.5V, la consommation est de 13 mA, sachant que la led alimentation consomme 0.57mA avec une alimentation de 10V, la consommation est de 21 mA, sachant que la led alimentation consomme 0.82mA

Pour l'arduino NANO alimenter sur VIN on a avec une alimentation de 5V une consommation de 23 mA.

J'ai réalisé le schéma ISIS ci-dessous représentant un hacheur. |500x275 Ce montage est composé de resistances allant de 1 ohm à 100 kohms, d'un transistor TIP 122, d'une diode Schottky (PBYR745), d'une inductance de 0.5 mH, d'une led de puissance et d'un mosfet IRF 9530. |500x375

Voici le montage final avec la platine d'essai : |500x375

La PWM est généré par un signal carré de fréquence 32 KHZ Le hacheur est alimenté à 8.4 V j'ai préferer utiliser un mosfet IRF9530 au lieu d'un transistors TIP 122 car une mosfet à une haute impédance et ne demande qu'un petit courant pour s'allumer.

L'utilisation de la diode schottky fait office de protection des autres composants. Elle a un temps de commutation trés court ce qui lui permet d'être trés réactive.

Suite à la commande de la LED avec le CI FL7760 de mar 19 2019 précèdent

On souhaite réaliser un programme pour augmenter le rapport cyclique de la PWM, de 0% à 100% avec un pas de 10%, par l’appui d’un bouton poussoir. Ce circuit demande une pwm de dimming minimale de 2kHz.

Mais comment gérer l’incrément de cette PWM avec le bouton poussoir ?

Pour vérifier notre programme, nous l’avons simulé avec ISIS, avec une carte Arduino Nano, donc nous avons utilisé le pin 3 pour la PWM et le pin 2 pour notre bouton poussoir.

Dans le setup de notre programme, on déclare le pin connecté au bouton poussoir comme une entrée et la PWM comme une sortie (voir figure ci-dessous).

|500x124

Fonction Loop :

Nous avons déclaré et initialisé un boolean « relâcher_bouton » qui nous permettra d’augmenter l’intensité lorsque on relâche le bouton poussoir. La variable intensité ne peut que varier de 0 à 255 car à « analogWrite() » avec Atmel 328 est sur 8bit. Donc pour cela nous avons créé une condition : si l’intensité est supérieure à 255 on revient à 0 qui permettra d’éteindre la LEDde puissance. Au niveau de l’affichage, on affiche la valeur de la variable pourcentage, cette variable reçoit la valeur de l’intensité en pourcentage, en sorte que analogWrite (PWM,255) demande un cycle de travail de 100 % et analogWrite(PWM,127) correspond à un cycle de travail à 50%.

Voici le programme de la fonction loop :

void loop() {  
  lcd.setCursor(0,0); // position du cousor en haut à gauche 
  analogWrite(3, intensite);    //on envoie sur le pignal PWM la valeur de l'intensité
  lcd.print("Duty cycle ");lcd.print(pourcentage);lcd.print("%  "); // affichage du rapport cyclique
  boolean relacher_bouton= false; 
    
  if(digitalRead(bouton)==HIGH){ // si on appuie sur le bouton alors
    while(!relacher_bouton){      // on rentre dans cette boucle jusqu'à ce qu'on relâche le bouton
      if(digitalRead(bouton)==LOW){ // si on relâche le bouton alors 
        relacher_bouton=true; // relâcher_bouton est vrai et
        intensite=intensite+25.5; // dès qu'on rêlache le bouton, on augmenté l'intensité
        if (intensite > 255){ // si le rapport cyclique arrive à 255, soit 100% alors
          intensite=0; //Reviens à 0
        }      
        pourcentage = ((100*intensite)/255); //formule pour afficher le rapport cyclique en pourcentage
      }
    }
  }
}

Voyons la simulation sur ISIS, on remarque bien que pour un rapport cyclique de 30 %, nous avons 1,8 carreaux à 5V sur 6 ce qui correspond à 0,3=1.8/6 donc 30%.

|500x350">

De même, pour un rapport cyclique de 90%, on remarque que 5,4 carreaux sont à 5V sur 6 ce qui corresponde à 0,9=5.4/6 donc 90%

|500x348">

Ci-dessous le programme complet réalisé sur Arduino

#include 

int bouton = 2;  //init bouton 
float intensite=0;
int pourcentage=0;
LiquidCrystal lcd(9,8,4,5,6,7); 

void setup() {
  pinMode(3, OUTPUT); // PWM en sortie 
  pinMode(bouton, INPUT); // Bouton en entrée
  TCCR2B = (TCCR2B & 0b11111000) | 0x01;         //pin 10  32khz    http://playground.arduino.cc/Main/TimerPWMCheatsheet                                       
}

void loop() {  
  lcd.setCursor(0,0); // position du cousor en haut à gauche 
  analogWrite(3, intensite);    //on envoie sur le pignal PWM la valeur de l'intensité
  lcd.print("Duty cycle ");lcd.print(pourcentage);lcd.print("%  "); // affichage du rapport cyclique
  boolean relacher_bouton= false; 
    
  if(digitalRead(bouton)==HIGH){ // si on appuie sur le bouton alors
    while(!relacher_bouton){      // on rentre dans cette boucle jusqu'à ce qu'on relâche le bouton
      if(digitalRead(bouton)==LOW){ // si on relâche le bouton alors 
        relacher_bouton=true; // relâcher_bouton est vrai et
        intensite=intensite+25.5; // dès qu'on rêlache le bouton, on augmenté l'intensité
        if (intensite > 255){ // si le rapport cyclique arrive à 255, soit 100% alors
          intensite=0; //Reviens à 0
        }      
        pourcentage = ((100*intensite)/255); //formule pour afficher le rapport cyclique en pourcentage
      }
    }
  }
}

Communication avec Arduino:

Le MPU6050 utilise le protocole de communication I²C dont la connexion est réalisée par l'intermédiaire de deux lignes : • SDA (Serial Data Line) : ligne de données bidirectionnelle • SCL (Serial Clock Line) : ligne d'horloge de synchronisation bidirectionnelle Dans le monde Arduino, il existe une librairie dédiée à ce protocole : Wire. En lisant la doc de la librairie Wire Arduino, on voit que sur un Arduino NANO ce sont les entrées analogiques A4 et A5 qui correspondent respectivement à SDA et SCL. On câble donc tout cela ensemble. Le MPU a besoin d'être alimenté en 3.3V, on relie donc la broche Vcc à la broche 3.3V de l'Arduino et le GND au GND de l'Arduino. Ce qui nous donne au final ce câblage :

|500x262

Configuration :

Sensibilité de l’accéléromètre :

Le registre ACCEL_CONFIG permet de configurer la plage de fonctionnement de l'accéléromètre.

Une plage de ±2g est suffisante pour l'étude, ce qui nous amène à utiliser le facteur AFS_SEL = 0

https://servimg.com/view/19537397/6 Structure du registre ACCEL_CONFIG

La paramètre AFS_SEL est codé sur les bits 3 & 4. La valeur 0 en binaire s'écrit alors 0 aussi. Les bits 0, 1 et 2 sont réservés, on les laisse donc à 0. Les bits 5, 6, 7 servent à effectuer un auto-test des axes X Y Z respectivement. Cela ne nous intéresse pas, on les laisse donc à 0.

Plus loin dans la datasheet, on arrive sur la page du registre Power Management. Ce registre nous permet de choisir la source d'horloge que le MPU va utiliser au travers du paramètre CLKSEL.

https://servimg.com/view/19537397/7

Nous allons utiliser ici son horloge interne de 8MHz, soit CLKSEL = 0.

|500x44

Structure du registre PWR_MGMT_1

Là encore, on voit que ce registre est codé sur 8 bits. CLKSEL est codé sur les bits 0, 1 & 2. La valeur 0 en binaire s'ecrit alors 000 Le bit 3 TEMP_DIS (temparture disabled) sert à désactiver la lecture de la température lorsqu'il est à 1. On va garder cette information, on laisse donc ce bit à 0. On laisse le reste à 0, ce qui nous donne au final 00000000 en binaire, soit 0x00 (hex). Enfin, l'adresse du registre est 0x6B en hexadécimal. Ce qui nous donne le code Arduino suivant :

Wire.beginTransmission(MPU);        // Start communication with MPU6050 // MPU=0x68
Wire.write(0x6B);                  // Talk to the register 6B
Wire.write(0x00);                  // Make reset - place a 0 into the 6B register

Filtre passe bas :

Le registre, de nom CONFIG, va nous servir à configurer la fréquence de coupure du filtre passe-bas de l'accéléromètre au travers du paramètre DLPF_CFG.

Digital Low Pass Filter

On va partir sur une fréquendce d'environ ~43Hz, ce qui nous amène à DLPF_CFG = 3. On laisse les autres bits à 0, ce qui nous amène à en binaire, soit 0x03 en hexadécimal. Enfin, l'adresse du registre est 0x1A en hexadécimal. Ce qui nous amène au code Arduino suivant :

Wire.write(0x1A);             // Request the CONFIG register
Wire.write(0x03);             // Apply the desired configuration to the register : DLPF about 43Hz

Fréquence d’horloge :

Plus loin dans la datasheet, on arrive sur la page du registre Power Management. Ce registre nous permet de choisir la source d'horloge que le MPU va utiliser au travers du paramètre CLKSEL. https://servimg.com/view/19537397/10 Nous allons utiliser ici son horloge interne de 8MHz, soit CLKSEL=0

|500x44

Structure du registre PWR_MGMT_1 Là encore, on voit que ce registre est codé sur 8 bits. CLKSEL est codé sur les bits 0, 1 & 2. La valeur 0 en binaire s'ecrit alors 000. Le bit 3 TEMP_DIS (temparture disabled) sert à désactiver la lecture de la température lorsqu'il est à 1. On va garder cette information, on laisse donc ce bit à 0. On laisse le reste à 0, ce qui nous donne au final 00000000 en binaire, soit 0x00 (hex). Enfin, l'adresse du registre est 0x6B en hexadécimal. Ce qui nous donne le code Arduino suivant :

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

LECTURE DES DONNEES BRUTES DU MPU6050 :

Maintenant que le MPU6050 est câblé et configuré, il ne reste plus qu'à lire les données brutes du capteur.

On constate dans la table des registres que les registres 59 à 64 stockent les valeurs de sorties de l'accéléromètre .

|500x209

On va donc simplement parcourir le contenu de ces 6 registres, en commençant à l'adresse 0x3B :

Wire.beginTransmission(MPU_ADDRESS);// Start communicating with the MPU-6050
Wire.write(0x3B);                   // Send the requested starting register
Wire.endTransmission(false);             // End the transmission
Wire.requestFrom(MPU_ADDRESS,6);   // Request 14 bytes from the MPU-6050

Mesure de l’accélération :

Un accéléromètre mesure l'accélération subite et l'exprime en g. 1g représente l'accélération de pesanteur sur Terre, soit environ 9,8m.s−29 et des bananes. L'accéléromètre au repos mesure donc une accélération de 1g.

Script intégral en C sur l’IDE Arduino :

#include // include la bibliothèque Wire.h

#define MPU_ADDRESS 0x68  // I2C address of the MPU-6050

#define X  0        // X axis
#define Y  1        // Y axis
#define Z  2        // Z axis
float acc_total_vector;

int acc_raw[3] = {0,0,0};

/**
* Configure la plage de fonctionnement de l'accéléromètre :
*  - accéléromètre: +/-2g

*
* @return void
*/
void setup() {
analogReference(EXTERNAL);
Serial.begin(19200);
Wire.begin();  
// 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 acceleromter's sensitivity
Wire.beginTransmission(MPU_ADDRESS); // Start communication with MPU
Wire.write(0x1C);                    // Request the ACCEL_CONFIG register
Wire.write(0x00);                    // Apply the desired configuration to the register : ±8g
Wire.endTransmission();              // End the transmission

// Configure low pass filter
Wire.beginTransmission(MPU_ADDRESS); // Start communication with MPU
Wire.write(0x1A);                    // Request the CONFIG register
Wire.write(0x00);                    // Set Digital Low Pass Filter about ~43Hz
Wire.endTransmission();              // End the transmission

Wire.endTransmission(true);        //end the transmission
}

void loop() {
Wire.beginTransmission(MPU_ADDRESS);// Start communicating with the MPU-6050
Wire.write(0x3B);                   // Send the requested starting register
Wire.endTransmission(false);             // End the transmission
Wire.requestFrom(MPU_ADDRESS,6);   // Request 14 bytes from the MPU-6050

// Wait until all the bytes are received
while(Wire.available() < 6);

acc_raw[X]  = (Wire.read() << 8 | Wire.read())/ 16384.0; // Add the low and high byte to the acc_raw[X] variable
acc_raw[Y]  = (Wire.read() << 8 | Wire.read())/ 16384.0; // Add the low and high byte to the acc_raw[Y] variable
acc_raw[Z]  = (Wire.read() << 8 | Wire.read())/ 16384.0; // Add the low and high byte to the acc_raw[Z] variable

acc_total_vector = sqrt(pow(acc_raw[X], 2) + pow(acc_raw[Y], 2) + pow(acc_raw[Z], 2));

Serial.print(acc_raw[X]);
Serial.print("/");
Serial.print(acc_raw[Y]);
Serial.print("/");
Serial.print(acc_raw[Z]);
Serial.print("/");
Serial.println(acc_total_vector);
delay(10);

}

Résultats moniteur Arduino:

1g suivant +X :

1g suivant -Y :

1g suivant +Z:

Conclusion:

Quant aux différents filtres, j’ai utilisé le filtre passe-bas numérique intégré dans le MPU6050 avec une bande passante d’environ 45Hz, quand j’essaie de bouger le capteur pour voir les réponses suivant plusieurs axes, les réponses sont quasi-stables dans le moniteur série d’IDE Arduino, le fait d’implanter des équations récurrentes de différents types de filtre (pass_bas pass_haut passe bande …), c’est facile, mais je n’y vois pas l’intérêt, car tous les résultats qu’on trouve sur le moniteur série Arduino, sont soit 1g suivant X soit 1g suivant Y soit 1g suivant Z.

Allumer un feu stop après un freinage ou un arrêt normal du vélo, est tout à fait possible avec un accéléromètre détectant la décélération, toutefois cela nécessite une étude comparatives de plusieurs accéléromètres analogiques et numériques, sans oublier les autres solutions technologiques pour répondre à cette problématique, comme par exemple un compteur de vitesse (Tr/min)

Pourquoi ne pas avoir utilisé une bibliothèque dédiée pour le MPU 6050 ?????? Mais en général, avec ces bibliothèques, la configuration est difficile…. donc c’est vraiment bien, ce que vous avez fait.

Est-ce que vous avez fait des essais du capteur MPU6050 dans une voiture et vérifier les dynamiques de l’accélération avec une application smartphone ???????

si tu mets

[url=https://servimg.com/view/19537397/16][img]https://i.servimg.com/u/f38/19/53/73/97/z10.png[/img][/url]

on verra l'image |173x500

Bref, les compteurs de vélos (odomètre capteur magnet KY03) qui mesurent la vitesse grâce à un compte tour de la roue pourrait aussi mesurer la décélération et activé un STOPT arrière. Mais quelle pourrait être la précision de cette méthode ? Faut-il mettre plusieurs aimants sur la roue ? Faut-il filtrer la valeur de la décélération ?

De plus, il existe des éclairages arrière vélos qui donnent la direction (clignotant droit et gauche) sans fil, mais sur un vélo, il n’y qu’à tendre la main à droite ou à gauche donc c’est inutile. Mais pour un velomobile (vélo caréné), cela est intéressant http://velorizontal.1fr1.net/t17956-velomobile-electric-leiba-x-stream-iut-aisne |500x375 Voici un bel article avec 2 arduinos et une communication bluetooth https://create.arduino.cc/projecthub/simonwongwong/bluetooth-enabled-bicycle-turn-signal-2f4f5d Mais les matrices de leds ne permettent pas d’être vu de jour (pas assez de lumen)

L’article suivant utilise une télécommande 4 boutons https://github.com/sdebby/Arduino_bike_blink Donc une télécommande et un récepteur, voici en voici l’électronique http://www.wzmicro.com/rf.htm Cela ne coute rien, mais il faudra mettre le compteur de vélo sur l’Arduino arrière pour avoir un feu stop |500x260

Donc, un compteur vélo avec Bluetooth va être réalisé et commander l’éclairage arrière comme on peut l’observer sur la figure suivante. Le compteur avec son afficher a permis de vérifier le bon fonctionnement de la programmation et s’il fallait filtrer la mesure de la décélération Il faudra prendre des Arduino Pro et pas nano pour leurs faibles consommations sur la batterie. Mais pour vérifier la programmation le nano a été utilisé. |500x305 L’indication droite et gauche est évidemment clignotante ainsi que le stop et lors de la décélération. Mais on aurait pu mettre une 4éme led, pour un feu stop mais cela n’a pas été fait. Le bouton poussoir stop est inutile, puisque la décélération est mesurée et active automatiquement l’éclairage arrière.

Le compteur vélo a 4 aimants sur la roue pour augmenter la précision des mesures de la vitesse dans les basses vitesses. Avec l’utilisation de la mesure en milliseonde à chaque quart de roue L’erreur de la vitesse est déterminée par l’équation suivante avec 4 aimants DeltaVitesse=(2010*3.6/4)/(Timer+1)( Timer) pour Timer=25ms=>2.78km/h pour vitesse 72km/h La précision correspond à l’équation suivante Précision=1/(Timer+1) donc à 72km/h précisons de 3.8% et à 18km/h 1%

Etant donné que l’accélération est déterminée aussi pour chaque quart de roue tournée, l’erreur de l’accélération correspondra aux équations suivantes DeltaAccelera=(277)/(Timer+1)( Timer) pour Timer=25ms=>0.42m/s^2 pour vitesse 72km/h DeltaAccelera=(277)/(Timer+1)( Timer) pour Timer=100ms=>0.027m/s^2 pour vitesse 18km/h

Pour ne pas avoir de décélération intempestive, le calcul de la décélération se fera seulement si l’erreur de mesure de la vitesse est plus faible que sa variation. Etant donné que la propriété de la routine d’interruption extérieure n’est pas si facile à imposer par rapport à routine d’interruption timer sur Atmel, il n’y aura pas d’interruption timer.

Voici le code

#include 
#include 
//#include 


#define led13     13       //    
#define BPLeft    12       // 
#define Night     11       // 
#define BPRight   10       //
#define BPStop     9       //


LiquidCrystal lcd(8, 3, 4, 5, 6, 7);   // LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
// Configuration des variables

 float Time=0; 
 float  TO=0; 
 float  temps=0; 
 float  Time1=0;               
            float kph=0;
            float kph1=0;
            float distance=0;

            float deceler=0;
            float erreur=0;
            bool stop=0;
            bool flagnight=0;
            bool attendre=0;
            
            byte   buffer1=0; 
            String readString;

// the setup function runs once when you press reset or power the board
void setup() {

pinMode(led13, OUTPUT);   //led carte arduino
pinMode (BPLeft, INPUT_PULLUP);
pinMode (Night, INPUT_PULLUP);
pinMode (BPRight, INPUT_PULLUP);
pinMode (BPStop, INPUT_PULLUP);

 lcd.begin(16, 2);                   //modifier pour un afficheur 20x4
 Serial.begin(9600);     //57600
 //SoftwareSerial mySerial(0, 1);   // RX, TX mais il n'y a pas trop le choix sur la nano


//  Timer1.initialize(10000);           // initialize timer1, and set a 0,1 second period =>  100 000  pour 0.01s  10 000
//  Timer1.attachInterrupt(Routinetimer1);   // attaches le sous programme  Routinetimer1 as a timer overflow interrupt

  TCCR2B = (TCCR2B & 0b11111000) | 0x01;         //pin 3  32khz    

attachInterrupt(0, interrup2, RISING);   // il vaut mieux utiliser  KY003 tout ou rien   RISING, FALLING, CHANGE
TO = millis();                                   
}//fin setup

void interrup2() // la fonction appelée par l'interruption externe n°0
{//digitalWrite(led13,HIGH);
Time=(millis()-TO);  //mesure du temps     //micros()    millis()
TO=millis();

distance=(distance+(2.01/4));     //perimetre/4 aimants
kph1=kph;                            
if (Time>=500) {kph=0;deceler=0; } 
          else {kph=((2.010*1000*3.6)/(Time*4));   //kph=perimetre/time  avec 4 aimants   //
                erreur=(kph/(Time-2));                                                                             
                if ( (kph<(kph1-erreur)))  {deceler=(((kph-kph1)*277)/Time);} else {deceler=0;}   
                }              // en m/s^2  277=1000milliseconde/3.6      
if (deceler<-40) {deceler=-40; }
if (deceler>40) {deceler=40; }
//  digitalWrite(led13,LOW);   de la routine interr exterieur durée 0.7ms 
}



// Interruptions  tous les 100ms fait par le timer1***********************************

//void Routinetimer1()  {
//  temps++;  
//}//fin routineinterruption


///////////////////////////////////////////// Boucle correspondant à la fonction main 
void loop() {  
Time1=(millis()-TO);
if (Time1>=500) {kph=0;deceler=0;}   //remise à 0, lorsqu'il n'y a plus d'interruption
attendre=0;

  lcd.setCursor(0,0);  // (X,Y)                               
  lcd.print(kph,1);
  lcd.print("kph    "); 
  lcd.setCursor(9,0);  // (X,Y)                                
  lcd.print(distance/1000,2);
  lcd.print("km  ");

    lcd.setCursor(0,1);  // (X,Y)                            
    lcd.print(deceler,1);
    lcd.print("m/s"); 
    lcd.print((char)94);
    lcd.print("2 "); 

    if  (deceler<(-2)) {stop=1;lcd.setCursor(10,1);lcd.print("STOP");Serial.print(2); }  
    if  (deceler>0)    {stop=0,lcd.setCursor(10,1);lcd.print("    "); }
    if  (digitalRead(BPStop)==0) {stop=1;lcd.setCursor(10,1);lcd.print("STOP");Serial.print(2); }  
    if (digitalRead(BPLeft)==0)     {Serial.print(1); } 
    if (digitalRead(BPRight)==0 )   {Serial.print(3); } 
    if (digitalRead(BPRight)==0 && digitalRead(BPStop)==0   )    {distance=0;}   //remise à zero du compteur
    if  (digitalRead(BPStop)==0) {stop=1;lcd.setCursor(10,1);lcd.print("STOP");Serial.print(2); }
 if ((digitalRead(Night)==0) && (flagnight==0) && attendre==0 )      {flagnight=1;Serial.print(0);attendre=1; }   //eteindre la lumiere
 if ((digitalRead(Night)==0) && (flagnight==1) && attendre==0)      {flagnight=0;Serial.print(4);attendre=1;}   //allume lumiere
 if (flagnight==1)  {lcd.setCursor(15,0);lcd.print("N"); }      //lumiere
 if (flagnight==0)  {lcd.setCursor(15,0);lcd.print(" "); } 

/*Serial.print(Time,0);
Serial.print(";");
Serial.print(kph,1);
Serial.print(";");
Serial.print(deceler,1);
Serial.println(";");  */
delay(100);             
   
} // fin loop

la suite du post precedent

Voici le résultat de la mesure de la vitesse et la deceleration avec excel, du programme precedent |500x389

Pas envie de mettre 2 fils d’alimentation et 1 fil de communication entre le compteur et l’éclairage arrière entre le compteur et la partie éclairage arrière. Donc une commination série Bluetooth HC06 a été choisie. Il sera possible d’indiquer sur le compteur rétroéclairer, l’état de la batterie arrière.

Le code de la récepteur et qui gère le clignotement

#include 
#include 
//#include 


#define led12     12       // 
#define led11     11       // 
#define led10     10       // 

            byte  temps12=0;
            byte  temps11=0; 
            byte  temps10=0;
            byte c=0;
            bool flag12=0;
            bool flag11=0;
            bool flag10=0;
            bool flagnight=0;
            


void setup() {
pinMode(led12, OUTPUT);   //lumiere gauche, direction
pinMode(led11, OUTPUT);   //lumiere centrale, stop et eclairage
pinMode(led10, OUTPUT);   //lumiere gauche, direction


Serial.begin(9600);     
 //SoftwareSerial Serial(0, 1);   // RX, TX mais il n'y a pas trop le choix sur la nano

 Timer1.initialize(400000);           // initialize timer1, and set a 0,1 second period =>  100 000  pour 0.01s  10 000
 Timer1.attachInterrupt(Routinetimer1);   // attaches le sous programme  Routinetimer1 as a timer overflow interrupt
                            
}//fin setup




// Interruptions  tous les 400ms fait par le timer1***********************************
void Routinetimer1()  {
  temps12++;
  temps11++;
  temps10++;
if (temps12<15 && flag12==1)  {if ( digitalRead(12)== 1 ) {digitalWrite(12,LOW);}  else {digitalWrite(12,HIGH);}}  //clignotement pendant 15=6s/0.4s  gauche
if (temps12>15 && flag12==1)  {flag12=0;digitalWrite(led12,LOW);} 

if (temps10<15 && flag10==1)  {if ( digitalRead(10)== 1 ) {digitalWrite(10,LOW);}  else {digitalWrite(10,HIGH);}}  //clignotement pendant 15=6s/0.4s droite
if (temps10>15 && flag10==1)  {flag10=0;digitalWrite(led10,LOW);} 

if (temps11<15 && flag11==1)  {if ( digitalRead(11)== 1 ) {digitalWrite(11,LOW);}  else {digitalWrite(11,HIGH);}}  //clignotement pendant 15=6s/0.4s stop
if (temps11>15 && flag11==1)  {flag11=0; 
                               if (flagnight==1) {digitalWrite(11,HIGH);}
                               if (flagnight==0) {digitalWrite(11,LOW);}
                              } 
}//fin routineinterruption



///////////////////////////////////////////// Boucle correspondant à la fonction main 
void loop() {  

while (Serial.available()) { c=Serial.read();//Serial.print(c,DEC);  
if (c==48)        {digitalWrite(led11,LOW);flagnight=0;}       //0 arret en continu
if (c==49)        {digitalWrite(led12,HIGH);digitalWrite(led10,LOW);flag12=1;flag10=0;temps12=0;}        //1  direction gauche +5s
if (c==50)        {digitalWrite(led11,HIGH);flag11=1;temps11=0;}                                         //2  feu stop
if (c==51)        {digitalWrite(led10,HIGH);digitalWrite(led12,LOW);flag10=1;flag12=0;temps10=0;}        //3  direction droite +5s
if (c==52)        {digitalWrite(led11,HIGH);flagnight=1;}                                                //4  allumage en continu
                            }

} // fin loop

A la place de faire de nombreux essais, sur le vélo pour vérifier le programme de la mesure vitesse et de la décélération, un Arduino génère les impulsions de l’aimant. |500x208

Voici le code du générateur de front qui fait varier la vitesse pour verifier le bon fonctionnement du programme

#include 
#include 
#include 
#include 



#define led12     12       // 



LiquidCrystal lcd(9, 3, 4, 5, 6, 7);   // LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
// Configuration des variables



unsigned    int   temps=0; 
unsigned    int tempsmono=0;
            float  tempsperiode=0;
            float   tempsdecelerat;
            float  tempsdec=0;
            float  a=0;
            float  b=0;
            float deceleration;
            bool flag;
            

// the setup function runs once when you press reset or power the board
void setup() {


pinMode(led12, OUTPUT);   //

 Serial.begin(9600);     //57600

  Timer1.initialize(1000);           // initialize timer1, and set a 0,1 second period =>  100 000  pour 0.01s  10 000
  Timer1.attachInterrupt(Routinetimer1);   // attaches le sous programme  Routinetimer1 as a timer overflow interrupt

  TCCR2B = (TCCR2B & 0b11111000) | 0x01;         //pin 3  32khz    


  a=0.144;                 //((400-40)/tdecel);   400  correspond à 4.5km/h , 40 à 45km/h utilsation 4 aimants    (4.5-45)/(2.5s*3.6)=4.5m/s^2
  b=40;                    //coefficient de le deceleration
    Serial.print(a,3);
    Serial.print(";");
    Serial.println(b,3) ;                               
}//fin setup



// Interruptions  tous les 1ms fait par le timer1***********************************
void Routinetimer1()  {
temps++;
tempsperiode++;
tempsmono++;

//*
if (tempsperiode<50)  {deceleration=2000;}     //creation profil acceleration et decele
if (tempsperiode>=50 &&  tempsperiode<2500)  {deceleration=-0.2*(tempsperiode-50)+400;        
                                              if (deceleration<40) {deceleration=40;}
                                              }    //acceleration
if (tempsperiode>=2500 &&  tempsperiode<3500)  {deceleration=40;}                                               
if (tempsperiode>=3500 &&  tempsperiode<6000)  {deceleration=a*(tempsperiode-3500)+b;}      //deceleration  

if (tempsperiode>=6000 && tempsperiode<7000 )  {deceleration=1000;}
if (tempsperiode>=7000)  {tempsperiode=0;} 
//*/
               
//Serial.print(tempsperiode,0) ; 
//Serial.print(";"); 
//Serial.println(deceleration,0) ;     
//deceleration=40;           //4 aimants,  400=>4.5km/h   40=>45km/h    valeur fixe de vitesse
   
if (temps>=deceleration  && flag==0) {digitalWrite(led12,HIGH);tempsmono=0;flag=1;temps=0; }  //monostable=10ms
if (flag==1 && tempsmono>=4)        {digitalWrite(led12,LOW);flag=0;} 




}//fin routineinterruption


///////////////////////////////////////////// Boucle correspondant à la fonction main 
void loop() {  



} // fin loop

Avec la batterie, du compteur, on pourrait faire aussi un éclairage blanc vers l’avant Mais, cela sera une autre histoire….

Voici le programme du capteur accéléromètre MPU6050 mais avec un ESP32+OLED et un filtre passe bas du troisième ordre, pour un éclairage automatique arrière de vélo. |500x252 La méthode de test et des explications sont téléchargeables sur ce lien https://www.fichier-pdf.fr/2020/09/17/esp32-mpu6050-arduino-filtre-passe-bas-1hz/

#include "Arduino.h"
#include "heltec.h"
#include "Wire.h"
//#include "BluetoothSerial.h"    //https://randomnerdtutorials.com/esp32-bluetooth-classic-arduino-ide/
                                  //


#define MPU_ADDRESS 0x68  // I2C address of the MPU-6050
int Te=100000  ; //periode d'echantillonnage micro seconde  =>0.1s

int16_t accX=0;
int16_t accY=0;
int16_t accZ=0;

 float accX_0=0;
 float accY_0=0;
 float accZ_0=0;

float accY_1 = 0;  // recurence n-1
float accY_2 = 0;  // recurence n-2
float accY_3 = 0;  // recurence n-3
float YaFout=0;
float YaF =0;
float YaF1 =0;
float YaF2 =0;
float YaF3 =0;

float  Y[127];     //12.7s



byte var=1;
byte i=0;   //incrementation for te curve
bool flagmesure=1;
bool flagenvoie=1;
bool flagstop=0;
bool flagfrein=0;
bool flagrear=0;
bool flaglight=0;
int16_t temps=0;
int16_t tensionbatt;




hw_timer_t * timer = NULL;
portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED;
uint32_t cp0_regs[18];

//******************************************************************
void IRAM_ATTR onTimer() {      //IRAM et DRAM   routine d'interruption toutes les TE 0.1s 
//digitalWrite(33,HIGH); 
 portENTER_CRITICAL_ISR(&timerMux);

xthal_set_cpenable(1);  xthal_save_cp0(cp0_regs);   // // Save FPU registers
if ( digitalRead(25)== 1 ) {digitalWrite(25,LOW);}  else {digitalWrite(25,HIGH);}    //led sur la carte heltec

flagmesure=1;
     
  xthal_restore_cp0(cp0_regs);  xthal_set_cpenable(0);  // and turn it back off
  portEXIT_CRITICAL_ISR(&timerMux);
  
//  digitalWrite(33,LOW);
}//fin routine interrupt







//*********************************
void setup(){
pinMode(0, INPUT_PULLUP);   //bouton prg carte heltec ESP32
pinMode(25, OUTPUT);   //led
//pinMode(13, OUTPUT);   //mesure temps instruction oscilloscope
pinMode(21, OUTPUT);   // lecture batterie lithium

 Serial.begin(115200);

 Wire.begin(4,15,400000);       //Wire.begin(I2C_SDA, I2C_SCL);       0x3C oled   et MPU6050  broche 4 et 15

  Heltec.begin(true /*DisplayEnable Enable*/, false /*LoRa Disable*/, true /*Serial Enable*/);
  Heltec.display->flipScreenVertically();
  Heltec.display->setFont(ArialMT_Plain_24);           //10, 16, 24
  Heltec.display->setTextAlignment(TEXT_ALIGN_LEFT);


Wire.beginTransmission(MPU_ADDRESS);
 Wire.write(0x6B);  // PWR_MGMT_1 register
 Wire.write(0x00);     // set to zero (wakes up the MPU-6050)
 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(0x00);                     // Apply the desired configuration to the register : ±2g=±20ms^-2     1g=16384
//Wire.write(0b00010000);             // Apply the desired configuration to the register : ±8g=±20ms^-2  1g=4096
Wire.endTransmission();              // End the transmission

// Configure low pass filter
Wire.beginTransmission(MPU_ADDRESS); // Start communication with MPU
Wire.write(0x1A);                    // Request the CONFIG register
//Wire.write(0x00);                    // Set Digital Low Pass Filter about ~260Hz   DLPF_CFG
Wire.write(0x06);                    // Set Digital Low Pass Filter about ~5Hz   DLPF_CFG
Wire.endTransmission();              // End the transmission

Wire.endTransmission(true);        //end the transmission

  timer = timerBegin(0, 80, true);
  timerAttachInterrupt(timer, &onTimer, true);
  timerAlarmWrite(timer, Te, true);      
  timerAlarmEnable(timer);

}


//************************
void loop(){

//if ( digitalRead(13)== 1 ) {digitalWrite(13,LOW);}  else {digitalWrite(13,HIGH);}     //teste du temps de la boucle
if (digitalRead(0)==0)   {var++;delay(1500); }    //utilisation du bouton prg de la carte ESP32 heltec
if (var>=5)   {var=1;flagenvoie=1; }              //4 valeurs pour afficher les valeurs numeriques ou courbes ou pause ou envoie des données
if ( touchRead(13)<30 )   {flagfrein=1;} else {flagfrein=0;}    //touchRead(13)



if ((flagmesure==1 && (var==1 | var==2)))   {    //mesure tous les 0.1ms
  temps++;
Wire.beginTransmission(MPU_ADDRESS);
Wire.write(0x3B);  // starting with register 0x3B (ACCEL_XOUT_H)
Wire.endTransmission(false);           // End the transmission
Wire.requestFrom(MPU_ADDRESS,6);   // Request 16 bytes from the MPU-6050

// Wait until all the bytes are received
while(Wire.available() < 6);

accX  = (Wire.read() << 8 | Wire.read()); // reading registers: 0x3B et 0x3C     MSB et LSB
accY  = (Wire.read() << 8 | Wire.read()); // reading registers: 0x3D 
accZ  = (Wire.read() << 8 | Wire.read()); // reading registers: 0x3F 

accX_0=accX/1638.0;   //en m/s^2  pour initilisation à 2*gravitation
accY_0=accY/1638.0;
accZ_0=accZ/1638.0;

accY_3=accY_2;
accY_2=accY_1;  //recurence n-2
accY_1=accY_0;  //recurence n-1

YaF3=YaF2;
YaF2=YaF1;
YaF1=YaF;         //filtre numerique passe bas 3éme orde Frequence de coupure=1Hz
YaF=accY_0+3*accY_1+3*accY_2+3*accY_3+0.278059*YaF3-1.18289*YaF2+1.76*YaF1;   //filtre numerique passe bas  Frequence de coupure=1Hz
YaFout=YaF/66;        //55 en theorie

i++;
if (i>=127) {i=0;}
//Y[i]=accY_0;    //sans filtre
Y[i]=YaFout;      //avec filtre    

if (YaFout>=2)  {flagstop=1;temps=0;}     //declenchement lumiere peandant 5seconde clignotant
if (YaFout<=-1) {flagstop=0;flagrear=0;temps=0;flaglight=0;}   //si acceleration arret lumiere arriere
if (flagstop==1 && temps<=50) {flagrear=1;}
if (temps>50) {flagrear=0;flaglight=0;}   
if (flagrear==1) {       if (flaglight== 1) {flaglight=0;}  else {flaglight=1;}     }  
                      

flagmesure=0;
 }  //fin if flagmesure




switch (var) {
  case 1:        //affichage value
//mesure de la charge de la batterie lithium 18650
digitalWrite(21,LOW);                    //active le pont diviseur
tensionbatt=analogRead(37);              //avec pont diviseur 100K et 220k  4.2V=>1.3125  donc 1630 decimale
tensionbatt=(tensionbatt/39+4);      //(volt*10) 12 bits 4096    0.35V chute de tension dans le transitor     3.3*3.2/409.6=1/39
tensionbatt = map(tensionbatt, 30, 42, 0, 100);    //map(value, fromLow, fromHigh, toLow, toHigh)   % de la charge
                                                   //2.9V=>-8%   3V=>0%    4.2V=100%    

//affichage  acceleration Y et  poucentage de la charge de la batterie
Heltec.display->clear();       //affichage numerique acceleration si appuie sur PRG
//Heltec.display->drawString(0, 0, "IUT GEII Soissons"); 
//Heltec.display->drawString(0, 11, "X "+String(accX_0,1)+"   ");
Heltec.display->drawString(0, 0, "Y "+String(accY_0,1)+"  ");          //acceleration filtré à 5HZ par le MPU6050
Heltec.display->drawString(83,0, String(tensionbatt)+"%");           //en poucentage de la charge
Heltec.display->drawString(0, 25,"Yf"+String(YaFout,1)+"   ");
Heltec.display->drawString(83, 25,String(flagfrein));
Heltec.display->drawString(100, 25,String(flaglight));
Heltec.display->display(); 
 break;  //case 1

case 2:       //affichage curve 
 Heltec.display->clear(); 
 Heltec.display->drawHorizontalLine(0,32,127);  //(x,y,length)      //trace les axes
 for (byte im = 0; im <= 127; im++) {    // affichage de la courbe
 Heltec.display->setPixel(im,(32-Y[im]*3));   //mettre la courbe au millieu et augmenter l'echelle de 3
 Heltec.display->display();  }
 break;  //case 2

case 3:       //mode pause

break;  //case 3



case 4:       //send data monitor 
if (flagenvoie>=1) {
 for (byte im = 0; im <= 127; im++) {    // affichage de la courbe
 Serial.print( Y[im]);Serial.println(";"); }
 Serial.println("stop");
flagenvoie=0;     }
break;  //case 4


 }//end switch 


 }//end loop

Le programme complet avec l’odomètre arrive, mais le programme sera moins lisible, donc on préfère le décomposer en plusieurs programmes.

Voici le programme du compteur de velo avec un capteur a effet hall et un aimant avec un ESP32+OLED qui gere plus facilement la commande du feu arriére que le capteur d’acceleration.
Les explications sont ici
https://www.fichier-pdf.fr/2020/10/02/esp32-odometre-alarme-capacimetrertc-heure/
le MPU6050 a été gardé pour realiser une alarme.
Il reste plus qu’à faire un tracker avec un GPS et l’envoie d’une notification……
Mais aussi realiser un boitier mécanique étanche, car pour l’instant ce n’est pas terrible


on va s’inpirer du boitier suivant

esp32_odometre_mpu6050_V3.ino (13.1 KB)

J’ai essayé votre programme sur un ESP32 TTGO avec un oled couleur d'aliexpress Mais j’ai un souci car je n’arrive pas à afficher quelques choses sur le oled pourtant j’ai bien télécharge les bibliothèques comme expliqué ici, ainsi que d’inclure les chemins ou sont les bibliothèques et le driver. cela compile bien https://github.com/Xinyuan-LilyGO/TTGO-T-Display https://www.instructables.com/Select-Color-Display-for-ESP32/

La variable i s’incrémente bien sur le moniteur série donc l’ESP32 fonctionne Pourriez-vous m’eclairer, SVP, car je suis dans le brouillard

Je mets le minimum du programme pour faire fonctionner le oled ici

#include 
#include 
//#include "WiFi.h"
#include 
//#include 
#include "esp_adc_cal.h"

#include 
//#include 
//#include  


//#include  
//#include 


//#define ST7789_DRIVER
//#define ILI9341_DRIVER

//#define CGRAM_OFFSET      // Library will add offsets required


//#define TFT_MOSI            19    //SDA
//#define TFT_SCLK            18    //SCL
//#define TFT_CS              5     //CS
//#define TFT_DC              16    //RS
//#define TFT_RST             23    //reset

//#define TFT_BL          4  // Display backlight control pin

#define TFT_BACKLIGHT_ON HIGH  // HIGH or LOW light OLED or not



//#define TFT_WIDTH  135
//#define TFT_HEIGHT 240
TFT_eSPI tft = TFT_eSPI (TFT_WIDTH, TFT_HEIGHT);  // édité



/*
#define LOAD_GLCD
#define LOAD_FONT2
#define LOAD_FONT4
#define LOAD_FONT6
#define LOAD_FONT7
#define LOAD_FONT8
#define LOAD_GFXFF

#define SMOOTH_FONT
*/


//#define SPI_FREQUENCY  27000000
//#define SPI_FREQUENCY    40000000   // Maximum for ILI9341


//#define SPI_READ_FREQUENCY  6000000 // 6 MHz is the maximum SPI read speed for the ST7789V

char buff[512];
int vref = 1100;
int i;

#define ADC_PIN 34

void setup()
{
  
Serial.begin(115200);

pinMode(2, OUTPUT);   //led
//pinMode(34, INPUT);   //led

tft.init();
tft.setRotation(1);
tft.fillScreen(TFT_BLACK);
tft.setTextSize(2);
tft.setTextColor(TFT_WHITE);
tft.setCursor(0, 0);
tft.setTextDatum(MC_DATUM);


if (TFT_BL > 0) { // TFT_BL has been set in the TFT_eSPI library in the User Setup file TTGO_T_Display.h
         pinMode(TFT_BL, OUTPUT); // Set backlight pin to output mode
         digitalWrite(TFT_BL, TFT_BACKLIGHT_ON); // Turn backlight on. TFT_BACKLIGHT_ON has been set in the TFT_eSPI library in the User Setup file TTGO_T_Display.h
    }
    

tft.setTextSize(1);
uint16_t v = analogRead(ADC_PIN);
float battery_voltage = ((float)v / 4095.0) * 2.0 * 3.3 * (vref / 1000.0);
String voltage = "Voltage :" + String(battery_voltage) + "V";
Serial.println(voltage);
tft.fillScreen(TFT_BLACK);
tft.setTextDatum(MC_DATUM);
tft.drawString(voltage, tft.width() / 2, tft.height() / 2 );
delay(1000);
tft.drawString("Press again to wake up", tft.width() / 2, tft.height() / 2 );
delay(1000);

     tft.fillRect(0,0,240,135, TFT_BLUE); // erase the screen display
     tft.setTextSize(3);   // (num colonne , num ligne)
     tft.setCursor(0, 35); // (x colonne , y ligne) - F6CZV
     tft.print("VFO"); // F6CZV
delay(1000);

}




void loop()
{
  i++;
  if ( digitalRead(2)== 1 ) {digitalWrite(2,LOW);}  else {digitalWrite(2,HIGH);}
  Serial.println(i);
//tft.setRotation(0);

tft.fillScreen(TFT_RED);
delay(1000);
tft.fillScreen(TFT_BLUE);
//espDelay(1000);
delay(1000);
tft.fillScreen(TFT_GREEN);
delay(1000);
}

il y a une instrumentation de velo sur ce forum ici, j’ai envoyé un mail mais sans reponse http://cyclurba.fr/forum/570020/dn-codage-protocole-sn-rie-bbs0x.html?from=571&discussionID=18542&messageID=638753&rubriqueID=102&pageprec

Ca peut venir du fait que le constructeur

TFT_eSPI tft = TFT_eSPI(135, 240); // Invoke custom library

est avant les define des pins du SPI.

J'utilise ce même module TTGO et ça fonctionne bien. Il faut sélectionner

#define ILI9341_DRIVER

dans le fichier User_Setup.h de la bibliothèque TFT_eSPI. Les autres lignes doivent commentées :

// Only define one driver, the other ones must be commented out
#define ILI9341_DRIVER
//#define ST7735_DRIVER      // Define additional parameters below for this display
//#define ILI9163_DRIVER     // Define additional parameters below for this display
//#define S6D02A1_DRIVER
//#define RPI_ILI9486_DRIVER // 20MHz maximum SPI
//#define HX8357D_DRIVER
//#define ILI9481_DRIVER
//#define ILI9486_DRIVER
//#define ILI9488_DRIVER     // WARNING: Do not connect ILI9488 display SDO to MISO if other devices share the SPI bus (TFT SDO does NOT tristate when CS is high)
//#define ST7789_DRIVER      // Full configuration option, define additional parameters below for this display
//#define ST7789_2_DRIVER    // Minimal configuration option, define additional parameters below for this display
//#define R61581_DRIVER
//#define RM68140_DRIVER
//#define ST7796_DRIVER
//#define SSD1963_480_DRIVER    // Untested
//#define SSD1963_800_DRIVER    // Untested
//#define SSD1963_800ALT_DRIVER // Untested
1 Like

A partir d’un d’éclairage arrière chinois à 5€, un Arduino pro mini a été programmé pour optimiser les performances de l’éclairage de la LED en mode flash et d’optimiser l’autonomie. En effet, un capteur de luminosité permet de faire d’augmenter l’éclairage de la led lorsque la luminosité extérieure est importante pour être bien vu de jour, mais aussi par temps de brouillard. C’est éclairage est devenu le plus performant de ce qui existe sur la marché. https://www.fub.fr/tests-eclairages Mais, il est possible de paramétrer l’éclairage par Bluetooth comme on peut le voir sur la photo suivante |500x375 En PDF, la méthodologie et le programme pour optimiser l’éclairage et les choix effectués ainsi que le programme….. https://www.fichier-pdf.fr/2021/01/31/rear-light-bike-3w-arduino-nano-bluetooth-mpu6050-v1/

D’autres prototypes devraient voir le jour avec amélioration et la minimisation du volume de l’électronique et du boitier.

1 Like

Suite au PDF précèdent,

Pour minimiser le câblage et éviter le problème du téléchargement d’un nouveau sketch de devoir déconnecter le HC06 à cause qu’il transmet tout le temps

J’ai voulu remplacé le HC06 par le BLE NAN0
Mais, je suis très déçu du BLE keywish qui ne se gère pas du tout comme un HC06
le manuel est tres bien fait
[keywish-nano-plus/Ble-Nano operation manual V.1.6.pdf at master · keywish/keywish-nano-plus · GitHub](http://“https://github.com/keywish/keywish-nano-plus/blob/master/BLE-Nano/Ble-Nano operation manual V.1.6.pdf”)

Par contre, il faut utiliser leurs applications
BLETestToosV1.0.apk

Mais qui est en mandarin, j’arrive quand même à commander l’éclairage et lire les valeurs du bluetooth….mais plus possible d’utiliser l’application bluetoothelectronics
https://www.keuwl.com/apps/bluetoothelectronics/
J’ai essayé de modifier le paramétrage avec la commande AT, le BLE NANO mais sans succès
j’ai envoyé un mail au support keywish, sans reponse depuis 1 semaine

La consommation moyenne du BLE nano est de 6mA avec un envoie 33 caracteres tous les 0.1s

On a modifié le programme de test du courant pour voir une commande continu et de modifier la periode lors de test de nouvelle LED

exemple, on a rajouté 3 led de petite puissance pour etre vu sur le coté
L’éclairage sur le côté ne demande pas d’être vu à 150m, sachant que lorsque l’on a un éclairage de de 10Watt à l’avant son flux est visible de côté ainsi que la réflexion de l’éclairage sur le sol
Pour être vu de coté à 6m avec 0.7 lux sur une largeur de 2m, il faut un angle d’environ de 6°
Avec 1 lumen ou 14 candela comme le démontre les équations suivantes

Par conséquent, de petite leds faibles puissance (50mA). seront suffisantes de diametre 5mm.
(3 led seront utilisé, 2 sur le coté et une pour l’arriere).

2 solutions pour faire la commande des 3 leds (3*50mA).

  • soit utiliser une résistance de limitation de courant qui aura des pertes mais sera une commande très fiable.
  • soit utiliser un hacheur qui minimisera les pertes mais si la régulation de courant n’est pas correcte alors il y a un risque de destruction des led et du transistor de commande. Pour ce courant pas la peine de prendre un transistor super-dimensionné avec un boitier TO251 mais un petit boitier SOT23 suffira
    L’inductance sera aussi bien plus petite devant supporte seulement un courant 150mA.

exemple de choix de led __*C503B-RAS *__6° 50mA 15 candela.
en mode eclairement continu, on peut mesurer les lux à 50cm sur un mur

Toujours à 50cm l’éclairage en fonction du courant est bien correct autour de 50mA avec un coefficient de performance de 3200lux/A
Puis, au-delà de 0.1A, les performances de l’éclairage se dégradent fortement.

Voici la commande des 3 led avec hacheur en boucle ouverte et de la led de puissance en simulation

le programme de test des leds en mode continu et pediodique en piece jointe

MPU6050_nano_blue_v1.ino (6 KB)

Pour mesurer le courant et faire une boucle fermée de la régulation de courant, des transistors canal P sont utilisés. De plus, avec une tension d’alimentation de 3 à 4.2 V il n’y a plus besoin de mettre le transistor NPN pour driver le transistor canal P comme sur le schéma datant du 31 Janvier 2021.

L’Arduino NANO a été remplacé par un Arduino Pro mini car ce dernier consomme beaucoup moins d'énergie.

Le capteur de température sera retiré car la LED de puissance en mode flash aura un incrément de température faible de 2°C par rapport à la température ambiante, une fois que le rapport cyclique sera de 1/20 (temps allumé de 0.05s sur une période de 1s.

Voici le nouveau schéma électrique de simulation qui nous a permis de valider le fonctionnement global avec le transistor canal P :

|500x303

La boucle fermée de régulation numerique a été simulé sous Simulink, voici le résultat obtenu pour une consigne de 1A.

|500x108

Etant donné que le temps d'echantillon et faible par rapport à la constante de temps de la regulation, la fonction de transfert en laplace va etre determiner pour faire un choix de ki |459x500

A partir de la fonction de transfert precedente, la constante de temps de la régulation de courant correspond à l’équation suivante

Sur cette figure suivante de matlab, on voit que l’erreur statique du courant est nulle et que le temps de réponse est de 0.03s, grâce au correcteur Intégral ayant un ki=10. De meme, on peut observer que le courant est nul pendant 0.01s, cela correspond au temps pour que la tension du hacheur soit supérieure à la tension de seuil de la LED.

|500x356

Il faut tester les transistors MOS en réel pour vérifier que cela fonctionne malgré la variation de la tension dans la batterie.

1 Like

Une autre façon de travailler avec le transistor canal N tout en faisant la régulation du courant a été trouvée.

Voici la façon dont la solution a été trouvée :

Tout d’abord il a été ajouté sur le schéma datant du 31 janvier, une résistance de 1ohm à la source du transistor canal N car cela permet de mesurer une tension qui est l’image du courant, par exemple : s’il y a un courant de 1A à la source du transistor, la tension vaut : R*I=1*1=1V.

Voici le schéma :

|500x489

Résultat obtenu en simulation

Sur cette figure on voit bien que le courant mesuré ne correspond pas au courant souhaité car lorsque le transistor est bloqué le courant mesuré vaut 0 et lorsqu’il est passant on ne maîtrise pas la valeur mesurée.

|500x323

Afin de résoudre ce problème il a été ajouté un condensateur à la source du transistor de façon à avoir un montage RC à la source du transistor. Avec ce montage en jouant sur la constante de temps R.C il sera possible de mesurer le vrai courant sur la LED.

La valeur du condensateur a été calculée de la façon suivante comme pour un filtre du premier ordre qui donnera la valeur moyenne de la mesure du courant

De façon à ne plus voir les instants auxquels le transistor est soit bloqué ou soit passant, il faut que la constante de temps soit très supérieure à la période d’hachage.

La période d’hachage vaut 1/Freqhachage=1/64kHz=0.0000156S, donc il faut une constante de temps très supérieure à 0.0000156S.

La constante de temps vaut t=R*C, si C=47uF, R*C=1*47=0.0000047S, ce qui est très supérieure à la période d’hachage. Donc on prend une valeur de 47uF pour le condensateur.

Voici le schéma

|500x489

Résultat obtenu en simulation :

On voit bien que maintenant le courant mesuré correspond au courant moyen du transitor avec un regime continu, donc les mesures effectuées à l’aide de l’Arduino seront cohérentes et grâce à cela il sera possible de faire la régulation du courant.

le courant dans la LED correspond à l’equation suivante I led=Imoyen transitor*255/PWM decimale

|500x332

Voici le schéma complet qui nous a permis de valider notre régulation avec le transistor canal N :

|500x346

1 Like

Suite à la réalisation du montage sur ISIS, il a été effectué différents tests tels que :

L'évolution du courant en fonction du rapport cyclique généré par la PWM grace à l'asservissement de courant avec une consigne de 1A. L Le temps de reponse est bien de 0.3s de la regulation, avec un coefficient integral de 10

Un programme qui envoies les données( Intensité du courant et rapport cyclique ) sur le terminal virtuel (UART ou USART) a été fait afin de pouvoir extraire et visualiser correctement l'allure du courant grâce au logiciel Excel. Sur l'image ci-dessous il y'a un terminal virtuel contenant les données qui seront utilisées pour tracer la courbe.

|500x346

Voici les données du terminal en fonction traiter dans Excel des mesures de la simulation. On peut observer que le courant est moyennement filtré ce qui provoque de légère ondulation autour de la consigne à la période d’échantillonnage de 0.1s ce qui provoque aussi des variations faibles de la sortie de régulation PWM.

|500x290

On retrouve bien le temps de 0.4s pour atteindre la consigne, comme dans Matlab Etant donné que la période d’échantillonnage est faible, la réponse échantillonnée est similaire à celle en continu.

voici le programme de l'asservissement

#include 
#include      //https://www.arduino.cc/en/Reference/SoftwareSerialBegin
#include 
#include        //chien de garde
//#include    //mise en veille
//#include 
#include "LowPower.h"     //https://github.com/rocketscream/Low-Power




#define BP3        2       // 
#define battery    A0      //relay magnetron



LiquidCrystal lcd(9, 8, 4, 10, 11, 7);   // LiquidCrystal lcd(rs, en, d4, d10, d11, d7);
// Configuration des variables


unsigned int temps=0, PWM2;    //temps de la routine d'interruption
byte  temps1=0,mode=1,PWM=255,Integralbyte;   
float I=0,Iled,erreur=0,kp=10,ki=10,Ic=1,Integral=150;



// the setup function runs once when you press reset or power the board
void setup() {
   pinMode(5, OUTPUT);      //PWM
   pinMode(6, OUTPUT);      //PWM


   Timer1.initialize(1000);           // initialize timer1, and set a 0,1 second period =>  100 000  pour 0.01s  10 000
   Timer1.attachInterrupt(callback);   // attaches callback() as a timer overflow interrupt
   lcd.begin(16, 2);                   //modifier pour un afficheur 20x4


   TCCR0B = (TCCR0B & 0b11111000) | 0x01;         //pin 5  64khz    http://playground.arduino.cc/Main/TimerPWMCheatsheet
                                            
   pinMode(A5, OUTPUT);
   pinMode(2, INPUT);
   analogWrite(5,255);
   attachInterrupt(digitalPinToInterrupt(2), interBP, LOW);   //routine d'interruption exterieur broche 2
   
   analogReference(INTERNAL);

  
}



// Interruptions  tous les 0.1s fait par le timer1***********************************
void callback()  {
 temps++;


}


//interruption exterieur front descendant de la broche 2
void interBP() {
//interrupts();
  mode++;                  //incrementation des modes 
  if (mode>3) mode=1; 

  switch (mode) {
  case 1:Ic=1;Integral=180;   break;   //donne un ordre de grandeur de la valeur de la PWM=255*(Rshunt*Ic-Useuil)/Ubattery
  case 2:Ic=0.75;Integral=240;   break;
  case 3:Ic=1.5;Integral=250;   break;
     }
   } 

   
void loop() {  
   SoftwareSerial serial(0,1);
   serial.begin(9600);
         
  if (temps>1)         //affichage tous les 100ms
  {
      // Lecture de la tension*2=courant car ll y a une resistence de mesure de 0.5ohm
      I=analogRead(A1);
      I=I*0.00215;     //I*1.1/(1024*0.5ohms)  i moyen transistor      
      Iled=(I*255)/PWM;
 erreur=Ic-Iled;

      lcd.setCursor(0,0); lcd.print(Ic);
      lcd.setCursor(0,1);lcd.print("Er=");lcd.print(erreur,1);
      lcd.setCursor(8,1);lcd.print("I=");lcd.print(I);
      


      //Correcteur PI; PWM=ki*Erreur/P********************************************************
      Integral= Integral+erreur*ki; 
      if (Integral>=255) Integral=255;
      if (Integral<=0) {Integral=0;}
      Integralbyte=Integral;
      
      PWM=Integralbyte;// Rapport cyclique inversé car le transistor est un Canal P
                        // Rapport cyclique entre 255(100%) et 0 (0%)
      serial.print(I); serial.print(";");    //
      serial.print(PWM2); serial.println(";");                 
      
      analogWrite(5,PWM);    //commande de la LED de puissance
    
      lcd.setCursor(8,0);
      PWM2=(Integralbyte*100)/255;
      lcd.print("PWM=");
      lcd.print(PWM2);
      lcd.print("%  ");
      
      temps=0;
}

   
} // fin loop

Les résultats obtenus sont corrects car la courbe possède les mêmes caractéristiques obtenu sur le logiciel MATLAB.

2 Likes

Suite à la commande en boucle ouverte des 3 leds de ce post du feb 09 2021 des tests on été fait pour ajuster la Commande PWM pour avoir le bon courant. En effet, l'inductance a été changé.

L'étude de ces leds est sur le lien suivant post sur du Mardi 16 Février sur le forum Vélorizontal, les graphes et équations pour la commande en PWM des LED 10mA à 120mA.

|500x291

La commande est faite en référence à la courbe ci-dessous : |500x309 On incrémente la PWM petit à petit en mode continu d'éclairage pour connaitre le courant pour une tension de batterie de 4.2V

|500x309

Mais la courbe précédente n'est pas très utile car l'on désire un courant constant de 10mA. par conséquent, c'est la courbe suivante pour connaitre la PWM en fonction de la variation de la tension batterie.

|500x309 A partir de la courbe précédente, voici l’équation permettant de contrôler le courant des diodes : PWM = (14*Iconsigne+1)*225/Vbatt.

Et voilà le programme de l'Arduino qui gère la led de puissance et les leds auxiliaires

#include  
#include    
#include 

float IconsigneP=0.1;
float IconsigneAux = 0.01;
float Imax=0;
float Res=0.22;   //resistance
float Tension=4.2;
float pourcetage;
float outregul1;

float T_3=4.2;
float T_2=4.2;
float T_1=4.2;     

float TF3;
float TF2;
float TF1;
float TF;
float TensionF;


int16_t temperat;
bool flagmesure=0;

uint8_t  counter=0;
int8_t  counter13=0;
int8_t  periode13=0;
uint8_t  counteraffichage=0;
uint8_t out=0;
uint8_t outregul=70;
uint8_t outregul2=70;
uint8_t out2=0;

uint8_t  timer=0;
uint8_t  heure;
uint8_t minuTe;   //déclaration minute
uint8_t seconde;  //déclaration seconde


float IconsigneMaxP = 0.7;
float IconsigneMinP = 0.1;

float IconsigneMaxAux = 0.12;
float IconsigneMinAux = 0.01;

uint8_t  mode=0;

char BluetoothData;
char BluetoothData2;

//SoftwareSerial BT(0, 1);   // RX, TX mais il n'y a pas trop le choix sur la nano //pas nécessaire de définir un objet serial sur l'UART existant


/*   https://docs.rs-online.com/c150/0900766b81414edd.pdf      registre datashhet mpu6050
     https://docs.rs-online.com/e2e2/0900766b81414ed9.pdf     specificiation
*/
void setup() {
pinMode(13, OUTPUT);    //test le temps de programme  //initilisable par le PCB
pinMode(12, OUTPUT);    //test le temps du flash      //initilisable par le PCB
//pinMode(3, OUTPUT);   //PWM 3 timer2  32KHz hachage //initilisable par le PCB
pinMode(5, OUTPUT);     //PWM 5 timer0  64KHz hachage

pinMode(6,OUTPUT);      //PWM LED auxiliaires
pinMode (3, INPUT_PULLUP);   //inutilisable par le PCB
pinMode (4, INPUT_PULLUP);   //inutilisable par le PCB
//pinMode(7, INPUT);         //inutilisable par le PCB

  Timer1.initialize(50000);           // initialize timer1, and set a 0,1 second period =>  100 000  pour 0.01s  10 000
  Timer1.attachInterrupt(callback);   // attaches callback() as a timer overflow interrupt

// TCCR2B = (TCCR2B & 0b11111000) | 0x01;       //pin 3  32khz    http://playground.arduino.cc/Main/TimerPWMCheatsheet
TCCR0B = (TCCR0B & 0b11111000) | 0x01;          //pin 5  64khz 

analogReference(INTERNAL) ;   //1.1V tension de refenrence inernal
//analogReference(DEFAULT) ;  // ne peut être utilisé étant donné que la tension d'alimentation est inférieure à 5 V et variable

outregul=100;   //mettre la PWM

minuTe=EEPROM.read(0);                //minute de fonctionnement de l'eclairage
heure = EEPROM.read(2);               //heure
if (minuTe==255)  {EEPROM.put(0, 0);}   //la premier fois FF donc ecriture à 0 minute et heure
if (heure==255)   {EEPROM.put(2, 0);}

mode=EEPROM.read(3);      //changement de mode
mode++;
if (mode==1) {IconsigneP=0.7;periode13=3;}
if (mode==2) {IconsigneP=0.5;periode13=10;} 
if (mode>=3) {IconsigneP=0.2;mode=0;periode13=19;}
EEPROM.put(3, mode);

//BT.begin(9600);
Serial.begin(38400);
}


// Interruptions  tous les 0.05s fait par le timer1***********************************
void callback()  {

//utilité à vérifier, car le pin 13 est lié à rien !!!
counter++;      //fonctionnement mode flash
if (counter<=1)  {out=outregul;digitalWrite(12,HIGH);}           //temps de 50ms, 
if (counter>=2)  {out=0;digitalWrite(12,LOW);}
if (counter>=19)  {counter=0;}            //temps de 1s                                                             

out2 = 200;
analogWrite(6,out);   //PWM 64kHz LED principale
analogWrite(5,outregul2);   //PWM LED auxiliaires en fonctionnement continu

//utilité à vérifier, car le pin 13 est lié à rien !!!
counter13++;      //fonctionnement mode flash
if (counter13<=1)  {digitalWrite(13,HIGH);}          //temps de 50ms, 
if (counter13>=2)  {digitalWrite(13,LOW);}
if (counter13>=periode13)  {counter13=0;}            //periode variable  


counteraffichage++;
if (counteraffichage>=4)  {flagmesure=1;counteraffichage=0; }  //perdiode d'affichage 0.2s       2

timer++;
if (timer>=19 && Tension>3.1)  {    
      seconde++;timer=0;        //etude temps de fonctionnement                                             
      if(seconde >= 60){seconde =0;  minuTe++; EEPROM.put(0, minuTe);        //EEPROM.write(address, value)
          if(minuTe >= 60){ minuTe =0;  heure++;EEPROM.put(2, heure);    }   } } //pas grave que 24h soit depassé
                                
}//fin callback


//**********************************
void loop() {



if (flagmesure==1)   {
//digitalWrite(13,HIGH);                 //duree 20ms
Tension=analogRead(A7);   //10bit
Tension=(Tension*1.1*4.21)/1024;                //4.21 correspond au pont diviseur

T_3=T_2;
T_2=T_1;      //recurence n-2
T_1=Tension;  //recurence n-1

TF3=TF2;
TF2=TF1;
TF1=TF;

TF=Tension+3*T_1+3*T_2+3*T_3+0.278059*TF3-1.18289*TF2+1.76*TF1;   
//filtre numerique passe bas Fc=0.5s 3eme ordre  de la mesure de la tension fe=5Hz  periode0.2s
TensionF=TF/69;        //55 en theorie

pourcetage=83*TensionF-250;                       //a=(100-0)/(4.2-3)=83.33   b=-250


if (TensionF>=3.5) {
  outregul1 = (((1.6*IconsigneP+1.9)/TensionF)*255);     //mettre la PWM
  outregul2 = (((14*IconsigneAux+1)/TensionF)*255);     //PWM LED auxiliaires 
  if (outregul1>255) {outregul1=255;} 
  if (outregul1<70) {outregul1=70;}
  
  if (outregul2>255) {outregul2=255;} 
  if (outregul2<70)  {outregul2=70;}   
  
  outregul=outregul1;}
if (TensionF<3.5) {IconsigneP=0.3;}
if (TensionF<=3.1) {outregul=0;}  

//envoie des données en bluetooth
Serial.print("*O"+String(outregul)+"*");  
Serial.print("*F"+String(outregul2)+"*");
Serial.print("*P"+String(pourcetage)+"*");
Serial.print("*T"+String(TensionF,2)+"*");
Serial.print("*I"+String(IconsigneP,1)+"*");
Serial.print("*R"+String(IconsigneAux,2)+"*");
Serial.print("*m"+String(minuTe)+"*");
Serial.print("*h"+String(heure)+"*");
Serial.println();
//Serial.print("test"); //debug
flagmesure=0;
//digitalWrite(13,LOW);     
}


if (Serial.available()){
  BluetoothData = Serial.read();        //Get next character from bluetooth


if (BluetoothData == 'A') IconsigneP = IconsigneP + 0.1;
if (BluetoothData == 'B') IconsigneP = IconsigneP - 0.1;

if (BluetoothData == 'a')IconsigneAux = IconsigneAux + 0.01;
if (BluetoothData == 'b')IconsigneAux = IconsigneAux - 0.01;


if(BluetoothData == 'H' or BluetoothData2 == 'H') {seconde = 0;minuTe = 0;heure = 0;}      //remise à zero
BluetoothData = 0; 
  }

if(IconsigneP > IconsigneMaxP) IconsigneP = IconsigneMaxP; 
if(IconsigneP < IconsigneMinP) IconsigneP = IconsigneMinP;

if(IconsigneAux > IconsigneMaxAux) IconsigneAux = IconsigneMaxAux; 
if(IconsigneAux < IconsigneMinAux) IconsigneAux = IconsigneMinAux;  


}//fin loop
2 Likes

Etude d’une LED 65cd 50mA, 8° vendu par farnell. Ci-dessous vous trouverez le Lien de farnell avec la datasheet de la LED. farnell : https://fr.farnell.com/vishay/vlcs5830/led-aec-q101-5mm-rouge-65cd-624nm/dp/2889660?ost=2889660 Datasheet : https://4donline.ihs.com/images/VipMasterIC/IC/VISH/VISHS87555/VISHS87555-1.pdf?hkey=6D3A4C79FDBF58556ACFDE234799DDF0

La Jonction de la LED peut supporter une température de 92°C comme nous pouvons voir sur le calcul ci-dessous : T° jonction =T° Ambiant+RTHja*Power=20°C+300*(2.4V*0.1A)= 92°C

Ci-dessous les photos de son éclairage à 40cm. On peut observer que l’intensité lumineuse est légèrement plus faible au centre que sur les côtés. Le demi angle correspond bien au donnée constructeur de Atan(rayon eclairage/distance) =Atan(4cm/40cm)=5.7°

|409x500

|500x225

D’ailleurs, sur la courbe suivante, on peut observer les lux en fonction du rayon.

|500x407

Pour avoir le lumen total nous avons utiliser la relation suivante ( L2+L3*8 )0,02*0,02 (qui correspond à la somme (du lux à la surface 0 et du demi côté de 0 à 4cm) 8 (correspond aux 8 points du capteur)*la surface du capteur)

Voici l’intensité lumineuse à 40cm en fonction du courant On peut observer que l’intensité est maximum à 0.2A.

|500x244

2 Likes

Ci-dessous vous trouverez l’image 3D du PCB et le lien pour télécharger les fichiers ISIS du schéma électrique ainsi que le typon(PCB) : TR ECLAIRAGE - Google Drive

Voici quelques mesures de courant en pratique.

Graphique pour C=220uF
Grâce au comportement du condensateur, le courant n’arrive pas à 0, en revanche le courant n’est pas en régime continu.

Graphique pour (C1+C2=440uF)

Il est maintenant remarquable qu’avec une constante de temps qui est deux fois plus grande que celle du graphique antérieur, le courant en fonction du temps se rapproche du régime continu.

3 Likes