Einfacher Failsafe Timer für eine selbstgebaute Brikettpresse

Hi, ich habe einen simplen code für eine selbstgebaute Brikettpresse geschrieben.

Im Prinzip steuern zwei Endschalter die Vorwärts- und Rückwärtsbewegung eines Hydraulik-Kolben.

Jetzt würde ich gern einen Failsafe einbauen, dass im Falle eines Fehlers (Endschalter spricht nicht an oder Maschine klemmt) nicht die Hydraulik heiss läuft und sich selbst zerlegt.

Die Zeit die der Kolben von Schalter1 bis Schalter2 braucht ist ca. 5. Sekunden.
Ich würde gern programmieren, dass der Prozess stoppt (also die Pneumatik, die den Lauf des Kolben steuert, den Status "LOW" annimmt und dort bleibt) falls der Kolben nach 10 Sekunden immer noch nicht bei Schalter2 angekommen ist.

Kann mit das bitte jemand helfen. Ich komme da nicht weiter. Ich habe schon recherchiert und bin auf "millis" gestoßen, aber wie ich das in dem Fall anwende bekomme ich leider nicht hin.

Hier mein Code:

int pneumatik = 8;          //  Steuert Vor/Rücklauf des Kolbens 
int schalter1 = 7;          //  Endschalter für Vorwärtslauf Kolben
int schalter2 = 4;          //  Endschalter für Rückwärtslauf Kolben
int mainschalter = 12;      //  Hauptschalter
int ruehrwerk = 10;         //  Schaltet Rührwerk im Spänebehälter an/aus
int SwitchStatus = 0; 
void setup ()
{

pinMode(pneumatik, OUTPUT); 
pinMode(ruehrwerk, OUTPUT);
pinMode(mainschalter, INPUT);
pinMode(schalter1, INPUT);
pinMode(schalter2, INPUT);  
}

void loop () {


SwitchStatus=digitalRead(mainschalter); //Hauptschalter
if (SwitchStatus == LOW)
{
digitalWrite(ruehrwerk, LOW);
digitalWrite(pneumatik, LOW);


SwitchStatus=digitalRead(schalter1); //Vorwärtsfahrt Kolben

if (SwitchStatus == HIGH)
{
 
  digitalWrite(pneumatik, HIGH);
  delay(500);
  
  
 
}

SwitchStatus=digitalRead(schalter2); // Rückwärtsfahrt Kolben
if (SwitchStatus == HIGH) 
{
 
  digitalWrite(pneumatik, LOW); 
  delay(500);
  
 
 }}

 else {
  digitalWrite(ruehrwerk, HIGH);
  digitalWrite(pneumatik, HIGH);


  
  
 } }

@beff
und das funktioniert schon?
Irgendwie reagiert der Hauptschalter, die zwei Outputs gehen auf HIGH und das wars bei mir.

was ist die Hardware?
Verwendest du externe Pulldown Widerstände für die Schalter?
Sind die Ausgänge eigentlich LOW Aktiv, also Relais drann die die Pegel umdrehen?

const byte pneumatikPin = 8;          //  Steuert Vor/Rücklauf des Kolbens
const byte endschalterVorPin = 7;     //  Endschalter für Vorwärtslauf Kolben
const byte endschalterRueckPin = 4;   //  Endschalter für Rückwärtslauf Kolben
const byte mainschalterPin = 12;      //  Hauptschalter
const byte ruehrwerkPin = 10;         //  Schaltet Rührwerk im Spänebehälter an/aus
const unsigned long bouncetime = 50;  //  zeit in ms
unsigned long startZeit = 0;
enum {an, aus};
enum {warten, ruehren, pressen, loesen, error};
byte schritt = warten;
void setup ()
{
  pinMode(pneumatikPin, OUTPUT);
  pinMode(ruehrwerkPin, OUTPUT);
  pinMode(mainschalterPin, INPUT);
  pinMode(endschalterVorPin, INPUT);
  pinMode(endschalterRueckPin, INPUT);
}

void loop ()
{
  if (mainSwitch() == aus)
  {
    schritt = warten;
  }
  switch (schritt)
  {
    case warten:
      ruehrwerk(aus);
      digitalWrite(pneumatikPin, aus);
      if (mainSwitch() == an)
      {
        schritt = ruehren;
      }
      break;
    case ruehren:
      ruehrwerk(an);
      schritt = pressen;
      startZeit = millis();
      break;
    case pressen:
      if (runterfahren() == false)
      {
        hochfahren();
        schritt = loesen;
        startZeit = millis();
      }
      if (millis() - startZeit > 5000)
        schritt = error;
      break;
    case loesen:
      if (hochfahren() == false)
      {
        runterfahren();
        schritt = pressen;
        startZeit = millis();
      }
      if (millis() - startZeit > 5000)
        schritt = error;
      break;
    case error:
      break;
      if (hochfahren() == false)
        schritt = pressen;
      break;
      presse(an);
  }
}

void ruehrwerk(const bool anaus)
{
  digitalWrite(ruehrwerkPin, anaus);
}

bool hochfahren()
{
  presse(aus);
  return digitalRead(endschalterRueckPin);
}

bool runterfahren()
{
  presse(an);
  return digitalRead(endschalterVorPin);
}

void presse (const bool richtung)
{
  digitalWrite(pneumatikPin, richtung);
}

bool mainSwitch()
{
  unsigned long startZeit = 0;
  static bool tik = false;
  if (millis() - startZeit >= bouncetime)
  {
    if (digitalRead(mainschalterPin) == LOW)
    {
      startZeit = millis();
      tik = true;
    }
    else
      tik = false;
  }
  return tik;
}

Macht was Du vorgegeben hast.
Deine Vorgabe ist etwas eigenartig...

Muss die startZeit nicht auch static? Sonst ergibt

ja wenig Sinn.

Ja!

Aber egal wie - das Original ist ja ebenfalls nicht funktional - also darf ich auch :slight_smile:
Danke - mal sehen was draus wird. Das WE war schön...

Danke für deinen Code. Ich werd ihn morgen mal ausprobieren.

Was meinst Du mit "nicht funktinal" und "eigenartige Vorgabe"?
Wenn Du meine Programmierkenntnisse meinst dann hast Du wahrscheinlich völlig recht :wink:

Aber, mein code funktioniert und hat schon ne Kiste Briketts gepresst. Ich muss halt nur immer daneben stehen, da manchmal was klemmt und dann ist die Hydraulik hinüber :wink:

Hey, ich weiss das ist wahrscheinlich ziemlicher Murks,.. ich bin kein Programmier.
Aber es funktioniert tatsächlich. Hab schon ne Kiste Briketts damit gepresst, muss nur halt noch sicherheitshalber daneben stehen, weil manchmal was klemmt und das ist nicht Sinn der Sache.

Arduino Uno mit zwei externen Relais.
Ja, die Schalter sind mit externen Wiederständen bestückt und die Ausgänge sind LOW aktiv und im Relais dann umgedreht. Hab ich glaub deshalb gemacht, weil der Grundzustand des Relais im ausgeschalteten Zustand dann der Richtige war. Weiss ich aber nicht mehr genau.

:weary:
Solange kann ich nicht warten ...

Ok - Spass beiseite.

Ich verstehe Deinen Ablauf nicht....

Du schaust erst, ob der Hauptschalter LOW steht.
Ist das der Fall, schreibst Du Pneumatik LOW
Um im nächsten Schritt schalter1 auf HIGH abzufragen, um dann pneumatik HIGH zu setzen.

Das geht nur mit deinen delay() - macht aber keinen Sinn und ist eher kontraproduktiv, weil es für Verwirrung sorgt.

Bitte beachte, was @wno158 geschrieben hat - verändere den Code dahingehend und schon ist schick...

Na denne... :wink:

ah.. da ist mir was reingerutscht beim Kopieren. Der code der momentan funktioniert ist folgender. Ich hab beim Hauptschalter Pneumatik nicht auf LOW gestellt

int pneumatik = 8;          //  Steuert Vor/Rücklauf des Kolbens 
int schalter1 = 7;          //  Endschalter für Vorwärtslauf Kolben
int schalter2 = 4;          //  Endschalter für Rückwärtslauf Kolben
int mainschalter = 12;      //  Hauptschalter
int ruehrwerk = 10;         //  Schaltet Rührwerk im Spänebehälter an/aus
int SwitchStatus = 0; 
void setup ()
{

pinMode(pneumatik, OUTPUT); 
pinMode(ruehrwerk, OUTPUT);
pinMode(mainschalter, INPUT);
pinMode(schalter1, INPUT);
pinMode(schalter2, INPUT);  
}

void loop () {


SwitchStatus=digitalRead(mainschalter); //Hauptschalter
if (SwitchStatus == LOW)
{
digitalWrite(ruehrwerk, LOW);



SwitchStatus=digitalRead(schalter1); //Vorwärtsfahrt Kolben

if (SwitchStatus == HIGH)
{
 
  digitalWrite(pneumatik, HIGH);
  delay(500);
  
  
 
}

SwitchStatus=digitalRead(schalter2); // Rückwärtsfahrt Kolben
if (SwitchStatus == HIGH) 
{
 
  digitalWrite(pneumatik, LOW); 
  delay(500);
  
 
 }}

 else {
  digitalWrite(ruehrwerk, HIGH);
  digitalWrite(pneumatik, HIGH);


  
  
 } }



 

Sorry dass ich zu doof dafür bin. Ich hab das grad mal in nem Simulator ausprobiert und leider macht Dein Code gar nichts. Die LED steht für Kolben Vor/zurück. Hier der Link.

Und hier mit meinem Code, der prinzipiell tut was er soll:

Könntest Du mir bitte noch mal helfen?

Ja, dann erzähl mal wie Deine Endschalter angebunden sind.
PULL_UP oder PULL_DOWN, Öffner oder Schliesser? Also welcher Pegel liegt am Pin an, wenn der Endschalter ausgelöst wird.

Wenn die Schalter auslösen sind sie geschlossen. Also ausgelöst 5v am Pin.

Dann las den mal laufen:

const byte pneumatikPin = 8;          //  Steuert Vor/Rücklauf des Kolbens
const byte endschalterVorPin = 7;     //  Endschalter für Vorwärtslauf Kolben
const byte endschalterRueckPin = 4;   //  Endschalter für Rückwärtslauf Kolben
const byte mainschalterPin = 12;      //  Hauptschalter
const byte ruehrwerkPin = 10;         //  Schaltet Rührwerk im Spänebehälter an/aus
const unsigned long bouncetime = 100; //  zeit in ms
const unsigned long failtime = 5000;
unsigned long startZeit = 0;

const bool an = LOW;   // Vorgabe für Antriebe
const bool aus = HIGH;
const bool ausgeloest = HIGH; // Vorgabe für Endschalter

enum {warten, ruehren, pressen, loesen, error};
byte schritt = warten;
void setup ()
{
  Serial.begin(115200);
  Serial.println(F("Start..."));
  pinMode(pneumatikPin, OUTPUT);
  pinMode(ruehrwerkPin, OUTPUT);
  pinMode(mainschalterPin, INPUT);
  pinMode(endschalterVorPin, INPUT);
  pinMode(endschalterRueckPin, INPUT);
}

void loop ()
{
  if (mainSwitch() != ausgeloest)
  {
    schritt = warten;
  }
  switch (schritt)
  {
    case warten:
      ruehrwerk(aus);
      presse(aus);
      if (mainSwitch() == ausgeloest)
      {
        schritt = ruehren;
      }
      break;
    case ruehren:
      ruehrwerk(an);
      Serial.println(F("ruehren ausgelöst"));
      schritt = pressen;
      Serial.println(F("Starte Presse"));
      startZeit = millis();
      break;
    case pressen:
      if (vorwaerts() == ausgeloest)
      {
        Serial.println(F("unten angekommen - fahre hoch"));
        schritt = loesen;
        startZeit = millis();
      }
      if (millis() - startZeit > failtime)
        schritt = error;
      break;
    case loesen:
      if (rueckwaerts() == ausgeloest)
      {
        Serial.println(F("oben angekommen - fahre runter"));
        schritt = pressen;
        startZeit = millis();
      }
      if (millis() - startZeit > failtime)
        schritt = error;
      break;
    case error:
      Serial.println(F("Zeit abgelaufen"));
      Serial.println(F("Warte auf abschalten"));
      presse(aus);
      ruehrwerk(aus);
      while (mainSwitch() == ausgeloest);
      Serial.println(F("MainSwitch aus"));
      break;
  }
}

void ruehrwerk(const bool anaus)
{
  digitalWrite(ruehrwerkPin, anaus);
}

bool rueckwaerts()
{
  presse(aus);
  return digitalRead(endschalterRueckPin);
}

bool vorwaerts()
{
  presse(an);
  return digitalRead(endschalterVorPin);
}

void presse (const bool richtung)
{
  digitalWrite(pneumatikPin, richtung);
}

bool mainSwitch()
{
  static unsigned long startZeit = 0;
  static bool tik = !ausgeloest;
  if (millis() - startZeit >= bouncetime)
  {
    if (digitalRead(mainschalterPin) == ausgeloest)
    {
      startZeit = millis();
      tik = ausgeloest;
    }
    else
      tik = !ausgeloest;
  }
  return tik;
}

Achte drauf, ich hab den Seriellen Monitor mit drin, damit Du siehst, was da passieren soll - und ggfls. sagen kannst wo es klemmt.

Super, funktioniert in der Simulation einwandfrei so wie ich es brauche.
Mega!
Vielen Dank!!

Bitte - gern geschehen.
War ja schon vorbereitet :wink:

Hi,
I have written a simple code that controls a hydraulic cylinder. There is two end-switches that control the forwards and backwards movement of the cylinder.

Now I would like to make the process a bit safer in case something goes wrong (switch does not activate or the machine jams) or else the machine will destroy itself.

The cylinder normally takes about 5 sec. from Switch1 to Switch2.
If Switch2 is not reached after 10 seconds I would like to stop the process by doing:

digitalWrite(ruehrwerk, LOW);
digitalWrite(pneumatik, LOW);

Please help me. This is beyond my programming knowledge.
Here is my full code

int pneumatik = 8;          //  controls cylinder movement 
int schalter1 = 7;          //  Switch1 for forward movement of the cylinder
int schalter2 = 4;          //  Switch2 for forward movement of the cylinder
int mainschalter = 12;      //  Main switch
int ruehrwerk = 10;         //  switches an electrical motor on/off
int SwitchStatus = 0; 
void setup ()
{

pinMode(pneumatik, OUTPUT); 
pinMode(ruehrwerk, OUTPUT);
pinMode(mainschalter, INPUT);
pinMode(schalter1, INPUT);
pinMode(schalter2, INPUT);  
}

void loop () {


SwitchStatus=digitalRead(mainschalter); // main switch
if (SwitchStatus == LOW)
{
digitalWrite(ruehrwerk, LOW);
digitalWrite(pneumatik, LOW);


SwitchStatus=digitalRead(schalter1); // cylinder forward movement

if (SwitchStatus == HIGH)
{
 
  digitalWrite(pneumatik, HIGH);
  delay(500);
  
  
 
}

SwitchStatus=digitalRead(schalter2); // cylinder backwards movement
if (SwitchStatus == HIGH) 
{
 
  digitalWrite(pneumatik, LOW); 
  delay(500);
  
 
 }}

 else {
  digitalWrite(ruehrwerk, HIGH);
  digitalWrite(pneumatik, HIGH);


  
  
 } }

Please describe the function of your three inputs.

A simple mechanical drawing of your project would help. Me anyway.

What besides time might mean a failure?

Also, apply “autoformat” tool in the IDE - your code layout is a bit unusual and obscures the flow.

And does HIGH turn things on or off? Does LOW mean a switch is closed or open?

A pencil drawn schematic would be nice help. Me.

a7

Look into using millis() as a timer. Start time would be the time you enable the output. Then wait 10sec. Read the input switch. If switch is is not on, use a while (1) function to lock the program in place. You could also add a reset button in the while loop to break out of it once the issue is resolved.

Hi beff,
you should post a description of the wanted behaviour with all details.

Written in normal words to make sure that it is easy to write for your and easy to understand. And to avoid sneaking in undiscovered mis-conceptions of how a program works.

To add about the programming:
a state-machine will simplify the programming once you have understood the concept of how state-machines work. This will need some time and some excercises. Once you have understood the concept you never want to go back.

the basic principle is to start timers based on function millis() which allows non-blocking timing.

As far as I have understood your description it shall work like this

All the names that you are using should be self-explaining
instead of "schalter1" give it a name that explains what its purpose is
schalter1 is an input
your comment sounds more like it is an output //Switch1 for forward movement of the cylinder

is schalter1 signaling cylinder has reached the most forward position and is an input
or is schalter1 a switch that initiatels the moving out of the cylinder and should be an output??

not sure but I guess
schalter1 / schalter2 seem to be endposition-switches

you have only one single output called "pneumatic"
what kind of valve is connected to this IO-pin?

Is this a valve with spring-return?
valve energised => cylinder moves out
valve not energised => cylinder moves in

Any user here would do a real bad job in providing a code-version that is based on assumings that are wrong. So it is very important that you give a very detailed description of

  • how your pneumatic works
  • how normal operation is
  • what can happen if there is any kind of disorder or malfunction
  • what the code should ideally do if a malfunction occurs

let's say cylinder is in moved-in position
what makes your cylinder start to move out?
a manually operated switch?
Do you wish to just have some monitoring or would you like to automate the whole process which would include controlling the cyclinder by the code too?

state-machine

state idle : cylinder does not move

if moving forward is detected by schalter1 == HIGH start a timer
change to state checkS1Low

state : check for schalter1 going low

if more than 0,5 seconds have passed by and schalter1 is still HIGH => stop the machine

if schalter1 has gone low before 0,5 seconds
start a timer
change to state awaiting S2 becoming high

state awaitS2HIGH
check if more than 10 seconds have passed by
if more than 10 seconds have passed by stop the machine
if schalter2 is HIGH before 10 seconds have passed by
switch pneumatik to low

How does the whole thing return to state idle?

From this description you can see which and how many informations your description should have to get a clear picture what the functionality should be

best regards Stefan

I don't recommend using while-loops. while loops are blocking and lead to inserting a lot of if-conditions to make the while-loop stop.

In the long run a state-machine is much easier to maintain and as a state-machine works non-blocking all kinds of watching multiple inputs must only be done in central place instead of multiple while-loops.

The state-machine stays inside one state until the conditions to change to the next state become true

The checking for faulty conditions sets a central and global variable to a value unequal to zero and whenever this variable is unequal to zero immidiately stop the machine = excecute some other code to stop the machine = de-energise valves etc.

best regards Stefan