Probleme mit Schrittmotor und Accelstepper-lib

Hallo alle

Ich möchte meinen Schrittmotor Step um Step entweder im Uhrzeigersinn, oder im Gegenuhrzeigersinn bewegen. Ich will also bewusst nicht eine limitierende Funktion wie "move" verwenden. Ich habe es mit "AccelStepper(forward/backward)" versucht, doch es funktioniert so nicht. Wenn ich danach run(); calle, dreht der Motor immer in die gleiche Richtung.
Am Schluss soll der Motor per Joystick so lange nach links oder rechts drehen, wie der Joystick bewegt wird. Und die Drehzahl steuere ich je nach Ausschlag des Joysticks. Der Code unten ist in der Loop vereinfacht, um zu Testen.

#include <AccelStepper.h>


#define motorInterfaceType 1

AccelStepper myStepper(motorInterfaceType, stepPin, dirPin);


int enablePin = 10;

void setup() {


pinMode(enablePin, OUTPUT);
Serial.begin(9600);
  
digitalWrite(enablePin, LOW);
 

  myStepper.setMaxSpeed(4000);
  myStepper.setAcceleration(50);
  //myStepper.setSpeed(700);

}
void loop() {

myStepper.setSpeed(700);
AccelStepper(backward);
myStepper.run();
}



Ich benutze einen Arduino Uno (Atmega328). Das Display ist ein 1,3 Zoll
128x64 von Adafruit. Ich verwende die I2C Schnittstelle (der default).

Logisch.
loop() macht genau das. Es läuft und läuft und ...

Du könntest eine random Funktion bauen, die den Speed verändert oder zumindest nach random Zeit ein stop() macht...
Alternativ: Hast Du einen Poti, den Du anschliessen kannst? (Ist der Joystick analog?)

Es ist mir bewusst, dass der Motor ewig dreht. Ist ja auch gut so. Aber ich kriege die Drehrichtung nicht geändert. Das ist mein Problem. Ja, ich habe ein Poti an A1 dran. Und ja, der Joystick ist analog.

welche accelstepperlib benutzt Du?
(Die von adafruit ist 12 Jahre alt und wird nicht gepflegt.)
Ich sehe in Deinem Code nirgend das Du die Drehrichtung wechseln willst.

Wenn Du an A1 einen Poti hast, dann sollte der in Mittelstellung ungefähr 500 - 530 ausgeben.

Ich würde dann die Drehrichtung entsprechend ändern:

// KURZSKETCH 
constexpr byte enablePin {LED_BUILTIN};
constexpr byte dirPin {3};
constexpr byte inputPin = A1;
void setup()
{
  Serial.begin(9600);
  Serial.println(F("Start... "));
  pinMode(dirPin, OUTPUT);
}
void loop()
{
  uint16_t analogWert = analogRead(A1);
  if (analogWert > 650)
  {
    Serial.println(F("forward"));
    digitalWrite(enablePin, HIGH);
    digitalWrite(dirPin, HIGH);
  }
  else if (analogWert < 450)
  {
    Serial.println(F("forward"));
    digitalWrite(enablePin, HIGH);
    digitalWrite(dirPin, LOW);
  }
  else
  {
    Serial.println(F("halt"));
    digitalWrite(enablePin, LOW);
  }
  delay(100); // Pause für den SerMOn
}

Ich benutze die AccelStepper v.1.64.0 von Patrick Wasp. Du würdest also ganz ohne Library arbeiten? Das Ding ist eben, ich will später auch vordefinierte Werte per Knopfdruck anfahren können und das mit accelleration und decelleration..

Umsteigen auf die MobaTools-Library

Da gibt es einen Befehl rotate()

rotate(1) // im Uhrzeigersinn endlos drehen
rotate(-1) gegen den Uhrzeigersinn endlos drehen

Da du das später mit dem Anfahren von ganz bestimmten Positionen kombinieren willst
ist die MobaTools-library sehr gut geeignet.
Die MobaTools zählen intern die Position mit.
Es gibt functions mit denen du eine relative Anzahl Schritte fahren kannst
und
es gibt functions für absolute Positionen anfahren
Diese function ermittelt dann von alleine ob der Motor nun im Uhrzeigersinn oder gegen den Uhrzeigersinn drehen muss um an diese Position zu kommen.

Viel bequemer geht nicht.

Außerdem erzeugen die MobaTools die Step-pulse im Hintergrund.
Das bedeutet du setzt den Befehl ab und musst gar keine run() oder sonstwas-function in hohem Tempo immer wieder neu aufrufen, sondern Befehl einmal aufrufen. Der Rest passiert von alleine
vgs

Hab jetzt umgestellt auf MobaTools und bereits meinen Code implementiert. Funktioniert einwandfrei. Vielen Dank StefanL38!

Hallo nochmal

Ich habe den Code erweitert, damit ich mit einem Button nullen kann. Mit dem zweiten Button soll der Stepper dann wieder auf 0 fahren, wenn der Stepper bewegt wurde (while-Schleife). Doch mein Code funktioniert nur, wenn ich auf einen negativen Wert fahre und dann den "GoToZero"-Knopf drücke. Im positiven Bereich stürzt das Programm ab.
Weiss wer warum?

/*  Example for MobaTools
    Moving a stepper back and forth
*/
#include <MobaTools.h>

// Adjust pins, steps and time as needed
const byte stepPin = 3;
const byte dirPin  = 2;
const int stepsPerRev = 400;   // Steps per Revolution ( example with 1/4 microsteps )
const long  targetPos = 1600;         // stepper moves between 0 and targetpos
int enable = 10;
long nextPos;
long Speed;
long PotVal;
long JoyStick = A2;
long Direction;
long SetZero = 5;
long GoToZero = 6;
long ActualStep;



MoToStepper myStepper ( stepsPerRev, STEPDIR );
MoToTimer stepperPause;                    // Pause between stepper moves
bool stepperRunning;

void setup() {
  Serial.begin(9600);
  myStepper.attach( stepPin, dirPin );
  myStepper.setSpeed( 600 );  // 60 Rev/Min ( if stepsPerRev is set correctly )
  myStepper.setRampLen( 50 );
  stepperRunning = true;
  pinMode(enable, OUTPUT);
  pinMode(PotVal, INPUT);
  pinMode(JoyStick, INPUT);
  pinMode(SetZero, INPUT_PULLUP);
  pinMode(GoToZero, INPUT_PULLUP);
  digitalWrite(enable, LOW);
  
}

void loop() {
  
Direction = analogRead(JoyStick);         //read value of Joystick
ActualStep = myStepper.read();            //read the actual step of the motor

Serial.println(ActualStep);

if(Direction <= 500) {                    //move the stepper CW infinitively
  myStepper.setSpeed((500/Direction))*4;
  myStepper.rotate(1);

}
else if(Direction >= 520) {               //move the stepper CCW infinitively
  myStepper.setSpeed(Direction*4);
  myStepper.rotate(-1);

}
else {
  myStepper.stop();
    }


if((digitalRead(SetZero)) == LOW) {     //read the button state to setzero
  myStepper.setZero(0);
}

if((digitalRead(GoToZero)) == LOW) {    //read the go to zero button state
  
  while(myStepper.read()!= 0) {         //while actual state is not 0, move to 0
  myStepper.write(0);
    }
  }
}

Woran erkennst du den Absturz?

Die Berechnung in der 2 Zeile ist wahrscheinlisch falsch. 510 ist dein Nullpunkt
den musst mit einrechnen

Der Motor bewegt sich nicht, wenn ich von einer positiven Position GoToZero drücke. Und wenn ich dann mit dem Joystick fahren möchte, passiert nix.

Ich muss vielleicht präzisieren: Das Programm stürzt nicht ab, es bleibt einfach in der while-Schleife hängen und bewegt den Motor nicht

Also ich habe das jetzt im Wokwi-Simulator nachgebaut und komfortablen debug-output hinzugefügt.

Im Wowki-Simulator funktioniert es wie erwartet.
Mit dem spezielleren debug-output bei dem die Anzeige nicht einfach so durchrennt müsstest du erkennen können was der Code macht
Quellcode so wie er auch im Wokwi-Simulator steht

// MACRO-START * MACRO-START * MACRO-START * MACRO-START * MACRO-START * MACRO-START *
// a detailed explanation how these macros work is given in this tutorial
// https://forum.arduino.cc/t/comfortable-serial-debug-output-short-to-write-fixed-text-name-and-content-of-any-variable-code-example/888298

#define dbg(myFixedText, variableName) \
  Serial.print( F(#myFixedText " "  #variableName"=") ); \
  Serial.println(variableName);

#define dbgi(myFixedText, variableName,timeInterval) \
  { \
    static unsigned long intervalStartTime; \
    if ( millis() - intervalStartTime >= timeInterval ){ \
      intervalStartTime = millis(); \
      Serial.print( F(#myFixedText " "  #variableName"=") ); \
      Serial.println(variableName); \
    } \
  }

#define dbgc(myFixedText, variableName) \
  { \
    static long lastState; \
    if ( lastState != variableName ){ \
      Serial.print( F(#myFixedText " "  #variableName" changed from ") ); \
      Serial.print(lastState); \
      Serial.print( F(" to ") ); \
      Serial.println(variableName); \
      lastState = variableName; \
    } \
  }

#define dbgcf(myFixedText, variableName) \
  { \
    static float lastState; \
    if ( lastState != variableName ){ \
      Serial.print( F(#myFixedText " "  #variableName" changed from ") ); \
      Serial.print(lastState); \
      Serial.print( F(" to ") ); \
      Serial.println(variableName); \
      lastState = variableName; \
    } \
  }
// MACRO-END * MACRO-END * MACRO-END * MACRO-END * MACRO-END * MACRO-END * MACRO-END *


/*  Example for MobaTools
    Moving a stepper back and forth
*/
#include <MobaTools.h>

// Adjust pins, steps and time as needed
const byte stepPin = 3;
const byte dirPin  = 2;
const int stepsPerRev = 400;   // Steps per Revolution ( example with 1/4 microsteps )
const long  targetPos = 1600;         // stepper moves between 0 and targetpos
int enable = 10;
long nextPos;
long Speed;
long PotVal;
long JoyStick = A2;
long Direction;
long SetZero = 5;
long GoToZero = 6;
long ActualStep;



MoToStepper myStepper ( stepsPerRev, STEPDIR );
MoToTimer stepperPause;                    // Pause between stepper moves
bool stepperRunning;

void setup() {
  Serial.begin(115200);
  while (!Serial);
  Serial.println("Setup-Start");
  myStepper.attach( stepPin, dirPin );
  myStepper.setSpeed( 600 );  // 60 Rev/Min ( if stepsPerRev is set correctly )
  myStepper.setRampLen( 50 );
  stepperRunning = true;
  pinMode(enable, OUTPUT);
  pinMode(PotVal, INPUT);
  pinMode(JoyStick, INPUT);
  pinMode(SetZero, INPUT_PULLUP);
  pinMode(GoToZero, INPUT_PULLUP);
  digitalWrite(enable, LOW);

}

void loop() {

  Direction = analogRead(JoyStick);         //read value of Joystick
  ActualStep = myStepper.read();            //read the actual step of the motor

  //Serial.println(ActualStep);
  dbgc("ToL",ActualStep);

  if (Direction <= 500) {                   //move the stepper CW infinitively
    myStepper.setSpeed((500 / Direction)) * 4;
    myStepper.rotate(1);

  }
  else if (Direction >= 520) {              //move the stepper CCW infinitively
    myStepper.setSpeed(Direction * 4);
    myStepper.rotate(-1);

  }
  else {
    myStepper.stop();
  }


  if ((digitalRead(SetZero)) == LOW) {    //read the button state to setzero
    dbgc("set",digitalRead(SetZero))
    myStepper.setZero(0);
  }

  if (digitalRead(GoToZero) == LOW) {   //read the go to zero button state
      dbgc("Go",digitalRead(GoToZero))

    while (myStepper.read() != 0) {       //while actual state is not 0, move to 0
      myStepper.write(0);
    }
  }
}

Noch ein Hinweis zum WOKWI-Simulator der Stepper-Motor weiß natürilch nix on der MobaTools-Library deshalb bleibt der Schrittzähler vom WOKWI-Schrittmotor auf seiner Schrittanzahl stehen.
As Empfehlung zum Testen fahre den Schrittzähler vom WOKWI-Schrittmotor auf eine in etwa runde Zahl 1027 oder so was. Dann setZero und dann fährste herum und testest Go to Zero
und hier der Link zur Simulation

vgs

Hallo StefanL38

Ich konnte das Problem inzwischen lösen. Und zwar habe ich mit einem SerialPrint in der while-Schleife sehen, dass der Motor steppt. Aber eben nur so ein Step pro Sekunde. Ich habe darauf setSpeed nochmals gesetzt. Seither funktioniert es in beide Richtungen.

Was überhaupt nix aussagt.
Es wäre ist nicht das erste Projekt, bei dem der Kram versagt.

Nun im WOKWI-Simulator kann man elementare Programmlogik-Probleme sichtbar machen.

Soweit wie ich WOKWI (gelegentlich) benutzt habe, habe ich keine solchen Probleme gehabt.
Schrittmotoren, Ultraschallsensor, Neopixel, LC-Display hat bei mir jeweils funktioniert.

Jetzt wäre interessant wenn du Links zu den Beispielen in denen WOKWI "versagt" hat posten würdest.

Reicht Dir #14 nicht?
Und nein, die SuFu gibt das vermutich nicht her. Da fehlt so das bissl KI. Wir hatten hier schon ganz andere Dinge, die da gut aussahen und in Wirklichkiet nicht funktionierten....
z.B. https://forum.arduino.cc/t/fastled-und-wokwi-mit-esp32-probleme-mit-vielfachem-von-8/1117313/7

Nein reicht mir nicht. Überhaupt nicht. Mindestens 10 Beispiele. Aber dazu bist du wohl zu bequem.
Ist auch OK. Ist ja alles freiwillig hier.

Das solltest Du so nicht programmieren. Da wird write(0) mit hoher Wiederholrate aufgerufen, was keinen Sinn macht ( und evtl. zu Problemen führt ... )
Einmal write(0) aufrufen reicht - und wenn Du da warten willst, bis der Punkt 0 erreicht ist, das hinterher prüfen ( was aber deinen gesamten Programmablauf blockiert )
Also so:

if((digitalRead(GoToZero)) == LOW) {    //read the go to zero button state
  
  myStepper.write(0);
  while(myStepper.moving() );         //wait blocking till zero position is reached
}

Du bist ja drollig.
Dein Code funktioniert beim Anwender nicht, weil Du Dich u.a. auf eine eigenartige Simulation verlässt und meinst jetzt tatsächlich um zu bewerten, dass Deine Simulation gescheitert ist, müssen andere herhalten.

Ich weiss ja, dass Du so Deine Probleme hast, aber das die so tief liegen lässt mich an Sachverstand zweifeln.