Go Down

Topic: MobaTools Library: Stepper mit Rampe - V1.1.3 freigegeben  (Read 1 time) previous topic - next topic

agmue

Hallo und erstmal eine Glückwunsch zur neuen Version!

Auch wenn es gelegentlich anders empfunden werden mag, so schreibe ich in tiefstem Respekt vor der Leistung des Bibliothekserstellers.

Heute erst habe ich meinen unipolaren Stepmotor 28BYJ-48 in die Hand bekommen und wer zu spät kommt ...

Dennoch erste Eindrücke:
  • In dem Beispiel Stepper_01 ist keine Rampe drin, oh wie schade.
  • setSpeed würde ich gerne um eine Rampe ergänzen, scheint aber im Gegensatz zu setSpeedSteps nicht vorgesehen zu sein. Oder?
  • Nach detach (detach from output) brennen die LEDs des Treibers weiter, sollten die Pins nicht auf Input stehen. Als Gegenprobe: Nach pinMode(j,INPUT) gehen die LEDs aus.

Drehen trotz delay ist ein gutes Argument für diese Bibliothek. Denn gelegentlich hat man ja doch mal eine kleine Blockade, die so nicht ins Gewicht fallen sollte.

Ich bleibe am Ball!
Wahnsinn und Verstand trennt nur eine dünne Wand. (Daniel Düsentrieb)

MicroBahner

#16
Jul 30, 2019, 09:56 pm Last Edit: Jul 30, 2019, 09:57 pm by MicroBahner
Hallo,
freut mich, dass Du dir meine Lib angeschaut hast, und danke für die Blumen 8)  :) .

Zu deinen Anmerkungen:
In dem Beispiel Stepper_01 ist keine Rampe drin, oh wie schade.
Stimmt, die Beispiele sollte ich auch um die Rampenfunktion ergänzen. Das kommt auf die ToDo-Liste für die nächste Version

setSpeed würde ich gerne um eine Rampe ergänzen, scheint aber im Gegensatz zu setSpeedSteps nicht vorgesehen zu sein. Oder?
setSpeed ist ja nur eine andere Art die Geschwindigkeit vorzugeben ( in Umdr/min ). Die aktuell eingestellte Rampe gilt da genauso. Letzendlich wird der Wert auch nur in eine Steprate umgerechnet, und dann intern setSpeedSteps aufgerufen.
Man kann allerdings die Rampenlänge nicht in einem Aufruf direkt mitgeben, sondern müsste sie danach mit einem eigenen Aufruf setzen, das stimmt. ( Oder man belässt es einfach bei der aktuell gültigen Rampe )

Nach detach (detach from output) brennen die LEDs des Treibers weiter, sollten die Pins nicht auf Input stehen. Als Gegenprobe: Nach pinMode(j,INPUT) gehen die LEDs aus.
Das stimmt wieder. Die Pins werden nur 'intern' getrennt und er greift nicht mehr darauf zu.
Da sie aber beim attach auch selbständig auf OUTPUT gestellt werden, würde es wohl Sinn machen, beim detach wieder auf INPUT zu stellen. Wäre dann auch ein Fall für die ToDo Liste.


Dass die Steperzeugung weitgehend unabhängig vom Ablauf im loop ist, war ein wesentlicher Beweggrund für diese Lib. Solange man im loop die Interrupts nicht länger aussperrt, oder den Prozessor anders mit Interrupts 'zunagelt' kann man da eigentlich treiben was man will.
Nachteil ist dann halt die HW-Abhängigkeit, da ja ein HW-Timer genutzt wird. Derzeit läuft die Lib daher nur auf den AVR ATmega und den STM32F1 Prozessoren. Der Due steht noch auf der ToDo-Liste, hat bisher aber keine Prio.

Wenn dir noch was auffällt - immer her damit. Die nächste Version steht schon in den Startlöchern, da im Stummiforum eine Anforderung aufkam. Die Stepper-Klasse wird dann auch einen 'enable' Ausgang steuern können, um gegebenenfalls den Motorstrom bei Stillstand abschalten oder reduzieren zu können.
Gruß, Franz-Peter

agmue

Stimmt, die Beispiele sollte ich auch um die Rampenfunktion ergänzen.
Ich hätte da einen Vorschlag, basierend auf Bounce der AccelStepper-Bibliothek.

Da ich delay() in den Beispielen nicht gut finde, habe ich es mit einer switch/case-Schrittkette realisiert.

Code: [Select]
/*  Demo zum Anschluß eines unipolaren Stepmotors 28BYJ-48
 *  mit Verwendung einer Beschleunigungsrampe
*/
#include <MobaTools.h>
Stepper4 Step1(4096);           // HALFSTEP ist default

void setup() {
  Step1.attach( 4, 5, 6, 7 ); // Anschluß an digitalen Ausgängen; Treiber IN1,IN2,IN3,IN4
  Step1.setSpeed( 240 );      // = 24 U/Min
  Step1.setRampLen(500);      // Beschleunigung
  Step1.setZero();            // Referenzpunkt für Motor 1 setzen
}

void loop() {
  uint32_t jetzt = millis();        // aktuelle Zeit
  static uint32_t vorhin = jetzt;   // gemerkte Zeit
  static byte status;               // Schrittkettenstatus

  switch (status) {
    case 0:
      Step1.write(360);               // 1 Umdrehung vorwärts
      status++;
      break;
    case 1:
      if ( !Step1.moving() ) {          // warten bis die Bewegung abgeschlossen ist
        vorhin = jetzt;                 // Zeit merken
        status++;
      }
      break;
    case 2:
      if ( jetzt - vorhin >= 1000 ) {   // 1 Sekunde warten
        status++;
      }
      break;
    case 3:
      Step1.write(0);                 // 1 Umdrehung zurück
      status++;
      break;
    case 4:
      if ( !Step1.moving() ) {          // warten bis die Bewegung abgeschlossen ist
        vorhin = jetzt;                 // Zeit merken
        status++;
      }
      break;
    case 5:
      if ( jetzt - vorhin >= 1000 ) {   // 1 Sekunde warten
        status++;
      }
      break;
    default:
      status = 0;
  }
}


Angeregt durch ein anderes, leider abgebrochenes Thema:

Code: [Select]
/*  Demo zum Anschluß eines unipolaren Stepmotors 28BYJ-48
    mit Verwendung einer Beschleunigungsrampe
    Slider-Minimalprogramm: Endposition - Startposition - Bewegung von Start- zu Endposition
*/
#include <MobaTools.h>
Stepper4 Step1(4096);           // HALFSTEP ist default
const byte linksPin = 8, rechtsPin = 9, weiterPin = 10;

void setup() {
  Serial.begin(9600);
  Serial.println("Anfang");
  pinMode(8, INPUT_PULLUP);   // aktiv LOW
  pinMode(9, INPUT_PULLUP);   // aktiv LOW
  pinMode(10, INPUT_PULLUP);  // aktiv LOW
  Step1.attach( 4, 5, 6, 7 ); // Anschluß an digitalen Ausgängen; Treiber IN1,IN2,IN3,IN4
  Step1.setSpeed( 60 );       // = 6 U/Min
}

void loop() {
  enum {ENDPOSITION, STARTPOSITION, BEWEGUNG};
  static byte status;               // Schrittkettenstatus
  static bool alt = digitalRead(weiterPin), akt = digitalRead(weiterPin);
  alt = akt;
  akt = digitalRead(weiterPin);
  if (alt != akt) {
    delay(30);                // einfaches Entprellen
  }

  switch (status) {
    case ENDPOSITION:
      if (!digitalRead(linksPin)) {
        Step1.doSteps(10);
      } else if (!digitalRead(rechtsPin)) {
        Step1.doSteps(-10);
      } else if (alt && !akt) {
        Step1.setZero();              // Endpunkt für Motor 1 setzen
        Serial.println("STARTPOSITION");
        status++;
      } else {
        Step1.stop();
      }
      break;
    case STARTPOSITION:
      if (!digitalRead(linksPin)) {
        Step1.doSteps(10);
      } else if (!digitalRead(rechtsPin)) {
        Step1.doSteps(-10);
      } else if (alt && !akt) {
        Step1.setSpeed( 240 );      // = 24 U/Min
        Step1.setRampLen(500);      // Beschleunigung
        Step1.write(0);               // Bewegung zu Endpunkt
        Serial.println("BEWEGUNG");
        status++;
      } else {
        Step1.stop();
      }
      break;
    case BEWEGUNG:
      if ( !Step1.moving() ) {          // warten bis die Bewegung abgeschlossen ist
        Step1.setSpeed( 60 );      // = 6 U/Min
        Step1.setRampLen(0);      // Beschleunigung
        Serial.println("ENDPOSITION");
        status = 0;
      }
      break;
    default:
      status = 0;
  }
}


Wenn Du was magst, kannst Du es gerne übernehmen.
Wahnsinn und Verstand trennt nur eine dünne Wand. (Daniel Düsentrieb)

MicroBahner

Hallo agmue,
danke für deine Demos. Die übernehme ich gerne in meine Beispiele.
Für die 1.1 muss ich noch ein Update machen, da ich noch einen Bug gefunden habe. Da kommen die dann schon rein  :)
Gruß, Franz-Peter

agmue

Ich bin etwas sparsam mit Kommentaren, könntest Du noch ergänzen. SPI kann ich mangels Hardware nicht testen.
Wahnsinn und Verstand trennt nur eine dünne Wand. (Daniel Düsentrieb)

MicroBahner

Da habe ich schon Programme mit weniger Kommentaren gesehen...

Ich habe nur die Zeitsteuerung im ersten Sketch auf den EggTimer umgestellt. Soll ja ein MobaTools-Beispiel sein  ;)
Gruß, Franz-Peter

agmue

Ich habe nur die Zeitsteuerung im ersten Sketch auf den EggTimer umgestellt. Soll ja ein MobaTools-Beispiel sein  ;)
Sehr gute Idee, an EggTimer hatte ich nicht gedacht. Dann könntest Du das delay zum Entprellen im zweiten Beispiel auch noch rauswerfen.
Wahnsinn und Verstand trennt nur eine dünne Wand. (Daniel Düsentrieb)

MicroBahner

Ach, das lass ich jetzt mal drin. Da sieht man, dass bei den MobaTools ein delay nicht stört  8) .
Ist ja immerhin ein Vorteil der MobaTools...
Gruß, Franz-Peter

agmue

Gerade wollte ich mir das Beispiel ProportionalControl vornehmen, da wirft mir der Compiler so viele Meldungen raus, daß ich den entscheidenden Fehler nicht erkennen kann:

Code: [Select]
/*  Demo zum Anschluß eines unipolaren Stepmotors 28BYJ-48
    Der Schrittmotor folgt den Bewegungen eines Potentiometer
*/
#include <MobaTools.h>
Stepper4 Step1(4096);           // HALFSTEP ist default
const byte analogPin = A0;

void setup() {
  Step1.attach( 4, 5, 6, 7 ); // Anschluß an digitalen Ausgängen; Treiber IN1,IN2,IN3,IN4
  Step1.setSpeed( 60 );       // = 6 U/Min
}

void loop() {
  long winkel = analogRead(analogPin) * 270L / 1024;
  Step1.write(winkel);               // Bewegung
}


F:\Arduino\libraries\MobaTools\src\MoToStepper.cpp: In function 'void stepperISR(uint8_t)':
F:\Arduino\libraries\MobaTools\src\MoToStepper.cpp:192:54: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
                        if ( stepperDataP->aCycRemain > (stepperDataP->stepsInRamp + RAMPOFFSET) ) {
                                                      ^
F:\Arduino\libraries\MobaTools\src\MoToStepper.cpp:220:51: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
                     if ( stepperDataP->aCycRemain > (stepperDataP->stepsInRamp + RAMPOFFSET) ) {
                                                   ^
F:\Arduino\libraries\MobaTools\src\MoToStepper.cpp:230:51: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
                     if ( stepperDataP->aCycRemain > (stepperDataP->stepsInRamp + RAMPOFFSET) ) {
                                                   ^
F:\Arduino\libraries\MobaTools\src\MoToStepper.cpp:180:24: warning: enumeration value 'INACTIVE' not handled in switch [-Wswitch]
                 switch ( stepperDataP->rampState ) {
                        ^
F:\Arduino\libraries\MobaTools\src\MoToStepper.cpp:180:24: warning: enumeration value 'RAMPSTART' not handled in switch [-Wswitch]
F:\Arduino\libraries\MobaTools\src\MoToStepper.cpp:38:13: warning: unused variable 'i' [-Wunused-variable]
     uint8_t i, spiChanged, changedPins, bitNr;
             ^
F:\Arduino\libraries\MobaTools\src\MoToStepper.cpp:39:14: warning: unused variable 'tmp' [-Wunused-variable]
     uint16_t tmp;
              ^
F:\Arduino\libraries\MobaTools\src\MoToStepper.cpp: In function 'void initSPI()':
F:\Arduino\libraries\MobaTools\src\MoToStepper.cpp:332:10: warning: unused variable 'tmp' [-Wunused-variable]
     byte tmp;
          ^
F:\Arduino\libraries\MobaTools\src\MoToStepper.cpp: At global scope:
F:\Arduino\libraries\MobaTools\src\MoToStepper.cpp:403:65: warning: unused parameter 'minStepTime' [-Wunused-parameter]
 void Stepper4::initialize ( int steps360, uint8_t mode, uint8_t minStepTime ) {
                                                                 ^
F:\Arduino\libraries\MobaTools\src\MoToStepper.cpp: In member function 'uint16_t Stepper4::setSpeedSteps(uint16_t, int16_t)':
F:\Arduino\libraries\MobaTools\src\MoToStepper.cpp:608:14: warning: unused variable 'fullRampLen' [-Wunused-variable]
     uint16_t fullRampLen;
              ^
F:\Arduino\libraries\MobaTools\src\MoToSoftled.cpp: In function 'void softledISR(uint8_t)':
F:\Arduino\libraries\MobaTools\src\MoToSoftled.cpp:135:50: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
                             if ( ledDataP->aStep > LED_STEP_MAX ) ledDataP->aStep = LED_STEP_MAX;
                                                  ^
F:\Arduino\libraries\MobaTools\src\MoToSoftled.cpp:140:50: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
                             if ( ledDataP->aStep > LED_STEP_MAX ) ledDataP->aStep = LED_STEP_MAX;
                                                  ^
F:\Arduino\libraries\MobaTools\src\MoToSoftled.cpp:148:50: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
                             if ( ledDataP->aStep > LED_STEP_MAX ) ledDataP->aStep = LED_STEP_MAX;
                                                  ^
F:\Arduino\libraries\MobaTools\src\MoToSoftled.cpp:156:50: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
                             if ( ledDataP->aStep > LED_STEP_MAX ) ledDataP->aStep = LED_STEP_MAX;
                                                  ^
F:\Arduino\libraries\MobaTools\src\MoToStepper.cpp: In member function 'void Stepper4::rotate(int8_t)':
F:\Arduino\libraries\MobaTools\src\MoToStepper.cpp:913:20: warning: enumeration value 'INACTIVE' not handled in switch [-Wswitch]
             switch ( _stepperData.rampState ) {
                    ^
F:\Arduino\libraries\MobaTools\src\MoToStepper.cpp:913:20: warning: enumeration value 'RAMPSTART' not handled in switch [-Wswitch]
F:\Arduino\libraries\MobaTools\src\MoToStepper.cpp:913:20: warning: enumeration value 'SPEEDDECEL' not handled in switch [-Wswitch]
Der Sketch verwendet 8780 Bytes (27%) des Programmspeicherplatzes. Das Maximum sind 32256 Bytes.
Globale Variablen verwenden 281 Bytes (13%) des dynamischen Speichers, 1767 Bytes für lokale Variablen verbleiben. Das Maximum sind 2048 Bytes.

Funktionieren tut es wohl. Wo steckt mein Fehler?
Wahnsinn und Verstand trennt nur eine dünne Wand. (Daniel Düsentrieb)

MicroBahner

#24
Aug 03, 2019, 11:40 am Last Edit: Aug 03, 2019, 11:47 am by MicroBahner
Ok, sollte ich wohl auch mal alle warnings einschalten beim Testen. Ich hab's nur auf 'Standard' stehen. Bei 'alle' ist er schon sehr pingelig. Aber da werde ich auf alle Fälle mal drüberschauen. Bei so Sachen wie 'unused variable' kann man dann ja auch den source vereinfachen.
Es ist immer gut, einen unabhängigen Tester zu haben, DANKE!

Funktionieren tut es wohl. Wo steckt mein Fehler?
Wenn es funktioniert, welchen Fehler meinst Du?
Gruß, Franz-Peter

agmue

Wenn es funktioniert, welchen Fehler meinst Du?
Den, über den der Compiler so erzürnt ist. So viel Text bekomme ich sonst nur, wenn ich mich an OOP versuche ::)

So findet es der Compiler netter:

Code: [Select]
#include <MobaTools.h>
Stepper4 Step1(4096);           // HALFSTEP ist default
const byte analogPin = A0;

void setup() {
  Step1.attach( 4, 5, 6, 7 ); // Anschluß an digitalen Ausgängen; Treiber IN1,IN2,IN3,IN4
  Step1.setSpeed( 60 );       // = 6 U/Min
  Step1.setRampLen(0);        // Beschleunigung
}

void loop() {
  long winkel = analogRead(analogPin) * 270L / 1024;
  Step1.write(winkel);               // Bewegung
}

Aber wie soll man keine Beschleunigung erklären?

Mysteriös wird es dann mit Step1.setRampLen(10); (war die Idee, um die Warnungen zu umgehen)
  • Programmstart, Poti auf 0, Motor ohne Bewegung
  • Drehe Poti auf Wert X, Motor dreht auf geschätzt passende Position
  • Der Motor bleibt nicht stehen, die TreiberLEDs flackern, sondern bewegt sich langsam in entgegengesetzte Richtung.

Das Verhalten ist reproduzierbar, nach der ersten Drehung bleibt der Motor nicht stehen und reagiert auch nicht auf neue Winkel. Motor und Poti werden vom UNO versorgt. Spontaner Verdacht: Der ständige Aufruf von write verträgt sich nicht mit der Rampe.
Wahnsinn und Verstand trennt nur eine dünne Wand. (Daniel Düsentrieb)

MicroBahner

#26
Aug 03, 2019, 01:46 pm Last Edit: Aug 03, 2019, 02:25 pm by MicroBahner
Ok, schau ich mir an.
Edit: Ich kann den Fehler reproduzieren, und deine Vermutung scheint zu stimmen: mit einem kleinen delay im loop tritt es nicht mehr auf.
Muss ich jetzt genauer untersuchen. Danke
Gruß, Franz-Peter

MicroBahner

Der Fehler lässt sich sehr gut reproduzieren - auch ohne Poti. Er tritt auf, wenn 2 unterschiedliche Absolutpositionen in extrem kurzen Abstand vorgegeben werden. Z.B. so:
Code: [Select]
void loop() {
  Step1.write(100);
  Step1.write(99);
  delay(5000);
}

Das geht evtl. 1 oder 2mal gut, und dann verhaspelt er sich. Auch ohne Rampe ist das nicht OK, der Effekt ist nur anders. Mit einem delay(20) dazwischen passiert nichts mehr.
Die Ursache ist mir noch nicht klar, das bedarf einer intensiveren Fehlersuche  :smiley-mr-green:

Hast Du gut gefunden. Wie sagt der Ami: 'good catch'  8)
Gruß, Franz-Peter

agmue

Hast Du gut gefunden. Wie sagt der Ami: 'good catch'  8)
Ich hatte überhaupt nicht gesucht, wollte nur etwas Programmierspaß haben. Aber auch das blinde Huhn findet bekanntlich ein Körnchen.

Die Ursache ist mir noch nicht klar, das bedarf einer intensiveren Fehlersuche  :smiley-mr-green:
Ich drängle nicht und wünsche Dir viel Erfolg!
Wahnsinn und Verstand trennt nur eine dünne Wand. (Daniel Düsentrieb)

MicroBahner

Ich hatte überhaupt nicht gesucht,
Na, das sind doch beste Voraussetzungen. Wenn man gezielt sucht, findet man bekanntlich nie das was man sucht, sondern eh immer was anderes :D .

wollte nur etwas Programmierspaß haben.
Ein kleines delay() ;)  reicht, und der Spaß kann weitergehen...
Gruß, Franz-Peter

Go Up