Stellmotor Heizung Abschaltung in Endposition

Guten Abend,
Will einen Vorlauf für einen Bodenheizungskreis steuern. Der Mischer ist ein Danfoss AmI 140 / 230V
eigentlich dachte ich er hätte eine Abschaltung in beiden Endpositionen. Hat er aber nur eingefahren. Wie könnte ich bewerkstelligen, dass die Relais nach max 1,5 Minuten auf High gehen und der Motor abstellt, auch wenn die Vorlaufstemperatur den Sollwert noch nicht erreicht hat. Der Arduino Uno müsste jedoch weiterhin Temperatur messen etc. und die Relais später wieder schalten können... Also eine Softwarelösung für die fehlende automatische Abschaltung im ausgefahrenen Zustand. Bin dankbar für eine Idee.

#include <Wire.h>
#include <DallasTemperature.h>
#include <LiquidCrystal.h>

// Initialisiere die Bibliothek mit den Nummern der Schnittstellenpins
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);

#define DS18B20_PIN A5          // Pin des Temperatursensors
#define RELAY_PIN_COOLER A1      // Pin Relais Kühler
#define RELAY_PIN_HEATER A2      // Pin Relais Heizung (sind beide an wird's wärmer siehe Schaltplan des Mischermotors)

OneWire oneWire(DS18B20_PIN);
DallasTemperature sensors(&oneWire);

int Zieltemperatur = 20; // Beispielwert, du kannst dies anpassen
int Toleranz = 1; // Toleranzbereich um die Zieltemperatur

void setup() {
  Serial.begin(115200);
  // Setze die Anzahl der Spalten und Zeilen des LCDs:
  lcd.begin(16, 2);
  lcd.setCursor(0, 0);

  sensors.begin();

  // Gebe die Anzahl der erkannten Sensoren aus
  Serial.print("Found ");
  Serial.print(sensors.getDeviceCount(), DEC);
  Serial.println(" devices.");

  // Setze die Relaispins
  pinMode(RELAY_PIN_COOLER, OUTPUT);
  pinMode(RELAY_PIN_HEATER, OUTPUT);
}

void loop() {
  int x;
  x = analogRead(0);
  lcd.setCursor(10, 1);
  Serial.print("x=");
  Serial.println(x);

  if (x < 60) {
    Serial.print("Rechts   ");
  } else if (x < 200 && Zieltemperatur < 55) {
    Serial.print("Hoch     ");
    Zieltemperatur++; // Erhöhe Zieltemperatur um 1, wenn kleiner als 55
  } else if (x < 400 && Zieltemperatur > 10) {
    Serial.print("Runter   ");
    Zieltemperatur--; // Verringere Zieltemperatur um 1, wenn größer als 10
  } else if (x < 600) {
    Serial.print("Links    ");
  } else if (x < 800) {
    Serial.print("Auswahl  ");
  }

  sensors.requestTemperatures();
  float currentTemperature = sensors.getTempCByIndex(0);

  // Steuere die Relais basierend auf der Differenz zwischen Zieltemperatur und Vorlauftemperatur
  if (currentTemperature < Zieltemperatur - Toleranz) {
    digitalWrite(RELAY_PIN_COOLER, LOW);
    digitalWrite(RELAY_PIN_HEATER, LOW);
  } else if (currentTemperature > Zieltemperatur + Toleranz) {
    digitalWrite(RELAY_PIN_COOLER, HIGH);
    digitalWrite(RELAY_PIN_HEATER, LOW);
  } else {
    // Im Toleranzbereich
    digitalWrite(RELAY_PIN_COOLER, HIGH);
    digitalWrite(RELAY_PIN_HEATER, HIGH);
  }

  lcd.clear(); // Lösche das Display, um die Werte zu aktualisieren

  lcd.setCursor(0, 0);
  lcd.print("Vorlauf: ");
  lcd.print(currentTemperature);
  lcd.print(" C ");

  lcd.setCursor(0, 1);
  lcd.print("Zieltemp: ");
  lcd.print(constrain(Zieltemperatur, 10, 55)); // Begrenze die Zieltemperatur auf 10 bis 55
  lcd.print(" C ");
}

Unter eingefahren verstehe ich die Ventilhubstange ist in die Position gefahren bei der sie nicht auf das Ventil drückt.

Das widerspricht der Aussage aus der Beschreibung

Das bedeutet wenn der Motor in "fast hinten Stellung ist" dass er beim 1,5 Minuten zurückfahren dann gegen den Anschlag fährt. Macht der Antrieb das gegen den hinteren (oberen) Anschlag fahren = Ventilstange ist komplett eingefahren
mit?

Das hört sich ja fast wie eine Aufforderung zu "wer programmiert mir das ?" an.
Idee:
mit Beginn des Ventil öffnens einen Zeitstempel speichern und dann vergleichen ob schon 1,5 Minuten vergangen sind.

Das Einlesen der Temperatur und nachregeln erfolgt unabhängig von der Zeitüberprüfung.

Jetzt beschreibe mal wie viel Programmiererfahrung du hast.
Dann kann man dir die zum Wissensstand passenden Tutorials posten.

vgs

Das ist korrekt wie du das schreibst. Und ja es steht so in der Beschreibung!
Aber der Stellmotor schaltet automatisch ab wenn die Hubstange komplett eingefahren ist. (Ob sich das beim Motor verstellen lässt habe ich nicht herausgefunden. Das würde meine Probleme lösen)
Zur Klarheit:
Mein Ventil öffnet sich, wenn die Stange hineingedrückt wird / der Vorlauf wird dann wärmer. Der Stellmotor hat keine Abschaltung in dieser Endposition

Das Ventil schliesst, wenn die Stange ausgefahren ist / der Vorlauf wird kalt.
Der Stellmotor schaltet automatisch ab in dieser Endposition.

Das ganze ist eine Übergangslösung bis dann im Sommer eine Steuerung für diesen Heizkreis in die Heizung kommt.

Meine Programmiererfahrung ist rudimentär. Ich bastle zusammen was ich finde, verstehe es und kann es anpassen. (Seit kurzem hilft meine Freundin Chat gpt auch noch ein bisschen :wink:

Wenn die Heizung abstellt (Pelltsheizung reinigt sich alle paar Stunden) Dann kann die Vorlauftemperatur nicht erreicht werden und der Mischer würde dann die ganze Zeit öffnen wollen. Das möchte ich verhindern. Da der Heizkreis für eine Wellnessanlage (zur Zeit noch teilweise im Bau) benutzt wird. brauche ich hohe Vorlauftemperaturen.

Das mit dem Zeitstempel habe ich versucht aber nicht hinbekommen. Der Motor schaltete zwar nach der gewünschten maximalen Öffnungszeit ab. Aber er beginnt dann nicht mehr zu regeln. Hier wäre ich sehr froh um ein Tutorial. Wie kompliziert wird das?

Eine andere Idee war einen zweiten Temperaturfühler anzuschliessen der die Kesseltemperatur misst. Ist diese tiefer als der Zielwert wird der Motor abgestellt.

Oder soll ich mir einfach einen anderen Mischer besorgen? :face_with_spiral_eyes:

Mein Rat:

Frage den Roboter so lange, bis er das richtige Ergebnis liefert, das du erwartest.

Eine Antwort könnte wahrscheinlich 42 sein.

"Frage den Roboter so lange, bis er das gewünschte Ergebnis liefert, das deinen Erwartungen entspricht. "(So müsste dein Satz heissen: das hat mir übrigens Chat GPT verraten :slight_smile: Du siehst ganz nutzlos ist das Roböterchen eben nicht.

Ich frage mal dumm nach: du willst das Ventil nur in den Stellungen komplett offen bzw. geschlossen betreiben, oder auch in Zwischenstellungen?

Meistens wird das Ventil 3/4 offen sein. Im Moment ist nur ein Handrad daran. Dass die Steuerung im Code noch viel zu grob ist. Und das ganze so hin und herschwanken wird ist mir bewusst.

Dann muss dein Code den Öffnungszustand, also 1,5min = 100% offen, als Variable mitführen um dann entsprechend abschalten zu können wenn die 100% erreicht sind. Auf ein regelmäßiges Zurückfahren auf "zu" als Grundzustand wirst du dennoch nicht herumkommen, zu vermeiden dass dein Programm meint, 50% offen während das Ventil schon 90% oder erst 10% hat.

1 Like
klicke auf das Dreieck um den Beitrag aufzuklappen

Es tut mir Leid. In der Formulierung verwirrt es mich bzw. es bleibt unklar was ist was.
Die Eine "Stange" fährt heraus die andere Stange macht das Gegenteil: sie wird hineingedrückt.

In der Beschreibung zum Stellmotor wird das "Bauteil das sich bewegt" Antriebsstange genannt.
Das werde ich jetzt im folgenden auch immer Stellmotor-Antriebsstange nennen.

Das Ventil ist vermutlich im Prinzip so ähnlich aufgebaut wie dieses

Da gibt es auch ein bewegliches Bauteil in Form eines schlanken Zylinders das nenne ich
Ventil-Stößel

So.
Wenn dein Ventil ähnlich aufgebaut ist dann würde die Funktionsbeschreibung so lauten

Wenn die Stellmotor-Antriebsstange ausgefahren ist drückt sie den Ventil-Stößel nach rechts und das Ventil ist geschlossen.

Wenn die Stellmotor-Antriebsstange eingefahren ist dann drückt die Rückstellfeder den Ventil-Stößel nach links und das Ventil ist geöffnet. (So wie in der Abbildung zu sehen).

Deine Beschreibung hört sich tendenziell genau gegenteilig an.
Deshalb schreibe erst mal ob das Bild zu deinem Ventil passt und ob meine Beschreibung zutreffend ist, oder wenn meine Beschreibung falsch ist, eine korrigierte Beschreibung.

Und dann mach dir bitte die Mühe nicht von "das" oder "der Stange" zu schreiben sondern diese beiden eindeutig voneinander unterschiedbaren Worte Stellmotor-Antriebsstange und Ventil-Stößel zu verwenden einfach um gleich Missverständnisse zu vermeiden.

Also du solltest auch ein Foto von dem Ventil posten.
Wenn das so ein Standard-Heizkörperventil ist, dann kann man das ganz schlecht auf 3/4 regeln.
Das ganze ist ein 2mm breiter Spalt. Und abhängig vom Überdruck der da durch die Pumpe vor Ort noch vorhanden ist, wird da bei einer Zwischenstellung mal mehr und mal weniger Wasser durchlaufen.
Und dieser Druck schwankt abhängig wie viele sonstige Heizkörper gerade geöffnet / geschlossen sind.

Zweipunktregelung heißt Ventil ganz auf / Ventil ganz zu. Da ist nix mit 3/4-Stellung.
Wenn du Zwischenstellungen haben willst dann nimmt man einen Drehwegemischer.

Die Anleitung spricht von

Und die Abbildung auf Seite zwei

Verstehe ich so:

Wenn die beiden Jumper waagerecht aufgesteckt sind, dann
schaltet der Stellmotor ab wenn die Stellmotor-Antriebsstange eingefahren ist.

Wenn die beiden Jumper senkrecht aufgesteckt sind dann schaltet der Stellmotor ab wenn die Stellmotor-Antriebsstange ausgefahren ist.

Das kannst du ja mal mit einer Steckdosenleiste die einen Schalter hat ausprobieren.
Mit Steckdosenleiste mit Schalter damit man im Notfall sofort abschalten kann.

Meine Empfehlung für das Programm ist die
switch-case-break-Anweisung zu verwenden.
Das funktioniert ähnlich wie eine If-else Bedingung hat aber zwei wichtige Unterschiede:

Die Bedingung ist kein "if (beliebige Bedingung)"
sondern
ein case ZAHL:

und das break ist verdammt wichtig weil nur durch das hinzufügen des

break;

funktioniert das ganze wie beabsichtigt.

man nennt das eine state-machine.
Je nach "Zustand" (english "state") einer bestimmten Variable wird immer nur ein Teil des Codes ausgeführt
und der Rest wird durch das

break;

nicht ausgeführt. (man könnte sagen der andere Code wird übergangen)"

So und da musst du jetzt eine Grundsatzentscheidung treffen:

Code mit Hilfe von ausschliesslich chatGPT
oder
Code ausschliesslich mit Hilfe von Forums-Menschen unter konsequentem weglassen von chatGPT erstellen.

Es wird gar nicht gerne gesehen und dann auch nur sehr ausweichend = nicht hilfreich geantwortet
wenn du Code von chatGPT postest den Code aber selber nicht verstehst und jetzt sollen andere User den von chatGPT generierten Code überarbeiten.
Zumindest was meine Person angeht. Ich persönlich überarbeite auf gar keinen Fall ChatGPT code.

vgs

Welcher der beiden Zweige ist der, bei dem Du mit dem Controller zeitgesteuert abschalten willst:

Alles andere ist vollkommen Wurscht und thematisch irrelevant.

Man mag mich jetzt schon wieder für auf irrelevante Details versessen halten

Soll-Temperatur nicht erreicht kann heißen
Ist-Temperatur höher als Soll-Temperatur
oder
Ist-Temperatur niedriger als Soll-Temperatur

Wenn man dazu nimmt

Ist das wohl der Fall
Ist-Temperatur niedriger als Soll-Temperatur
Also muss der Code "beobachten" ob die Ist-Temperatur beim Öffnen ansteigt oder nicht.
Wenn die Temperatur nicht ansteigt (weil Kessel abgeschaltet) dann Ventil wieder zu.

Kommt mir am einfachsten vor.

Wenn du auch noch proportional regeln willst einen Dreiwegemischer

Also der Mischmotor ist komisch! Wenn ein Draht Spannung hat fährt er zurück wenn 2 Drähte Spannung haben wird die Stellmotor-Antiriebsstange :slight_smile: ausgefahren. Habe mich zuerst gar nicht getraut das so anzuschliessen, aber ist so! und funktioniert. Die Jumpers sind leider nicht dafür da die Abschaltung in der Endposition umzustellen sondern stellen die Drehrichtung um.

Daher zu deiner Frage die beiden Stränge sind nicht fürs abschalten sondern zum öffnen und schliessen. Beide auf LOW öffnet.

Ich habe nun den Tip von Dieterr befolgt und eine Variable z eigeführt die den Öffnungsgrad in Prozent überwacht! funktioniert so bestens.

#include <Wire.h>
#include <DallasTemperature.h>
#include <LiquidCrystal.h>

LiquidCrystal lcd(8, 9, 4, 5, 6, 7);

#define DS18B20_PIN A5
#define RELAY_PIN_COOLER A1
#define RELAY_PIN_HEATER A2

OneWire oneWire(DS18B20_PIN);
DallasTemperature sensors(&oneWire);

int Zieltemperatur = 20;
int Toleranz = 1;
float Z = 0.0;  // Variable für den Öffnungsgrad des Mischmotors

void setup() {
  Serial.begin(115200);
  lcd.begin(16, 2);
  lcd.setCursor(0, 0);

  sensors.begin();
  Serial.print("Found ");
  Serial.print(sensors.getDeviceCount(), DEC);
  Serial.println(" devices.");

  pinMode(RELAY_PIN_COOLER, OUTPUT);
  pinMode(RELAY_PIN_HEATER, OUTPUT);
}

void loop() {
  int x;
  x = analogRead(0);
  lcd.setCursor(10, 1);
  Serial.print("x=");
  Serial.println(x);

  if (x < 60) {
    Serial.print("Rechts   ");
  } else if (x < 200 && Zieltemperatur < 55) {
    Serial.print("Hoch     ");
    Zieltemperatur++;
  } else if (x < 400 && Zieltemperatur > 10) {
    Serial.print("Runter   ");
    Zieltemperatur--;
  } else if (x < 600) {
    Serial.print("Links    ");
  } else if (x < 800) {
    Serial.print("Auswahl  ");
  }

  sensors.requestTemperatures();
  float currentTemperature = sensors.getTempCByIndex(0);

  if (currentTemperature < Zieltemperatur - Toleranz) {
    digitalWrite(RELAY_PIN_COOLER, LOW);
    digitalWrite(RELAY_PIN_HEATER, LOW);
    Z = constrain(Z + 1.0 / 10, 0.0, 1.0);  // Öffne den Mischmotor um 10% pro Sekunde
  } else if (currentTemperature > Zieltemperatur + Toleranz) {
    digitalWrite(RELAY_PIN_COOLER, HIGH);
    digitalWrite(RELAY_PIN_HEATER, LOW);
    Z = constrain(Z - 1.0 / 10, 0.0, 1.0);  // Schließe den Mischmotor um 10% pro Sekunde
  } else {
    digitalWrite(RELAY_PIN_COOLER, HIGH);
    digitalWrite(RELAY_PIN_HEATER, HIGH);
    // Im Toleranzbereich
  }

  lcd.clear();

  lcd.setCursor(0, 0);
  lcd.print("Vorlauf: ");
  lcd.print(currentTemperature);
  lcd.print(" C ");

  lcd.setCursor(0, 1);
  lcd.print("Z: ");
  lcd.print(constrain(Zieltemperatur, 10, 55));
  lcd.print(" C ");
  lcd.print(" M: ");
  lcd.print(Z * 100, 1);  // Zeige den Öffnungsgrad in Prozent
  lcd.print("%");
}

Wenn ich jetzt aber erreichen will dass wenn Z = 1 oder Z = 0 ist die Relais abgeschaltet werden sollen. Dann tuen sie das auch aber siehe da sie fallen immer wieder zurück auf ihren vorheriegen Zustand und werden dann sogleich wieder abgeschaltet weil z das ja immer noch so will. Gibt es da eine einfache Lösung? Vielen vielen Dank!

hier der Code:

#include <Wire.h>
#include <DallasTemperature.h>
#include <LiquidCrystal.h>

LiquidCrystal lcd(8, 9, 4, 5, 6, 7);

#define DS18B20_PIN A5
#define RELAY_PIN_COOLER A1
#define RELAY_PIN_HEATER A2

OneWire oneWire(DS18B20_PIN);
DallasTemperature sensors(&oneWire);

int Zieltemperatur = 20;
int Toleranz = 1;
float Z = 0.0;  // Variable für den Öffnungsgrad des Mischmotors

void setup() {
  Serial.begin(115200);
  lcd.begin(16, 2);
  lcd.setCursor(0, 0);

  sensors.begin();
  Serial.print("Found ");
  Serial.print(sensors.getDeviceCount(), DEC);
  Serial.println(" devices.");

  pinMode(RELAY_PIN_COOLER, OUTPUT);
  pinMode(RELAY_PIN_HEATER, OUTPUT);
}

void loop() {
  int x;
  x = analogRead(0);
  lcd.setCursor(10, 1);
  Serial.print("x=");
  Serial.println(x);

  if (x < 60) {
    Serial.print("Rechts   ");
  } else if (x < 200 && Zieltemperatur < 55) {
    Serial.print("Hoch     ");
    Zieltemperatur++;
  } else if (x < 400 && Zieltemperatur > 10) {
    Serial.print("Runter   ");
    Zieltemperatur--;
  } else if (x < 600) {
    Serial.print("Links    ");
  } else if (x < 800) {
    Serial.print("Auswahl  ");
  }

  sensors.requestTemperatures();
  float currentTemperature = sensors.getTempCByIndex(0);

  if (currentTemperature < Zieltemperatur - Toleranz) {
    digitalWrite(RELAY_PIN_COOLER, LOW);
    digitalWrite(RELAY_PIN_HEATER, LOW);
    Z = constrain(Z + 1.0 / 10, 0.0, 1.0);  // Öffne den Mischmotor um 10% pro Sekunde
  } else if (currentTemperature > Zieltemperatur + Toleranz) {
    digitalWrite(RELAY_PIN_COOLER, HIGH);
    digitalWrite(RELAY_PIN_HEATER, LOW);
    Z = constrain(Z - 1.0 / 10, 0.0, 1.0);  // Schließe den Mischmotor um 10% pro Sekunde
  } else {
    digitalWrite(RELAY_PIN_COOLER, HIGH);
    digitalWrite(RELAY_PIN_HEATER, HIGH);
    // Im Toleranzbereich
  }

  lcd.clear();

  lcd.setCursor(0, 0);
  lcd.print("Vorlauf: ");
  lcd.print(currentTemperature);
  lcd.print(" C ");

  lcd.setCursor(0, 1);
  lcd.print("Z: ");
  lcd.print(constrain(Zieltemperatur, 10, 55));
  lcd.print(" C ");
  lcd.print(" M: ");
  lcd.print(Z * 100, 1);  // Zeige den Öffnungsgrad in Prozent
  lcd.print("%");

  if (Z <= 0.01 || Z >= 0.99) {
    digitalWrite(RELAY_PIN_COOLER, HIGH);
    digitalWrite(RELAY_PIN_HEATER, HIGH);
  }
}

Ja, steht da im Datenblatt vollkommen unübersehbar.

Das ist mir klar.
Aber Du willst ja irgendwann abschalten.
Also wann, wenn er den ersten oder den zweiten Zweig nimmt?
Oder anders: In welchem Zweig schaltet der antrieb alleine ab?

das war damals noch nicht im code.... hatte keinen vernünftigen Ansatz den ich posten konnte....
die Frage war wie ich das irgendwie ergänzen könnte.

Mit einem Timer.
Was ist denn jetzt so schwer zu sagen, wann der abschalten soll?` :man_facepalming:

Er soll abschalten wenn beide Relais auf Low sind.
Im anderen Fall erledigt das die Abschaltung in der Endstellung

Aber die Idee von Dieterr hat super geklappt. Ich muss nur noch irgendwie erreichen dass die Relais nicht immer hin und her geschalten werden! der Rest funktioniert bestens

Das ist Unsinn.
Du willst nach einer bestimmten Zeit abschalten und nicht, wenn die Temperatur im Sollbereich ist.

Um es vorweg zu nehmen: Ich habe eine solche Steuerung für Heizkörperventile getestet und dann einen DreiWegeMischer damit ausgestattet. Ich weiss also wie das geht.

Aber mach mal @StefanL38 wird Dir schon erklären wie es geht. Ich bin nicht in der Verfassung x Postst zu verfassen um eine valide Aussage zu bekommen.
#bye

Wer ist Dieterr?
:crazy_face:

nö im Sollbereich stehen die Relais auf HiGH!