Delay nur für bestimmten Teil des Codes

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:

 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 :confused:
Danke

#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());
  }
  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?

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

Whandall:

  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

ElEspanol:
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 :slight_smile:

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

Gruß Tommy

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:

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

... 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:

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.

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.

Profiler64:
... 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 Hysterese – Wikipedia

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

Gruß

Gregor

Hysterese hat er doch 0,01bar, oder?

Mahimus:
Hysterese hat er doch 0,01bar, oder?

Huch, habe ich was übersehen? Der Sketch ist übel formatiert.

Gruß

Gregor

Mahimus:
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

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.

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

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.

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 :slight_smile:

Hi

Auf 0,01Bar genau ist nun nicht viel Spielraum, aber brauchst Du einen so genauen Druck?
Druckregler gibt's ja doch schon käuflich zu erwerben, befürchte also, daß Du diesen Weg schon hinter Dir hast.
Wenn's um den Druckbereich geht, da könnte im Airbrush-Bereich was Interessantes zu finden sein - wobei hier wenig Volumen benötigt wird - könnte mir ebenfalls vorstellen, daß Das dann für Dich 'zu lütt' ist.

MfG

Hallo,

es gibt doch fertige Druckminder-Ventile auch für kleine Messbereiche , 1 bar Festo, baut sowas.

Druckminderer

Profiler64:
Selbst wenn der Druck im Toleranzbereich liegt regelt der Servo danach noch einmal drüber. Das könnte daran liegen.
Danke :slight_smile:

Aber hat das Schwingen nur mit so einer kleinen Amplitude stattgefunden? Das wäre ja dann nur der minimale Verfahrweg vom Servo. Wenns nur das kleine hin und her zappeln war ist dein Regelansatz vielleicht ausreichend und du brauchst keinen PID.

Wie gesagt check auch mal wie deine Messwerte eigentlich aussehen, ob die schön glatt oder verrauscht sind. Erst Messwerte schön machen, dann ggf. Regler optimieren.