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.
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:
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..
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
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);
}
}
}
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
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.
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.
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.