Schrittmotor mit Reed stoppen und zurückfahren

Hallo zusammen,

ich habe hier einen kleinen Teil für ein Projekt bei dem es um eine
Toranlage (Modellbau) geht.
Die eigentliche Steuerung via IR funktioniert und das ist nicht mein Problem.
Allerdings soll der kleine Schrittmotor (5V- 28BYJ-48) beim Anfahren eines Reed-Schalters
sofort stoppen und ein kleines Stück zurück drehen um den Schalter wieder freizugeben.

Ich hänge gerade an der Position, dass der Motor beim Einschalten quasi das Tor hochfährt aber erst stoppt, wenn der Vorgang, sprich alle Schritte abgefahren sind.
Dann löst der Reed aus und fährt korrekt die paar Schritte zurück.
Dann verharrt er in dieser Position.

#include <AccelStepper.h>
int reed_schalter;
int led_green;
int led_red;
bool marker;
AccelStepper stepper(AccelStepper::FULL4WIRE, 8, 10, 9, 11); // Defaults to AccelStepper::FULL4WIRE (4 pins) on 2, 3, 4, 5
void setup()
{
  reed_schalter = 12;
  led_red =2;
  led_green = 3;
  pinMode(led_green, OUTPUT);
  pinMode(led_red, OUTPUT);
  pinMode(reed_schalter, INPUT_PULLUP);
  stepper.setMaxSpeed(1000);
  stepper.setAcceleration(500);
}
void loop()
{
  if (digitalRead(reed_schalter) == HIGH)    // Wenn Reed Schalter geschlossen ist
  {
    if (marker == false)
    {
      marker = false;
      digitalWrite(led_green, HIGH);
      digitalWrite(led_red, LOW);
      stepper.runToNewPosition(2048); // Tor offen
      stepper.stop();
    }
  }
  else
  {
      marker = true;
      digitalWrite(led_green, LOW);
      digitalWrite(led_red, HIGH);
      stepper.stop();
      stepper.runToNewPosition(1800); // Tor zurück um Reed freizugeben
      stepper.stop();
  } 
}

Die LED´s habe ich nur mal zur Visualisierung eingebaut, kommen hernach wieder weg.

Wie kann ich den Verfahrvorgang sofort stoppen, nicht erst, wenn die Schrittzahl abgefahren ist?

Herzliche Grüße
Chris

Das wird wohl an der AccelStepper liegen, die fährt durch bis zum Ende - und erst danach geht es weiter.
Aus deren Dokumentation (rote Farbe von mir):

Ich würde Umstieg auf MobaTools empfehlen.

1 Like

Danke Walter,
ich hab mir die Tools gestern mal angeschaut und ausprobiert.
Sehr vielversprechend!
Herzlichen Dank erstmal!

Bei den MobaTools kann man jederzeit eine stop-function aufrufen und dann wird auch postwendend gestoppt.

Hallo,
ich hab da mal ein Beispiel aus meiner Bastelkiste rausgesucht.
In Verbindung mit move und stop geht das ganz gut.

Es gibt eine function die das Referenz fahren erledigt und dann einen Wert zurück gibt. Allerdings wird der Schalter nicht frei gefahren, sondern der Motor bleibt auf der Flanke stehen.Das lässt sich ja aber erweitern z.B über eine Schrittkette.

#include <AccelStepper.h>

bool revfahren() {
  stepper.setSpeed(-100);  // langsam  minus fahren
  stepper.move(2000);      // zuück fahren grösser als gesamter Fahrweg

  if (rev_Pos) {          // wenn schalter angefahren
    stepper.stop();

    stepper.setSpeed(300);   // normale Geschw.
    stepper.setCurrentPosition(0); // auf pos o setzten
    // stepper.moveTo(0);   // auf o fahren um stop abzuschliessen
    return 1;
  }
  return 0;
}

...und wo wird die ominöse Bedingung revPos festgelegt?

Mit AccelStepper dürfte das so nicht funktionieren, da nirgends Stepimpulse erzeugt werden.

Hallo
Sorry ich hatte besser den ganzen Sketch gepostet und nicht nur die function zum Referenz fahren

Aber die Ausgabe der Impulse würd im Loop gemacht.

Gruß Heinz

Im Loop
Da wird ein Eingang eingelesen und auf eine bool variable gelegt.

Ich liefere heute Abend den gesamten Sketch nach

Gruß Heinz

Wieder ein Musterbeispiel, das Code-Schnipsel nur Verwirrung bringen :joy: :joy:

Erzählen wir unseren Fragestellern ja auch immer :wink: :innocent:

Ich mag eigentlich nicht "den" gesamten Sketch, sondern lieber einen (den kleinsten) kompletten Sketch, falls der noch das Problem zeigt. Oft zeigt der schon beim Test vor dem Posten, dass das Problem woanders war.

1 Like

Hallo
hier mein code aus der Bastelkiste.
ich bitte nochmals um Entschuldigung wenn da Verwirrung aufgetreten ist , mir ging es darum zu zeigen wie man den Motor schnellst möglich anhalten kann unter Verwendung von stepper.move() und stepper.stop() siehe Doku zur stop Methode.

/*Versuch zum Steppermotor 28BYJ-48
   Referenzpunkt einmalig anfahren in minus Richtung bis Endschalter. 
   Der Refpunkt sollte außerhalb normalen Fahrbereichs liegen.
   da ist die Null Position. 
  0----------pos1------------------------------------pos2
   Taster Start fährt auf Pos1
   nach zeit wird auf pos2 gefahren.
   Hardware UNO , Schalter gegen 0V schaltend
   Anzeige auf Plotter möglich
   März2019
*/


#include <AccelStepper.h>

const byte butonRev = 8;
const byte butonStart = 9;
const byte led = 13;

bool rev_Pos, startbtn; // status Taster
bool rev_OK;    // status rev erfolgt

unsigned long altzeit, altwzeit;

long aktpos; // aktuelle Position
const long setpos1 = 2068;    // Sollposition 1&2
const long setpos2 = 200;

// Define a stepper and the pins it will use
// die  beiden mittleren gedreht mittels Software
AccelStepper stepper(AccelStepper::FULL4WIRE, 2, 4, 3, 5);

void setup()
{
  pinMode(butonRev, INPUT_PULLUP);
  pinMode(butonStart, INPUT_PULLUP);
  pinMode(led, OUTPUT);
  Serial.begin(115200);
  stepper.setAcceleration(300);
  stepper.setMaxSpeed(300);
}

void loop()
{
  // Taster und aktuelle Position einlesen
  rev_Pos = !digitalRead(butonRev);
  startbtn = !digitalRead(butonStart);
  aktpos = stepper.currentPosition();

  if (rev_OK == false) {  // Rev noch nicht angefahren
    rev_OK =  revfahren();
  }

  // --- auf Pos 1 fahren
  if ( rev_OK && startbtn) {    // Start gedückt
    stepper.moveTo(setpos1);    // auf Pos fahren
  }
  // -----auf Pos 2 fahren
  if (rev_OK && aktpos == setpos1) {    // Pos 1 erreicht
    if (millis() - altwzeit >= 3000) {  // Wartezeit
      stepper.moveTo(setpos2);          // Position 2 anfahren
    }
  }
  else altwzeit = millis();

  // ----------- Ausgaben
  digitalWrite(led, rev_OK);  // Satus LED 
  stepper.run();              // Pulse ausgeben
  // ------------Anzeige
  if (millis() - altzeit >= 200) {
    altzeit = millis();
    //Serial.print("aktual Position ");
    Serial.println(aktpos);
  }
}// ---------- loop ende

bool revfahren() {
  stepper.setSpeed(-100);  // langsam  minus fahren
  stepper.move(2000);      // zuück fahren

  if (rev_Pos) {          // wenn schalter angefahren
    stepper.stop();

    stepper.setSpeed(300);   // normale Geschw.
    stepper.setCurrentPosition(0); // auf pos o setzten
    // stepper.moveTo(0);   // auf o fahren um stop abzuschliessen
    return 1;
  }
  return 0;
}

Guten Abend zusammen und danke für Eure Tipps.
Ich bin mit den MobaTools ein gutes Stück weiter gekommen.
Leider hat sich ein für mich neues Problem aufgetan.

Ich steuere den Motor(später die Motoren) mit einem einfachen Keypad.
Der Stepper soll rauf bzw. runter fahren und wenn er meinen Reed-Schalter auslöst
kurz zurück drehen und abschalten.
Das klappt in diesem kleinen Beispielskeetch einwandfrei.

/* ====== minimumStepper =======================================
 *  Bare minimum to get a stepper with step/dir driver turning
 */
#include <MobaTools.h>

const int FULLROT1 = 400;
int REED = 12;
int LED_GREEN = 2;
int LED_RED = 3;
MoToStepper stepper1(400,FULLSTEP); 

void setup() {
  pinMode(REED, INPUT_PULLUP);
  pinMode(LED_GREEN, OUTPUT);
  pinMode(LED_RED, OUTPUT);
  digitalWrite(LED_RED, LOW);
  digitalWrite(LED_GREEN, LOW);
  stepper1.setSpeed(400); 
  stepper1.setRampLen(FULLROT1/4); 
  stepper1.attach( 8,9,10,11 );
  stepper1.setZero();
}
void loop() {

if (digitalRead(REED) == HIGH){
  digitalWrite(LED_RED, LOW);
  digitalWrite(LED_GREEN, HIGH);
  stepper1.write(1600);
  
  digitalWrite(LED_GREEN, LOW);
}
else
{
  digitalWrite(LED_RED, HIGH);
  stepper1.stop();
  stepper1.write(-100);
  delay(2000);
  stepper1.detach();
}

} 

Hier verfährt der Stepper und schaltet dann die LEDs an bzw aus und beim Auslösen des Reed korrekt die 100 zurück.
Dann übernehme ich diese Teile der If-Schleife mit dem Reed Schalter in mein Keypad-Skeetch und der Reed funktioniert zum einen nicht (nur dessen LED leuchtet bei Kontakt) mehr und auch die einzelnen Schritte werden unmittelbar nacheinander abgearbeitet und nicht einer nach dem anderen.

#include <Keypad.h>
#include <MobaTools.h>
int REED = 12;
const byte LED_GREEN = 2;
const byte LED_RED = 3;
const byte LED3 = 4;
const byte LED4 = 5;
const byte LED5 = 13;
bool marker;
const int FULLROT1 = 800;
MoToStepper stepper1(400,FULLSTEP); 
const byte ROWS = 4; //four rows
const byte COLS = 4; //three columns
char keys[ROWS][COLS] =
{
  {'1', '2', '3', 'A'},
  {'4', '5', '6', 'B'},
  {'7', '8', '9', 'C'},
  {'*', '0', '#', 'D'}
};
byte rowPins[ROWS] = {29,28,26,27}; // Pins fuer die Reihen
byte colPins[COLS] = {25,24,22,23}; // Pins fuer die Spalten
Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );
//******************************************************************************
void setup()
{
  Serial.begin(115200);
  pinMode(LED_GREEN, OUTPUT);
  pinMode(LED_RED, OUTPUT);
  pinMode(LED3, OUTPUT);
  pinMode(LED4, OUTPUT);
  pinMode(LED5, OUTPUT);
  stepper1.setSpeed(400);
  stepper1.setRampLen( FULLROT1/4 );
  pinMode(REED, INPUT_PULLUP);
  digitalWrite(LED_RED, LOW);
  digitalWrite(LED_GREEN, LOW);     
  stepper1.attach( 8,9,10,11 );
  stepper1.setZero();

} //END of setup()


//******************************************************************************
void loop()
{
  char key = keypad.getKey();

  switch (key)
  {
    case '1':  
      if (digitalRead(REED) == HIGH)
      {
        Serial.println("Tor 1 öffnen");
        digitalWrite(LED_RED, LOW);
        digitalWrite(LED_GREEN, HIGH);
        stepper1.write(1900);
        digitalWrite(LED_GREEN, LOW);
        Serial.println("Tor 1 geöffnet");
      }
      else
      {
        digitalWrite(LED_RED, HIGH);
        stepper1.stop();
        stepper1.write(-100);
        Serial.println("REED");
        delay(2000);
        stepper1.detach();
      }
      break;

    case '4':
            Serial.println("Tor 1 schließen");
            digitalWrite(LED_GREEN, LOW);
            digitalWrite(LED_RED, HIGH);
            stepper1.write(0);
            digitalWrite(LED_RED, LOW);
            Serial.println("Tor 1 geschlossen");
      break;

    case '0':
      digitalWrite(LED_GREEN, LOW);
      digitalWrite(LED_RED, LOW);
      
      break;
      }
   //END of switch/case
  } //END of loop()

Ich zerbreche mir jetzt seit ewigen Zeiten den Kopf und komme einfach auf keine Lösung.
Wo setzt es da bei mir aus?

Danke und Gruß
Chris

Das kann ich mir bei deinem Sketch nicht vorstellen. Vielleicht solltest Du auch mal deinen mechanischen Aufbau zeigen.

attach() muss immer als erstes aufgerufen werden. Das ist sowas wie ein 'begin' oder 'init' Die vorherigen beiden Befehle werden in deinem Fall ignoriert und im attach auf die default-Werte gesetzt.

Mit diesem Befehl wird die Zielposition in Winkelgeraden angegeben, was aber nur funktioniert, wenn auch die Schritte/Umdrehung beim instanziieren richtig gesetzt werden ( was bei dir nicht der Fall ist, der kleine Stepper braucht im FULLSTEPP 2048 Schritte / Umdrehung ). Daher ist das Ziel bei dir eher Zufall.

Damit bewegst Du den Stepper nicht 'ein Stück' zurück, sondern auf die Position -100° ( was aber bei Dir auch nicht wirklich funktioniert, s.o. ).

Damit schaltest Du die gesamte Stepper-Funktionalität wieder ab - Du brauchtest danach wieder ein neues attach().

Bedenke, dass der loop() das macht, wie er heist. Und dein Sketch bleibt bei den Stepper1.xxx Aufrufen nicht stehen - die sind nicht blockierend (im Gegensatz zu deinem ersten Sketch mit AccelStepper ).

Dein 2. Sketch hat grundsätzlich die gleichen Probleme - nur kommt dann noch das Keypad hinzu.

Hi, danke für deine Rückmeldung.
Ich versuche das mal so umzusetzen wie du mir geschrieben hast.
Anbei ein Link zu dem kurzen Video das ich mal schnell gemacht habe.
Dort ist der Aufbau zu sehen aus dem "kleinen" Skeetch.
Der Motor dreht korrekt in die + Richtung auf "1600", sobald der Magnet den Reed erreicht schaltet der Motor um, fährt 100 zurück und bleibt stehen.
Vielleicht ist es auch nur Zufall, dass es "grad so funktioniert".

Video kleiner Skeetch

So ist es. Das ist das was wirklich passiert:

  digitalWrite(LED_RED, HIGH);
  stepper1.stop();         // Stepper hält an
  stepper1.write(-100);    // Stepper startet in die entgegengesetzten Richtung zu Winkel -100
  delay(2000);             // Stepper dreht für 2 Sekunden ( hat Winkel -100 bei weitem noch nicht erreicht
  stepper1.detach();       // Alles wird abgeschaltet, Stepper steht

So, mit etwas nachdenken und Try&Error habe ich es
zumindest hier für meinen Fall geschafft.

Der Stepper dreht sich korrekt auf seine Position bei Taste "1".
Bei Taste "2" dreht er korrekt zurück.
Ausgaben in der Konsole stimmen und werden korrekt abgearbeitet.
Sollte der Stepper zwischendrin plötzlich abschalten (Stromausfall / Reset)
fährt der Motor bei Taste "1" hoch bis zum Reed.
Dort wird sofort gestoppt und der Nullpunkt neu gesetzt.
Fährt der Motor wieder zurück, stimmen meine Markierungen
exakt überein und werden hernach bei erneutem rauf-/runterfahren wieder korrekt
angesteuert.
Somit, zumindest für meine Teil funktioniert es so wie es soll.
Ob der Code nun zu 100% korrekt ist, kann ich nicht sagen.
Den "stepper.detach" setze ich absichtlich um den Motor bei Nichtbenutzung
abzuschalten. Natürlich jetzt korrekt das attach wieder zu Beginn gesetzt und die
dauffolgenden Einstellungen des Steppers funktionieren nun auch.
Dank Dir für den Hinweis @MicroBahner

Hier mal der Code:

#include <Keypad.h>
#include <MobaTools.h>
int REED = 12;
const byte LED_GREEN = 2;
const byte LED_RED = 3;
const byte LED_BLINK = 6;
const byte LED4 = 5;
const byte LED5 = 13;
bool marker;
const int FULLROT1 = 400;
MoToStepper stepper1(400,FULLSTEP); 
const byte ROWS = 4; //four rows
const byte COLS = 4; //three columns
char keys[ROWS][COLS] =
{
  {'1', '2', '3', 'A'},
  {'4', '5', '6', 'B'},
  {'7', '8', '9', 'C'},
  {'*', '0', '#', 'D'}
};
byte rowPins[ROWS] = {29,28,26,27}; // Pins fuer die Reihen
byte colPins[COLS] = {25,24,22,23}; // Pins fuer die Spalten
Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );
//******************************************************************************
void setup()
{
  Serial.begin(115200);
  pinMode(LED_GREEN, OUTPUT);
  pinMode(LED_RED, OUTPUT);
  pinMode(LED_BLINK, OUTPUT);
  pinMode(LED4, OUTPUT);
  pinMode(LED5, OUTPUT);
  stepper1.setSpeed(400);
  stepper1.setRampLen( FULLROT1/2 );
  pinMode(REED, INPUT_PULLUP);
  stepper1.setZero();

} //END of setup()


//******************************************************************************
void loop()
{
  char key = keypad.getKey();

  switch (key)
  {
    case '1':  
            stepper1.attach( 8,9,10,11 );
            stepper1.setSpeed(400);
            stepper1.setRampLen( FULLROT1/2 );
            Serial.println("Tor 1 öffnen");
            digitalWrite(LED_RED, LOW);
            digitalWrite(LED_BLINK, LOW);
            digitalWrite(LED_GREEN, HIGH);
            stepper1.write(1700);        
            while 
            (stepper1.moving())
            if (digitalRead(REED) == !HIGH){
              delay(20);
              stepper1.stop();
              digitalWrite(LED_BLINK, HIGH);
              Serial.println(stepper1.readSteps());
              Serial.println("REED");
              stepper1.setZero(-1950);
            }
            digitalWrite(LED_GREEN, LOW);
          //  digitalWrite(LED_BLINK, LOW);
            Serial.println("Tor 1 geöffnet");
            Serial.println(stepper1.readSteps());
            stepper1.detach();
            
      break;
    case '4':
            stepper1.attach( 8,9,10,11 );
            stepper1.setSpeed(400);
            stepper1.setRampLen( FULLROT1/2 );
            Serial.println("Tor 1 schließen");
            digitalWrite(LED_GREEN, LOW);
            digitalWrite(LED_BLINK, LOW);
            digitalWrite(LED_RED, HIGH);
            stepper1.write(0);
            while 
            (stepper1.moving())
            
            digitalWrite(LED_RED, LOW);
            Serial.println("Tor 1 geschlossen");
            Serial.println(stepper1.readSteps());
            stepper1.detach();

            
      break;

    case '0':
      digitalWrite(LED_GREEN, LOW);
      digitalWrite(LED_RED, LOW);
      stepper1.detach();
      
      break;
    case '#':
      Serial.println("Setting new ZERO");
      digitalWrite(LED_GREEN, LOW);
      digitalWrite(LED_RED, LOW);
      stepper1.detach();
      stepper1.setZero();
      
      break;
      }
   //END of switch/case
  } //END of loop()

Es ist noch etwas mehr drin, da ich noch erweitern möchte.

Ich danke Euch erstmal für die Hilfe und hoffe ich hab nicht allzuviel Mist da drin noch produziert.

Liebe Grüße
Chris

Das mit dem 'Motor im Stillstand abschalten' können die MobaTools ganz alleine, da ist kein detach/attach notwendig.
Schau in der Doku mal nach 'attachEnable' :wink:
Da bleibt dann auch die aktuell gespeicherte Position erhalten.

Macht dein kleiner Stepper wirklich nur 400 Steps/umdr.? Ich kenne die kleinen nur mit 2048 Steps/Umdr. ( Manchmal aufgrund unterschiedlicher Getriebe auch +/- ein paar wenige Steps).
Du vermischt auch immer noch die Ansteuerung mit Steps oder mit Winkeln. Den MobaTools ist das zwar egal, aber so wird das nur ein Rumprobieren, und kein exaktes Vorgehen.
Auch das:

ist ziemlich sinnfrei. Mit detach verliert der Stepper alle intern gespeicherten Werte und reagiert bis zum nächsten attach auf keine Methodenaufrufe mehr.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.