Closed yankobogdan closed 5 years ago
Hey there,
Sorry for the delay in responding, it's been a busy December! Yes, you can calculate this. It will be approximate, but maybe more than good enough. And perhaps if if I sit down with the math I can figure out a way to calculate it exactly.
There's only one main challenge here: the motor doesn't always have time to accelerate up to the maximum speed. So you have to do some extra math to figure out the actual top speed. You can't (yet) use starting speeds other than 0, so that does simplify things a little bit, but only a little.
All you need to do to figure out how long it will take to accelerate or decelerate is divide the number of steps taken by the average speed during the acceleration. Since acceleration is linear, the average speed is the midpoint between 0 and the top speed, so you can get that by dividing the top speed by 2. But because acceleration and deceleration will take the same time, you only really need to calculate it for one, then multiply by 2. Then add the time taken to move at constant speed. This makes the math really simple, and the hard part is figuring out the top speed.
Here is some code that MIGHT work. Not bug tested, and you might well have some integer overflow problems here that you will need to sort out, but it's a start.
// calculate total distance
uint32_t totalDist = (target > pos) ? (target - pos) : (pos - target);
// get maximum speed (or replace all references to maxSpeed below with your local variable)
uint16_t maxSpeed = mot.getMaxSpeed();
// calculate distance required to accel to maximum speed
uint32_t maxAccelDist = mot.calcMaxAccelDist();
// calculate move time
uint32_t moveTime; // in microseconds
if (maxAccelDist >= (totalDist / 2))
{
// triangular profile, max speed may not be reached
uint32_t distAccel = totalDist / 2;
uint16_t topSpeed = ((uint32_t)maxSpeed * distAccel) / maxAccelDist;
float microsPerStep = 1000000.0 / topSpeed;
moveTime = distAccel * microsPerStep; // in microseconds
}
else
{
// trapezoidal profile, max speed will be reached
uint32_t distAccel = maxAccelDist;
uint32_t distRun = totalDist - distAccel*2; // distance at constant speed
uint16_t topSpeed = maxSpeed; // where maxSpeed is what you previously supplied to mot.setSpeed(...)
float microsPerStep = 1000000.0 / topSpeed;
moveTime = (distAccel * microsPerStep) + (distRun * microsPerStep); // in microseconds
}
Of course if you use either stop() or decelerate() after calculating the time, it won't match up with reality.
I've added a getTopSpeed() function to the library. Although not an official release yet, I have tested it and I think it's working quite well.
Just be aware that it IS a bit of an estimate and does suffer from rounding errors, so it's not perfect.
Using this function, the method to calculate how much time (in seconds) it will take to move is this (after calling prepareMove):
uint16_t topSpeed = mot.getTopSpeed();
uint32_t accelDist, runDist, decelDist;
float accelTime, runTime, decelTime, totalTime;
topSpeed = mot.getTopSpeed();
accelDist = mot.getAccelDist();
runDist = mot.getRunDist();
decelDist = mot.getDecelDist();
accelTime = accelDist / (topSpeed / 2.0);
runTime = runDist / (float)topSpeed;
decelTime = decelDist / (topSpeed / 2.0);
totalTime = accelTime + runTime + decelTime;
That's a bit verbose, you can simplify it if you like. You can also change it to calculate integer milliseconds (if you want to avoid floating point math), etc.
I'll close this issue for now. If you have problems, create a new issue and let me know!
Hi. Firstly huge thanks for this great, fast and reliable library. Im using it in my motion control device. And in software part I need smth that will help me to predict move time. In case of constant speed its easy, but for the acceleration standart phisics formula not useful. Can you help me with math formula for example to calculate moving time when we go from A to B point with start speed C and axxel X?