70h long project

On my last year STI2D of high school we work, in team, choose a system to improve. This project was evaluated at Baccalauréat coefficient 12.


A "connected" bike

For this project we have chosen to add three systems on the bike with Arduino type card:

The speedometer is in the shape of little screen on the handlebars.
The accident detector send a text message at a person of your choice with a GPS coordinates of the bike.
The pollution sensor send a rate of pollution witch the location on a server ThingSpeak .

Use case diagram

Use case diagram

Sustainable development

Our project had to get into a process of sustainable development.
The three pillar of sustainable development
Social:
Thanks to the on-board system, the cyclist knows that if he has an acident, someone will be warned. And the same for his family. For example for parents, they know that nevermind what's happen to their child they will be warned.
Furthermore, the user has the possibility to choose his course in fuction of polluton rate.

Environmental:
with the sending of pollution and localisation's data on the ThingSpeak server, we can, in time, create a map of the pollution in France even in the isolated places where the instalation of fix sensor is unnecessary.

Economic:
- This full system can sold around 50/60€. Furthermore, we can adapt the system as required by the user and reduce the cost for sale.
- Creation of jobs for the production, the service after sell, the collect and the transmition of datas.


My part

In this project, I have work on a speedometer and this display.

For the speedometer i have use a hall effect sensor (sensor of magnetic field).
I have fix a senor on a fork and a magnet on the wheel witch allows me to detect a turn of wheel. At every turn of wheel I run stopwatch to optain the time between 2 turn. Then I calculate the speed with a formula:
perimeter of the wheel / time between .

For display, I have use one OLED 0.96 screen fix on the handlebars with a connexion on I2C.

For the micro controller I have use one ESP8266 because to send data of pollution on a server we need a WI-FI chip. On ESP8266 this chip is integrate on the card.


Set up

To make a speedometer we need:

  • An micro controller
  • An I2C screen
  • An hall effect sensor
  • An button
  • 2 resistance of 10kΩ
  • A cables
Here is a assembly drawing:

Assembly drawing of project

The speed calculation

sensor photo
The sensor works betweeb 3.3V ans 24V. Perject for one Raspberry pi or one ESP8266.
Its detection distance is 0 to aboute 15cm.
We can found around 1€ on AliExpress for example.
As far as the assembly itself is concerned, here is an electrical schematic:
Electrical diagram


// ----------========== Partie déclarative ===========----------
// -----===== calcul du délai =====-----
float delais;
float temps;

int tempoV = 0;


// -----===== calcul de la vitesse =====-----
int etat_capt = 0;
float vitesse;
float moyV = 0;
float sommeV = 0;
int compteur = 1;
int arreter = 0;


// -----===== capteur =====-----
int capteur_hall = D4;     //capteur sur la pin digital 8


// -----===== roue =====-----
const float pi = 3.14;              //pi est egale a 3.14
const int Droue = 24;               //le diamètre de la roue en pouce
float Proue;                        //le périmètre de la roue


// ----------========== Partie SETUP ===========----------

void setup(){
  pinMode(capteur_hall, INPUT);     //le capteur en entrée
    Serial.begin(115200);

// -----===== calcul périmètre roue =====-----
  Proue = ((Droue * 2.54) * pi)/100;            //périmètre de la roue en m
  Serial.print("périmetre de la roue :   ");
  Serial.print(Proue);
  Serial.println("  mètre");

}

// ----------========== Partie code (LOOP) ===========----------

void loop(){

  if(digitalRead(capteur_hall) == 0){
    if(etat_capt == 0){                 //pour détécter l'aimant
    delais = millis() - temps;          //temps en ms
    Serial.println(delais);
    temps = millis();
    etat_capt = 1;
    arreter = 0;

    delais = delais / 1000;              //temps en s
    vitesse = Proue / delais;            //vitesse en m/s
    vitesse = (vitesse * 3600) / 1000;   //vitesse en km/h


    // -----===== calcul de la moyenne =====-----
      sommeV = sommeV + vitesse;
      moyV = sommeV / compteur;
      compteur++;


    // -----===== affichage vitesse =====-----
    Serial.print("vitesse :  ");
    Serial.print(vitesse);
    Serial.println("  en km/h");
    Serial.print("vitesse moy :  ");
    Serial.print(moyV);
    Serial.println("  en km/h");
    }
  }

   // ---== en cas d'arrêt ==---
    else{
    etat_capt = 0;
      if(arreter == 0){
      if((millis() - temps) >= 5000){
        Serial.println ("vitesse : 0km/h ");
        arreter = 1; }
    }
  }
}
          

The display on the screen

The display on the I2C screen is make with a library Adafruit_SSD1306. It allows to write but also display a graphics effect like a geometrical shape or scrolling text for example.
Screen photo
The screen have:
- A size of 0.96 inch, hence this name.
- One resolution of 128 x 32 pixels.
- One voltage between 3.3 and 5V.
For a price neighbouring 2€50.

// -------======== Déclaration de bibliothèque ========-------

#include 
#include 

// adresse de l'écran OLED
#define OLED_ADDR   0x3C

Adafruit_SSD1306 display(-1);

#if (SSD1306_LCDHEIGHT != 64)
//#error("largeur incorrect, fix Adafruit_SSD1306.h!");
#endif

void setup() {

  // Initialisation de l'écran
  display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR);
  display.clearDisplay();
  display.display();
  display.setTextSize(2);         //taille du texte à 1
  display.setTextColor(WHITE);    //couleur blanche
}

void loop() {
  display.clearDisplay();         //on efface l'écran

  display.setCursor(1,9);         //on met le curseur à 1 pixel du bord gauche et à 9 pixels du haut

  display.print("Hello world");   //on affiche "Hello world"

  display.display();              //update de l'écran
}
          

The full code

This is the full code commented of my part of the project. With a follow-up of action of the system on a serial monitor.
A possible improvement would be to create functions for repeating instructions. For the speed calculate or average speed for example.

// -------======== Déclaration de bibliothèque ========-------

#include 
#include 

// adresse de l'écran OLED
#define OLED_ADDR   0x3C

Adafruit_SSD1306 display(-1);

#if (SSD1306_LCDHEIGHT != 64)
//#error("largeur incorrect, fix Adafruit_SSD1306.h!");
#endif


// -------======== Déclaration de Variable/capteur ========-------

// -----===== calcul delais =====-----
float delais;
float temps;

// -----===== calcul vitesse =====-----
int etat_capt = 0;
float vitesse;
float moyV = 0;
float Vmax = 0;
float sommeV = 0;
int compteur = 1;
int arreter = 0;
int nbr_tour = 0;
float distance = 0;

// -----===== Bouton =====-----
int BP = D3;               //bouton sur la pin digital 7
int Etat_BP = 1;           //variable pour savoir sur quel écran on est
int nbr_ecran = 5;         //pour définir le nombre d'écran
int affichage = 0;

// -----===== capteur =====-----
int capteur_hall = D4;     //capteur sur la pin digital 8

// -----===== roue =====-----
const float pi = 3.14;              //pi est egal a 3.14
const int Droue = 15;               //le diamètre de la roue en pouce
float Proue;                        //le périmètre de la roue




void setup() {
  // ----------------======================= SET UP =======================---------------
  Serial.begin(115200);                  //lancement du moniteur série à 115 200 baud
  Serial.println(" ----- SET UP -----");

  // initialisation de l'écran
  display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR);
  display.clearDisplay();
  display.display();
  display.setTextSize(2);         //taille du texte à 1
  display.setTextColor(WHITE);    //couleur blanche

  // afficher un pixel à chaque coin de l'écran
  /*display.drawPixel(0, 0, WHITE);
  display.drawPixel(127, 0, WHITE);
  display.drawPixel(0, 32, WHITE);
  display.drawPixel(127, 32, WHITE);*/


  pinMode(capteur_hall, INPUT);       //le capteur est en entrée
  pinMode(BP, INPUT);                 //le bouton est en entrée

  // -----===== calcul périmètre roue =====-----
  Proue = ((Droue * 2.54) * pi)/100;            //périmètre de la roue en m
  Serial.print("périmetre de la roue :   ");    //affichage dans le moniteur série
  Serial.print(Proue);
  Serial.println("  mètre");
  Serial.println(" ----- fin SET UP ----- ");

}

void loop() {
  // ----------------======================= LOOP =======================----------------

  // -----===== changement d'écran =====-----
  if(Etat_BP <= nbr_ecran){
    if(digitalRead(BP) == 0){
      Etat_BP++;
      //Serial.print("Etat bouton   ");
      //Serial.println(Etat_BP);
      delay(250);
  }}
  else{
    Etat_BP = 1;
  }



  // --------------------==================== Ecran 1 : vitesse ====================--------------------
  if(Etat_BP == 1){

    if (affichage == 0){
       Serial.println(" --------------- ");
       Serial.println("écran 1 : vitesse actuelle");
       affichage = 1;
    }

  if(digitalRead(capteur_hall) == 0){
    if(etat_capt == 0){                       //pour détecter l'entrée de l'aimant
       delais = millis() - temps;             //délai entre 2 tours en ms
        //Serial.println(delais);             //affichage du temps en ms
        temps = millis();
        etat_capt = 1;                        //le capteur est déjà là
        arreter = 0;                          //on met la variable "arrêter" à 0

    // -----===== calcul de la vitesse =====-----
    delais = delais / 1000;                //temps en s
    vitesse = Proue / delais;              //vitesse en m/s
    vitesse = (vitesse * 3600) / 1000;     //vitesse en km/h


    // -----===== calcul de la moyenne =====-----
      sommeV = sommeV + vitesse;            //on calcule la somme de toutes les vitesses
      moyV = sommeV / compteur;             //et on divise par la somme des tours de roue
      nbr_tour++;                           //on ajoute 1 au nombre de tours (pour calculer la moyenne et la distance)


    // -----===== calcul de la vitesse max =====-----
      if (vitesse > Vmax){
        Vmax = vitesse;
      }

    // -----===== affichage vitesse dans le moniteur série =====-----
    Serial.println("---------------");
    Serial.print("vitesse :  ");
    Serial.print(vitesse);
    Serial.println(" en km/h");

    Serial.print("vitesse moyenne :  ");
    Serial.print(moyV);
    Serial.println("  en km/h");

    Serial.print("vitesse max :   ");
    Serial.print(Vmax);
    Serial.println("  en km/h");



  // -----===== affichage écran =====-----

  display.clearDisplay();         //on efface l'écran

  display.setCursor(1,9);         //on met le curseur à 1 pixel du bord gauche et à 9 pixels du haut
  if(vitesse >=10){
    display.print(vitesse);       //on affiche la vitesse
    display.print(" km/h");       //en km/h
  }
  if(vitesse < 10){
    display.print(vitesse);       //on affiche la vitesse
    display.print("  km/h");      //en km/h
  }

  display.display();              //update de l'écran


 }
}

  // --=== si le capteur ne détecte pas l'aimant (la roue ne tourne pas) ===--
  else{
    //Serial.println("capteur plus detecté");
    etat_capt = 0;                                 //on met la variable pour détecter l'entrée de l'aimant à 0

    if(arreter == 0){                              //si on n'est pas déjà arrêté
      if((millis() - temps) >= 3000){              //si le capteur n'a rien détecté depuis x secondes
        Serial.println ("vitesse : 0km/h ");
        arreter = 1;                               //on passe à arrêter
        vitesse = 0;                               //et on met la vitesse à 0


    // --=== affiche la vitesse à l'arrêt ===--
    display.clearDisplay();
    display.setCursor(1,9);         //on met le curseur à 1 pixel du bord gauche et à 9 pixels du haut
    display.print(vitesse);
    display.print("  km/h");
    display.display();
    }
   }
  }

 }
    // --------------------=================== Ecran 2 : vitesse moyenne ====================--------------------
    if(Etat_BP == 2){

      if (affichage == 1){
      Serial.println(" --------------- ");
      Serial.println("écran 2 : vitesse moyenne");
      affichage = 0;
      }

    if(digitalRead(capteur_hall) == 0){
      if(etat_capt == 0){                   //Pour détécter l'entrée de l'aimant
      delais = millis() - temps;            //temps en ms
      //Serial.println(delais);
      temps = millis();
      etat_capt = 1;                        //le capteur est déjà là
      arreter = 0;                          //on passe à "en mouvement"

    // -----===== calcul de la vitesse =====-----
    delais = delais / 1000;                 //temps en s
    vitesse = Proue / delais;               //vitesse en m/s
    vitesse = (vitesse * 3600) / 1000;      //vitesse en km/h

    nbr_tour++;                             //on ajoute 1 au nombre de tours (pour calculer la moyenne et la distance)

    // ---==== calcul distance ====---
    distance = nbr_tour * Proue;               //la distance en mètre
    distance = distance / 1000;                //la distance en km


    // -----===== calcul de la moyenne =====-----
      moyV = distance / millis();


    // -----===== calcul de la vitesse max =====-----
      if (vitesse > Vmax){
        Vmax = vitesse;
      }


    // -----===== affichage vitesse =====-----
    Serial.println("---------------");
    Serial.print("vitesse :  ");
    Serial.print(vitesse);
    Serial.println(" en km/h");

    Serial.print("vitesse moynne :  ");
    Serial.print(moyV);
    Serial.println("  en km/h");

    Serial.print("vitesse max :   ");
    Serial.print(Vmax);
    Serial.println("  en km/h");

  // -----===== affichage écran =====-----

  display.clearDisplay();         //on efface l'écran

  display.setCursor(1,9);         //on met le curseur à 1 pixel du bord gauche et à 9 pixels du haut
  if(moyV >=10){
  display.print(moyV);            //on affiche la vitesse
  display.print(" Vmoy");         //en km/h
  }
  if(moyV < 10){
  display.print(moyV);            //on affiche la vitesse
  display.print("  Vmoy");        //en km/h
  }


  display.display();              //update de l'écran

  }
}

  // --=== si le capteur ne détecte pas l'aimant ===--
  else{
    etat_capt = 0;                //on met la variable pour détecter l'entrée de l'aimant à 0
  }
 }

   // --------------------==================== Ecran 3 : vitesse max ====================--------------------
  if(Etat_BP == 3){

    if(affichage == 0){
      Serial.println(" --------------- ");
      Serial.println("écran 3 : vitesse max");
      affichage = 1;
}

   if(digitalRead(capteur_hall) == 0){
    if(etat_capt == 0){                   //pour détécter l'entrée de l'aimant
    delais = millis() - temps;            //délai entre 2 tours en ms
    //Serial.println(delais);             //affichage temps en ms
    temps = millis();
    etat_capt = 1;                        //le capteur est déjà là
    arreter = 0;                          //on passe à "en mouvement"

    // -----===== calcul de la vitesse =====-----
    delais = delais / 1000;                //temps en s
    vitesse = Proue / delais;              //vitesse en m/s
    /*Serial.print("vitesse :  ");
    Serial.print(vitesse);
    Serial.println(" en m/s");*/
    vitesse = (vitesse * 3600) / 1000;     //vitesse en km/h

    nbr_tour++;                            //on ajoute 1 au nombre de tours (pour calculer la moyenne et la distance)


    // -----===== calcul de la vitesse max =====-----
      if (vitesse > Vmax){
        Vmax = vitesse;
      }

    // -----===== affichage vitesse dans le moniteur série =====-----
    Serial.println("---------------");
    Serial.print("vitesse :  ");
    Serial.print(vitesse);
    Serial.println(" en km/h");

    Serial.print("vitesse moyenne :  ");
    Serial.print(moyV);
    Serial.println("  en km/h");

    Serial.print("vitesse max :   ");
    Serial.print(Vmax);
    Serial.println("  en km/h");




    // -----===== affichage écran =====-----

     display.clearDisplay();          //on efface l'écran

      display.setCursor(1,9);         //on met le curseur à 1 pixel du bord gauche et à 9 pixels du haut
      if(Vmax >=10){
      display.print(Vmax);            //on affiche la vitesse
      display.print(" VMax");         //en km/h
     }
      if(Vmax < 10){
      display.print(Vmax);            //on affiche la vitesse
      display.print("  Vmax");        //en km/h
     }


  display.display();                 //update de l'écran

   }
}
    // --=== si le capteur ne détecte pas l'aimant ===--
  else{
    etat_capt = 0;                //on met la variable pour détecter l'entré de l'aimant à 0
  }
  }

   // --------------------==================== Ecran 4 : distance ====================--------------------
   if(Etat_BP == 4){

    if (affichage == 1){
      Serial.println(" --------------- ");
      Serial.println("écran 4 : distance");
      affichage = 0;
   }

    if(digitalRead(capteur_hall) == 0){
    if(etat_capt == 0){                    //pour détécter l'entrée de l'aimant
      Serial.println("capteur detecté");
      delais = millis() - temps;            //délai entre 2 tours en ms
      //Serial.println(delais);             //affichage temps en ms
      temps = millis();
      etat_capt = 1;                        //le capteur est déjà là
      arreter = 0;                          //on passe à "en mouvement"

    // -----===== calcul de la vitesse =====-----
    delais = delais / 1000;                //temps en s
    vitesse = Proue / delais;              //vitesse en m/s
    /*Serial.print("vitesse :  ");
    Serial.print(vitesse);
    Serial.println(" en m/s");*/
    vitesse = (vitesse * 3600) / 1000;     //vitesse en km/h

    nbr_tour++;                            //on ajoute 1 au nombre de tours (pour calculer la moyenne et la distance)


    // -----===== calcul de la vitesse max =====-----
      if (vitesse > Vmax){
        Vmax = vitesse;
      }

    // -----===== affichage vitesse dans le moniteur série =====-----
    Serial.println("---------------");
    Serial.print("vitesse :  ");
    Serial.print(vitesse);
    Serial.println(" en km/h");

    Serial.print("vitesse moyenne :  ");
    Serial.print(moyV);
    Serial.println("  en km/h");

    Serial.print("vitesse max :   ");
    Serial.print(Vmax);
    Serial.println("  en km/h");


    // ---==== calcul distance ====---
    distance = nbr_tour * Proue;               //la distance en mètre
    distance = distance / 1000;                //la distance en km

    display.clearDisplay();
    display.setCursor(1,9);                    //on met le curseur à 1 pixel du bord gauche et à 9 pixels du haut
    display.print(distance);
    display.print("  km");
    display.display();

    }
    }

    else{
    etat_capt = 0;                //on met la variable pour detecter l'entrée de l'aimant à 0
       }

   }
   // --------------------==================== Ecran 5 : pollution ====================--------------------
   if(Etat_BP == 5){

    if (affichage == 0){
    Serial.println(" --------------- ");
    Serial.println("écran 5 : pollution");
    affichage = 1;
    }

    if(digitalRead(capteur_hall) == 0){
    if(etat_capt == 0){                    //pour détécter l'entrée de l'aimant
      Serial.println("capteur detecté");
      delais = millis() - temps;            //délai entre 2 tours en ms
      //Serial.println(delais);             //affichage temps en ms
      temps = millis();
      etat_capt = 1;                        //le capteur est déjà là
      arreter = 0;                          //on passe à "en mouvement"

    // -----===== calcul de la vitesse =====-----
    delais = delais / 1000;                //temps en s
    vitesse = Proue / delais;              //vitesse en m/s
    /*Serial.print("vitesse :  ");
    Serial.print(vitesse);
    Serial.println(" en m/s");*/
    vitesse = (vitesse * 3600) / 1000;     //vitesse en km/h

    nbr_tour++;                            //on ajoute 1 au nombre de tours (pour calculer la moyenne et la distance)


    // -----===== calcul de la vitesse max =====-----
      if (vitesse > Vmax){
        Vmax = vitesse;
      }

    // -----===== affichage vitesse dans le moniteur série =====-----
    Serial.println("---------------");
    Serial.print("vitesse :  ");
    Serial.print(vitesse);
    Serial.println(" en km/h");

    Serial.print("vitesse moyenne :  ");
    Serial.print(moyV);
    Serial.println("  en km/h");

    Serial.print("vitesse max :   ");
    Serial.print(Vmax);
    Serial.println("  en km/h");


    display.clearDisplay();
    display.setCursor(1,9);         //on met le curseur à 1 pixel du bord gauche et à 9 pixels du haut
    display.print("pollution");
    display.display();

    }
    }

    else{
    etat_capt = 0;                //on met la variable pour detecter l'entrée de l'aimant à 0
    }
   }
}