Go Down

Topic: Delay nur für bestimmten Teil des Codes (Read 755 times) previous topic - next topic

Profiler64

Hallo ich habe einen Projekt wobei I2C Drucksenosren ausgelsen werden und das immer wieder in einem Loop (delay 15).

In dem Loop werden zwei Werte abgeglichen. Mit einem Potentiometer kann man den sogenannten Soll-Druck einstellen (0-1Bar) und ein Sensor misst den Ist-Druck in Bar.
In einem Sketch steht im Loop nun folgendes:
Code: [Select]
if (istbar < (sollbar + 0.01)) myservo.write(var++);
 if (istbar > (sollbar - 0.01)) myservo.write(var--);

Dabei gleicht er die Werte mit einer Toleranz von +-0.01 Bar ab und stellt dann wenn der Druck zu hoch ist den Servo ein bisschen zu und wenn der Druck zu niedrig ist wird der Servo in die andere Richtung gedreht.  Am Servo hängt ein kleiner Kugelhahn der den Durchfluss regelt.

Nun zu meinem Probelm:
Dadurch dass ich den Drucksensor möglichst schnell aktualisiert haben möchte habe ich ein Delay von 15ms gewählt. Aber durch diesen kleinen Delay reagiert der Servo (also die Druckregelung) zu sensibel
und übersteuert und untersteuert immer den Zielbereich. Ich hätte gerne einen separaten Delay für den oben genannten Codeschnipsel. Nur weiß ich leider nicht wie ich dass hinbekomme ohne auch die Sensorrate zu verringern.

Ich füge mal den gesamten Code bei und hoffe dass ich nicht gesteinigt werden.

Ich hoffe man kann mir helfen :smiley-confuse:
Danke
Code: [Select]

#include <Servo.h>
#include <Adafruit_BMP085.h>
#include <SPI.h>
#include <Wire.h>
#include "U8glib.h"
#include <SparkFun_MS5803_I2C.h>
const int buttonPin = 2;     // the number of the pushbutton pin
int buttonState = 0;
const int secbuttonPin = 3;     // the number of the pushbutton pin
int secbuttonState = 0;
float pressure_abs;
float pressure_earth = 0.0;



U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NO_ACK);
MS5803 sensor(ADDRESS_HIGH);

Servo myservo;  // create servo object to control a servo
Adafruit_BMP085 bmp;

int potpin = 0;  // analog pin used to connect the potentiometer
int val;    // variable to read the value from the analog pin
int var = 50;    //variable zur servo steurung

void setup() {
  myservo.attach(9);  // attaches the servo on pin 9 to the servo object
  Serial.begin(9600);
  pinMode(buttonPin, INPUT);
  pinMode(secbuttonPin, INPUT);
  sensor.reset();
  sensor.begin();
  if (!bmp.begin()) {
  Serial.println("Could not find a valid BMP085 sensor, check wiring!");
  while (1) {}
  }

}

void loop()
{
  pressure_earth = ((bmp.readPressure()/100) * 0.9936);
  pressure_abs = (sensor.getPressure(ADC_4096) - pressure_earth);
  val = analogRead(potpin);            // reads the value of the potentiometer (value between 0 and 1023)
  float PercentageAct = map(val, 0, 1023, 0, 1000);
  float sollbar = (PercentageAct / 1000); //Convert Pot_Motor to % and Round for Display
  float mbar = (pressure_abs / 1000);
  float istbar = (mbar);
  delay(15);   // waits for the servo to get there
  Serial.print("Soll:");
  Serial.print(sollbar, 3);
  Serial.println(" bar");
  Serial.print("Ist:");
 Serial.print(istbar, 3);
 Serial.println(" bar");
 u8g.firstPage();

  do
  {
    u8g.setFont(u8g_font_fub14);
    u8g.setFontRefHeightExtendedText();
    u8g.setDefaultForegroundColor();
    u8g.setFontPosTop();
    u8g.drawStr(3, 0, "Soll");
    u8g.setFont(u8g_font_fub14);
    u8g.setPrintPos(53, 0);
    u8g.print(sollbar);
    u8g.setFont(u8g_font_fub14);
    u8g.setPrintPos(98, 0);
    u8g.print("Bar");
    u8g.drawStr(3, 30, "Ist");
    u8g.setPrintPos(53, 30);
    u8g.print(istbar);
    u8g.setFont(u8g_font_fub14);
    u8g.setPrintPos(98, 30);
    u8g.print("Bar");
    u8g.setFont(u8g_font_7x14);
    u8g.drawStr(3, 64, "Modus:");
   
    buttonState = digitalRead(buttonPin);
    secbuttonState = digitalRead(secbuttonPin);

  // check if the pushbutton is pressed. If it is, the buttonState is HIGH:
  if (buttonState == HIGH) {
  if (var > 105) var=105;
 if (var < 1) var =1;
   
    //activate Auto modus:
    if (istbar < (sollbar + 0.01)) myservo.write(var++);
 if (istbar > (sollbar - 0.01)) myservo.write(var--);
    u8g.setPrintPos(50, 64);
    u8g.print("Auto");
 
  } 

    if (secbuttonState == HIGH){
      myservo.write(105);
      u8g.setPrintPos(50, 64);
      u8g.print("An");
      }
     
if (secbuttonState == LOW) {
  if (buttonState == LOW){ 
    // close valve:
   myservo.write(1);
   u8g.setPrintPos(50, 64);
   u8g.print("Aus");
      }
}
   
   

   
     
  }
  while (u8g.nextPage());
  }



 

Whandall

Code: [Select]
  if (istbar < (sollbar + 0.01)) myservo.write(var++);
  if (istbar > (sollbar - 0.01)) myservo.write(var--);

Warum willst du den alten Wert benutzen und erst nach der Benutzung ändern?
Ah, this is obviously some strange usage of the word 'safe' that I wasn't previously aware of. (D.Adams)

ElEspanol

Dein System schwingt. Du solltest evtl. Eine Hysterese einbauen.
Und vor allem anstatt delay lieber millis benutzen

Profiler64

Code: [Select]
  if (istbar < (sollbar + 0.01)) myservo.write(var++);
  if (istbar > (sollbar - 0.01)) myservo.write(var--);

Warum willst du den alten Wert benutzen und erst nach der Benutzung ändern?
Ich weiß nicht genau was du meinst. Sorry

Dein System schwingt. Du solltest evtl. Eine Hysterese einbauen.
Und vor allem anstatt delay lieber millis benutzen
Ja genau mein System schwingt. Es würde mir schon reichen wenn ich die Angleichung von Soll und Ist Druck nur alle 100ms Sekunden machen lasse, aber der Sensor weiter alle 15ms Sekunde. Ich werde mir heute Abend mal den Unterschied zwischen millis und delay durchlesen. Ich bring mir alles selbst bei durch Foren und Tutorials und bin noch nicht so der Experte.
Aber Danke schon mal :)

Tommy56

Shau Dir mal den Unterschied zwischen val++ und ++val an. Dann verstehst Du, was Whandall meint.

Gruß Tommy
"Wer den schnellen Erfolg sucht, sollte nicht programmieren, sondern Holz hacken." (Quelle unbekannt)

combie

Quote
Nun zu meinem Probelm:
Dadurch dass ich den Drucksensor möglichst schnell aktualisiert haben möchte habe ich ein Delay von 15ms gewählt. Aber durch diesen kleinen Delay reagiert der Servo (also die Druckregelung) zu sensibel
und übersteuert und untersteuert immer den Zielbereich. Ich hätte gerne einen separaten Delay für den oben genannten Codeschnipsel. Nur weiß ich leider nicht wie ich dass hinbekomme ohne auch die Sensorrate zu verringern.
Ablaufsteuerung
Meine Standardantwort zu Ablaufsteuerungen:
Quote
Eine Stichworte Sammlung für Google Suchen:
Endlicher Automat,
State Machine,
Multitasking,
Coroutinen,
Ablaufsteuerung,
Schrittkette,
BlinkWithoutDelay, 
--
Blink Without Delay
Der Wachmann
--
Multitasking Macros
Intervall Macro
Nobody is perfect!
(und selbst der nicht zu 100%)

michael_x

Quote
... reagiert der Servo (also die Druckregelung) zu sensibel und übersteuert und untersteuert immer den Zielbereich ...
Regelungstechnik ist eine Wissenschaft. Dein Regler ist offensichtlich viel zu empfindlich eingestellt.
Das kriegst du eher nicht durch größere delays in den Griff.

Mach dich mal über PID-Regler schlau, gib einen kleinen Proportional-Anteil (soll - ist)*Kp dazu und reduziere deinen I-Anteil.


Evtl. findest du erstmal bei festem Sollwert einen Arbeitspunkt, wo kleinere äußere Störungen ausgeregelt werden, ohne dass es gleich zu schwingen anfängt. Fang bei einer Einstellung an,  die sehr langsam auf Regelabweichung reagiert, obwohl sie mit hoher Abtastrate läuft.

Zappelt deine Druck-Messung? Das erschwert das Leben ungemein.
Probier zum ersten Test mal ganz ohne I Anteil, aber mit gedämpftem Messwert:

Code: [Select]
const float Kp=0.01;  // ausprobieren
static float stellwert;
stellwert = ((soll - ist)*Kp + stellwert*9.0)/10.0;  // stellwert mit Tiefpass

myservo.write(Arbeitspunkt + stellwert); // Arbeitspunkt sollte halbwegs passen
Reiner P-Regler, hat immer eine Regelabweichung, eher unkritisches Zeitverhalten, aber kann auch schwingen

Für eine ordentliche Regelung brauchst du eine ziemlich saubere regelmäßige Zeitbasis, die nicht durch
delays in der Anzeige oder sonstwo gestört wird. (Schau dir eine PID Library an)

Und, falls es dir ein Trost ist: Anfänger stellen Regelungen immer zu heftig ein.



Mahimus

#7
Feb 21, 2019, 06:40 pm Last Edit: Feb 21, 2019, 08:05 pm by Mahimus
Durch längere Totzeit/Abtastzeit würde der Regler noch instabiler werden und ziemlich sicher noch stärker schwingen. Ich versteh daher nicht so ganz warum du genau das erzielen möchtest.

Je nach dem was dein Anspruch ist reicht evtl. auch ein P-Regler, dann aber mit kleinerem Proportionalwert (weniger Servo verstellen bei gleicher Abweichung vom Solldruck).
Edit: Proportionalwert/Verstärkung ist bei dir ja so wie ich es verstehe quasi schon klein, da du den Servowert ja immer nur um 1 änderst. Vielleicht ist auch genau da das Problem. Wenn du das nur alle 15ms stellst kommt der Regler denk ich nicht nach.
Schlauer wäre doch bei großer Abweichung auch gleich große Stellwerte zu setzen. Das wäre dann tatsächlich ein Proportionalregler.

gregorss

... weiß ich leider nicht wie ich dass hinbekomme ohne auch die Sensorrate zu verringern.
Das Stichwort Hysterese ist ja schon gefallen. Genau das (ein gewisser „Abstand" zwischen den „an/aus"-Werten) wäre mein Ansatz.

Siehe https://de.wikipedia.org/wiki/Hysterese

Bei meiner Toner-Transfer-Quetsche nutze ich das, damit der Ex-Laminator nicht ständig die Heizung an- und ausschaltet.

Gruß

Gregor
„Ich glaube, ich leg' mich noch mal hin", sagte das Bit.

Mahimus


gregorss

Hysterese hat er doch 0,01bar, oder?
Huch, habe ich was übersehen? Der Sketch ist übel formatiert.

Gruß

Gregor
„Ich glaube, ich leg' mich noch mal hin", sagte das Bit.

Tommy56

Hysterese hat er doch 0,01bar, oder?
Wenn sein Messwert bei konstantem Druck aber z.B. um >0,01 bar schwankt (die Info haben wir nicht), ist das zu wenig. Raten wir weiter.

Gruß Tommy
"Wer den schnellen Erfolg sucht, sollte nicht programmieren, sondern Holz hacken." (Quelle unbekannt)

Profiler64

Also ich danke euch allen für die ganzen Tipps. Ich hab jetzt erstmal den Delay entfernt und mit millis gearbeitet. Mal schauen ob es funktioniert. Ich hab jetzt mehrere Intervalle.
OLED 10ms
Sensoren 10ms
Und Servo 100ms
Ich probiere es einfach mal aus.
Ich hoffe der einfachste Weg führt zum Erfolg.
Wenn nicht, werde ich mal eure weitern Vorschläge probieren.
Ich Versuch gerne die einfachsten Lösungen zu gehen. Hoffentlich reicht das.
Ja sorry Leute für mein schlecht sortierten Sketch. Aber ich denke mal Neulinge verfassen öfters so schrecklich aufgebaute Sketche.


So nunmal zu dem gesamten Projekt:
Mein Vater hat bei der Firma seines Kumpels investiert und ich finde das Thema sehr interessant weshalb ich da gerne mithelfe. Die Firma hat einen Extruder für Rohre in einen LKW-Auflieger gepackt. Somit kann man an dem gewünschten Standort, endlose Plexiglasrohre produzieren. Zu Beginn des Prozesses kommt die zähe Plexiglasmasse aus dem Extruder und wird zusammen gedrückt sodass quasi das Rohr was raus kommt vorne geschlossen ist. Dieses Rohr muss so lange der Prozess noch nicht vollständig läuft mit Druckluft (sehr geringer Druck) gefüllt werden sodass die Form erhalten bleibt. Da das Rohr dabei ja länger wird und somit das Volumen wächst, muss kontinuierlich Luft in das innere des Rohres fließen. Man kann das mit einem Luftballon Vergleich der kontinuierlich und gleichmäßig Luft verliert. Also habe ich an dem Kompressor den Druckminderer auf 1 Bar gestellt und zwischen dem Anschluss am Extruder und dem Kompressor einen Drucksensor angebracht und einen Servo mit Kugelhahn. Jetzt soll das halt so gesteuert werden dass der Druck automatisch gehalten wird.

Vor meiner Idee wurde der Druck mit einem Kugelhahn per Hand geregelt. Da aber beim Anfahren des Prozessen andere Sachen zu tun sind. Würden wir das gerne automatisieren.

Mahimus

#13
Feb 22, 2019, 01:45 pm Last Edit: Feb 22, 2019, 01:55 pm by Mahimus
Also ich danke euch allen für die ganzen Tipps. Ich hab jetzt erstmal den Delay entfernt und mit millis gearbeitet. Mal schauen ob es funktioniert. Ich hab jetzt mehrere Intervalle.
OLED 10ms
Sensoren 10ms
Und Servo 100ms

millis() statt delay ist schonmal gut, gerade bei deinem Vorhaben.

Allerdings versteh ich das Aufteilen in Intervalle nicht. Du solltest eine Loop mit diesem Ablauf haben:

Sensor auslesen -> Stellwert für Servo ermitteln -> Servo stellen

Alles so schnell hintereinander wie es geht.

Du könntest deinen Regelansatz noch verbessern indem du bei höheren Abweichungen den Stellwert für den Servo eben nicht nur um 1 erhöhst oder verkleinerst.

also so etwa: if(betrag von (istbar-sollbar)) > x) { var = var + K}   myservo.write(var)

x und k musst du wählen. Ein richtiger P/ PI/ PID-Regeler ist das immer noch nicht. Wie man den implementiert will ich dir hier nicht erklären, das geht etwas zu weit. Kannst du sicher recherchieren.

Und in deinem Ansatz auf jeden Fall var++ durch ++var ersetzen! Siehe Language Reference.

Edit: Und wie dir schon gesagt wurde solltest du zuerst mal schauen, ob dein Messsignal verrauscht ist und es ggf. glätten. Das ist überhaupt die Grundlage.



Profiler64

Ok ich werde mich nach meinem Urlaub mit der PID Libary beschäftigen. Und ich hab eben den Unterschied zwischen var++ und ++var gegoogelt. Und ich denke das ist mit einer der großen Probleme beim mir.
Selbst wenn der Druck im Toleranzbereich liegt regelt der Servo danach noch einmal drüber. Das könnte daran liegen.
Danke :)

Go Up