Newbie: Ansatz für Hysterese Servomotor

Hallo zusammen

Ich finde den Ansatz nicht um eine dreistufige Hysterese zu programmieren.
Folgendes würde ich gerne umsetzen:

Einen Servomotor auf 3 Winkel ansteuern aufgrund einer Temperaturmessung

Aus
Stufe 1
Stufe 2

Der erste Ansatz von mir sieht so aus, der natürlich nicht das gewünschte ausführt:

#define solltemp 22                 // Solltemperatur 22°C
#define stufe1 solltemp+3           // Stufe 1 sind 3°C mehr als Soll


void servoAktion()                                                        // Funktion Servomotor ansteuern
{
  if (temp <= solltemp) {                                                 // wenn Temperatur kleiner gleich Soll-Temp, dann
    myservo.write(16);                                                    // Servomotor auf 16° steuern (Grundstellung
    status = "AUS     ";                                                  // den String AUS an Status zuweisen
  } else if (temp >= stufe1) {                                            // oder wenn Temperatur grösser gleich Soll-Temp, dann
    myservo.write(140);                                                   // Servomotor auf 140° steuern
    status = "Stufe 2";                                                   // den String Stufe 2 an Status zuweisen
  } else if (temp >= solltemp) {                                          // oder wenn Temperatur grösser gleich Stufe 1, dann
    myservo.write(70);                                                    // Servomotor auf 70° steuern
    status = "Stufe 1";                                                   // den String Stufe 1 an Status zuweisen
  }
}


Momentan pendelt der Servomotor wenn sich die Temperatur nahe der Grenzwerte bewegt.
Das heisst bei 22° Stellmotor zu, bei 22.1° Stufe 1. Wenn nun die Temperatur wieder 22° beträgt soll er nicht gerade wieder schliessen, sondern es soll um jeden Grenzwert (22°,25°,28°) einen Bereich geben, in dem der Servo-Motor noch nicht angesteuert wird.

Vielen Dank für eure Inputs.

Du mußt die aktuell eingestellte Stufe berücksichtigen. Geschaltet wird dann z.B. wenn die Ist-Temperatur 2° über oder unter der eingestellten Soll-Temperatur liegt.

Du hast nur einen Grenzwert.
Zumindest in Deinem Code.
Das würde bei mir dann so aussehen:

const int solltemp = 22;
const int hysterese = 3;
enum stufe {aus, stufe1, stufe2};

void servoAktion()
{
  if (stufe == stufe1)
  {
    if (temp <= solltemp - hysterese)
    {
      myservo.write(16);
      stufe = aus;
    }
    if (temp >= solltemp + hysterese)
    {
      myservo.write(140);
      stufe = stufe2;
    }
  }
  else
  {
    if (temp = solltemp))
    {
      myservo.write(70);
      stufe = stufe1;
    }
  }
}

Allerdings weiss ich nicht, ob die Aufgabenstellung verstanden wurde.

also
22+Hysterese -> Stufe 2
22-Hysterese -> Stufe 1
hysterese zB 0,5°
und das für jeden Sollwert getrennt.

Grüße Uwe

Hallo,

vielleicht mit einem switch case. Und gewöhne dir die defines ab. Verwende Datentypen.

Je nach Temperatur wird eine andere Servopos. verwendet. Falls keine Temperatur zutrifft kommt default zum Zug. Lässt man default frei, dass heißt nicht weglassen, dann bleibt bei nicht zutreffen der alte Wert aktiv. Solange bis wieder eine case gültig wird. Falls noch 0,5°C Auflösung benötigt wird multipilziere mit 10 usw., dann entsprechen 215 eben 21,5°C.

void servoMotor (const int temp)
{
  // static int servoPos {0};  // für leeres default
  int servoPos {0};            // mit Default Pos.

  switch(temp)
  {
    case 21 ... 23: servoPos =  16; break;
    case 24 ... 26: servoPos = 140; break;
    case 27 ... 29: servoPos =  70; break;
    default: servoPos = 100; break;
  }

  myservo.write(servoPos);
}

Hallo,
ich fand das zunächst die beste Losung, doch was passiert wenn die Temperatur zwischen 23 und 24 Grad wechselt. Ist keine richtige Hysterese sondern ehr eine Fenster Lösung
Heinz

Hi my_xy_projekt

Vielen Dank für deinen Input.
Hab deinen Code gerade mal versucht zu verifizieren und bekomme ein paar Fehlermeldungen:

Growduino_Final_210122:30:7: error: expected unqualified-id before '=' token
 stufe = stufe1;
       ^
C:\Users\ibiza\OneDrive\HFU_Uster_OneDrive_20AE\4_Semester\Vordiplomarbeit Modul (AET)\Vordiplom_Stefano\Sketchs_Arduino\Growduino_Final_210122\Growduino_Final_210122.ino: In function 'void servoAktion()':
Growduino_Final_210122:124:13: error: expected primary-expression before '==' token
   if (stufe == stufe1)
             ^~
Growduino_Final_210122:129:13: error: expected unqualified-id before '=' token
       stufe = aus;
             ^
Growduino_Final_210122:134:13: error: expected unqualified-id before '=' token
       stufe = stufe2;
             ^
Growduino_Final_210122:142:13: error: expected unqualified-id before '=' token
       stufe = stufe1;
             ^
C:\Users\ibiza\OneDrive\HFU_Uster_OneDrive_20AE\4_Semester\Vordiplomarbeit Modul (AET)\Vordiplom_Stefano\Sketchs_Arduino\Growduino_Final_210122\Growduino_Final_210122.ino: In function 'void AnzeigenEins()':
Growduino_Final_210122:170:18: error: expected primary-expression before ')' token
   lcd.print(stufe);                                                       // schreibe Wort aus status

Sowie ich das interpretiere stimmt etwas mit diesem enum stufe nicht? Kannst du das bestätigen oder ist da sonst noch was nicht in Ordnung?

Dankeschön

Das ist überhaupt keine Hysterese, nur lineares Mapping.

Naja, nen bissl selber machen :wink:

Ok ich habs mal ganz kurz geschrieben.
Da muss noch der Servo deklariert werden und dann dein Sensor.
Dann sollte es was werden.

const int solltemp = 22;
const int hysterese = 3;
enum {aus, stufe1, stufe2};
byte stufe = stufe1;
int temp;

void setup()
{}

void loop()
{servoAktion();}
void servoAktion()
{
  if (stufe == stufe1)
  {
    if (temp <= solltemp - hysterese)
    {
      myservo.write(16);
      stufe = aus;
    }
    if (temp >= solltemp + hysterese)
    {
      myservo.write(140);
      stufe = stufe2;
    }
  }
  else
  {
    if (temp == solltemp))
    {
      myservo.write(70);
      stufe = stufe1;
    }
  }
}

Noch 'n Hinweis:
Ich würde das setzen der gewollten Position aus der Ermittlung der Position rauslösen und in einer zusätzlichen Funktion anhand der Variable stufe mit einem switch/case den Servo setzen.

Das ist auch mein Ansatz. Ich habe bewusst nach einer Bestätigung gefragt und nicht nach einer vordefinierten Lösung. Ob ich dann damit weiter komme, steht auf einem anderen Blatt.

Dann bestätige ich, das der Ansatz nicht passt :wink:
Du kannst den Gegenvorschlag gerne verwenden. Ich habe ihn nicht kommentiert - da ist also noch Luft um das als fertige Lösung zu verwenden.

Hallo,

die case Bereiche muss der TO selbst ändern wie es ihm passt.

die Vorgabe vom TO lässt nicht viel Spielraum.
jeden Grenzwert (22°,25°,28°)
mit angenommer Hysterese 1°C wäre das
21...23
24...26
27...29

das habe ich pauschal eingesetzt. Die case Bereiche kann der TO selbst ändern wie es ihm passt. Er muss überlegen wohin er den Totbereich legt.

Hallo,

sehr direkt, okay, kann man machen, wenn man es selbst verträgt. Nur für das Protokoll. Von einer Bestätigungsanfrage lese ich nichts.

Keine Angst, ich vertrage viel. Ich habe bewusst so gefragt, weil ich weiss wie es den erfahrenen Forum-Experten auf den Kecks gehen kann, wenn der TO nicht selbst was überlegt, nichts neues ausprobieren möchte und eine vorgefertigte funktionierende Antwort erwartet. Eine Diskussion soll erlaubt sein, auch wenn gewisse Fragen vielleicht mehrfach gestellt werden müssen.

Von demher alles i.O und ich bin extrem dankbar dafür, dass ich auf eine erfahrene Community setzen kann (euch)!

..24 //25-1
23..27 //22+1 28-1
26.. //25+1
Hysterese bedeutet, daß sich die Wertebereiche überschneiden.

Linear könnte man mappen mit
map(temp, 22,28, 0,140);
oder
map(temp, 22,28, 0,2)*70;
Das entspräche dann einem P-Regler. Mit einem PID Regler mit leicht negativem D Anteil könnte man das Schwingen an den Bereichsgrenzen reduzieren.

bezüglich den defines abgewöhnen versuche ich mich daran zu halten.

Dein Vorschlag ist sehr interessant und versuche das auszutesten und anzupassen.
Eine kleine Frage dazu:

die Variable temp ist bei mir vom Datentyp float (Anzeige der Temperatur auf einem Display mit Kommastellen)
mit dem Datentyp float funktioniert aber die switch case nicht, weil der natürlich einen Int benötigt.
Gibts dafür eine alternative Variante oder lege ich einfach 2 Variablen an für die temp:

temp1 für die servoAktion
temp2 für die Anzeige in float auf dem Display

Ja. Temperatur in Zehntelgrad als Integer führen und nur bei der Ausgabe auf das Display mit der einen Nachkommastelle hantieren.

Hallo,
wenn Du was mit switch machen willst könntest Du eine Hilfsvariabe benutzen und Deinen Wert mit 10 multiplizieren dann kann es ein Int sein.
Heinz

Weder noch.
Du übergibst temp beim Aufruf, die Funktion erwartet einen Parameter.
Eine Umwandlung findet automatisch statt

void servoMotor (const int temp)

@Doc_Arduino sein temp ist etwas missverständlich, aber die da deklarierte Variable wird nur lokal verwendet.
Der Übersicht halber, vielleicht so:

void loop()
{
  servoMotor(temp);
}


void servoMotor (const int temperatur)
{
  // static int servoPos {0};  // für leeres default
  int servoPos {0};            // mit Default Pos.
  switch (temperatur)
  {
    case 21 ... 23: servoPos =  16; break;
    case 24 ... 26: servoPos = 140; break;
    case 27 ... 29: servoPos =  70; break;
    default: servoPos = 100; break;
  }
}

Das mit den defines versuche ich mir in dem Fall abzugewöhnen.

Versuche es gerade umzudefinieren aber stehe grad an.
Habe gelesen, dass die defines am besten mit const datentyp abgeändert werden.

Wenn ich nun für einen DHT-Sensor sowas habe:

#include "DHT.h"                    // Bibliothek für Feuchte- und Temp.sensor DHT11 oder DHT22
#define DHTTYPE DHT22             // definiere den Sensortyp
//#define DHTPIN 13
const int DHTPIN = 13;                    // Eingangspin 13 an DHT zuweisen
//String DHTTYPE = String DHT22;
DHT dht(DHTPIN, DHTTYPE);           // Objekt dht anlegen und Zuweisung Typ und PIN13

das mit dem Pin funktioniert, da dies nur ein Integer ist.
Wie sieht das mit dem Wort DHT22 in die Variable DHTTYPE aus? Müsste doch in einen String gesetzt werden?