What do I need to do to assign a second movement operation to the steppers after an operation like this?

yea.
in that last step might as well step all the motors

With the Bresenham algorithm, the math takes care of itself.

What step would be the best choice for a 1/20 movement step? At step 19, 0, or maybe in the middle at step 9?

Dave

here's an approach that uses fixed-pt integer math

the lower 5-bits are used as a fractional increment, 2^B * n / N where B is the binary-pt, 5, n the required # of steps and N the max # of steps of any motor. The increment for the motor requiring N steps is a value of 1Q5 = 2^B = 32. (hope this is understandable)

there will be N iterations. the step [] value for each motor incremented by the above. A step (*'d below) is made if the value >= 2^(B-1), half. Of course the motor requiring N steps is incremented each iteration. The other motors are incremented when their step value is >= 2^(B-1), 16

i see the total # of steps being made for each case and sometimes the last step is made sooner than the last iteration which i believe is correct.

i think this approach is avoids the use of floats and is probably simpler than Bresenham's algorithm and more easily undersood. of course the value of B can be adjusted as needed as well as the size of the integer to accommodate the larges # of steps, N

          20         7        12        13
          32        11        19        20       binary increment
   0      32 *      11        19 *      20 *
   1      32 *      22 *       6         8
   2      32 *       1        25 *      28 *
   3      32 *      12        12        16 *
   4      32 *      23 *      31 *       4
   5      32 *       2        18 *      24 *
   6      32 *      13         5        12
   7      32 *      24 *      24 *      32 *
   8      32 *       3        11        20 *
   9      32 *      14        30 *       8
  10      32 *      25 *      17 *      28 *
  11      32 *       4         4        16 *
  12      32 *      15        23 *       4
  13      32 *      26 *      10        24 *
  14      32 *       5        29 *      12
  15      32 *      16 *      16 *      32 *
  16      32 *      -5         3        20 *
  17      32 *       6        22 *       8
  18      32 *      17 *       9        28 *
  19      32 *      -4        28 *      16 *
          20         7        12        13       total # of steps
function syncInt () {
    printf "syncInt:\n"

    B = 5           #/ binary pt
    N = fld [1]

    printf "  "
    for (f = 1; f <= F; f++)
        printf " %9d", fld [f]
    printf "\n"

    printf "  "
    for (f = 1; f <= F; f++)
        printf " %9d", binInc [f] = int(2^B * fld [f] / N)
    printf "       binary increment\n"

    for (n = 0; n < N; n++)  {
        printf " %3d", n
        for (f = 1; f <= F; f++)  {
            steps [f] += binInc [f]
            printf " %7d", steps [f]

            c = " "
            if (steps [f] >= 2^(B-1))  {
                steps [f] -= 2^B
                pos   [f]++
                c = "*"
            }
            printf " %s", c
        }
            
        printf "\n"
    }

    printf "  "
    for (f = 1; f <= F; f++)
            printf " %9d", pos [f]
    printf "       total # of steps \n"
    printf "\n"
}

If you use B=1 and multiply everything by N, (increment 2^1*n/N*N=2n, step and decrement by N if sum>=N* 2^(1-1)=N it is still almost exactly Bresenham. (Wait?!?--what are you decrementing by when you step?)

Bresenham's algorithm isn't particularly difficult--it does the dividing with elementary school adding and subtracting: if you have a n/N ratio, you add 'n' each time the controlling axis takes a step, and whenever you've got 'N' in the accumulator, subtract 'N' and act. With n/N=7/20, at the end of 20 iterations, you've added 7 twenty times to make 140, and subtracted 20 and stepped 7 times to use up 140. A class of elementary school kids could handle counting this out with jellybeans. Especially if you gave them a 20 jellybean box.

  const int N = 20;
  int n[] = {N, 7, 12, 13, 1, N-1};
  const int num = sizeof(n) / sizeof(n[0]);
  int D[num];

  void setup(void){
  Serial.begin(115200);

  Serial.print("It/n:");
  // Initialize to center the sub-steps
  for (int j = 0; j < num; ++j) {
    D[j] = N / 2 + n[j]; // center
    Serial.print("\t+=");
    Serial.print(n[j]);
  }
  Serial.println();

  for (int i = 0; i < N; ++i) {
    Serial.print("i:");
    Serial.print(i);
    for (int j = 0; j < num; ++j) {
      Serial.print("\t");
      Serial.print(D[j]);
      if (D[j] > N) {
        D[j] -= N;
        Serial.print("*-");
        Serial.print(N);
      }
      D[j] += n[j];
      //    Serial.print("\t");
    }
    Serial.println();
  }
}

void loop() {
}

gives:

It/n: +=20 +=7 +=12 +=13 +=1 +=19
i:0 30*-20 17 22*-20 23*-20 11 29*-20
i:1 30*-20 24*-20 14 16 12 28*-20
i:2 30*-20 11 26*-20 29*-20 13 27*-20
i:3 30*-20 18 18 22*-20 14 26*-20
i:4 30*-20 25*-20 30*-20 15 15 25*-20
i:5 30*-20 12 22*-20 28*-20 16 24*-20
i:6 30*-20 19 14 21*-20 17 23*-20
i:7 30*-20 26*-20 26*-20 14 18 22*-20
i:8 30*-20 13 18 27*-20 19 21*-20
i:9 30*-20 20 30*-20 20 20 20
i:10 30*-20 27*-20 22*-20 33*-20 21*-20 39*-20
i:11 30*-20 14 14 26*-20 2 38*-20
i:12 30*-20 21*-20 26*-20 19 3 37*-20
i:13 30*-20 8 18 32*-20 4 36*-20
i:14 30*-20 15 30*-20 25*-20 5 35*-20
i:15 30*-20 22*-20 22*-20 18 6 34*-20
i:16 30*-20 9 14 31*-20 7 33*-20
i:17 30*-20 16 26*-20 24*-20 8 32*-20
i:18 30*-20 23*-20 18 17 9 31*-20
i:19 30*-20 10 30*-20 30*-20 10 30*-20

(cool! -- pasting tab-delimited data into a code block in the forum makes a Markdown table that you can remove the code tags to get a formatted table)

Bresenham did add a couple complications to center small fractions like 1/20 or 2/20 within the series and to speed the calculations: Initialize the accumulators with -N/2+n to make the decision rule be if(sum>0) and also multiply everything by two (use Q*.1 numbers?) to deal with the potential 1/2 fraction from centering within odd Ns. But the elementary schoolchildren might not handle the summing with negative jellybeans reliably.

First of all, since I used more than two steppers, I decided to use "int" value instead of "bool".

Does specifying the "if(joint1.distanceToGo())" definition in each "void newPosition()" cause a loop? Does the "joint" defined in it target the previous step or the first one? That's why I emphasized this part in my previous comment. The problem is exactly this;

Steppers do not transition from newPosition2 to newPosition3. It enters the loop between newPosition1 and newPosition2. Therefore, there is no transition to the newPosition3. Maybe I am having a problem with finishedMotion=0; part. It seemed to me that it was performing the same operation by rewinding in the directory it was located in somewhere.

Maybe there is something wrong with the "void loop" part. Maybe I need to add something different, I don't know.

In addition; I know that it is necessary to define each movement sequentially by adding general definitions to the "void setup" and a few steps (void newPosition) in different methods to carry out the next steps. Finally, we must write the "joints" into the "loop" so that all steppers work at the same time. I guess there is nothing wrong with the logic so far.

Full Code:

int finishedMotion = 0;

void setup() {
  Serial.begin(250000);

  // Configure each stepper
  joint1.setMaxSpeed(500.0);       //Safe Value: 500
  joint1.setAcceleration(400.0);   //Safe Value: 400
  joint1.moveTo(0);                //Safe Value: 400
  
  joint2.setMaxSpeed(500.0);       //Safe Value: 500
  joint2.setAcceleration(400.0);   //Safe Value: 400
  joint2.moveTo(0);                //Safe Value: 400

  joint3.setMaxSpeed(3500.0);      //Safe Value: 3500
  joint3.setAcceleration(3500.0);  //Safe Value: 3500
  joint3.moveTo(0);                //Safe Value: 4000

  joint4.setMaxSpeed(500.0);       //Safe Value: 500
  joint4.setAcceleration(400.0);   //Safe Value: 400
  joint4.moveTo(0);                //Safe Value: 400
  
  joint5.setMaxSpeed(500.0);       //Safe Value: 500
  joint5.setAcceleration(400.0);   //Safe Value: 400
  joint5.moveTo(0);                //Safe Value: 400
}

void newPosition1(){
  if(joint1.distanceToGo() || joint2.distanceToGo() || joint3.distanceToGo() || joint4.distanceToGo() || joint5.distanceToGo() ) {
  ; // still moving
  } else {
  finishedMotion = 1;
  }

  if(finishedMotion){
  delay(2000);
  //set new target
  joint1.moveTo(400);
  joint2.moveTo(400);
  joint3.moveTo(4000);
  joint4.moveTo(400);
  joint5.moveTo(400);

  finishedMotion = 0;
  }
}

void newPosition2(){
  if(joint1.distanceToGo() || joint2.distanceToGo() || joint3.distanceToGo() || joint4.distanceToGo() || joint5.distanceToGo() ) {
  ;
  } else {
  finishedMotion = 2;
  }

  if(finishedMotion){
  delay(3000);
  joint1.moveTo(0);
  joint2.moveTo(150);
  joint3.moveTo(2000);
  joint4.moveTo(200);
  joint5.moveTo(200);

  finishedMotion = 0;
  }
}

void newPosition3(){
  if(joint1.distanceToGo() || joint2.distanceToGo() || joint3.distanceToGo() || joint4.distanceToGo() || joint5.distanceToGo() ) {
  ;
  } else {
  finishedMotion = 3;
  }

  if(finishedMotion){
  delay(3000);
  joint1.moveTo(-400);
  joint2.moveTo(400);
  joint3.moveTo(4000);
  joint4.moveTo(400);
  joint5.moveTo(400);

  finishedMotion = 0;
  }
}

void newPosition4(){
  if(joint1.distanceToGo() || joint2.distanceToGo() || joint3.distanceToGo() || joint4.distanceToGo() || joint5.distanceToGo() ) {
  ;
  } else {
  finishedMotion = 4;
  }

  if(finishedMotion){
  delay(3000);
  joint1.moveTo(0);
  joint2.moveTo(0);
  joint3.moveTo(0);
  joint4.moveTo(0);
  joint5.moveTo(0);

  finishedMotion = 0;
  }
}

void loop() {
  joint1.run();
  joint2.run();
  joint3.run();
  joint4.run();
  joint5.run();
  newPosition1();
  newPosition2();
  newPosition3();
  newPosition4();
}

No, an if doesn't cause a loop. You can cause looping with while(){}, for(...) etc, or you can depend on the arduino repeatedly calling your loop() function after it is done with setup. Arduino has this code in its main() definition:

Note that loop() is called in an infinite for(;;){...} loop.

If you need to transition between motions, sequentially, you can either lay out the re-targeting and subsequent motions sequentially in setup(){..} or write your re-targeting and motions in such a way that the computer can understand when to run the steppers and when to retarget.

Up above in #3 I was aiming at two sequential motions and nothing else, with advice for something like this completely untested code:

#include <AccelStepper.h>

// Joint 1
#define E1_STEP_PIN        36
#define E1_DIR_PIN         34
#define E1_ENABLE_PIN      30

// Joint 2
#define Z_STEP_PIN         46
#define Z_DIR_PIN          48
#define Z_ENABLE_PIN       62
#define Z_MIN_PIN          18
#define Z_MAX_PIN          19

// Joint 3
#define Y_STEP_PIN         60
#define Y_DIR_PIN          61
#define Y_ENABLE_PIN       56
#define Y_MIN_PIN          14
#define Y_MAX_PIN          15

// Joint 4
#define X_STEP_PIN         54
#define X_DIR_PIN          55
#define X_ENABLE_PIN       38

// Joint 5 
#define E0_STEP_PIN        26
#define E0_DIR_PIN         28
#define E0_ENABLE_PIN      24


// EG X-Y position bed driven by 2 steppers
AccelStepper joint1(1, E1_STEP_PIN, E1_DIR_PIN);
AccelStepper joint2(1, Z_STEP_PIN, Z_DIR_PIN);
AccelStepper joint3(1, Y_STEP_PIN, Y_DIR_PIN);
AccelStepper joint4(1, X_STEP_PIN, X_DIR_PIN);
AccelStepper joint5(1, E0_STEP_PIN, E0_DIR_PIN);

//test with uint8 converted to long
unsigned int x = 1000;

void setup() {
  Serial.begin(250000);

  // Configure each stepper
  joint1.setMaxSpeed(500.0);       //Safe Value: 500
  joint1.setAcceleration(400.0);   //Safe Value: 400
  joint1.moveTo(400);              //Safe Value: 400

  joint2.setMaxSpeed(500.0);       //Safe Value: 500
  joint2.setAcceleration(400.0);   //Safe Value: 400
  joint2.moveTo(400);              //Safe Value: 400

  joint3.setMaxSpeed(3500.0);       //Safe Value: 3500
  joint3.setAcceleration(3500.0);   //Safe Value: 3500
  joint3.moveTo(4000);              //Safe Value: 4000
  
  joint4.setMaxSpeed(500.0);       //Safe Value: 500
  joint4.setAcceleration(400.0);   //Safe Value: 400
  joint4.moveTo(400);              //Safe Value: 400

  joint5.setMaxSpeed(500.0);       //Safe Value: 500
  joint5.setAcceleration(400.0);   //Safe Value: 400
  joint5.moveTo(400);              //Safe Value: 400

while{ joint1.distanceToGo() || joint2.distanceToGo() || joint3.distanceToGo() || joint4.distanceToGo() || joint5.distanceToGo() ){ 
  joint1.run();
  joint2.run();
  joint3.run();
  joint4.run();
  joint5.run();
}

  // Re-Configure each stepper
  joint1.setMaxSpeed(500.0);       //Safe Value: 500
  joint1.setAcceleration(400.0);   //Safe Value: 400
  joint1.moveTo(-400);              //Safe Value: 400

  joint2.setMaxSpeed(500.0);       //Safe Value: 500
  joint2.setAcceleration(400.0);   //Safe Value: 400
  joint2.moveTo(-400);              //Safe Value: 400

  joint3.setMaxSpeed(3500.0);       //Safe Value: 3500
  joint3.setAcceleration(3500.0);   //Safe Value: 3500
  joint3.moveTo(-4000);              //Safe Value: 4000
  
  joint4.setMaxSpeed(500.0);       //Safe Value: 500
  joint4.setAcceleration(400.0);   //Safe Value: 400
  joint4.moveTo(-400);              //Safe Value: 400

  joint5.setMaxSpeed(500.0);       //Safe Value: 500
  joint5.setAcceleration(400.0);   //Safe Value: 400
  joint5.moveTo(-400);              //Safe Value: 400

... repeat as necessary
}

void loop() {
// empty because it is all handled sequentially in setup()
}

The above code runs the two motions sequentially and then stays in an endless loop().

If you want more motions than 2, it might make sense to define some arrays holding the different motion's targets, accelerations, and maximum speeds and use a state machine within loop() to switch between the motions. Perhaps with some bits like those in this completely untested code:


int targets[][5] = {{0,0,0,0,0},
                    {400,400,4000,400,400},
                    {0,150,2000,200,200},
                    ...
                    };


int motionNumber = 0;

...
void loop() {
  joint1.run();
  joint2.run();
  joint3.run();
  joint4.run();
  joint5.run();
  
  if( ! (joint1.distanceToGo() || joint2.distanceToGo() || joint3.distanceToGo() || joint4.distanceToGo() || joint5.distanceToGo() ) ) {
   //set new target
   if(motionNumber < 5){ // don't advance past the final target
     motionNumber = motionNumber+1;
   }
   // Configure each stepper
   joint1.moveTo(targets[motionNumber][0];    
   joint2.moveTo(targets[motionNumber][0];    
   joint3.moveTo(targets[motionNumber][0];    
   joint4.moveTo(targets[motionNumber][0];    
   joint5.moveTo(targets[motionNumber][0];    
   ...
 }
}

As is, your #25 code runs loop repeatedly, steps the motors as needed, and then the newPosition*() commands retarget if there isn't distance to go. Their logical tests don't care about order. newPosition1() is only checking if the motors are stopped, and them being stopped after moving to newPosition2 is good enough for newPosition1() to trigger.

I'd add a Serial.print("1"); in newPosition1(), etc... and probably see how the flow is happening.

Another fix would be to rewrite your if() conditions to check that the expected preceding motion finished before setting the new target. For example:

void newPosition1(){
  if(currentMotion == 0 && !(joint1.distanceToGo() || joint2.distanceToGo() || joint3.distanceToGo() || joint4.distanceToGo() || joint5.distanceToGo() ) ) {
    currentMotion = 1;
    delay(2000);
    //set new target
    joint1.moveTo(400);
    joint2.moveTo(400);
    joint3.moveTo(4000);
    joint4.moveTo(400);
    joint5.moveTo(400);
  }
}
...

Man, thanks a lot. Both code methods worked. However, one stepper in the arrays definition created a synchronization mismatch. It works but something seems to be going wrong. That's why I used the code with the "currentMotion" command you last shared. As you said, i need to check that the expected preceding motion finished before setting the new target. This little command solved the problem.