Go Down

Topic: Réalisation d'un afficheur de vitesse pour voiture (Read 3752 times) previous topic - next topic

jeec

Dec 23, 2012, 12:13 am Last Edit: Dec 24, 2012, 09:03 am by jeec Reason: 1
Bonjour

J'ai démarré un nouveau projet, avec comme but d'afficher la vitesse de ma voiture dans un afficheur qui puisse être mieux placé dans le champ de vision que le compteur d'origine (dans le style speed visio de Valeo).

Comme je possède un véhicule relativement récent, il y a un fil info vitesse, et j'ai pu y brancher un nouveau cable en accédant aux branchements du compteur d'origine grâce à des informations trouvées sur les forums auto.

Pour la phase suivante, j'ai espionné avec un oscillo numérique de poche les infos qui circulaient sur ce cable.

Le signal est un signal carré, le niveau bas est à 0, le niveau haut à 13 V.
A 40 km/h, la demi-période est d'environ 10 ms, à 80 km/h de 5 ms. La loi qui donne la vitesse serait donc: vitesse=400/demi-période.

Enfin, j'ai développé le prototype.

Pour la partie électronique, je récupére le signal du cable sur une entrée numérique de l'arduino, après l'avoir adaptée au niveau de tension acceptable, en utilisant un pont diviseur (6 k/10 k), ce qui donne 4,88 V en entrée en niveau haut.

Pour la partie logicielle, je me contente pour l'instant, dans la boucle principale, de déterminer la demi-période du signal, d'en déduire la vitesse, et de l'afficher.

Je n'ai pas opté, dans ce projet, pour l'utilisation des interruptions (par exemple sur signal montant), mais plutôt sur un test en continu de la valeur (haute ou basse) de mon entrée vitesse.

Voici la partie du code qui effectue le "calcul" dans la fonction principale void loop()

   
Code: [Select]

valBitInfoVitesse=digitalRead(bitInfoVitesse);
 
while(valBitInfoVitesse==LOW)
  {
    valBitInfoVitesse=digitalRead(bitInfoVitesse);
    }
 
 
t=micros();  

while(valBitInfoVitesse==HIGH)
  {
    valBitInfoVitesse=digitalRead(bitInfoVitesse);
    }
 
  ecartMicroS=micros()-t;
  vitesse=400000/ecartMicroS;
    ecrireNombre(vitesse);

J'ai testé l'ensemble sur mon véhicule, en fait en deux fois. Dans la première version, j'affichais seulement la valeur de la demi-période, en mS. Dans une deuxième version, après avoir rajouté le calcul, c'est la vitesse que j'affichais.

Ces deux expériences ont eu un résultat plutôt mitigé. La demi- période (ou dans la deuxième expérience, la vitesse) étaient très instables, bien que globalement cela tourne autour des valeurs attendues, mais avec très souvent des résultats aberrants.

Mes compétences en électronique sont limitées, mais j'imagine que c'est l'environnement perturbé du véhicule qui crée ces problèmes. Peut-être faut-il diminuer la valeur des deux résistances du pont pour augmenter l'intensité (si oui, jusqu'où aller)? L'arduino est alimenté par la prise allume-cigare, cela pose-t-il problème? Y a t-il des choses à faire?

Merci pour votre aide, et bonnes fêtes de fin d'année à tous.

Christian_R

Le principe du capteur est le bon, Fréquence = k x Vitesse.

Mais il est possible que tu loupes un cycle de temps en temps, si l'arduino est en train de faire "autre chose" (calculs dans un autre bout du programme) que de surveiller la broche au bon moment quand elle bascule.

J'opterai plutôt pour un convertisseur fréquence / tension, dédié à ça, puis lecture de tension (stable) par l'arduino pour rafraîchir un affichage périodiquement.

* Quelques résistances, capa, et une diode de redressement :
http://www.astuces-pratiques.fr/electronique/convertisseur-frequence-tension-passif-simple

*Ou un circuit intégré "frequency to voltage converter" (type LM2907 http://www.ti.com/lit/ds/symlink/lm2907-n.pdf)
Christian

fdufnews

L'erreur peut aussi être causée par le fait que c'est la période et non la demi periode qui porte l'information. Tu pourrais essayer d'utiliser l'instruction pulsin() pour faire ta mesure. Il faut penser à mettre un hors  temps  afin de sortir de la fonction lorsque la voiture est à l'arrêt

fdufnews

Autre chose il serait prudent de mettre une zener pour protéger l'entrée de mesure.
Il faudra sans doute faire un filtrage sur le résultat  car il y a toujours une petite fluctuation sur ce genre de mesure. Une moyenne glissante ou un filtrage en:
Mesure * a + résultat précédent * (1-a)
Peut régler le problème.

jeec

Pour répondre à Cristian_R:
Le convertisseur fréquence/tension est une bonne piste pour le futur de mon projet, pour l'instant je veux comprendre ce qui ne fonctionne pas dans le prototype.
Par ailleurs, l'arduino ne fait que deux choses, de façon répétitive: Calculer la durée d'une demi-période, entre le début d'un état haut et le début d'un état bas, puis afficher.
Comme je le précise, il n'y a aucune interruption qui pourrait perturber le fonctionnement.

Pour répondre à fdufnews:
C'est grâce à la trace de l'oscillo que j'ai déterminé que la demi-période fournissait une info exploitable.
Je ne connaissais pas pulsin(), d'après la référence, ça a l'air de faire exactement la même chose que ce que j'ai écrit.
J'avais bien pensé à faire une moyenne glissante, mais le risque est d'obtenir une mesure stable mais fausse.
Sinon, je retiens la protection par Zener.

jeec

Je reviens sur l'utilisation du convertisseur fréquence/tension. Sauf erreur de ma part, c'est une solution très utile pour fabriquer un compteur de vitesse ne faisant pas appel à de l'informatique embarquée, il suffit de brancher le convertisseur sur un appareil à cadran de type voltmètre, et c'est tout.

Dans mon cas, où je passe par l'arduino, je pense que cela ne ferait que compliquer le montage, et rajouter une marge d'erreur supplémentaire.

Christian_R


Comme je le précise, il n'y a aucune interruption qui pourrait perturber le fonctionnement.

Si, à mon avis il y a un bug.
L'état du signal n'est pas connu au moment où on exécute ce bloc :
Code: [Select]
while(valBitInfoVitesse==LOW)
    {
         valBitInfoVitesse=digitalRead(bitInfoVitesse);
      }
t=micros(); 

Si on a la chance d'être sur LOW, tout ira bien, on attend bien pour sortir de la boucle le passage sur High.
Mais si on est déjà pendant un état HIGH du signal, ce bloc est sauté sans attendre.
La variable t est censée mémoriser en sortie de cette boucle l'instant précis d'un front montant.
Au lieu de ça elle va mémoriser un instant quelconque pendant un état HIGH.
Christian

jeec

#7
Dec 23, 2012, 12:46 pm Last Edit: Dec 24, 2012, 09:05 am by jeec Reason: 1
Quand je fais:
Code: [Select]

while(valBitInfoVitesse==LOW)
    {
         valBitInfoVitesse=digitalRead(bitInfoVitesse);
    }

je ne fais qu'attendre un nouveau passage à l'état haut:

Soit je suis déjà à l'état haut (cet etat haut a déjà démarré, il ne m'interesse pas), et je ne rentrerai dans la boucle que quand l'état repassera à bas.
soit je suis à l'état bas, et je rentre dans la boucle.

C'est en sortant de la boucle, alors que l'état vient de passer à haut,  que je commence mon comptage.

Christian_R


cet etat haut a déjà démarré, il ne m'interesse pas

Il faut pourtant bien s'y intéresser, car il fixe quand même une valeur de t juste après cette boucle d'attente que l'on saute, avec une mauvaise valeur qui n'est pas celle d'un front.
Christian

jeec

#9
Dec 23, 2012, 02:06 pm Last Edit: Dec 24, 2012, 09:06 am by jeec Reason: 1
Bon, je vais essayer d'expliciter un peu plus:


L'instruction "t=micros(); " est exécutée au moment du passage à l'état haut.
Il s'agit maintenant de se mettre en attente de la fin de cet état haut, ce que réalise la boucle:
Code: [Select]

while(valBitInfoVitesse==HIGH)
    {
         valBitInfoVitesse=digitalRead(bitInfoVitesse);
    }

C'est le passage à l'état bas qui fait sortir de la boucle, et qui permet maintenant de calculer la demi-période (écart de temps entre le passage à l'état haut, soit t, et le passage à l'état bas, soit le temps présent ).


J'en reviens à mon problème de base, qui me semble quand même être lié à des perturbations CEM.

Christian_R


L'instruction "t=micros(); " est exécutée au moment du passage à l'état haut.

Ben non, je persiste et signe.
Imagine que bitInfoVitesse soit HIGH dès le départ, et exécute méthodiquement ton code ligne par ligne.
Code: [Select]
valBitInfoVitesse=digitalRead(bitInfoVitesse);
     while(valBitInfoVitesse==LOW)
     {
          valBitInfoVitesse=digitalRead(bitInfoVitesse);
       }
      t=micros(); 

t=micros() sera exécuté sur le champ (on zape la boucle LOW) donc n'importe quand, sans même détecter ce passage à l'état haut.

le point de départ du chronométrage est faux, donc le deltaT qui suit juste derrière le sera aussi.
Christian

jeec

#11
Dec 23, 2012, 05:07 pm Last Edit: Dec 24, 2012, 09:07 am by jeec Reason: 1
L'erreur est vraiment énorme, tellement que je ne la voyais pas. Je te remercie d'avoir insisté!

Je vais attendre l'état haut permettant de démarrer la mesure en faisant plutôt:

Code: [Select]

valBitInfoVitesse=digitalRead(bitInfoVitesse);
while(valBitInfoVitesse==HIGH)
    {
         valBitInfoVitesse=digitalRead(bitInfoVitesse);
    }
while(valBitInfoVitesse==LOW)
    {
         valBitInfoVitesse=digitalRead(bitInfoVitesse);
    }

Jean-François

Est ce que tu pourrais rééditer tes message et mettre le code entre les balises code (le bouton avec #)

Pour ton projet, pourquoi ne pas utiliser un optocoupleur et le mettre sur une pin d'interruption (il y a une limite en fréquence)
MacBook intel core 2 duo  os X snow Leopard 10.6<br/> eMac PPc G4  os X Leopard 10.5<br/>powerbook G4 os X Leopard 10.5
imac PPC G3 os X Pa

Super_Cinci

Salut,

Je viens de lire un peu tout ça, et ayant déjà pas mal planché sur ce genre de projet, quelques choses m'embête un peu...

Tu dis avoir une demi période de 10ms pour 40km/h, ce qui donnerait une impulsion tous les 22,222222... cm parcourus. Chez Renault (et certainement beaucoup d'autres), les capteurs vitesse utilisés sont donnés à une impulsion pour 20cm parcourus (ou encore 5 impulsions par mètre). Je pense que c'est ton cas (ça donne une erreur de 11% dans tes mesures, c'est possible). Par ailleurs, ce signal est très précis, donc mieux vaut être précis autant que possible.

Pour la mesure, j'utiliserais une méthode très différente, car l'arduino propose une fonction matérielle super puissante : "ICP1". Matériel veut dire que la gestion est purement électronique, aucun (ou presque) code n'intervient.

En gros, sur la pin 8, tu mets ton signal info vitesse, et avec un peu de config, chaque impulsion viendra mettre la variable vitesse à jour en utilisant une interruption. ICP (Input Capture Pin) a pour but de sauvegarder la valeur d'un compteur à chaque impulsion. Ce compteur est le timer 1 qu'il te suffit de configurer pour qu'il compte en continu, à une fréquence optimale (ça demande à réfléchir un peu, mais ça vaut largement le coup).

Tu pourras donc dans ton loop() faire simplement :

Code: [Select]

byte vitesse; // variable contenant la vitesse mesurée
void loop() {
  lcd.print(vitesse);
  delay(100); // mise à jour sur le LCD 10 fois par secondes, si trop rapide, ce sera illisible
}


Sachant que tu auras une ISR (Interrupt Sub Routine : fonction d'interruption) qui sera appelée à chaque impulsion et qui mettra à jour la variable vitesse.

Bonus : si tu utilises par exemple une variable de type long (long distance; par exemple), dans l'ISR, tu peux rajouter la ligne "distance++;". Ca mange pas de pain, mais du coup, tu auras un totaliseur kilométrique précis à 20cm... (kilométrage = distance / 5000;).

Ce n'est qu'une idée, mais j'aurais fait comme ça, car niveau exécution, c'est top et ça permet de rajouter un max de fonctions par la suite!

jeec

Quote
Pour ton projet, pourquoi ne pas utiliser un optocoupleur et le mettre sur une pin d'interruption (il y a une limite en fréquence)


Je n'ai jamais utilisé d'optocoupleur, je crois seulement savoir que ça permet de protéger un circuit de surtensions. Peux-tu m'indiquer quelle référence utiliser, et ou trouver l'information pour le montage? En ce qui concerne la limite de fréquence, tu veux dire qu'un optocoupleur pourrait ne pas laisser passer certaines fréquences?

Quote
Tu dis avoir une demi période de 10ms pour 40km/h, ce qui donnerait une impulsion tous les 22,222222... cm parcourus. Chez Renault (et certainement beaucoup d'autres), les capteurs vitesse utilisés sont donnés à une impulsion pour 20cm parcourus (ou encore 5 impulsions par mètre). Je pense que c'est ton cas (ça donne une erreur de 11% dans tes mesures, c'est possible). Par ailleurs, ce signal est très précis, donc mieux vaut être précis autant que possible.


J'étais bien conscient que les mesures que j'avais faites n'étaient pas bien précises (ce n'est pas facile en roulant!). Mon intention était de toutes façon d'étalonner le compteur avec un GPS, par la suite. Je vais utiliser tes paramètres, cela m'évitera probablement l'étalonnage.

Quote
Pour la mesure, j'utiliserais une méthode très différente, car l'arduino propose une fonction matérielle super puissante : "ICP1". Matériel veut dire que la gestion est purement électronique, aucun (ou presque) code n'intervient.


Je vais expérimenter tout ça.
Je vais être absent du forum quelque temps, mais vous tiens au courant de l'avancement à mon retour.

Go Up