[Projet en cours] tableau de bord pour moto

Bonjour tout le monde,
Pour mon second projet arduino, j'avais prévu un découpeur plasma automatisé (ou fraiseuse, ou tout ce qu'on peut mettre dans l'emplacement de découpe...) mais je ne me sens pas encore prêt pour un tel projet. En attendant, je me suis mangé un peu le bitume avec ma moto, et dans l'accident, le cable de mon compteur de vitesse / km parcourus s'est arraché salement. Comme ma moto ne disposait que de deux cadrans avec compte-tour d'un coté et vitesse/km parcourus de l'autre, je me suis dit que le moment était donc venu d'ajouter quelques fonctionnalités à celle-ci.
Les fonctions qui me manquaient le plus étant une horloge, et une jauge à essence. En effet, le témoin de réserve s’avère un peu short pour anticiper, surtout depuis que je ne vois plus combien de km j'ai parcouru depuis le dernier plein.

Voici donc comment se compose ce projet aujourd'hui :
Un arduino Uno (prochainement remplacé soit par un atmega 328p sur une pcb custom, soit par un arduino mini)
Un afficheur 16x2 rétroéclairé bleu
Un capteur à effet Hall pour compter les tours de roue (avec aimant sur la jante)
Un capteur de température ambiante TMP36 (pur gadget)
Une sonde de thermocouple K avec son ampli pour la température moteur (ya pas de radiateur sur ma moto, la température peut être intéressante à surveiller)
Un DS1307 pour avoir l'heure
Une jauge à liquides à résistance variable (56? / cm) de 25 cm
Une carte micro-SD pour enregistrer le nombre de KM parcourus entre deux coupures de circuits (la memoire EEPROM à un nombre limité d'écritures, et il faut écrire assez souvent sur la carte SD pour ne pas rater trop de km)

Vu que tout le monde aime les illustrations de projet :
Bazar de fils

Le capteur à effet Hall

Le tout allumé (les infos avec l'heure s'affichent toutes les deux secondes)

La ou ça doit rentrer (le boitier blanc)

L'heure n'est pas encore connectée (breadboard trop petite) et la jauge est simulée par une resistance variable pour le moment. Le thermocouple est aussi en attente de branchement.

Bonjour,
j'ai un peu le même problème: la partie cristaux liquide ne marche plus. Problème récurent sur les Varadero. Tu pourrait nous en dire plus sur ton projet: schéma, codes ...
Merci d'avance

Il s'agit pour mon cas d'une virago, avec à l'origine deux cadrans à aiguilles. Seul le compte tours reste.
Je mettrais les schémas et codes dés que le tout sera propre.

Je mets pour les annales une photo du compteur d'origine :

Bonsoir.
Excellent petit projet.
Tu n'a pas envisagé de gérer aussi le compte tour?
avec une pince ampermetrique sur un câble de bougie et un bargraph vu ton afficheur tu serais très proche de ce qui se fait sur le marché de l'adaptable. Et ça te ferait un combiné instruments complet et en une pièce.

Le suivi budget du projet est intéressant pour comparer aux produits existants. On sera forcément en dessous vu qu'on oublie l'homologation et tout ça, mais c'est bien pour avoir une idée pour celui qui se lancerait sur un projet équivalent.
Bon courage.

Un arduino mini 16€
Un afficheur 16x2 rétroéclairé bleu 7,50€
Un capteur à effet Hall 3,40€
Une sonde de thermocouple K 7,70€
Un ampli max31855 13,50€
Un DS1307 pour avoir l'heure 6,90€
Une jauge à liquides à résistance variable (56? / cm) de 25 cm 30€
Une carte micro-SD et son lecteur 5,50€
Différents composants (résistances,LEDs,fils, pcb, pins mâles et femelles...) autour de 10€

Total environ 84€
Disons avec ce que j'ai pu oublier 100€
Sur le commerce, un ordinateur de bord pour moto coute en moyenne 300€

Intéressant.
Si tu fais un suivi projet complet je le suivrai de près. Je suis sur autre chose, mais j'aime bien l'idée. A reprendre un de ces jours qui sait.

Voici donc le code actuel, presque terminé, et complétement dégueu sale :

moto.ino

// Inclusion des librairies
#include <Wire.h>
#include <LiquidCrystal.h>
LiquidCrystal lcd(9, 8, 7, 6, 5, 4); // Initialisation de la librairie Liquid Crystal
#include <SD.h>
#include "RTClib.h"
#include "LcdBigFont.h"


RTC_DS1307 RTC; //initialisation de la librairie du module RTC

int tmpPin = A0;    // Selection de l'entrée analogique pour la sonde température TMP36
int jaugePin = A1; // Jauge d'essence sur A1
int lastJauge=500000; // initialisation impossible pour la comparaison de jauge
float vitesse = 0; // initialisation de la vitesse float
int intVitesse=0; // initialisation de la vitesse à afficher (int)
float temperature[10]; // tableau de valeur pour stocker 10 echantillons de température
int index=0 ;          // index du tableau pour s'y retrouver
long previousMillis = 0;       
long interval = 3000; // interval de defilement des parametres sur le lcd
int lcdState = 0;  // parametre en cours d'affichage
volatile byte rpmcount; // compteur tours de roues
float kmcount=0; // compteur de km
char kmprev[10]; // tableau pour lire la carte SD
int bufPos = 0; // buffer pour lire la carte SD
char byteIn = 0; // byte de la carte SD
String erreur=""; // code erreur

unsigned int rpm;
unsigned long timeold; // marqueur de temps
const int chipSelect = 10; // pin cs de la carte SD

void setup() {
// Configuration de l'afficheur 16 caractères en 2 lignes 
lcd.begin(16, 2);
// creation des caracteres speciaux
bigFontBegin();

// Lien avec l'horloge RTC
Wire.begin();
RTC.begin();

memset(kmprev,0,sizeof(kmprev)); 

erreur = "Init";//initialize
// make sure that the default chip select pin is set to
// output, even if you don't use it:
pinMode(10, OUTPUT);

// see if the card is present and can be initialized:
if (!SD.begin(chipSelect)) {
  erreur = "SD";//Card failed, or not present"
  // don't do anything more:
  return;
}

// on lit le nombre de km parcouru jusqu'ici
File dataFile = SD.open("datalog.txt");

// if the file is available, write to it:
if (dataFile) {
  while (dataFile.available()) {

     byteIn = dataFile.read();
if (bufPos < sizeof(kmprev))
kmprev[bufPos++] = byteIn;
  }
  dataFile.close();
  kmcount = strtod(kmprev, NULL);
}  
// if the file isn't open, pop up an error:
else {
  erreur = "File";//error opening datalog.txt
} 
// On verifie la présence de l'horloge, de sa pile...
if (! RTC.isrunning()) 
{
    erreur = "RTC";
    //RTC.adjust(DateTime(__DATE__, __TIME__));//Décommenter pour initialiser l'heure
}

 attachInterrupt(0, rpm_fun, RISING); // LA fonction qui compte les tours de roues en background

 rpmcount = 0;
 rpm = 0;
 timeold = 0;
}

void loop() {
DateTime now = RTC.now();
if (rpmcount >= 10) { 
   //Update RPM every 10 counts, increase this for better RPM resolution,
   //decrease for faster update
   rpm = 30*1000/(millis() - timeold)*rpmcount;
   timeold = millis();
   rpmcount = 0;
   vitesse= rpm*60;
   vitesse= vitesse*2.10;
   intVitesse = vitesse/1000;

   File dataFile = SD.open("datalog.txt", FILE_WRITE); // on ecrit le nombre de km parcourus dans un fichier
    // if the file is available, write to it:
if (dataFile) {
  dataFile.seek(0);
  dataFile.print(kmcount);
  dataFile.close();
}  
// if the file isn't open, pop up an error:
else {
 erreur = "File"; //error opening datalog.txt
} 
 }

//acquisition de la valeur analogique dans sensorValue
// de 0 à 1023 -> 0 à 5V
int sensorValue = analogRead(tmpPin); 


//transformation en milliVolts dans outputValue
float outputValue = (((float)(sensorValue))*5000.0)/1023.0;

//Calcul de la température en fonction des milliVolts
float outputTemp = ( (float) outputValue - 500.0) /10.0;

//insertion de la température dans le tableau
temperature[index] = outputTemp;

//incrémentation de l'index modulo 10
index = (index + 1) % 10;

// calcul de la moyenne ( Méthode barbare, une boucle for l'aurait mieux fait)  
int tempMoy = (temperature[0]+temperature[1]+temperature[2]+temperature[3]+temperature[4]+temperature[5]+temperature[6]+temperature[7]+temperature[8]+temperature[9])/10;

lcd.setCursor(0, 0);
bigFont(intVitesse); // affichage de la vitesse en gros, fonctionne seulement si inferieur a 999!

int jaugeValue = analogRead(jaugePin); // lecture de la jauge
jaugeValue = map(jaugeValue, 500, 1000, 0, 5); 
if (lastJauge != jaugeValue) // si le niveau à bougé, on update l'affichage
{
lastJauge = jaugeValue;
lcd.setCursor(11, 1);
lcd.write(byte(1));
lcd.write(byte(4));
lcd.write(byte(4));
lcd.write(byte(4));
lcd.write(byte(2));
lcd.setCursor(11, 1);
int i=0;
while ( i < jaugeValue){
    lcd.write(byte(3));
    i++;
 } 
}
// on gere l'affichage des options heure et temperature
  unsigned long currentMillis = millis();
  if(currentMillis - previousMillis > interval) {
  lcdState ++;


  previousMillis = currentMillis;   

  }
  lcd.setCursor(11, 0);
  if(erreur=="")
  {
  if(lcdState == 0){//affichage de l'heure
    lcd.print(now.hour());
    lcd.print(":");
    lcd.print(now.minute());

  }
  else if(lcdState == 1){//affichage de la temperature moyenne exterieur
    lcd.print("  ");
    lcd.print(tempMoy);
lcd.setCursor(15, 0);
lcd.write(byte(0));
  }
  else if(lcdState == 2){//affichage de la température moteur
    lcd.print("  ");
    lcd.print(tempMoy+(tempMoy*272)/100);//Cette partie est simulée tant que je n'ai pas cablé le thermocouple
lcd.setCursor(15, 0);
lcd.write(byte(0));
  }
  else{

    lcdState = 0;
  }
  }
  else
  {
    if(erreur == "Init")
    {
      lcd.print(erreur);
      delay(700);
      lcd.setCursor(11, 0);

      lcd.print(".");
      delay(700);
      lcd.print(".");
      delay(700);
      lcd.print(".");
      delay(700);
      lcd.print(".");
      delay(700);
      lcd.print(".");
      delay(700);
    erreur = "";

    }
    lcd.print(erreur);
    
  }
delay(30); // un petit delais pour ne pas trop mouliner

}

void rpm_fun()
{
 rpmcount++;
 kmcount= kmcount + 0.0021;
}

LcdBigFont.h

#ifndef LcdBigFont_h
#define LcdBigFont_h

byte degre[8] = { B01000, B10100, B01000, B00000, B00000, B00000, B00000, B00000}; // °
byte endJauge[8] = { B11111, B00001, B00001, B00001, B00001, B00001, B00001, B11111 }; // ]
byte startJauge[8] = { B11111, B10000, B10000, B10000, B10000, B10000, B10000, B11111 }; // [
byte fullJauge[8] = { B11111, B11111, B11111, B11111, B11111, B11111, B11111, B11111 }; // carré plein
byte emptyJauge[8] = { B11111, B00000, B00000, B00000, B00000, B00000, B00000, B11111 }; // carré vide
byte haut[8] = { B11111, B11111, B00000, B00000, B00000, B00000, B00000, B00000 }; // trait en haut
byte bas[8] = { B00000, B00000, B00000, B00000, B00000, B00000, B11111, B11111 }; // trait en bas
byte lesDeux[8] = { B11111, B11111, B00000, B00000, B00000, B00000, B11111, B11111 }; // les deux

void bigFontBegin(){
lcd.createChar(0, degre);
lcd.createChar(1, startJauge);
lcd.createChar(2, endJauge);
lcd.createChar(3, fullJauge);
lcd.createChar(4, emptyJauge);
lcd.createChar(5, haut);
lcd.createChar(6, bas);
lcd.createChar(7, lesDeux);
}

void unHaut(){
lcd.write(byte(5));
lcd.write(byte(3));
lcd.print(" ");
}
void unBas(){
lcd.write(byte(6));
lcd.write(byte(3));
lcd.write(byte(6));
}

void deuxHaut(){
lcd.write(byte(7));
lcd.write(byte(7));
lcd.write(byte(3));
}
void deuxBas(){
lcd.write(byte(3));
lcd.write(byte(6));
lcd.write(byte(6));
}
void troisHaut(){
lcd.write(byte(5));
lcd.write(byte(7));
lcd.write(byte(3));
}
void troisBas(){
lcd.write(byte(6));
lcd.write(byte(6));
lcd.write(byte(3));
}
void quatreHaut(){
lcd.write(byte(3));
lcd.write(byte(6));
lcd.write(byte(3));
}
void quatreBas(){
lcd.print(" ");
lcd.print(" ");
lcd.write(byte(3));
}
void cinqHaut(){
lcd.write(byte(3));
lcd.write(byte(7));
lcd.write(byte(7));
}
void cinqBas(){
lcd.write(byte(6));
lcd.write(byte(6));
lcd.write(byte(3));
}
void sixHaut(){
lcd.write(byte(3));
lcd.write(byte(7));
lcd.write(byte(7));
}
void sixBas(){
lcd.write(byte(3));
lcd.write(byte(6));
lcd.write(byte(3));
}
void septHaut(){
lcd.write(byte(5));
lcd.write(byte(5));
lcd.write(byte(3));
}
void septBas(){
lcd.print(" ");
lcd.print(" ");
lcd.write(byte(3));
}
void huitHaut(){
lcd.write(byte(3));
lcd.write(byte(7));
lcd.write(byte(3));
}
void huitBas(){
lcd.write(byte(3));
lcd.write(byte(6));
lcd.write(byte(3));
}
void neufHaut(){
lcd.write(byte(3));
lcd.write(byte(7));
lcd.write(byte(3));
}
void neufBas(){
lcd.write(byte(6));
lcd.write(byte(6));
lcd.write(byte(3));
}
void zeroHaut(){
lcd.write(byte(3));
lcd.write(byte(5));
lcd.write(byte(3));
}
void zeroBas(){
lcd.write(byte(3));
lcd.write(byte(6));
lcd.write(byte(3));
}

int bigFont(int x)//fonctionne uniquement si x toujours inferieur a 999 et x un chiffre
{
int a = x/100;
int b = (x/10)-(a*10);
int c = x-(a*100)-(b*10);

switch (a) {

case 0 :
  zeroHaut();  break;
case 1 :
  unHaut();  break;
case 2 :
  deuxHaut();  break;
case 3 :
  troisHaut();  break;
case 4 :
  quatreHaut();  break;
case 5 :
  cinqHaut();  break;
case 6 :
  sixHaut();  break;
case 7 :
  septHaut();  break;
case 8 :
  huitHaut();  break;
case 9 :
  neufHaut();  break;
}  
lcd.print(" ");
switch (b) {  
case 0 :
  zeroHaut();  break;
case 1 :
  unHaut();  break;
case 2 :
  deuxHaut();  break;
case 3 :
  troisHaut();  break;
case 4 :
  quatreHaut();  break;
case 5 :
  cinqHaut();  break;
case 6 :
  sixHaut();  break;
case 7 :
  septHaut();  break;
case 8 :
  huitHaut();  break;
case 9 :
  neufHaut();  break;
}  
lcd.print(" ");
switch (c) {  
case 0 :
  zeroHaut();  break;
case 1 :
  unHaut();  break;
case 2 :
  deuxHaut();  break;
case 3 :
  troisHaut();  break;
case 4 :
  quatreHaut();  break;
case 5 :
  cinqHaut();  break;
case 6 :
  sixHaut();  break;
case 7 :
  septHaut();  break;
case 8 :
  huitHaut();  break;
case 9 :
  neufHaut();  break;
}
lcd.setCursor(0, 1);

switch (a) {  
case 0 :
  zeroBas();  break;
case 1 :
  unBas();  break;
case 2 :
  deuxBas();  break;
case 3 :
  troisBas();  break;
case 4 :
  quatreBas();  break;
case 5 :
  cinqBas();  break;
case 6 :
  sixBas();  break;
case 7 :
  septBas();  break;
case 8 :
  huitBas();  break;
case 9 :
  neufBas();  break;
}  
lcd.print(" ");
switch (b) {  
case 0 :
  zeroBas();  break;
case 1 :
  unBas();  break;
case 2 :
  deuxBas();  break;
case 3 :
  troisBas();  break;
case 4 :
  quatreBas();  break;
case 5 :
  cinqBas();  break;
case 6 :
  sixBas();  break;
case 7 :
  septBas();  break;
case 8 :
  huitBas();  break;
case 9 :
  neufBas();  break;
}  
lcd.print(" ");
switch (c) {  
case 0 :
  zeroBas();  break;
case 1 :
  unBas();  break;
case 2 :
  deuxBas();  break;
case 3 :
  troisBas();  break;
case 4 :
  quatreBas();  break;
case 5 :
  cinqBas();  break;
case 6 :
  sixBas();  break;
case 7 :
  septBas();  break;
case 8 :
  huitBas();  break;
case 9 :
  neufBas();  break;
}


}
#endif

Désolé pour le double post, mais le forum trouvait que tout en un seul post était trop gros...

Se serait possible d'avoir un schéma de câblage pour tester tout ça de mon côté ?

Rovhell:
Une jauge à liquides à résistance variable (56? / cm) de 25 cm 30€

Chuis feignant, où c'est'y que t'as trouvé ça ?
Merci d'avance XD

Les schémas viendront, avec les photos du montage final. J'ai d'ailleurs bien fait de mettre un arduino mini, j'étais à cours de pins.
Pour la jauge, c'est le E-tape de chez adafruit.

Le matériel manquant est commandé :slight_smile:

Rovhell:
Pour la jauge, c'est le E-tape de chez adafruit.

Dans la doc (succinte) chez Lextronic, il est dit de ne pas l'utiliser pour des liquides inflammables ?
Cela ne m'inquiète pas vraiment.
Les anciennes jauges à flotteurs utilisaient des potentiomètres qui trempaient dans l'essence !
Mais quid de la résistance du Etape aux hydrocarbures?

Ils sont obligé de décliner leur responsabilité quand à mélanger électronique et liquides inflammables. La partie immergée de la jauge est étanche, et je doute fort de faire une quelquonque flamme ou étincelle avec une résistance. Je compte bien sur blinder l'étanchéité de mes branchements en haut de la jauge.
Pour la variabilité de la résistance avec des hydrocarbures, il est clair que ce ne sera pas la même qu'avec l'eau, et un petit test s'impose afin de calibrer le tout.
Le Etape fonctionne grâce à la pression du liquide.

De toute façon même avec une flamme, le mélange air essence dans le réservoir devrais être suffisamment merdique pour que ca ne puisse pas exploser si ? :stuck_out_tongue:

M'enfin j'avoue que moi je flipperai quand même ! :stuck_out_tongue:

J'essaye aussi de mon coté de me faire un équipement de BMW sur une suzuki gladius. Bon pour le moment j'en suis à faire un grille pain avec l'arduino, je pourrais peut être en tapisser les pneus pour les faire chauffer... Ca va me couter cher !

Pas de panique ! toutes les jauges récentes sont de ce type. Pas de chauffe, pas d'étincelle possible, juste une mesure de valeur de résistance. Il faut juste rajouter un hystérésis pour une moto (surtout quand on arsouille dans les virages, je sais c'est maaaaal, mea culpa maxima :smiley: ).
Exemple d'une jauge de série pour une Honda:

C'est pas le risque d'explosion qui m'inquiète XD
Je me pose plutôt la question de la résistance aux hydrocarbures de la sonde.

La sonde fonctionne par différence de pression. Une partie de la sonde doit rester hors du liquide. Donc, à moins que le SP n'exerce sur l'Etape une pression proche de celle de l'air, ce dont je doute, il y a de fortes chances que ça marche.

Bon je voulais savoir, si à tout hasard, quelqu'un aurait déjà eu un bug avec le LCD 16x2?
Voilà ce que ça donne avec le arduino mini :
image

Voir le premier post pour ce que ça donne avec l'arduino uno, même code.
Vu que j'ai mis 75 essais à programmer le mini, je ne sais pas si y'a pas encore un soucis avec mon mini.

Bon, erreur toute bête de ma part, les pins du mini sont dans l'ordre inverse de ceux du Uno (parce que ma carte est dos à l'écran). Donc si quelqu'un un jour à le même soucis, c'est juste les fils qui sont pas dans le bon ordre.

Ça y'est, l'affichage fonctionne. Mais plus la carte sd pour le moment. Je vais vérifier mes soudures.