Pages: [1]   Go Down
Author Topic: Gastank mit Schwimmer  (Read 879 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 14
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hallo Forum,

ich habe folgendes:
Gastank mit Schwimmer, 1 Anzeige (Direkt am Tank) wie voll dieser noch ist, eine die Digital umgerechnet wird, und Widerstände für Voll-Mittel-Lehr.

Z.Z. gibt die Anzeige (Digital) 4 LED´s an. Heißt, wenn alle 4 LED´s an sind ist der Tank voll, 2 ist die häflte, und keine ist logischerweise Lehr smiley
Da mir diese Anzeige zu ungenau ist, habe ich mir eine Anzeige gebaut (Arduino) die den Widerstand abgreift und auswertet in % und Balken.
Nur dieser Tank bewegt sich, so das es zu Schwankungen in der Prozentzahl sowie auch in den Balken gibt smiley-sad .
Die Zeit hab ich schon verändert aber das bringt mich nicht wirklich weiter.
Erst zeigt die Anzeige  z.B. 75 % an und nach 5 sec 34% und wieder 5sec. später 85% usw. .
Also dieses Schwanken geht mir auf den Keks. DAs einzige was ruhig bleibt ist der Analoge Zeiger vom Tank direkt. KA warum diese nicht schwank smiley-sad
Gibt es vllt. irgendeine Idee/Lösung die mir da aushelfen kann? Z.B. ein Algoritmus der innerhalb von z.B. 5 min. die Bewegungen aufzeichnet und davon z.B. die 3. höchste Zahl (von allen aufgezeichneteten) annimmt, die aber nicht über die alte Zahl die vor 5 min angezeigt wurde drüber hinaus kommt ? Hoffentlich konnte ich mich richtig ausdrücken.

Ich schaff das einfach nicht zu realisieren. so gut bin ich da nicht smiley-sad

Danke für Eure Mühe! smiley
Logged

Germany
Offline Offline
Edison Member
*
Karma: 46
Posts: 2310
Arduino rocks
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Ich würde annehmen, dass die Anzeige immer um den richtigen Mittelwert herumschwankt. Also musst du mehrere Messungen machen und eine Mittelwertbildung vornehmen. Man könnte bspw. ein Array in gewissen Zeitabständen befüllen und wenn ein neuer Messwert anliegt den ältesten Messwert rauskicken (FIFO-Prinzip).
Alternativ spricht auch nichts dagegen, das Signal vorab mit einem RC-Glied zu glätten - das spart zumindest Speicher im Arduino.
Logged

Mein Arduino-Blog: http://www.sth77.de/ - letzte Einträge: Teensy 3.0 - Teensyduino unter Window 7 - Teensyduino unter Windows 8

AREA COLOGNE
Offline Offline
Edison Member
*
Karma: 21
Posts: 1125
I am 1 of 10 who understands binary
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Wie wäre es mit einem Integrator?
hier wäre einer
So ungefähr und das nur nach prüfung ob der neue Wert < Altwert ist,
Die Wert Variabelen müssen datatype long sein

Code:
Wertaktuell=analogRead(A0);       // Aktuellwert Einlesen
X=Wertneu*10;                         // Neuerwert nur 10% Einfluss auf den alten Diesen Einfluss dann
Y=Wertalt*90;                         // Wert aus dem Vorherigien Zyklus auf 90% diesen auch zusammen müssen 100% ereben
Wertneu=X+Y/100;                 // Beide Werte addieren und Neuen Wert Bilden
Wertalt=Wertneu;                 // Für den nächsten Zyklus ist der neue (aktueller gesmoother Wert)

Somit hat pro Lesezyklus der neue Wert nur 10% Einfluss dass heisst würde der neue Gelesene Wert 0 haben so hat der nur 10% Einfluss und würde den Wert in einem Zyklus um 10% nach unten korrigieren.
Damit kannst du eine schöne Smoothesfekt machen das heisst aussreise des Schwanken beeinflussen den Wert nur gering. Und du hängst auch nicht in einer for-Schleife im einem Programm fest. Wenn dein neu eingelesener Wert noch weniger einfluss haben soll dann die Multipiktoren auf 5/95 setzten soll der neue Wert mehr einfluss haben dann z.B. auf 20/80 setzten.

Gruß
Der Dani
Logged

So ist das Leben:
Manchmal bis du das Denkmal, manchmal die Taube!

Offline Offline
Newbie
*
Karma: 0
Posts: 14
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hier mal mein jetziger Code mit Balkenanzeige und Prozentanzeige smiley-wink
Wie binde ich das da jetz ein? weil soweit bin ich echt noch nicht um euch da voll folgen zu können. smiley-sad


Code:
    #include <LiquidCrystal.h>
    #include <LcdBarGraph.h>
     
    byte lcdNumCols = 16; // -- Anzahl der vollen Balken im LCD
    byte sensorPin = 1; // -- Analogeingang
     
    LiquidCrystal lcd(8, 9, 4, 5, 6, 7); // -- Aufbau der LCD Verbindung
    LcdBarGraph lbg(&lcd, lcdNumCols);  // -- Aufbau der Balken
     
/////////////////////////////////////////////////////////////////////////////////////////////////   
   
    void setup(){

      analogReference (INTERNAL);   //  Interne Spannung 1,1 V DC am AREF Ausgang
      lcd.begin(2, lcdNumCols);   // -- Initialisierung des LCD
      lcd.clear();
      delay(1000);
    }
     
     
//////////////////////////////////////////////////////////////////////////////////////////////////     
    void loop()
    {
 
      lbg.drawValue( analogRead(sensorPin), 1024);   // -- Setzt den Wert vom Analogen Eingang
      delay(300);
         
         
 int poti = analogRead(sensorPin);                  // Poti-Wert auslesen, max. Wert 1024
 int potiVal = ((poti/4) * 100)/251;                // Potiwert in Prozent umrechnen
 lcd.setCursor(0,1);                                // 0 = Zeile  ;  1 = Spalte
 lcd.print("Tankinhalt");
 lcd.setCursor(14,1);
 lcd.print("%");
 lcd.setCursor(11,1);
 lcd.print(potiVal);
  if( potiVal < 100 )                               // Ist potiVal kleiner als 100 setze ein leerzeichen
  lcd.print( " " );
  if( potiVal < 10 )                                // Ist potiVal kleiner als 10 setze ein leerzeichen
  lcd.print( " " );

 delay(300);
    }
Logged

Offline Offline
Edison Member
*
Karma: 21
Posts: 1419
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Ungfähr so:
Code:
    #include <LiquidCrystal.h>
    #include <LcdBarGraph.h>
     
    byte lcdNumCols = 16; // -- Anzahl der vollen Balken im LCD
    byte sensorPin = 1; // -- Analogeingang
 
    long data = 0;

    LiquidCrystal lcd(8, 9, 4, 5, 6, 7); // -- Aufbau der LCD Verbindung
    LcdBarGraph lbg(&lcd, lcdNumCols);  // -- Aufbau der Balken
     
/////////////////////////////////////////////////////////////////////////////////////////////////   
   
    void setup(){

      analogReference (INTERNAL);   //  Interne Spannung 1,1 V DC am AREF Ausgang
      lcd.begin(2, lcdNumCols);   // -- Initialisierung des LCD
      lcd.clear();
      delay(1000);

      //einmal initialen Wert setzen, damit nicht bei "0" angefangen wird
      data = analogRead(sensorPin);
    }
     
     

//////////////////////////////////////////////////////////////////////////////////////////////////     
    void loop()
    {
      data = ((data * 90 ) + ( analogRead(sensorPin) * 10)) / 100;
     
      lbg.drawValue( data, 1024);   // -- Setzt den Wert vom Analogen Eingang
      delay(300);
         
      int potiVal = ((data/4) * 100)/251;                // Potiwert in Prozent umrechnen
 lcd.setCursor(0,1);                                // 0 = Zeile  ;  1 = Spalte
 lcd.print("Tankinhalt");
 lcd.setCursor(14,1);
 lcd.print("%");
 lcd.setCursor(11,1);
 lcd.print(potiVal);
  if( potiVal < 100 )                               // Ist potiVal kleiner als 100 setze ein leerzeichen
  lcd.print( " " );
  if( potiVal < 10 )                                // Ist potiVal kleiner als 10 setze ein leerzeichen
  lcd.print( " " );

 delay(300);
    }

Ich habe zwei Dinge geändert. Zum Einen wird das Wert nur einmal je loop() eingelesen und dann immer nur der gelesene Wert verarbeitet. Das sollte man grundsätzlich so machen, damit man an allen Stellen mit dem gleichen Wert rechnet. Vor allem aber, wenn die gemessenen Werte stark schwanken. Als Zweites habe ich die Formel von volvodani eingebaut, allerdings etwas mehr zusammengefasst, um Variablen zu sparen.
Der Trick dieser Formel ist, das Du den neuen Wert nicht ausschliesslich aus dem gemessenen Wert nimmst, sondern den vorherigen Messwert auch mit verwendest.
Das macht die Formel:
Quote
data = ((data * 90 ) + ( analogRead(sensorPin) * 10)) / 100;
Ein Beispiel.

Angenommen "data" hat den Wert von 730 und mittels analogRead() werden aktuell 840 gemessen und im nächsten Durchlauf wieder nur 590 und dann wieder 710, dann hättest Du die stark schwankende Anzeige die Du jetzt hast.
Setzen wir nun mal die Wert in die Formel ein.

1. Wert:  730 (initiale Messung im setup())
2. Wert:  ((730 * 90) + (840 * 10)) / 100 = 741  ~ 72%
3. Wert:  ((741 * 90) + (590 * 10)) / 100 = 726  ~ 71%
4. Wert:  ((726 * 90) + (710 * 10)) / 100 = 724  ~ 71%

Nun das Ganze nochmal mit 95/5

1. Wert:  730 (initiale Messung im setup())
2. Wert:  ((730 * 95) + (840 * 5)) / 100 = 735  ~ 72%
3. Wert:  ((735 * 95) + (590 * 5)) / 100 = 728  ~ 71%
4. Wert:  ((728 * 95) + (710 * 5)) / 100 = 727  ~ 71%

Man sieht, die Werte schwanken noch weniger. Das Ganze klappt natürlich nur, wenn der eigentliche Messwert ohne Fehler sich nur sehr langsam ändert. Ich hoffe jetzt ist es etwas klarer.
Mario.
Logged

AREA COLOGNE
Offline Offline
Edison Member
*
Karma: 21
Posts: 1125
I am 1 of 10 who understands binary
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Der Code ist ein bisschen Unglücklich. Ich habe mal die delays raus geschmissen und Routinen rein gebracht die einmal alle 10ms durchlaufen werden, für den Integrator. Und eine Routine mit 300ms für das Display. Dadurch verbringt die CPU keine Zeit in nichts tun.
Diese Art von "warten" bzw..  Durchlaufen in einem bestimmten Zeitpunkt findest du auch in dem Beispiel "Blink without delay".
Dadurch hast du eine Durchlaufzeit in dem ganzen Programm von weniger als 1ms und kannst viel einfacher nachher deinen Code erweitern ohne nochmal alles umbauen zu müssen

Code:
#include <LiquidCrystal.h>
#include <LcdBarGraph.h>

byte lcdNumCols = 16; // -- Anzahl der vollen Balken im LCD
byte sensorPin = 1; // -- Analogeingang

long data = 0;
unsigned long actmillis,lmillis1,lmillis2=0;
int time1=300;
int time2=10;

LiquidCrystal lcd(8, 9, 4, 5, 6, 7); // -- Aufbau der LCD Verbindung
LcdBarGraph lbg(&lcd, lcdNumCols);  // -- Aufbau der Balken

/////////////////////////////////////////////////////////////////////////////////////////////////    

void setup(){

  analogReference (INTERNAL);   //  Interne Spannung 1,1 V DC am AREF Ausgang
  lcd.begin(2, lcdNumCols);   // -- Initialisierung des LCD
  lcd.clear();
  delay(1000);

  //einmal initialen Wert setzen, damit nicht bei "0" angefangen wird
  data = analogRead(sensorPin);
}



//////////////////////////////////////////////////////////////////////////////////////////////////    
void loop()
{
  actmillis=millis();
  if (actmillis-lmillis2>time2){                                      // alle 10ms durchlaufen um den Integrator ein bisschen besser zu machen
    data = ((data * 90 ) + ( analogRead(sensorPin) * 10)) / 100;
    int potiVal = ((data/4) * 100)/251;                                        // Potiwert in Prozent umrechnen
    lmillis2=millis();  
  }

  if (actmillis-lmillis1>time1){                           // alle 300ms durchlauf da 3mal in der Sekunde das Display auffrischen reicht
    lbg.drawValue( data, 1024);   // -- Setzt den Wert vom Analogen Eingang
    lcd.setCursor(0,1);                                // 0 = Zeile  ;  1 = Spalte
    lcd.print("Tankinhalt");
    lcd.setCursor(14,1);
    lcd.print("%");
    lcd.setCursor(11,1);
    lcd.print(potiVal);
    if( potiVal < 100 )                               // Ist potiVal kleiner als 100 setze ein leerzeichen
      lcd.print( " " );
    if( potiVal < 10 )                                // Ist potiVal kleiner als 10 setze ein leerzeichen
      lcd.print( " " );
    lmillis1=millis()
    }
  }

Gruß
Der Dani
« Last Edit: November 13, 2012, 02:55:37 am by volvodani » Logged

So ist das Leben:
Manchmal bis du das Denkmal, manchmal die Taube!

Offline Offline
Newbie
*
Karma: 0
Posts: 14
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Das hät ich in 4 Monaten nicht hinbekommen, was ihr da in einer Nacht gewerkelt habt smiley-grin.

Also Mario´s konnt ich noch verfolgen aber das mit den Millis usw. das wirft mich aus der Bahn.
Ich muss halt noch viel üben und dann kommt das von alleine smiley-wink
Das mit den "starken Schwankungen" kann ich nicht vermeiden smiley-sad werd ich merken.
Ich werde es testen und dann berichten smiley-wink

Frage an beide : Ist da jetz sowas eingebaut das der "neue Wert" nicht höher kommen kann wie der alte? (Ich Persönlich würde behaupten ja durch die Formel)

Danke an euch BEIDEN! smiley
Logged

Offline Offline
Edison Member
*
Karma: 21
Posts: 1419
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Frage an beide : Ist da jetz sowas eingebaut das der "neue Wert" nicht höher kommen kann wie der alte? (Ich Persönlich würde behaupten ja durch die Formel)

Ähm, nein. Natürlich kann der neue Wert größer sein als der alte. Sonst dürftes Du den Tank nie wieder füllen. Außerdem mußt Du bei schwankenden Messwerten immer alle Werte berücksichtigen. Sonst würde bei zu kleinen Messwerten der Durchscnittswert auch immer kleiner werden.
Die Formel sorgt nur dafür das die aktuellen  Messwerte keine großen Sprünge der Daten mehr erzeugen.
Mario.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 14
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Ja wer lesen kann und nachdenkt erkennt das auch .... smiley-sad sorry. Hast ja recht smiley-wink

EDIT : Eben hab ich aber noch einen Fehler endekt oder vielmer das Prog.

potival ist nicht declariert smiley-sad ??

Mario seins funktioniert!
« Last Edit: November 13, 2012, 12:32:26 pm by KAmin » Logged

Offline Offline
Edison Member
*
Karma: 21
Posts: 1419
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

deklarier einfach "int potiVal" außerhalb des if-Blocks in dem es gesetzt wird. Z.B. am Anfang der loop() oder komplett außerhalb als globale Variable, dann sollte es gehen. Die Variable ist außerhalb des if-Blocks nicht sichtbar.
Waren noch zwei kleine andere Dinge drin. Das hier sollte funktionieren:
Code:
#include <LiquidCrystal.h>
//#include <LcdBarGraph.h>

byte lcdNumCols = 16; // -- Anzahl der vollen Balken im LCD
byte sensorPin = 1; // -- Analogeingang

long data = 0;
unsigned long actmillis,lmillis1,lmillis2=0;
int time1=300;
int time2=10;

int potiVal;

LiquidCrystal lcd(8, 9, 4, 5, 6, 7); // -- Aufbau der LCD Verbindung
//LcdBarGraph lbg(&lcd, lcdNumCols);  // -- Aufbau der Balken

/////////////////////////////////////////////////////////////////////////////////////////////////   

void setup(){

  analogReference (INTERNAL);   //  Interne Spannung 1,1 V DC am AREF Ausgang
  lcd.begin(2, lcdNumCols);   // -- Initialisierung des LCD
  lcd.clear();
  delay(1000);

  //einmal initialen Wert setzen, damit nicht bei "0" angefangen wird
  data = analogRead(sensorPin);
}



//////////////////////////////////////////////////////////////////////////////////////////////////     
void loop()
{
  actmillis=millis();
  if (actmillis-lmillis2>time2){                                      // alle 10ms durchlaufen um den Integrator ein bisschen besser zu machen
    data = ((data * 90 ) + ( analogRead(sensorPin) * 10)) / 100;
    potiVal = ((data/4) * 100)/251;                                        // Potiwert in Prozent umrechnen
    lmillis2=millis(); 
  }

  if (actmillis-lmillis1>time1){                           // alle 300ms durchlauf da 3mal in der Sekunde das Display auffrischen reicht
    //lbg.drawValue( data, 1024);   // -- Setzt den Wert vom Analogen Eingang
    lcd.setCursor(0,1);                                // 0 = Zeile  ;  1 = Spalte
    lcd.print("Tankinhalt");
    lcd.setCursor(14,1);
    lcd.print("%");
    lcd.setCursor(11,1);
    lcd.print(potiVal);
    if( potiVal < 100 )                               // Ist potiVal kleiner als 100 setze ein leerzeichen
      lcd.print( " " );
    if( potiVal < 10 )                                // Ist potiVal kleiner als 10 setze ein leerzeichen
      lcd.print( " " );
    lmillis1=millis();
    }
  }
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 14
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Mario ich dank dir! smiley-wink
Ich hab da zwar keine große Veränderung gefunden smiley-grin aber es geht.
Sei mir nicht böse aber die Balkenanziege habe ich wieder mit rein genommen. (Will diese auch beherschen smiley-wink )
Was mich gleich zu einer weiteren Frage aufwirft.

Wenn ich den Arduino starte geht alles mit den Balken i.o.
Manchmal starte ich den und es verzieht sich eine kleine Apalte in der Balkenanzeige die beim nächsten start wieder weg ist. Mhh...
Was ist das für ein Misterium?
Liest das die IC zu schnell?

Code:
#include <LiquidCrystal.h>
#include <LcdBarGraph.h>

byte lcdNumCols = 16; // -- Anzahl der vollen Balken im LCD
byte sensorPin = 1; // -- Analogeingang

long data = 0;
unsigned long actmillis,lmillis1,lmillis2=0;
int time1=300;                         // Zeit für LCD
int time2=10000;                       // Zeit für Loopdurchlauf

int potiVal;

LiquidCrystal lcd(8, 9, 4, 5, 6, 7); // -- Aufbau der LCD Verbindung
LcdBarGraph lbg(&lcd, lcdNumCols);  // -- Aufbau der Balken

/////////////////////////////////////////////////////////////////////////////////////////////////   

void setup(){

  analogReference (INTERNAL);   //  Interne Spannung 1,1 V DC am AREF Ausgang
  lcd.begin(2, lcdNumCols);   // -- Initialisierung des LCD
  lcd.clear();
  delay(1000);

  //einmal initialen Wert setzen, damit nicht bei "0" angefangen wird
  data = analogRead(sensorPin);
}



//////////////////////////////////////////////////////////////////////////////////////////////////     
void loop()
{
  actmillis=millis();
  if (actmillis-lmillis2>time2){                                      // alle 10ms durchlaufen um den Integrator ein bisschen besser zu machen
    data = ((data * 95 ) + ( analogRead(sensorPin) * 5)) / 100;
    potiVal = ((data/4) * 100)/251;                                        // Potiwert in Prozent umrechnen
    lmillis2=millis(); 
  }

  if (actmillis-lmillis1>time1){                           // alle 300ms durchlauf da 3mal in der Sekunde das Display auffrischen reicht
    lbg.drawValue( data, 1024);   // -- Setzt den Wert vom Analogen Eingang
    lcd.setCursor(0,1);                                // 0 = Zeile  ;  1 = Spalte
    lcd.print("Tankinhalt");
    lcd.setCursor(14,1);
    lcd.print("%");
    lcd.setCursor(11,1);
    lcd.print(potiVal);
    if( potiVal < 100 )                               // Ist potiVal kleiner als 100 setze ein leerzeichen
      lcd.print( " " );
    if( potiVal < 10 )                                // Ist potiVal kleiner als 10 setze ein leerzeichen
      lcd.print( " " );
    lmillis1=millis();
    }
  }
Logged

Offline Offline
Edison Member
*
Karma: 21
Posts: 1419
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Sorry, die Balkenanzeige hatte ich nur für mich rausgenommen, damit ich es cmpilieren kann. Hatte die Lib nicht zur Hand. Hab dann beim posten vergessen die Kommentare zu entfernen.
Die "kleinen" Unterschiede sind aber genau das wichtige. Daher nochmal genau schauen was sich geändert hat. Falls Du ein Linux oder einen Mac zur Hand hast, das Tool "diff" ist da sehr hilfreich.
Logged

Pages: [1]   Go Up
Jump to: