pas besoin de mettre 58.0
suffit 58 car Cm est un unsigned int
Je ne sais pas comme ils font les pros mais même si c'est pareil moi je mets toujours des parenthèses:
Bonjour à tous,
voici mon code final.
Il fonctionne, mais aléatoirement. quelques fois, il y a une ligne erronée. Je ne sais pas si ça vient de mon code, du HC-SR04 qui manque de fiabilité, peut être existe t'il un appareil plus précis, mais je n'en ai pas connaissance ou le LCD ?
Si c'est le code, je vous serais très reconnaissant d'apporter votre oeil averti.
Merci
#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
int trig = 8;
int echo = 9;
float lecture_echo, Litres = 0.0, Cm = 0.0;
float hcsrpos = 110.0;
float Volume = 0.0;
void setup() {
pinMode(trig, OUTPUT);
Serial.begin(9600);
delay (5000);// pendant 5 secondes
}
void loop() {
digitalWrite(trig, HIGH);
digitalWrite(trig, LOW);
lecture_echo = pulseIn(echo, HIGH);
//Mesure de la hauteur d'eau restante
Serial.print("Hauteur d' eau: ");
unsigned int Cm = hcsrpos - (lecture_echo / 58);
Serial.println(Cm);
Serial.print("CM ");
//Calcul du volume restant dans la cuve
Serial.print("Volume d' eau: ");
Serial.println(Volume);
Volume = Cm * 10;// Calcul le résultat final en multipliant par 10 Litres
Serial.print("Litres ");
delay(5000);// rafraichissement toutes les 5 secondes
pinMode(echo, INPUT);
lcd.begin(16, 2);
lcd.setCursor(3, 0); // écrit à partir de la 4 éme case
lcd.print ("Niveau cuve");// écrit Niveau cuve
delay (3000);// pendant 3 secondes
lcd.clear();// efface le LCD
digitalWrite(trig, HIGH);
delayMicroseconds(10);
digitalWrite(trig, LOW);
lecture_echo = pulseIn(echo, HIGH);
Cm = hcsrpos - (lecture_echo / 58);
lcd.setCursor (0, 0); // commence l'écriture à la 1 ére case
lcd.print ("Haut eau: ");// écrit Haut eau:
lcd.setCursor (10, 0); // continue à la 11 éme case ligne 1 pour écrir la distance trouvée
lcd.print (Cm);// écrit la valeur de la mesure trouvée
lcd.setCursor (14, 0); // continue à la 15 éme case ligne 1
lcd.print ("CM");// écrit CM
lcd.setCursor (0, 1); // commence l'écriture à la 1 ére case de la ligne 2
lcd.print ("Volume: ");// écrit Volume:
lcd.setCursor (8, 1); // continue à la 8 éme case ligne 1 de la ligne 2 pour écrir Volume:
lcd.print (Volume);// affiche le volume d'eau restante
lcd.print ("L");// écrit L pour Litres
delay(3000);// rafraichissement toutes les 3 secondes
lcd.clear();// efface le LCD
}
Tu peux nous faire un exemple de ligne erronée?
J'ai fais un thermostat et j'ai inséré une fonction pour contrôler le niveau de fioul dans ma cuve.
J'ai utilisé la librairie NewPing pour avoir le niveau de fioul.
J'ai toujours une bonne valeur en Cm même si ma cuve est un cylindre horizontal de 3000L.
Je pense que l'important est de mettre le capteur le plus au centre possible de la cuve.
Si tu veux savoir s'il y a encore de choses à faire dans ton code:
lcd.begin(16, 2);
C'est mieux le mettre dans ton setup.
Il y a peux de temps j'ai appris la fonction printf. Tu peux simplifier beaucoup ton code avec cette fonction.
Bonjour,
Merci pour votre réponse.
J'ai simplement essayé sur mon bureau devant l'ordinateur.
J'ai placé le HC-SR à 1.10m du mur, ce qui représente la hauteur du bouchon de remplissage et je simule la hauteur d'eau avec une revue.
Quelques fois j'ai 0 cm et le bon volume d'eau d'autres fois une bonne hauteur et 65000 Litres de volume il arrive que ce soit exact etc...
C'est bizarre je n'ai pas la librairie NewPing
Je vais continuer mes essais et je vous tiendrai informé.
@+
Robert
Ce module ultra son est rudimentaire, il ne faut pas trop lui en demander. Tu peux prendre en compte ses défauts.
Tu peux modifier ton programme :
_ faire une série de X mesures (x= 5 parrait un chiffre raisonnable)
_par test exclure les mesures fausses et faire la moyenne de celle qui restent.
68tjs:
Tu peux modifier ton programme :
_ faire une série de X mesures (x= 5 parrait un chiffre raisonnable)
_par test exclure les mesures fausses et faire la moyenne de celle qui restent.
Tu viens de dire que de temps en temps tu as une mesure erronée, il faut donc l'éliminer.
Soit tu arrive a trouver la cause physique et tu remédie au problème , soit tu n'y arrive pas
Si tu n'y arrive pas on va ruser.
Au lieu de faire des cycles d'une seule mesure je te propose de faire des cycles constitués par une série 5 ou 10 mesures espacées d'une seconde.
Tu obtiendra par exemple : 1,1 ; 1,15; 0,2 ; 1,12 ; 1,14
Nous sommes d'accord la mesure 3 qui donne 0,2 m est fausse.
A partir de ce constat à l'aide d'un algorithme que va créer tu éliminera la mesure fausse.
Pour améliorer la précision tu fera la moyenne des mesures restantes.
Vous pouvez avoir une idée de ce qu'est une valeur fausse (ex: hors des tolérances des dimensions de la cuve) et decider d'ignorer ces valeurs hors bornes (en refaisant une mesure).
Le seul petit problème, c'est que se passe-t-il si toutes valeurs ont hors bornes.
Vous pouvez essayer de lisser les valeurs jugées vraisemblables, en stockant quelques mesures consécutives:68tjs recommande 5 valeurs , puis en en faisant la moyenne.
Je serais tenté de rajouter moyenne ou médianehttps://fr.wikipedia.org/wiki/M%C3%A9diane_(statistiques).
En effet, je n'ai aucune idée des bornes. Je vais prendre la série suivante:
10,11,9,1111,1080
Si je prends la moyenne, j'aurai :
> mean(c(10,11,9,1111,1080))
[1] 444.2
qui est à plus de 400 de chacun des elements
Si je prends la médiane, je trouverai 11 qui est undes elements de la série (il suffit de parier que moinsde 50% des mesures sont aberrantes pour que la médiane donne une valeur plausible)
Le seul petit problème avec la médiane est que cela implique de trier Tri par insertion — Wikipédia les mesures : en pratique, jusqu'à des tableaux de 15 valeurs, cela n'est pas lent (pour moi)...
Il y a un autre problème dans votre code (dans l'état, c'est un problème cosmétique; ça peut devenr ennyeux si vous voules géréer d'autres mesures): ous faites appel à delay(), qui est bloquant (et qui complique enormement la vie lors d'evolution). Fans les exemples d'arduino, vous avez un "blinkWithoutDelay" qui explique comment utiliser l'horloge de l'arduino pour ne pa mettre de delais bloquants )
Pour bien traiter les valeurs aberrantes, et le message de dbrion06 le montre , il est utile d'étudier la distribution des valeurs puis au vu des résultats, choisir et adapter la méthode.
Un tableur peut aider à représenter et analyser la série de valeurs pour la traiter de manière acceptable
(je suis souvent amené à privilégier le filtre médian dans les situations que je rencontre)
J'ai volontairement passé sous silence les méthodes pour éliminer. Perso je suis un grand fan de l'écart type.
al1fch:
il est utile d'étudier la distribution des valeurs puis au vu des résultats, choisir et adapter la méthode.
Un tableur peut aider à représenter et analyser la série de valeurs pour la traiter de manière acceptable
(je suis souvent amené à privilégier le filtre médian dans les situations que je rencontre)
Je partage totalement. C'est très utile et important.
C'est du travail préalable qui permet de choisir la meilleure méthode et la meilleure méthode ce n'est pas celle d'untel ou d'untel c'est celle qui est la mieux appropriée au conditions du projet.
La première recherche que je ferais c'est d'étudier si les mesures fausses ne reviennent pas à intervale régulier ou si au contraire leur apparition est aléatoire.
Si leur apparition est régulièrement espacée elles sont certainement dues à l'environnement et leur cause pourrait être supprimée.
Ensuite évidement il y a les bornes min et max, là un simple test immédiatement après la prise de mesure permet de les évacuer.
Avec cette étude on peut déterminer le nombre de mesures par salve, j'ai cité 5 ou 10 un peu au hasard mais peut être que l'étude montrera que 20 mesures rendront plus simple la sélection entre mesures correcte et mesures éronnées.
Un tableur peut aider à représenter et analyser la série de valeurs pour la traiter de manière acceptable
Encore faut il donner au tableur (ou à R, octave, python+matplotlib) les valeurs suspectes:
je suggérerais, côté Arduino, de passer la vitesse de transmission série à 115200 bauds (marche partout; est le maximum pour un RPi) au lieu de 9600 et, dans une première étape, d'utiliser la partie graphique de la console série ;
Dans une seconde étape, j'investirais du temps dans python+ pyserial pour pouvoir recupérer (sur PC ou RPi) les valeurs à analyser....
A noter que retirer le min et le max (ou le faire avec acharnement, jusqu'à ce qu'il ne reste qu'un ou deux éléments: c'est une façon de calculer une médiane....) ne marche que si les valeurs aberrantes sont isolées.... (la médiane ne fonctionne que si 50% dex valeurs sont vraies: si un capteur est trop sensible à certains moments, et que ce comportement perdure, le filtrage médian sera inopérant -comme tout filtrage: il faut augmenter la période d'échantillonnage en pariant que , au bout d'un certain temps, ce comportement aberrant se calmera....)
Encore faut il donner au tableur (ou à R, octave, python+matplotlib) les valeurs suspectes:
Il ne s'agit pas dans mon esprit de faire continuellement un filtrage par un tableur contenu dans un PC.
Pas du tout, il s'agit d'obtenir une représentation graphique, de l'examiner avec un outil universel : son cerveau .
Accessoirement de pouvoir faire quelques opérations statistiques rudimentaires.
Le but étant d'avoir une aide pour le choix de la méthode la plus adapté à la réalité du système de mesure de cuve pris dans son environnement.
C'est un travail préalable à l'écriture du code définitif.
J'utilise un tableur parce que c'est amplement suffisant et que tout le monde sait s'en servir sans prise de tête.
Sans expérience préalable d'octave ou de mathplot ou autres je ne pense pas que ce serait pareil.
Pour l'acquisition des mesures je reste très basique : affichage dans le moniteur de l'IDE copié collé dans un tableur -> ne pas oublier un cherche le point et remplace par une virgule ça peut aider avec des nombres.
Si on veut du plus luxueux : carte SD.
"Il ne s'agit pas dans mon esprit de faire continuellement un filtrage par un tableur contenu dans un PC."
Pas plus que dans le mien: il s'agit de comprendre...
Une étape intermédiaire entre
le copier coller (et je parie qu'Excel -fait à Richmond- , tout comme R, octave, -et python, bien sûr- sait reconnaître des nombres en représentation non-française -avec des points decimaux!-) et
la carte SD
est l'enregistrement en continu (ou par paquets) depuis la ligne série -déjà existante- sur PC/RPi (adapter -passage en ASCII pour ne pas s'ennuyer avec des binaires ...- Capturing an analog signal with Arduino and python | Freedom Embedded est très rapide....)
Ensuite, le choix du tableur (décodeur/analyseur est très ouvert (j'ai évoqué R et python, qui m'ont donné satisfaction et octave, que j'ai recommandé à ub ami: il doit y en avoir des dizaines d'autres....)
Nota: je ne sais pas ce qu'est excel....(mais c'est certainement très bien: R arrive à lire des *.xls)
edit: la façon la plus rapide d'avoir un graphique -moins beau qu'avec excel ou matplotlib, cependant- est d'utiliser la sortie graphique du terminal série, très simple d'emploi et vraisemblablement disponible avec l'IDE d'arduino...
Bonjour à tous,
Là les amis, je suis totalement dépassé par vos dialogues.
J'ai peut être trouvé un début de cause des erreurs.
Les temps n'étaient pas les mêmes partout.
Ligne 12 5000
Ligne 30 5000
Ligne 35 3000
Ligne 53 3000
J'ai tout mis à 2000 et les mesures sembles correctes
J'avais critiqué votre façon de gerer le temps (avec delay, qui est bordelique: regardez l'exemple blinkWithoutDelay de l'IDE Arduino), ceci pour des raisons cosmétiques et de maintenance à terme.
Je ne pense pas que les valeurs aberrantes de votre capteur se règlent par la gestion du temps (en presence de valeurs aberrantes, il faut essayer de comprendre pourquoi -chacun ayant ses recettes pour tenter de comprendre, voire traiter, d'iù la complexité de nos discussions- : là, je ne vois pas de lien logique: c'est peut être un miracle)
dbrion06:
J'avais critiqué votre façon de gerer le temps
Je suis preneur de toutes critiques car je débute dans la programmation.
C'est pour cette raison que si vous désirez corriger mon code, je l'accepterai avec plaisir.
Avoir l'avis de connaisseurs permet de s'améliorer
JE vais vous proposer (je n'ai pas d'arduino sous la main cette semaine: je ne peux pas le tester) une version de votre programme qui:
ne fait aucun delai
n'affiche que si une valeur significative de variation (1 litre) a été detectée (il n'y a rien de plus exasperant que de faire defiler sur un écran série les mêmes valeurs, ou que de faire clignoter un LCD pour des valeurs très voisines)
Prepare le terrain pour le filtrage (mais ça devrait faire l'objet d'u programme à part)
Je me suis basé sur le dernier code que vous avez montré
J'ai mis tous les calculs en flottant (ça fait en tout 5 operations: de memoire, ça fait moins de 0.6 milliseconde sur arduino : l'affichage série à 115200 bauds mange plus de 4 millisecondes par affichage -10 000 caractères par seconde pour plus de 40 caractères)...
J'ai rajouté un saut de ligne par affichage (sinon, comment pouvez vous lire), sans enjoliver (tabulations)
// NON TESTE
#include <LiquidCrystal.h>
LiquidCrystal lcd(12,11,5,4,3,2);
const int trig = 8;
const int echo = 9;
float lecture_echo,Litres = 0.0, Cm = 0.0;
float hcsrpos = 110.0;
float hcsrres, HautEau, Volume = 0.0;
void setup() {
pinMode(trig, OUTPUT);//ok
Serial.begin(115200);
delay (5000);// pendant 5 secondes
}
// prepare le terrain pour filtrage par moyenne ou mediane ou....
#define TAILLEBUFF = 2*5+1 // je mets un buffer de 11
float tablo [TAILLEBUFF];
uint8_t indicetablo=0;
//
// valeur precedemment affichee
//
float affichePred =-99.0; // on n'a que des grandeurs positives: forcera l'affichage au demarrage
//
void loop() {
digitalWrite(trig, HIGH);
digitalWrite(trig, LOW);
lecture_echo = pulseIn(echo,HIGH);
// Mesure de la hauteur d'eau restante
/* unsigned int */ // non: pour ne rien degrader, on fait tous les calculs en float
float Cm = hcsrpos-lecture_echo /58.0;
// Calcul du volume restant dans la cuve
Volume = Cm * 10;// Calcul le résultat final en multipliant par 10 Litres
if (abs(Volume - affichePred) > 1.0) { // on n'affiche que si ca a varié de plus d'un litre
//
// reamorcage affichage
//
affichePred = Volume;
//
Serial.print("Hauteur d' eau: ");//ok
Serial.println(Cm);//ok
Serial.print("CM ");//ok
Serial.print("Volume d' eau: ");//ok
Serial.println(Volume);
Serial.print("Litres ");
Serian.println; // saut à la ligne
}
// remplissage du tableau
tablo[indiceTablo] = Volume;
indiceTablo ++;
if (indiceTablo >= TAILLEBUF){
le tableau est plein : on peut -ce n'est pas fait- calculer un min, un max, une moyenne, une médiane
indiceTablo = 0; // on le reamorce
}
} // de loop
A noter que, si du bruit ou des valeurs aberrantes viennent vous chahuter, les sauts seront tels que ça sera systematiquement affiché....
Desolé, (j'ai bien spécifié que je ne l'avais pas testé) mais le message d'erreur est assez clair (j'ai une longue habitude de messages d'erreurs):
vous ne pouvez pas mettre de signe egal dans une macro (#define).
La ligne
#define TAILLEBUFF (2*5+1) // je mets un buffer de 11
a de fortes chances d'être correcte.
En passant, pulseIn peut avoir 2 ou 3 arguments. Dans le cas que vous employez, avec 2 arguments, le programme peut être bloqué en attente d'un echo pendant une seconde pulseIn() - Arduino Reference, ce qui correspond à une profondeur de votre tonneau de 150 mètres (une demi tour Eiffel ou 50 étages...). Je ne pense pas que votre tonneau soit aussi profond.
J
e modifierais l'invocation de pulseIn ainsi lecture_echo = pulseIn(echo,HIGH, 50000UL); qui bloque au maximum pendant 50 millisecondes (profondeur de votre foudre 7.8 mètres) ou une autre valeur realiste -notez en passant la convention pour les les entiers longs -pouvant dépasser 65532- non signés-.
A terme, mais certainement pas dans une phase de recherche et de tentative de traitement de valeurs aberrantes, cette valeur devrait être exclue des calculs .