rec/play 3 axis with accelstepper.h question

hi all, first post here.

I’m trying to make a record and play multiple axis arm with steppers (instead of servo’s, alot of examples there…) and i’m a little stuck i think.
I’m mostly learning how to work with arduino (using a uno now) and made a piece of code mostly rewrinting tutorials, so not everything is as nice as could be but bear with me (and if you have tips how i could do it better/easier, feel welcome).

i’m using 3 analog potmeters, 3* a4988 drivers with 12v steppers (but maybe they need 24v but i don’t have a 24v power supply, but they are working mostly as they have to) and a fan to cool everything. :slight_smile:

but now the problem / question:

on the bottom part of the code (see below) i try to make a replay of earlier saved data.
and this works if/when i was using: runToNewPosition() (and every other command what blocks the rest)
but the problem is that if i use this function, the 2nd stepper waits for the 1st to finish (and the 3th for th 2nd) before they start moving, i want them to move at the same time (but the speed and acceleration stepper indepenent)

i can also use multistepper but the multistepper library doesn’t support acceleration (right?) because it calculates where each stepper has to be in the same time and if acceleration would be on diagonal lines could be “not straight” (right?).

the steppers don’t need to end at the same time, but they have to move/start together with acceleration because the arm needs to move fluent

the problem now is that if i replay the positions it skips kinda through the if statement:
if (stepper1.isRunning() == false) i was assuming that as long the steppers don’t hit the position and are moving the if is not valid and it can’t go on to the next switch case, but it does anyway.

i also tried: if(stepper1.distanceToGo () == 0) so the zero should be not zero if it is moving to something(?) but here’s the same problem (arduino thinks the stepper is zero already i think?)

(oh and p.s. it’ not that the steppers do nothing. But they only do parts and mostly do only case/position 3, what makes me even more confused).

case 3:
     val1 = PosSave1[2] ;
     val2 = PosSave2[2] ;
     val3 = PosSave3[2] ;
     if (stepper1.isRunning() == false && stepper2.isRunning() == false && stepper3.isRunning() == false){
     delay(2000);
     Serial.println("Pos3 done");
     playback = 4; 
     }
     break;

Hope some one can shed some light on it for me.
thanks in advance!

record_continue_and_play_stepper.ino (6.19 KB)

#include <AccelStepper.h>
// EG X-Y-Z position arm driven by 3 steppers
// Alas its not possible to build an array of these with different pins for each :-(
AccelStepper stepper1(AccelStepper::DRIVER, 6, 7);
AccelStepper stepper2(AccelStepper::DRIVER, 4, 5);
AccelStepper stepper3(AccelStepper::DRIVER, 2, 3);

//define the buttons
const int button1 = 12; //reccord button
const int button2 = 13; //replay button

//define variable for values of the button
int button1Pressed = 0;   //for switch case recording
boolean button2Pressed = false;

//define potentiometers
const int pot1 = A3;
const int pot2 = A4;
const int pot3 = A5;

// stepper positions setup
int val1 = 0;
int previous1 = 0;
int long newval1 = 0; 

int val2 = 0;
int previous2 = 0;
int long newval2 = 0; 

int val3 = 0;
int previous3 = 0;
int long newval3 = 0; 

//define variable for saved position 
int PosSave1[]={1023,0,512,1023,350};
int PosSave2[]={1023,0,1023,0,1023};
int PosSave3[]={1023,0,512,1023,350};
int playback = 1; // for switch case replay

void setup() {
   // Configure each stepper
  stepper1.setMaxSpeed(200);
  stepper1.setAcceleration(250);
  stepper2.setMaxSpeed(400);
  stepper2.setAcceleration(250);
  stepper3.setMaxSpeed(600);
  stepper3.setAcceleration(250);

  //define buttons as input units
  pinMode(button1, INPUT);
  pinMode(button2, INPUT);

  //initialize serial communication for saved position
  Serial.begin(9600);
}

void loop() {
        //read the potentiometer values and define the potentiometer value with the map function
  if(button2Pressed == false){   // made this so if button 2 is pressed for replay the potmeters won't interfere
  val1 = analogRead(A3);
  val2 = analogRead(A4);
  val3 = analogRead(A5);
  }
 
 //  {if ((val1 > previous1+6) || (val1 < previous1-6)) // Check that a move of the pot is at least > or < than 6 in case of jitter
    { 
    newval1 = map(val1, 0, 1023, 0, 200);  // Map value (1600 = 1 stepper shaft rotation)
    stepper1.moveTo(newval1);   // Move stepper to new position
    stepper1.run();
    previous1 = val1;  // save current value into variable previous
    } 
//  }
//  {if ((val2 > previous2+6) || (val2 < previous2-6))  // Check that a move of the pot is at least > or < than 6 in case of jitter
    {
    newval2 = map(val2, 0, 1023, 0, 300);  // Map value (1600 = 1 stepper shaft rotation)
    stepper2.moveTo(newval2);
    stepper2.run();  // Move stepper to new position
    previous2 = val2;  // save current value into variable previous
    }  
//  }
//  {if ((val3 > previous3+6) || (val3 < previous3-6))  // Check that a move of the pot is at least > or < than 6 in case of jitter
    {
    newval3 = map(val3, 0, 1023, 0, 800);  // Map value (1600 = 1 stepper shaft rotation)
    stepper3.moveTo(newval3);
    stepper3.run();  // Move stepper to new position
    previous3 = val3;  // save current value into variable previous
    }
//  }
  
  
  //if button1 is pressed (HIGH), save the potentiometers position  
  //(the delay is kinda long because i don't have switches now, i pull the cable and have to put it back in time XD)
  if(digitalRead(button1) == HIGH){
    button1Pressed++;
    delay(2000);
    switch(button1Pressed){
      case 1:
        PosSave1[0] = val1;
        PosSave2[0] = val2;
        PosSave3[0] = val3;
        Serial.println("Position #1 Saved");
        Serial.println(PosSave1[0]);
        Serial.println(PosSave2[0]);
        Serial.println(PosSave3[0]);
       break;
       case 2:
        PosSave1[1] = val1;
        PosSave2[1] = val2;
        PosSave3[1] = val3;
        Serial.println("Position #2 Saved");
        Serial.println(PosSave1[1]);
        Serial.println(PosSave2[1]);
        Serial.println(PosSave3[1]);
       break;
       case 3:
        PosSave1[2] = val1;
        PosSave2[2] = val2;
        PosSave3[2] = val3;
        Serial.println("Position #3 Saved");
        Serial.println(PosSave1[2]);
        Serial.println(PosSave2[2]);
        Serial.println(PosSave3[2]);
       break;
       case 4:
        PosSave1[3] = val1;
        PosSave2[3] = val2;
        PosSave3[3] = val3;
        Serial.println("Position #4 Saved");
        Serial.println(PosSave1[3]);
        Serial.println(PosSave2[3]);
        Serial.println(PosSave3[3]);
       break;
       case 5:
        PosSave1[4] = val1;
        PosSave2[4] = val2;
        PosSave3[4] = val3;
        Serial.println("Position #5 Saved");
        Serial.println(PosSave1[4]);
        Serial.println(PosSave2[4]);
        Serial.println(PosSave3[4]);
       break;
    }
  }
  //if button2 pressed (HIGH), the steppers (should) move to saved position
  if(digitalRead(button2) == HIGH){
    Serial.println("Button2 Go");
    delay(2000);
    button2Pressed = true;
  }
  
  if(button2Pressed){
   
   switch(playback){
     case 1:
     val1 = PosSave1[0] ;
     val2 = PosSave2[0] ;
     val3 = PosSave3[0] ;
     if (stepper1.isRunning() == false && stepper2.isRunning() == false && stepper3.isRunning() == false){
     delay(2000);
     Serial.println("Pos1 done");
     playback = 2; 
     }
     break;
     
     case 2:
     val1 = PosSave1[1] ;
     val2 = PosSave2[1] ;
     val3 = PosSave3[1] ;
     if (stepper1.isRunning() == false && stepper2.isRunning() == false && stepper3.isRunning() == false){
     delay(2000);
     Serial.println("Pos2 done");
     playback = 3;
     }
     break;
     
     case 3:
     val1 = PosSave1[2] ;
     val2 = PosSave2[2] ;
     val3 = PosSave3[2] ;
     if (stepper1.isRunning() == false && stepper2.isRunning() == false && stepper3.isRunning() == false){
     delay(2000);
     Serial.println("Pos3 done");
     playback = 4; 
     }
     break;
     
     case 4:
     val1 = PosSave1[3] ;
     val2 = PosSave2[3] ;
     val3 = PosSave3[3] ;
     if (stepper1.isRunning() == false && stepper2.isRunning() == false && stepper3.isRunning() == false){
     delay(2000);
     Serial.println("Pos4 done");
     playback = 5; 
     }
     break;
     
    case 5:
     val1 = PosSave1[4] ;
     val2 = PosSave2[4] ;
     val3 = PosSave3[4] ;
     if (stepper1.isRunning() == false && stepper2.isRunning() == false && stepper3.isRunning() == false){
     delay(2000);
     Serial.println("Pos5 done");
     playback = 1; 
     button2Pressed = false;
     }
     break;
   }
  }
}

// Alas its not possible to build an array of these with different pins for each :-(

Yes it is. You do have to declare the objects individually but then you can have an array which contains those objects.

AccelStepper steppers[] = {stepper1, stepper2, stepper3};
void setup() {
  steppers[0].setMaxSpeed(200);

There's probably a better way to do this without the intermediate objects. I'm not really very good at object-oriented stuff.

MultiStepper doesn't have acceleration because there's so many ways you might want to do it, the library can't even begin to get it right for you. If you want the steppers to smoothly accelerate, decelerate AND arrive at a target position simultaneously, then you have to do all of the calculations yourself. That's going to be a bit of head-scratching maths until you get it figured out what looks good for your particular robot.

wel they don't need to arrive simultaneously,

what i in fact want is that the steppers respond to the code like in the recording section: i have 3 values from 3 potentiometers (lets say i turn the potentiometers from zero to full), the steppers go all 3 simultanious, i don't mind some being slower because they turn more or have slower acceleration.

so now i have the record part (lets say again the steppers are at the zero position and the first recorded object is full, whatever the numbers may be). i want the stepper to go there at the same time start at the same time, but i can't seem to ge it to work.

and the problem lays somewhere in that the arduino wants really badly to go to the 2nd, 3th,4th and 5th saved position/switch case.

now i could make some sort of delay with millis for each recorded part, but that would be bad because if i save a position with only 1 stepper moving 1 step, i still would have to wait just as long for the next position as if i turn all three steppers to the max.

i guess if i made the play switch case separate and pushed trough playback++ with a button instead in code. it would probably work because the steppers have time to go the desired position and i push the button when they are done for the next position. but i want to let the Arduino do this him self. Only the code i would have tought should do that won't do that.

and the problem lays here i think:

 if (stepper1.isRunning() == false && stepper2.isRunning() == false && stepper3.isRunning() == false){
delay(2000);
     Serial.println("Pos1 done");
     playback = 2;             // go to next case

code position switch case:

if(digitalRead(button2) == HIGH){
    Serial.println("Button2 Go");
    delay(2000);
    button2Pressed = true;
  }
  
  if(button2Pressed){
   
   switch(playback){
     case 1:
     val1 = PosSave1[0] ;
     val2 = PosSave2[0] ;
     val3 = PosSave3[0] ;
     if (stepper1.isRunning() == false && stepper2.isRunning() == false && stepper3.isRunning() == false){
     delay(2000);
     Serial.println("Pos1 done");
     playback = 2; 
     }
     break;
     
     case 2:
     val1 = PosSave1[1] ;
     val2 = PosSave2[1] ;
     val3 = PosSave3[1] ;
     if (stepper1.isRunning() == false && stepper2.isRunning() == false && stepper3.isRunning() == false){
     delay(2000);
     Serial.println("Pos2 done");
     playback = 3;
     }
     break;
     
     case 3:
     val1 = PosSave1[2] ;
     val2 = PosSave2[2] ;
     val3 = PosSave3[2] ;
     if (stepper1.isRunning() == false && stepper2.isRunning() == false && stepper3.isRunning() == false){
     delay(2000);
     Serial.println("Pos3 done");
     playback = 4; 
     }
     break;
     
     case 4:
     val1 = PosSave1[3] ;
     val2 = PosSave2[3] ;
     val3 = PosSave3[3] ;
     if (stepper1.isRunning() == false && stepper2.isRunning() == false && stepper3.isRunning() == false){
     delay(2000);
     Serial.println("Pos4 done");
     playback = 5; 
     }
     break;
     
    case 5:
     val1 = PosSave1[4] ;
     val2 = PosSave2[4] ;
     val3 = PosSave3[4] ;
     if (stepper1.isRunning() == false && stepper2.isRunning() == false && stepper3.isRunning() == false){
     delay(2000);
     Serial.println("Pos5 done");
     playback = 1; 
     button2Pressed = false;
     }
     break;
   }
  }
}

You need to set up the destination for each AccelStepper, then call .run() repeatedly on all three until they all arrive at their destinations.

Basically you call .run() every time you go through the loop. If the stepper is already at its destination then this does nothing.

am i not doing that here:?

 { 
    newval1 = map(val1, 0, 1023, 0, 200);  // Map value (1600 = 1 stepper shaft rotation)
    stepper1.moveTo(newval1);   // Move stepper to new position
    stepper1.run();
    previous1 = val1;  // save current value into variable previous
    } 
//  }
//  {if ((val2 > previous2+6) || (val2 < previous2-6))  // Check that a move of the pot is at least > or < than 6 in case of jitter
    {
    newval2 = map(val2, 0, 1023, 0, 300);  // Map value (1600 = 1 stepper shaft rotation)
    stepper2.moveTo(newval2);
    stepper2.run();  // Move stepper to new position
    previous2 = val2;  // save current value into variable previous
    }  
//  }
//  {if ((val3 > previous3+6) || (val3 < previous3-6))  // Check that a move of the pot is at least > or < than 6 in case of jitter
    {
    newval3 = map(val3, 0, 1023, 0, 800);  // Map value (1600 = 1 stepper shaft rotation)
    stepper3.moveTo(newval3);
    stepper3.run();  // Move stepper to new position
    previous3 = val3;  // save current value into variable previous
    }
//  }

what do i do wrong to set the saved position “val1 / val2 / val3” for stepper 1, 2 and 3 as “the destination”

If you want stepper.run() to work properly there must be NO delay() that can interfere with how fast .run() can be called.

I would put the calls to stepper.run() for all the motors as the last item in loop()

It is not difficult to create your own acceleration code without using the AccelStepper library - see this link - and it is also not difficult to accelerate several motors and have them all arrive at the same time. Just figure out the acceleration for the motor that moves fastest and link the moves of the other motors to that.

...R Stepper Motor Basics Simple Stepper Code

Have a look at the Bresenham Algorithm for a clue on how to drive the motors together. Decide which one has the longest distance to go and use that as the master - then the others take zero or one step for each step of the master.

Robin2: If you want stepper.run() to work properly there must be NO delay() that can interfere with how fast .run() can be called.

I would put the calls to stepper.run() for all the motors as the last item in loop()

sounds really dumb asking this but still.... you say NO delay() but i only use delays at points in the code where something happens (like pushing a button) where i don't record or change or let steppers run at all. so normally if i don't push a button or the steppers aren't moving there shouldn't be a delay. the stepper.run() is free to use in the normal to be followed loop.

as for the stepper.run() location, i moved it to the back but this changes nothing.

Robin2: It is not difficult to create your own acceleration code without using the AccelStepper library - see this link - and it is also not difficult to accelerate several motors and have them all arrive at the same time. Just figure out the acceleration for the motor that moves fastest and link the moves of the other motors to that.

...R Stepper Motor Basics Simple Stepper Code

also they don't need to move in sync, i'd rather they didn't. i want them to do like they do know, responding to the potmeters. if i turn pot 1 and 2 to full they do that together, but if i turn pot 3 a second later the 3th stepper wil go a second later and not in sync with the other to. (this example is now not possible with the replay like i make it know, it's more for future improvemend, i would like to make that possible)

MorganS: Have a look at the Bresenham Algorithm for a clue on how to drive the motors together. Decide which one has the longest distance to go and use that as the master - then the others take zero or one step for each step of the master.

so it's not the sync i want.

i just want to know why the code isn't working like i was thinking it should:

   switch(playback)
    {
     case 1:
      val1 = PosSave1[0] ;
      val2 = PosSave2[0] ;
      val3 = PosSave3[0] ;
      Serial.println(stepper1.isRunning());
      Serial.println(stepper2.isRunning());
      Serial.println(stepper3.isRunning());
        if (stepper1.isRunning() == false && stepper2.isRunning() == false && stepper3.isRunning() == false) . // wait untill all steppers reached position or atleast stopped moving
        {
         delay(2000);
         Serial.println("Pos1 done");
         playback = 2;     // go to next saved position
        }
       break;

// case 2: // playckack 2 ... etc etc etc

    { 
    newval1 = map(val1, 0, 1023, 0, rotation1);  // Map value (rotation[] = stepper shaft rotation)
    stepper1.moveTo(newval1);   // Move stepper to new position
    stepper1.run();
    }
    {
    newval2 = map(val2, 0, 1023, 0, rotation2);   // Map value (rotation[] = stepper shaft rotation)
    stepper2.moveTo(newval2);
    stepper2.run();  // Move stepper to new position
    }
    {
    newval3 = map(val3, 0, 1023, 0, rotation3);   // Map value (rotation[] = stepper shaft rotation)
    stepper3.moveTo(newval3);
    stepper3.run();  // Move stepper to new position
    }
}

i made a Serial.printin(stepper1.isrunning()) and it gives me mostly 0's and 1's where the distance stepper1.moveto(newval1) should be a lot bigger or am i mis understanding the function???? i also tried stepper.distancetogo but same problem here, i can't really measure the distance, and it will valid the if statement while the steppers didn't do anything or almost nothing

i would like to have a line of code what checks if my steppers are running and make sure the next position isn't launched while they are not in position yet.

sorry for the difficult question

I didn't have a problem with the delays that you have now but ultimately you will end up removing them. There's always something useful the Arduino can do, even if it appears to be waiting. My projects often have a GPS sending in data continuously and I cannot delay for any more than a few microseconds because the Serial buffer overflows and I lose sync with the GPS data.

i just want to know why the code isn't working like i was thinking it should

There's several things wrong with the way you asked this question. First, we don't know what you're thinking although right now, we have got a few posts from you that have some description of what you think it should do. Second, you didn't say what it actually does. Third and most importantly, you didn't post the whole code. You said that you moved the stepper_.run() to the end but that's not visible here. My signature below tells you that the problem is not where you think it is. There's always stuff that the programmer (even the guru) doesn't fully understand and you just put it in like a magic incantation that must be there. But that's often where the problem is. You don't look there because you think you got the magic incantation correct. The classic problem we see here every single day is incorrect variable declarations. The beginner doesn't understand the importance of the declaration and just beats on it until the compiler stops complaining. That invariably results in an error. But they don't post that because it's "their" code that isn't working right.

OK, rant over...

I'm trying to look back to the last time you posted a complete program with setup() and loop(). That's in reply #1. Then I try to merge in the code you posted in reply #8. They don't really go together, but let's assume that they do...

Your switch(playback) selects the different locations to go to and then tests to see if it reached the destination. Below that, running on every loop, you tell the steppers to stop what they were doing and start going towards the desired location. Then you let them each take a step before the loop repeats and you give them the same destination again. I don't think AccelStepper works that way.

I think you need more states in your state machine. For each of the destinations you have at least 3 sub-states: begin moving, actually moving, arrived. You need to assign a destination in "begin" then immediately change to "moving". That way you only assign the destination once. In "moving" you spend a lot of time looping over and over and letting the motors take steps as often as they need to. Then when you've arrived, you can make sure everything is shut down and ready for the next destination.

This is one path to removing those gigantic delay(2000)'s from your code. The "arrived" state can wait there for as long as you want. It has the advantage that you can check buttons like "emergency stop" or "go back to the start" instead of sitting in the dark with your hands tied for 2000 milliseconds.

Oh, you can {delete} the {unnecessary} {braces}.

MorganS: First, we don't know what you're thinking although right now, we have got a few posts from you that have some description of what you think it should do. Second, you didn't say what it actually does.

+1

To be more specific, I don't know what it is that you want to play back.

If you just want to record some end-point and be able to move between ZERO and that point repeatedly then the simple thing would seem to be to record the number of steps to get to that point.

...R

MorganS: I didn't have a problem with the delays that you have now but ultimately you will end up removing them. There's always something useful the Arduino can do, even if it appears to be waiting. My projects often have a GPS sending in data continuously and I cannot delay for any more than a few microseconds because the Serial buffer overflows and I lose sync with the GPS data.

thanks, didn't think of it that way, for now i need the delays because i lack hardware buttons and need to pull a wire to switch a button like explained in the initial topic. The delays give me time to put back the wire w/o triggering other events. When i get switches soon i will remove them. the delays in between position changes gives me time to check the serial. But i wil remove them now.

There's several things wrong with the way you asked this question. First, we don't know what you're thinking although right now, we have got a few posts from you that have some description of what you think it should do.

is it? in the post i asked this:

on the bottom part of the code (see below) i try to make a replay of earlier saved data. and this works if/when i was using: runToNewPosition() (and every other command what blocks the rest) but the problem is that if i use this function, the 2nd stepper waits for the 1st to finish (and the 3th for th 2nd) before they start moving, i want them to move at the same time (but the speed and acceleration stepper indepenent)

and

the steppers don't need to end at the same time, but they have to move/start together with acceleration because the arm needs to move fluent

but the firt reply is about how to let them run in sync, while i don't need/want that.

Second, you didn't say what it actually does.

i did in the topic and it didn't change

the problem now is that if i replay the positions it skips kinda through the if statement: if (stepper1.isRunning() == false) i was assuming that as long the steppers don't hit the position and are moving the if is not valid and it can't go on to the next switch case, but it does anyway.

(oh and p.s. it' not that the steppers do nothing. But they only do parts and mostly do only case/position 3, what makes me even more confused).

Third and most importantly, you didn't post the whole code. You said that you moved the stepper_.run() to the end but that's not visible here. My signature below tells you that the problem is not where you think it is. There's always stuff that the programmer (even the guru) doesn't fully understand and you just put it in like a magic incantation that must be there. But that's often where the problem is. You don't look there because you think you got the magic incantation correct. The classic problem we see here every single day is incorrect variable declarations. The beginner doesn't understand the importance of the declaration and just beats on it until the compiler stops complaining. That invariably results in an error. But they don't post that because it's "their" code that isn't working right.

yes, i'm sorry, i only changed the location and i wasn't thinking you would like to see it again. for me it did't change anything but i get what you mean. The last bit of code was more a way to explain again what i was thinking and asking, it's more a view in to my head then actual code, and it was stupid of me that i didn't say this because that would make things easier.

Your switch(playback) selects the different locations to go to and then tests to see if it reached the destination. Below that, running on every loop, you tell the steppers to stop what they were doing and start going towards the desired location. Then you let them each take a step before the loop repeats and you give them the same destination again. I don't think AccelStepper works that way.

this is a good example of whats wrong with my code. thanks it also explains why the Serial.printin(stepper1.isrunning()) is never higher than 1.

I think you need more states in your state machine. For each of the destinations you have at least 3 sub-states: begin moving, actually moving, arrived. You need to assign a destination in "begin" then immediately change to "moving". That way you only assign the destination once. In "moving" you spend a lot of time looping over and over and letting the motors take steps as often as they need to. Then when you've arrived, you can make sure everything is shut down and ready for the next destination.

This is really something i could work with! i'm going to work this out. let you know if it works out and if not will post the full code again.

This is one path to removing those gigantic delay(2000)'s from your code. The "arrived" state can wait there for as long as you want. It has the advantage that you can check buttons like "emergency stop" or "go back to the start" instead of sitting in the dark with your hands tied for 2000 milliseconds.

Oh, you can {delete} the {unnecessary} {braces}.

the braces are for me to keep a little overview of whats happening where especially if i'm splitting it up to difrent locations in the code, i will remove them once the code is like i would like it to be.

To finish it off. I'm sorry i wasn't clear enough in most of my posts. I find it difficult to filter what you need to know and what just is to much text. Because of I type to much (like in my initial topic) and don't ask specific enough questions people won't read or assume things. It's difficult balans between "need to know" and "way to much info for people to care to read everything" i think. And i'm glad people are caring to help. Thanks

So let's see if I can help reduce this to its essentials - it is quite likely I have got some of the details incorrect, so please let me know.

  • You have 3 potentiometers and the position of each pot determines the position of a stepper motor.
  • You want to be able to press a button and cause the potentiometer values to be saved.
  • At some later stage you want to be able to make the stepper motors move to the saved positions.

  • Currently the part of the program that causes the motors to move when the pots are turned is working

  • And the part of the program that saves the pot values is working

  • But the ability to get the motors to move based on the saved values is not working.

? What happens when you try to get the motors to use the saved values?

...R

you are exactly right.

right as it is now, the steppers do mostly nothing if recall all the positions
sometimes a singel stepper moves a little but not al the way where they should go.
the serial gives back mostly 0’s and sometime a 1 for the " Serial.println(stepper1.isRunning()); "
like 12 digits each (not always the same) and then valids the if and gives me a Position 1 done in the serial monitor and goes to the next case.

the switch case is now triggering it self by an “if”, but if i remove the “if” and trigger the individual cases (by hardware switch) they move in to position like they should

see below the full code as is now.

#include <AccelStepper.h>
#include <MultiStepper.h>
// EG X-Y-Z position arm driven by 3 steppers
// Alas its not possible to build an array of these with different pins for each :-(
AccelStepper stepper1(AccelStepper::DRIVER, 6, 7);
AccelStepper stepper2(AccelStepper::DRIVER, 4, 5);
AccelStepper stepper3(AccelStepper::DRIVER, 2, 3);

//define the buttons
const int button1 = 12; //reccord button
const int button2 = 13; //replay button

//define variable for values of the button
int button1Pressed = 0;   //for switch case recording
boolean button2Pressed = false;

//define potentiometers
const int pot1 = A3;
const int pot2 = A4;
const int pot3 = A5;

// stepper positions setup
int val1 = 0;
int previous1 = 0;
int long newval1 = 0; 

int val2 = 0;
int previous2 = 0;
int long newval2 = 0; 

int val3 = 0;
int previous3 = 0;
int long newval3 = 0; 

//define variable for saved position 
int PosSave1[]={1023,0,512,1023,350};
int PosSave2[]={1023,0,1023,0,1023};
int PosSave3[]={1023,0,512,1023,350};
int playback = 1; // for switch case replay

void setup() {
   // Configure each stepper
  stepper1.setMaxSpeed(200);
  stepper1.setAcceleration(250);
  stepper2.setMaxSpeed(400);
  stepper2.setAcceleration(250);
  stepper3.setMaxSpeed(600);
  stepper3.setAcceleration(250);

  //define buttons as input units
  pinMode(button1, INPUT);
  pinMode(button2, INPUT);

  //initialize serial communication for saved position
  Serial.begin(9600);
}

void loop() {
        //read the potentiometer values and define the potentiometer value with the map function
  if(button2Pressed == false){   // made this so if button 2 is pressed for replay the potmeters won't interfere
  val1 = analogRead(A3);
  val2 = analogRead(A4);
  val3 = analogRead(A5);
  
   //  {if ((val1 > previous1+6) || (val1 < previous1-6)) // Check that a move of the pot is at least > or < than 6 in case of jitter
    { 
    newval1 = map(val1, 0, 1023, 0, 200);  // Map value (1600 = 1 stepper shaft rotation)
    stepper1.moveTo(newval1);   // Move stepper to new position
    stepper1.run();
    previous1 = val1;  // save current value into variable previous
    } 
//  }
//  {if ((val2 > previous2+6) || (val2 < previous2-6))  // Check that a move of the pot is at least > or < than 6 in case of jitter
    {
    newval2 = map(val2, 0, 1023, 0, 300);  // Map value (1600 = 1 stepper shaft rotation)
    stepper2.moveTo(newval2);
    stepper2.run();  // Move stepper to new position
    previous2 = val2;  // save current value into variable previous
    }  
//  }
//  {if ((val3 > previous3+6) || (val3 < previous3-6))  // Check that a move of the pot is at least > or < than 6 in case of jitter
    {
    newval3 = map(val3, 0, 1023, 0, 800);  // Map value (1600 = 1 stepper shaft rotation)
    stepper3.moveTo(newval3);
    stepper3.run();  // Move stepper to new position
    previous3 = val3;  // save current value into variable previous
    }
//  }
  }
 

  
  
  //if button1 is pressed (HIGH), save the potentiometers position  
  //(the delay is kinda long because i don't have switches now, i pull the cable and have to put it back in time XD)
  if(digitalRead(button1) == HIGH){
    button1Pressed++;
    delay(2000);
    switch(button1Pressed){
      case 1:
        PosSave1[0] = val1;
        PosSave2[0] = val2;
        PosSave3[0] = val3;
        Serial.println("Position #1 Saved");
        Serial.println(PosSave1[0]);
        Serial.println(PosSave2[0]);
        Serial.println(PosSave3[0]);
       break;
       case 2:
        PosSave1[1] = val1;
        PosSave2[1] = val2;
        PosSave3[1] = val3;
        Serial.println("Position #2 Saved");
        Serial.println(PosSave1[1]);
        Serial.println(PosSave2[1]);
        Serial.println(PosSave3[1]);
       break;
       case 3:
        PosSave1[2] = val1;
        PosSave2[2] = val2;
        PosSave3[2] = val3;
        Serial.println("Position #3 Saved");
        Serial.println(PosSave1[2]);
        Serial.println(PosSave2[2]);
        Serial.println(PosSave3[2]);
       break;
       case 4:
        PosSave1[3] = val1;
        PosSave2[3] = val2;
        PosSave3[3] = val3;
        Serial.println("Position #4 Saved");
        Serial.println(PosSave1[3]);
        Serial.println(PosSave2[3]);
        Serial.println(PosSave3[3]);
       break;
       case 5:
        PosSave1[4] = val1;
        PosSave2[4] = val2;
        PosSave3[4] = val3;
        Serial.println("Position #5 Saved");
        Serial.println(PosSave1[4]);
        Serial.println(PosSave2[4]);
        Serial.println(PosSave3[4]);
       break;
    }
  }
  //if button2 pressed (HIGH), the steppers (should) move to saved position
  if(digitalRead(button2) == HIGH){
    Serial.println("Button2 Go");
    delay(2000);
    button2Pressed = true;
  }
  
  if(button2Pressed){
   
   switch(playback){
     case 1:
     val1 = PosSave1[0] ;
     val2 = PosSave2[0] ;
     val3 = PosSave3[0] ;
      Serial.println(stepper1.isRunning());
      Serial.println(stepper2.isRunning());
      Serial.println(stepper3.isRunning());
     if (stepper1.isRunning() == false && stepper2.isRunning() == false && stepper3.isRunning() == false){
     delay(2000);
     Serial.println("Pos1 done");
     playback = 2; 
     }
     break;
     
     case 2:
     val1 = PosSave1[1] ;
     val2 = PosSave2[1] ;
     val3 = PosSave3[1] ;
      Serial.println(stepper1.isRunning());
      Serial.println(stepper2.isRunning());
      Serial.println(stepper3.isRunning());
     if (stepper1.isRunning() == false && stepper2.isRunning() == false && stepper3.isRunning() == false){
     delay(2000);
     Serial.println("Pos2 done");
     playback = 3;
     }
     break;
     
     case 3:
     val1 = PosSave1[2] ;
     val2 = PosSave2[2] ;
     val3 = PosSave3[2] ;
      Serial.println(stepper1.isRunning());
      Serial.println(stepper2.isRunning());
      Serial.println(stepper3.isRunning());
     if (stepper1.isRunning() == false && stepper2.isRunning() == false && stepper3.isRunning() == false){
     delay(2000);
     Serial.println("Pos3 done");
     playback = 4; 
     }
     break;
     
     case 4:
     val1 = PosSave1[3] ;
     val2 = PosSave2[3] ;
     val3 = PosSave3[3] ;
      Serial.println(stepper1.isRunning());
      Serial.println(stepper2.isRunning());
      Serial.println(stepper3.isRunning());
     if (stepper1.isRunning() == false && stepper2.isRunning() == false && stepper3.isRunning() == false){
     delay(2000);
     Serial.println("Pos4 done");
     playback = 5; 
     }
     break;
     
    case 5:
     val1 = PosSave1[4] ;
     val2 = PosSave2[4] ;
     val3 = PosSave3[4] ;
      Serial.println(stepper1.isRunning());
      Serial.println(stepper2.isRunning());
      Serial.println(stepper3.isRunning());
     if (stepper1.isRunning() == false && stepper2.isRunning() == false && stepper3.isRunning() == false){
     delay(2000);
     Serial.println("Pos5 done");
     playback = 1; 
     button2Pressed = false;
     }
     break;
    }
    newval1 = map(val1, 0, 1023, 0, 200);  // Map value (1600 = 1 stepper shaft rotation)
    stepper1.moveTo(newval1);   // Move stepper to new position
    stepper1.run();
    
    newval2 = map(val2, 0, 1023, 0, 300);  // Map value (1600 = 1 stepper shaft rotation)
    stepper2.moveTo(newval2);
    stepper2.run();  // Move stepper to new position
    
    newval3 = map(val3, 0, 1023, 0, 800);  // Map value (1600 = 1 stepper shaft rotation)
    stepper3.moveTo(newval3);
    stepper3.run();  // Move stepper to new position

  }
}

I don't understand how this is supposed to work

  if(digitalRead(button1) == HIGH){
    button1Pressed++;

Can you explain what it is intended to achieve?

Using one button to cause different actions can get very confusing for the user - as well as for the code.

Also, can you explain in more detail how your concept of replay is intended to work. I can see how you can save the pot values but I don't understand how you propose to use the saved values? For example, in what circumstances will the saved values be used? And where will the motors be positioned prior to the saved values being used?

...R

It looks to me like the OP is trying to recreate a path or series of actions spread out over time and space.

If it was my project, I would do it with Gcode but the ability to directly set a position and hit the "memorize" button has its merits. So while this is not how I would do it, it is not wrong.

Start by just assigning the destination once, at the point where you extract the destination from the arrays.

MorganS: It looks to me like the OP is trying to recreate a path or series of actions spread out over time and space.

That sounds plausible but I have seen no evidence for it in the OP's code or his Posts.

Maybe we are being presented with an XY problem and I had not realized it.

...R

i have seem to worked it out. it isn't nice yet but it is working

MorganS: It looks to me like the OP is trying to recreate a path or series of actions spread out over time and space.

yes and no,my goal is to save xyz positions to replay but not on a time based events.

It is and was not an x/y problem because my main goal posting this all here is to understand how this code could work and why it wasn't. I wasn't looking for other solutions (tough they are welcome) but i am just trying to understand and learn from my mistakes and why it didn't work. or maybe it was an x/y problem but i just didn't really mind for "x" because i would't have learned what i have now. i wanted to learn how to solve y, and i did.

i also didn't understand your question about the button having 2 functions? where is the second function?

Robin2: if(digitalRead(button1) == HIGH){ button1Pressed++;

if button 1 is pressed: add 1 to button1pressed the button1pressed is used in the record section with a switch case so if i press button 1, the count goes to 1, to switch case 1, with the code to record position 1.

maybe you where confused with the second button? int button1Pressed = 0; //for switch case recording boolean button2Pressed = false; // is for the replay section

when the second button is pressed/true its starting to replay (and blocks the recording input because that is only active when button2pressed is false)

and about the gcode, I have looked into it but the learning curve looks way to steep (for me for now) to understand. Especially because i want to create a stand alone system/arm what's easy to use and understand for almost everyone (a few potentiometers, a record button, a close/open gripper (or maybe an electromagnet), and a replay button, and maybe a potentiometer for speed/acceleration control (mostly like it already is).

But i have another question. my arm has 2 axis what can turn infinity turning the arm left right, and the gripper (in theory for now. not yet because cables and such, but atleast 1440 degrees for now) so a limit switch is not really desired.

Is it possible/usefull to make a switch and every time the arm spins around and hits the 0 position it will recalibrate the position? or is it better to only do this at the setup? I have to make a little pin on the arm what hits the switch within 1.8 degrees from step angel. i don't want to recalibrate it wrongly if the arm is turning the other way around.

HighSolutions: i also didn't understand your question about the button having 2 functions?

If you look back to Reply #14 you will see that I did not use the number 2 or the word "function"

All I was/am trying to find out is why a variable is incremented every time a button is pressed.

And trying to point out that it would be very easy for the user to forget how many times it was pressed, or to press it once too often by accident.

...R

Is it possible/usefull to make a switch and every time the arm spins around and hits the 0 position it will recalibrate the position? or is it better to only do this at the setup?

Yes.

Usually this would be done with an optical or magnetic sensor. It is difficult to make a mechanical switch work reliably when it can be hit from either direction. A magnetic switch doesn't always require a magnet either. It may be just observing the proximity of a bolt head on the rotor.

I like the QRE1113 optical sensor. Sparkfun sells them on useful boards. It can sense an arm sticking out or just a dot of white paint.

Whatever sensor you use, you would usually drive the stepper one direction at medium speed until the sensor activates and then back off at low speed until it deactivates. Then you know exactly where it is.