Code in nicht Blockierenden Code umschreiben

Hallo miteinander,

für eine Drehachse möchte ich den Nullpunkt ermitteln.

Das habe ich mir auf dem Blatt Papier überlegt und dann umgesetzt.
Natürlich erst mal ganz Primitiv so wie ich es schnell und einfach in meinem Kopf zusammen gebaut bekommen habe.

Das Klappt auch :-), doch leider ist das ein Code der Blockiert und das mag ich nicht !!, daher möchte ich den umschreiben in einen Code der nicht Blockierend ist.

den Ersten Ansatz habe ich auch geschafft, jetzt benötige ich einen Denkanstoß von euch.

Mein Drehachse ist so was: Drehachse mit Motor

Info: Der Nullpunkt ist immer am Anfang des Sensors Der Positiven Seite, die Drehachse hat keinen Endschalter !

Wie ermittle ich den 0 Punkt.

  1. Mache ein paar schritte ins Negative
  2. Prüfe ob Sensor Aktiviert ist
    Wenn JA:
    2.2 mache einen Schritt ins Positive
    2.3 Prüfe ob Sensor Aktiviert ist
    2.4 Springe zu 2.
    Wenn Nein:
    2.5 Setze Neuen Nullpunkt an Motorposition
    Fertig

Das ist der Code dazu:

/*  
 *   Testprogramm für einzelne Motoren
 */
    #include <AccelStepper.h>                          // Installiren der AccelStepper LIB 

// Motor Pins 
    int PUL = 2;                                       // PIN für Tackt
    int DIR = 3;                                       // PIN für Drehrichtungsangabe      HIGH = Im Uhrzeigersinn LOW = Gegen den Uhrzeigersinn
    int ENA = 4;                                       // PIN für Treiber ON/OFF           HIGH = Motor OFF        LOW = Motor ON 
// Motorpins Typ zuweisen
    AccelStepper Achse(1, PUL, DIR);                   //  Motoren Installiren (1, PUL, DIR) 
// Sensor Pin
    int Sensor = 28;                                   // Pin für Sensor
// Nullpunkt Marker 
    bool A_Null = false;                               // Wenn Nullpunkt gesetzt wurde = true sonst false 


void setup() {
    Serial.begin(250000);                              // Datenrate für die serielle Datenübertragung festlegen.  
// Motor 
    pinMode(ENA, OUTPUT);                              // EAN auf Output setzen
    Achse.setAcceleration(3000);                       // Beschleunigung 
    Achse.setMaxSpeed(1000);                           // RPM
    digitalWrite(ENA, LOW);                            // Motor Aktiviren 
    Serial.println(F("OK, Motor Start"));              // Ausgabe das Motor Startklar ist
// Sensor 
    pinMode(Sensor, INPUT);                            // Sensor auf Input setzen  
} // void setup

 

void loop() {
  while(!A_Null) {                                     // Nullpunkt Prüfen
// Sensor suchen mit - (minus) schritten 
    while(!digitalRead(Sensor)) {                      // Sensor Prüfen
      Achse.move(-100);                                // Sollposition relativ zur aktuellen Position einstellen
      Achse.run();                                     // mache einen Schritt wenn diser fällig ist 
    } // !digitalRead(Sensor)
// Sensor anfang suchen mit + (plus) schreitten 
    while(digitalRead(Sensor)) {                       // Sensor Prüfen
      Achse.move(1);                                   // Sollposition relativ zur aktuellen Position einstellen
      Achse.run();                                     // mache einen Schritt wenn diser fällig ist 
    } // digitalRead(Sensor)
// Position auf 0 Setzen   
    Achse.setCurrentPosition(0);                       // Motorposition auf 0 Setzen 
    A_Null = true;                                     // Null wurde gefunden
  } // !A_Null 
} // void loop

Jetzt habe ich angefangen den CODE so zu schreiben das er nicht Blockiert:
Habe das auch bis auf den letzten Punkt hin bekommen.
Ich mache die Negativen Schritte, dann die Positiven, JETZT KOMMT DAS DENKPROBLEM
Wie kann ich dann den Nullpunkt setzen?
Mir ist nicht klar wie ich die Abfrage gestalten muss dafür.

Das ist mein Ansatz als CODE

/*  
 *   Testprogramm für einzelne Motoren
 */
    #include <AccelStepper.h>                          // Installiren der AccelStepper LIB 

// Motor Pins 
    int PUL = 2;                                       // PIN für Tackt
    int DIR = 3;                                       // PIN für Drehrichtungsangabe      HIGH = Im Uhrzeigersinn LOW = Gegen den Uhrzeigersinn
    int ENA = 4;                                       // PIN für Treiber ON/OFF           HIGH = Motor OFF        LOW = Motor ON 
// Motorpins Typ zuweisen
    AccelStepper Achse(1, PUL, DIR);                   //  Motoren Installiren (1, PUL, DIR) 
// Sensor Pin
    int Sensor = 28;                                   // Pin für Sensor
// Nullpunkt Marker 
    bool Null = false;                                 // Wenn Nullpunkt gesetzt wurde = true sonst false
    bool A_Null = false;                               // Wenn Nullpunkt gesetzt wurde = true sonst false 



void setup() {
    Serial.begin(250000);                              // Datenrate für die serielle Datenübertragung festlegen.  
// Motor 
    pinMode(ENA, OUTPUT);                              // EAN auf Output setzen
    Achse.setAcceleration(3000);                       // Beschleunigung 
    Achse.setMaxSpeed(1000);                           // RPM
    digitalWrite(ENA, LOW);                            // Motor Aktiviren 
    Serial.println(F("OK, Motor Start"));              // Ausgabe das Motor Startklar ist
// Sensor 
    pinMode(Sensor, INPUT);                            // Sensor auf Input setzen  
} // void setup

 

void loop() {
  Achse.run();                                         // mache einen Schritt wenn diser fällig ist 
  if (!Null) {                                         // Prüfen auf Nullpunkt
      Nullpunkt();                                     // Nullpunkt setzen
  } 
} // void loop

void Nullpunkt() {
  /* 
   *  Nullpunkt ermitteln ohne das alles Blockiert wird
   */
// Sensor suchen mit - (minus) schritten 
  if ((!A_Null) && (!digitalRead(Sensor))) {           // Achse Null nicht gefunden und Sensor in Aktiv
      Achse.move(-100);                                // Sollposition relativ zur aktuellen Position einstellen    
  } // (!A_Null) && (!digitalRead(Sensor)) 
// Sensor anfang suchen mit + (plus) schreitten 
  if ((!A_Null) && (digitalRead(Sensor))) {            // Achse Null nicht gefunden und Sensor ist Aktiv 
      Achse.move(1);                                   // Sollposition relativ zur aktuellen Position einstellen    
  } // if 
// Position auf 0 Setzen  
    /*
    * Achse.setCurrentPosition(0);                       // Motorposition auf 0 Setzen 
    * A_Null = true;                                     // Null wurde gefunden
    * Null = true;                                       // Null wurde gefunden
    */
} // void Nullpunkt()

Könntet Ihr mir einen Denkanstoß geben.

Gruß Mücke

Hallo Mücke,
wie so oft - ein kleiner Automat bzw. eine einfache Schrittkette. Der hat 3 Zustände:
-erst fährst Du rückwarts bis der Sensor anspricht.
-dann vorwärts bis der Sensor wieder abfällt
-und dann setzt Du den Nullpunkt.
Du brauchst also einen Zustandsmerker, der immer wenn die Bedingung efüllt ist, eins weiterpringt. Und erst im dritten Zustand setzt Du den Nullpunkt.

Das Anfahren des Nullpunkts gehört eigentlich nach setup(), da darf es notfalls auch blockieren. Oder soll loop() irgendwas wichtiges machen, bevor der Nullpunkt ermittelt ist?

Muecke:
Könntet Ihr mir einen Denkanstoß geben.

Bitteschön, nur Deine Ideen und Prinzessin Efesem wachgeküsst1):

void loop() {
  Achse.run();                                         // mache einen Schritt wenn diser fällig ist
  if (Nullpunkt()) {                                   // Nullpunkt setzen
    // Hier weitere Bewegungen
  }
} // void loop

bool Nullpunkt() {
  enum {FERTIG, SUCHEN, FINDEN, SCHLEICHEN, VERLASSEN};
  byte static status = SUCHEN;
  switch (status) {
    case SUCHEN:
      Serial.println(F("Suchen"));
      Achse.move(-4096);                                // Sollposition relativ zur aktuellen Position einstellen
      status = FINDEN;
      break;
    case FINDEN:
      if (!digitalRead(Sensor)) {                       // Referenzpunkt gefunden
        Serial.println(F("Gefunden"));
        Achse.stop();
        status = SCHLEICHEN;
      }
      break;
    case SCHLEICHEN:
      Serial.println(F("Schleichen"));
      Achse.move(+4096);                                // Referenzpunkt schleichend verlassen
      status = VERLASSEN;
      break;
    case VERLASSEN:
      if (digitalRead(Sensor)) {                        // Referenzpunkt verlassen
        Achse.setCurrentPosition(0);
        Serial.println(F("Fertig"));
        status = FERTIG;
      }
      break;
  }
  return status == FERTIG;
} // void Nullpunkt()

Getestet habe ich mit einem kleinen unipolaren Motor, weshalb setup und globale Variablen anders aussehen, drum habe ich den Teil weggelassen.

Bei Deinem Motor mußt Du eventuell die Geschwindigkeiten auf Schleichen reduzieren.


Anm.:

  1. Ein Scherz aus einem anderen Thema übernommen: FSM = finite state machine = endlicher Automat = Schrittkette

Sorry, für die Späte Rückmeldung, komme gerade nicht so oft dazu etwas weiter zu machen.

@MicroBahner: Oh man warum bin ich nicht drauf gekommen :-(, das ist eine Gute Idee.

@DrDiettrich: zum teil gebe ich dir recht, das beim Nullpunkt ermitteln der Code auch Blockiren darf.
Ich sehe da ein paar Dinge jedoch die ich gerne garantieren möchte.
Mein CNC Portal ist 70cm Hoch und 1,5M Breit und 70cm Tief, hier kann also nicht nur ein Finger irgend wo dazwischen kommen sondern auch mal etwas mehr :frowning: die Motoren sind dazu auch entsprechende groß und Stark, somit muss ich den Notaus Schalter immer auslösen können. Wobei ich den glaube ich auf einen Interrupt Pins legen werde.
Das andere ist das ich es mir angewöhnen möchte gleich so zu denken das der Code nicht Blockiert ich hoffe das es dann mit der zeit besser wird beim Programmiren :slight_smile:

@agmue: und schon wider was neues dazu gelernt.
Wust gar nicht das eine Variable wie eine Funktion aufgebaut werden kann.
das werde ich Stück für Stück durcharbeiten, finde die Idee Cool.
Danke.

Gruß Mücke

Muecke:
Wust gar nicht das eine Variable wie eine Funktion aufgebaut werden kann.

Auf welchen Programmteil bezieht sich diese Erkenntnis?

agmue:
Auf welchen Programmteil bezieht sich diese Erkenntnis?

bool Nullpunkt() {
  enum {FERTIG, SUCHEN, FINDEN, SCHLEICHEN, VERLASSEN};

bool ... kenne ich als Variable die kann Richtig oder Falsch beinhalten.
Du hast mir einen Weg gezeigt in der die noch mehr werte kann :frowning: wenn ich das richtig verstanden habe.
da bin ich gerade am testen ob das Stimmt was ich da im Kopf habe.

Muecke:

bool Nullpunkt() {

Die Funktion Nullpunkt() hat einen Rückgabewert vom Typ bool. Ich lenke Deine Aufwerksamkeit auf diese Zeilen:

bool Nullpunkt() {
...
  return status == FERTIG;

Wenn der Status der Schrittkette gleich FERTIG ist, dann gibt die Funktion den Wert true zurück, sonst false.

Das if prüft in der Klammer auf true oder false1), das paßt dann zum Rückgabewert der Funktion.


Anm.:

  1. Eigentlich ist es ein Vergleich, ob der Wert ungleich 0 ist, wenn ich mir das richtig gemerkt habe. Ursprünglich wollte ich daher dies machen:
if (!Nullpunkt()) {
...
bool Nullpunkt() {
...
  return status;

Das entspräche dann:

if (!(Nullpunkt() > 0)) {

OK, jetzt habe ich das enum verstanden.
Der erste wert ist 1 = true, alle darauf folgenden werte sind 0 = false

Dadurch das der Status byte static status eine static Variable ist, also nicht von außen verändert werden kann der wert wird in der aufgerufenen Funktion jedoch auch nach dem Verlassen nicht vergessen, kann man so wenn die Bedingung nicht Wahr ist verschiedenen Arbeiten erledigen bis alles gemacht wurde was man haben möchte und so kann man den Code natürlich deutlich verkürzen.

Was ich jetzt nicht verstehe ist die ziele:

return status == FERTIG;

Ich kenne das so:
Zuweisung =
Wert Vergleich ==
Type Vergleichen === (gibt es glaube ich im C++ nicht)

Somit würde die Zeile die bedeuten.
Rückgabe wert Status vergleiche mit FERTIG.

Oha, jetzt verstehe ich, klar ich gebe einen Rückgabe wert und gleiche ab ob der Status mit FERTIG übereinstimmt wenn das nicht der Fall ist dann 0 (false) wenn die Bedingung wahr ist dann 1 (true)

demnach hat die bool Nullpunkt() gar keine verschiedenen Staus sondern der Status wird am Schluss immer wider neue gesetzt.

Oh man ich muss noch so viel lernen. :frowning:

Muecke:
OK, jetzt habe ich das enum verstanden.
Der erste wert ist 1 = true, alle darauf folgenden werte sind 0 = false

enum {FERTIG, SUCHEN, FINDEN, SCHLEICHEN, VERLASSEN};

FERTIG==0
SUCHEN==1
VERLASSEN==4

Der Aufzählungstyp »enum« (das ist ein C-Buch, nicht C++!), aber für mich verständlich.

Sonst OK.

Muecke:
@MicroBahner: Oh man warum bin ich nicht drauf gekommen :-(, das ist eine Gute Idee.

Manchmal sieht man das Byte vor lauter Bits nicht oder so ähnlich ging das Sprichwort... ;D

Kann man deine CNC Maschine später irgendwie oder -wo bestaunen?

Gruß

Wobei ich den glaube ich auf einen Interrupt Pins legen werde.

Das tust du nicht.
Nein!

Du kannst nicht garantieren, dass der µC jederzeit Interrupts abarbeiten kann.
Denn es gibt ja einen Grund, warum du Not-Aus drücken musst.

OK, jetzt habe ich das enum verstanden.
Der erste wert ist 1 = true, alle darauf folgenden werte sind 0 = false

enum {FERTIG, SUCHEN, FINDEN, SCHLEICHEN, VERLASSEN};
Umgekehrt.
Der erste Wert "FERTIG" entspricht 0 und damit false.
Die anderen entsprechen 1,2,3,... und damit true

Das wäre meine Nächste frage gewesen, dann das enum war mir jetzt nicht ganz klar.
habe da aus deinem Link gelesen, so ganz habe ich das glaube ich noch nicht verstanden die es geht aber schon in die richtige Richtung im Kopf glaube ich.

@Scherheinz: Oh ja, manchmal ist das zum verrückt werden. ich sitze hier Stunden lang und überlege und probiere aus. dann schreibe ich im Forum keine 10 min später die Lösung meines problemloses ist geschrieben.

Manchmal überlege ich echt, ob nicht jemand hier in der Nähe (Stuttgart) sitzt der mir dabei helfen möchte, der deutlich besser ist wie ich.

Scherheinz:
Kann man deine CNC Maschine später irgendwie oder -wo bestaunen?

Wenn Sie denn mal fertig wird sehr gerne, ich habe auch vor diese hier im Forum dann zu Präsentieren, da mir wirklich extrem viel geholfen wird hier von euch, wofür ich euch allen Dankbar bin.

Wenn du in der Groben Umgebung Stuttgart bist kannst du gerne vorbei kommen.

combie:
Das tust du nicht.
Nein!

Du kannst nicht garantieren, dass der µC jederzeit Interrupts abarbeiten kann.
Denn es gibt ja einen Grund, warum du Not-Aus drücken musst.

Mit dem Notaus wird auch Mechanisch der Strom von den Motoren genommen etc.
Jedoch muss ich auch den Controller sagen das er nicht mehr arbeiten darf.

Hi

Thema NotAus:
Davon sollte Es, bei den Maschinen-Ausmaßen, nicht nur Einen geben.
Auch sollte Dieser irgend eine Spannung weg nehmen, Die dringend für die Bewegung gebraucht wird.
Einzige Ausnahme: Achsen, Die bei Spannungsverlust herunter fallen - Z auf Kugelspindeln wäre Da so ein Favorit.

Die Kiste muß keinen internationalen Sicherheitsbestimmungen stand halten, sollte aber bei NotAus nicht mehr selbstständig irgend was machen können.
Klar, bei einer gebremsten Achse (Z liegt nahe dem Maschinentisch, die Hand liegt aber dazwischen) ist man aber auch wieder 'am A***' - hier wäre eine freie Achse, Die aber beim NotAus in den Tisch kracht, besser gewesen.

Industriell hat der NotAus 2 Öffner-Kontakte, damit ein verklebter Kontakt den NotAus nicht deaktiviert.

MfG

PS: Der Controller ist in der Situation NotAus zweitrangig - aber wenn der Strom bereits Geschichte ist, darfst Du dem µC gerne sagen, daß Da ein NotAus betätigt wurde :slight_smile:
Allerdings ist DAFÜR kein Interrupt nötig - der µC kann eh Nichts machen, was Dir an der Maschine hilft oder schadet.
Ein Blinke-Lämpchen fände ich schön ...

Thema NotAus:
Oh ja das teil muss alles abschalten und das Ohne das irgend ein Rechenprozess das prüfen muss.
Ich möchte auch das die Motoren dann alle Ohne Haltemoment sind, ich habe keinen Achse die Fallen kann, sind alle Selbst haltend.

Das Blinklicht ist eine Gute Idee, ich gleich ich besorge mir so ein Gelbes Drehlicht :slight_smile: dafür oder so ein Ampellicht das an Maschinen dran ist.

Thema enum:

Diese Auflistung ist an keine Variable gebunden?
sondern es wird Definiert das der Wert (als Schrift) was für eine zahl zugewiesen wurde, und es wird immer um eins nach oben gezählt.

Man kann also auch so was schreiben?

  enum {FERTIG_A, SUCHEN_A, FINDEN_A, SCHLEICHEN_A, VERLASSEN_A};  // Achse A 
  enum {FERTIG, SUCHEN_X_Null, GEFUNDEN_X_Null, ARBEITSBEREICH_X_SUCHEN, VERLASSEN_X};  // ACHSE X
  enum {FERTIG, SUCHEN_Z_Null, GEFUNDEN_Z_Null, ARBEITSBEREICH_Z_SUCHEN, VERLASSEN_Z}; // Achse Z

Dann kann ich meine 3 Ereignis ketten darunter setzen die leider alle etwas unterschiedlich laufen.

und ganz am Schluss frage ich dann ab ob alle auf Fertig stehen und kann so meinen Status der Variabel dann richtig zurück geben.

Ja, das geht so mit enum.

Hi


Die obere Ampel kommt bei mir nicht, hier Mal als URL.
Wobei die Dinger mit 24V laufen - da braucht der Arduino noch einen FET.

MfG