User claims to achieve Syncd Starts & Ends with AccelstepperLibrary - help

This user claims to achieve synchronized starts and stops regardless of step counts with a simple formula. But his method is very unconventional and I don't really understand the way he describes it. Can anyone decipher it for me so I can achieve this in my own project?

I wish I could talk to him directly but the topic is closed.

There are a lot of posts on this subject, but no one has a good method of getting around this using accelstepper. I know that multi-stepper exists for this but I have issues with it too.

Thanks for any insight.

1 Like

@shydevil

2 Likes

It isn't clearly spelled out in that code, but the point of the method seems to be to scale the accelerations of the slower motions by their distances so they all end up finishing at the same time.

The math ends up equivalent to using the d=0.5*a*t^2 formula from physics/kinematics, where if you identify the longest motion and it's acceleration, you then know t^2 for the full coordinated motion, and since, for the slower axis motions you know their distance 'stepperDis's you can then calculate their accelerations as axisAccelN= maxAccel*abs(stepperDis/distance).

2 Likes

You can ask @shydevil to help you by including his / her username after @, as I have done, he / she will now get a notification about this topic and can join in if he / she wants to.

The general rule for this forum is to discourage adding new questions on to other people's topics, so, while I considered opening the topic for you I decided it better to continue here with your topic.

2 Likes

Thank you so much for breaking this down for me. I'm new to Arduino and programming but this goal I have keeps me up at night haha. I'll be applying this formula to my code.

I have a really cool setup at the moment.

Controlling stepper motors over LAN with an Ethernet shield. Client is sending http messages to the Arduino with PS4 controller input over python script running pygame. The motor's speeds are mapped to those inputs.

It works great, but I want the functionality for adding point A and B. Wanted to figure out how this works before trying though. So I really appreciate it!!

(The goal is to have 3 motors that do this function)

Here is the functionality In a video :slight_smile:

Hi Sorry i didnt check on the forum in some time. Synchronizing the steppers was quite easy tho i discovered it on accident. I was setting the stepper speed at first which didnt really work well so i tried to set the acceleration just to see what would happen and suddenly it worked

distance was the biggest distance. if motor 1 goes 800 steps, motor 2 goes 200 steps and motor 3 500 steps, the distance value would be 800 because motor one has to travel the most and therefore the others have to move slower so the'd finish with motor 1

maxSpeed was the speed i initially set for all motors. this value would be 2000 as example

stepperDis was the distance of the motor im trying to calculate the acceleration for

// distance is the biggest distance one out of all motors has to travel, 
// maxSpeed is the speed the motors should travel at. 
// stepperDis is the travel distance of the current motor im trying to calculate.
// 
// the motor with the biggest distance goes full speed, the others go slower so they all stop at the same time 

float speedOnePerc = (100 / distance);
float usageSpeedPerc = speedOnePerc * stepperDis;
float stepperSpeed = (maxAccel / 100) * usageSpeedPerc;
if(stepperSpeed < 0){ stepperSpeed = (abs(stepperSpeed));  }

I made a method like the following

i then used the function the following way to set the acceleration for the motors

in order to find out which motor has to travel the most i made the following code to save the individual stepper motors in an array to then sort them by size


its a bit hard to exmplain and if you have discord maybe i could explain it to you there in a better way. my discord would be shydevil or shydevil#0001

the result looks like this
done

tried this with my 6 axis robot and it seems to work fine :slight_smile: thank you!

Another important thing to mention is the ratio of acceleration to max speed.

It only works when the acceleration time is long enough to accelerate 50% of the distance to go.
As I understand it, the motors never actually reach the maximum speed - Because of that it works because we just have to scale the acceleration.

2 Likes

The way GRBL and many other projects solve this is through the Bresenham line drawing algorithm--instead of expensively calculating accelerations for each phase of the motions on all axes, the acceleration calculations are done only on the long/fast axis and the smaller/slower motions are all stepped at a ratio to the fast motion. If the fast axis reaches speed in 10% of the distance and the acceleration phase ends and it switches to cruise for 80%, tying the motion of the other axes in to the fast axes by the step ratio keeps the other axes in sync through any of the speed/acceleration transitions. Bresenham does this without having to calculate the corresponding accelerations, times, and max speeds of the slower axes, using only additions and subtractions to coordinate the motions.

All Bresenham would require from AccelStepper would be knowing when stepper.run() actually makes a step or not, which you can get from something like if(stepper.run() && (stepper.currentPosition() != lastPosition){...}

thank you @DaveX that sounds much more "clean" than what i use now.

For my understanding: i have to scale the MaxDistance to the Shorter Movments.

-Stepper1 with the most distance (Like DistanceToGo: 1500 steps) managed by accelstepper starts moving.(with accerleration)

-Stepper2 (DistanceToGo: 750 steps)
-Stepper3 DistanceToGo: 500 Steps.

in that case: Stepper1 Starts moving - managed by accelstepper and i simply have to let stepper2 make a step every 2 steps of stepper1. and Stepper3 preform a step every 3 steps of Stepper1. is that right?

if(Stepper2DistanceToGo/MaxdistanceToGo*Stepper1StepsDone - Stepper2StepsDone >=1){Stepper2.stepForward(); Stepper2StepsDone=Stepper2StepsDone+1;}

in numbers (Stepper1 moves)
750/1500x1-0 = 0,5
750/1500x2-0 = 1-> make a step
750/1500x3-1 = 0,5
750/1500x4-1 = 1 -> make a step

Yes, that sounds right. In relation to your 1500:759:500 example, the Bresenham Algorithm is designed to also work for less-nice ratios like 1500:1 to 1500:1499 or even 1500:1500.

This simulation doesn't do acceleration, but it does do 6-axis Bresenham with random targeting:

One trick it uses is to do sort of an extra virtual axis for the fastest/longest movement (dx), and then does the accounting for all the real axes (dy_0...dy_5) in relation the the virtual axis.

very interesting example.

I think the virtual motor would make programming much easier, as you don't always have to search for the motor AccelStepper has to drive.

AccelStepper will always drive my virtual axis
and i can treat all real axes the same way to follow

I'm still quite new to Arduino programming is there any other advantages about the virtual axis I’m missing?

You still have to search out the longest/fastest motion in order to assign it to the virtual axis, but the logic of computing the motions of the other axes relative to the longest/fastest axis is much simpler if there's only one fastest axis.

I’m going to test a few things :slight_smile:

thank you @DaveX that helped me a lot

It has to be >=o and also stepForward is a protected function. But it worked with a few adjustment’s.

I then tryed the bresemham and it is much simpler.. worked perfect! Only problem here was that AccelStepper can not step 6 motors with much speed. I now only use one AccelStepper as virtual axis and let all other steppers follow by simply using digitalWrite to Puls them. Now all 6 motors run synchron with 2000 steps/s and with acceleration.

1 Like

I wish AccelStepper had a run() that returned true if it stepped so that it would make this easier.

As an alternative to:

I was playing with this:

class myAccelStepper : public AccelStepper
{
  public:
    boolean myAccelStepper::stepAsNeeded()
    {
      bool stepped = false;
      if (stepped = runSpeed())
        computeNewSpeed();
      return stepped;
    }
    using AccelStepper::AccelStepper;
    using AccelStepper::setMaxSpeed;
    using AccelStepper::moveTo;
    //...
};

...but I'm really not sure if that's the best way to add a function to a class.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.