Acceleration formulas - grrr.

Chris DeHut

Senior Member
Hi guys,

I am having a tough time working through this and I don't know why - it should be simple for me. I am working on a routine to run a stepper motor. I need to accelerate the stepper up to speed and decel it back down when required.

I understand acceleration as a change in velocity over time such as:

Steps per second change over so many seconds.

Many folks write this out as SPS squared or SPS/Sec etc.

So I understand the concept, but I will be darned if I can get something to work out good, accurate, and correct.

The accel/decel values will be in Steps per second, the velocity is reltated to in steps per second - this is all communicated to the PICAXE from a host computer. However, I would like the routine to start out at the existing velocity X, then based on the parameter of acceleration rate, accelerate up to the new velocity.

From motion command to motion command, all I want to pass to the PICAXE is the velocity and the number of steps to move. I want the routine to figure out, on the fly, the acceleration dynamically. The rates for the acceleration will be pre-loaded as a parameter prior to any motion commands.

Anyone have an accel/decel routine they would mind sharing?

Thanks!

Chris
 

hippy

Ex-Staff (retired)
Don't know if this helps, but it's what first jumped into my mind -

Speed can also be measured as the time between stepping motor steps. You can calculate the step time change from current to what it needs to be, and given the time over which that step change needs to ocuur, you can work out by how much per 'tick' the step time should be altered.

I recall the trick is to work in units most appropriate ( step time in the micro, speed in the real world, etc ) and then work out what the relationships are between the two sets. I'm sure they are all 1/(N*K) relationships, so it's really a case of just finding the right ones.
 

evanh

Senior Member
I would try it without any accel, or speed settings. Just have a tight loop that feeds the sequence to the motor at full speed. I think you'll find the picaxe running flat out is about right for a stepper. And stepper motors tend to perform quite well at ramping up and down instantly.


Evan
 

Jeremy Leach

Senior Member
Hi Chris, this sort of problem always interests me ! This is my attempt (in pseudo code) ...

<code><pre><font size=2 face='Courier'>

Symbol RampTime_MS = 5000 'milliseconds. Set it to what you want.
Symbol PrepAndStepTime_MS = 10 'milliseconds (guess) has to be obtained with scope


HandleSpeedChangeRequest:
If TargetSpeed_SPM&gt; EntrySpeed_SPM then
Gosub RampUpSpeed
Else
Gosub RampDownSpeed
End
Return


RampUpSpeed:
'This smoothly ramps speed up from EntrySpeed to TargetSpeed in RampTime_MS milliseconds.

Acceleration_SPMPM = (TargetSpeed_SPM - EntrySpeed_SPM) * (60000 / RampTime_MS)
Time_MS = 0

Loop
CurrentSpeed_SPM = Acceleration_SPMPM * (Time_MS / 60000) + EntrySpeed_SPM

If CurrentSpeed_SPM = 0 then
PauseTime_MS =65535
Else
PauseTime_MS = (60000/CurrentSpeed_SPM) - PrepAndStepTime_MS
Endif

Pause PauseTime_MS

Gosub StepOnce 'Steps the stepper motor once

Time_MS = Time_MS + PauseTime_MS+ PrepAndStepTime_MS

If Time_MS &lt; RampTime_MS then Loop
Return

RampDownSpeed:
'very similar code to RampUpSpeed
....
Return

StepOnce:
'This steps the stepper one step (in the right direction).
....
Return

</font></pre></code>

<b>Explanation </b>


1. Assume that the maximum speed is 1000 steps per second, or 60*1000 = 60000 Steps per Minute (SPM)

2. Assume that the Minimum RampTime is 1 second. Therefore the maximum acceleration is 0 to 1000 Steps/s in 1 second, or 60*1000 = 60000 StepsPerMinutePerMinute.

If you know the Entry and Target Speeds then (keeping all units in minutes) :
Acceleration_SPMPM = (TargetSpeed_SPM - EntrySpeed_SPM) /RampTime_M

If the RampTime is in milliseconds:
Acceleration_SPMPM = (TargetSpeed_SPM - EntrySpeed_SPM) /(RampTime_MS/60000)
Or:
Acceleration_SPMPM = (TargetSpeed_SPM - EntrySpeed_SPM) * (60000/(RampTime_MS)

3. To acheive the desired 'CurrentSpeed_SPM' you need to pause between steps for the correct amount of time. In reality there's preparation time and step time (a constant PrepAndStep_M) to take into account so that the steps are exactly spaced to give the correct speed:
|&lt;--Preparation---&gt;|&lt;--Step---&gt;|&lt;---Pause--&gt;|&lt;--Preparation---&gt;|&lt;--Step---&gt;|&lt;---Pause--&gt; etc..

The overall period between steps is therefore:
StepPeriod_M = PrepAndStepTime_M + PauseTime_M

Also the overall period between steps is inversely proportional to the speed :
StepPeriod_M = 1/CurrentSpeed_SPM

So:
1/CurrentSpeed_SPM = PrepAndStepTime_M + PauseTime_M
Or:
PauseTime_M = (1/CurrentSpeed_SPM) - PrepAndStepTime_M


To be useful in integer maths, we need to express Pause in milliseconds:

PauseTime_MS = (60000/CurrentSpeed_SPM) - PrepAndStepTime_MS

PrepAndStepTime_MS can be obtained with a scope, but in practice can probably be ignored.
CurrentSpeed_SPM can't be 0 otherwise overflow, so this case must be handled.
If the CurrentSpeed_SPM = 1 then PauseTime_MS = around 60000, which nicely fits in a Word variable.

Edited by - Jeremy Leach on 22/03/2006 13:59:27
 

Jeremy Leach

Senior Member
Actually there's a flaw in my routine which won't give a super-smooth ramp up. I think it's better to base the routine on the distance (steps) travelled in a certain time. This (I think) should be more accurate:

<code><pre><font size=2 face='Courier'>

Symbol UpdateInterval_MS = 50 'milliseconds.
Symbol RampTime_MS = 5000 'milliseconds.
Symbol PrepTime_MS = 10 'milliseconds.
Symbol StepTime_MS = 2 'milliseconds


RampUpSpeed:
'This smoothly ramps speed up from EntrySpeed to TargetSpeed in RampTime_MS milliseconds.

Acceleration_SPMPM = (TargetSpeed_SPM - EntrySpeed_SPM) * (60000 / RampTime_MS)
ActualTotalSteps = 0

For Time_MS = 0 to RampTime_MS Step UpdateInterval_MS
ExpectedTotalSteps = (Time_MS/60000) * [EntrySpeed_SPM + (0.5 * Acceleration_SPMPM * (Time_MS/60000) )]

StepsToTake = ExpectedTotalSteps - ActualTotalSteps

For StepCount = 1 to StepsToTake
Gosub StepOnce
Next

ActualTotalSteps = ActualTotalSteps + StepsToTake

PauseTime_MS = UpdateInterval_MS - (StepsToTake * StepTime_MS) - PrepTime_MS
Pause PauseTime_MS
Next
Return

</font></pre></code>

<b> Explanation </b>

Standard formula for distance travelled in time T : S = (Vi*T) + (0.5*A*T^2), or S = T[Vi + (0.5*A*T)]

where S = distance, Vi is initial velocity, A = acceleration, T = time.

In our case steps is equivalent to distance. So:

TotalSteps = Time_M[EntrySpeed_SPM + (0.5* Acceleration_SPMPM * Time_M)]

If Time is expressed in milliseconds:
TotalSteps = (Time_MS/60000) * [EntrySpeed_SPM + (0.5 * Acceleration_SPMPM * (Time_MS/60000) )]

To calculate TotalSteps in integer maths will need a bit of careful ordering of calculations.

So the code calculates the ExpectedTotalSteps in time Time_MS, compares it to the actual steps that have been taken, and then adjusts the stepper-motor accordingly.

It only updates the stepper every UpdateInterval_MS milliseconds. To get the update intervals exact, you need to take account of the delay in stepping and the Prep time (calculations).

PauseTime_MS = UpdateInterval_MS - (StepsToTake * StepTime_MS) - PrepTime_MS

The shorter the update interval the smoother the stepper will run.

Edited by - Jeremy Leach on 22/03/2006 15:14:47
 

Chris DeHut

Senior Member
WOW, thanks a lot guys and especially Jermey. I can see from your post that you went down some of the same pathes I did. However, I see a couple of interesting tidbits in there that just might get this too all smooth out.

I have been back and forth between acceleration on Steps versus Time about 20 times now, so I am somewhat keen to why you switched too. Each one has some drawbacks, but I can see that there is hope in there somewhere!

Thanks again, will hopefully get some coding time some night this week or next weekend to see what comes of it.

Chris
 

Jeremy Leach

Senior Member
Hi Chris. I came to the conclusion that if you work out a speed at a certain time then pause a set timeinterval to step at that speed it isn't actually correct, because by the time the pause has ended the speed should have changed.

I think if you base it on the formula for distance travelled (ie total steps) it will probably give a better result.

It was also easier for me to get my head round - the formula tells you how many steps should have passed at any instant. If the actual steps are less than this then quickly make up the difference.

I say 'probably give better result' because to be honest this isn't easy stuff and there's room for mistakes and overlooked factors !

Another thing to watch out for is the processing overhead and how this will affect the maximum step speed. If there's so much maths to do in each loop (and it does look pretty busy to me!) then you might find it's not a realistic solution. You might have to resort to lookup tables etc. Or you might end up ditching any sort of accurate ramp-up and go for something simpler.

I've based my code on the assumption that you want a constant acceleration to smoothly increase the speed. But do you ? It might be better to have an exponential response, where the acceleration is proportional to the difference in the speeds (equivalent to a capacitor charging). In which case the maths actually might be easier (although I'm only guessing).

Also, I've never messed about with steppers (with PICAXEs), but maybe it would be good to have a picaxe dedicated to driving the stepper? Can you drive them via a background PWM signal? If so then you just issue commands to this slave PICAXE to tell it to go faster/slower etc. This way you perhaps might get a smoother operation.

 

Jeremy Leach

Senior Member
Hi Chris. Been thinking about this more. The reason my second routine should be more accurate is that it corrects errors as it goes. It calculates the total distance that should have been travelled each time round the loop. The first routine would introduce errors.

Anyway, if it was me I'd go for a more simple approach. Here is a routine that is based on feedback. It uses the errorSpeed to adjust the CurrentSpeed until the CurrentSpeed eventually reaches the TargetSpeed.



<code><pre><font size=2 face='Courier'>
'*****************
'*** CONSTANTS ***
'*****************

Symbol DampingFactor = 10
Symbol Yes = 1
Symbol No = 0

'*****************
'*** VARIABLES ***
'*****************

'Word 0 (b0 and b1)
Increase = bit0
'Word 1 (b2 and b3)
TargetSpeed_SPM = w1
'Word 2 (b4 and b5)
SpeedError_SPM = w2
'Word 3 (b6 and b7)
Adjustment = w3
'Word 4 (b8 and b9)
EntrySpeed_SPM = w4
CurrentSpeed_SPM = w4
'Word 5 (b10 and b11)
PeriodBetweenSteps_MS = w5
'Word 6 (b12 and b13)

'*****************
'*** MAIN ********
'*****************

AdjustToTargetSpeed:
'Uses feedback of speed error to adjust to the TargetSpeed.
'ON ENTRY: Pass EntrySpeed_SPM and TargetSpeed_SPM to the routine.
'Routine exits when CurrentSpeed matches TargetSpeed (as close as it's going to get).

CurrentSpeed_SPM = EntrySpeed_SPM
Adjust:
SpeedError_SPM = TargetSpeed_SPM - CurrentSpeed_SPM
If TargetSpeed_SPM &gt; CurrentSpeed_SPM Then IncreaseSpeed:
DecreaseSpeed:
SpeedError_SPM = CurrentSpeed_SPM - TargetSpeed_SPM
Adjustment = SpeedError_SPM / DampingFactor
CurrentSpeed_SPM = CurrentSpeed_SPM - Adjustment
Goto WaitForPeriod

IncreaseSpeed:
SpeedError_SPM = TargetSpeed_SPM - CurrentSpeed_SPM
Adjustment = SpeedError_SPM / DampingFactor
CurrentSpeed_SPM = CurrentSpeed_SPM - Adjustment

WaitForPeriod:
PeriodBetweenSteps_MS = 60000 / CurrentSpeed_SPM
Pause PeriodBetweenSteps_MS

Gosub StepOnce

If Adjustment &gt; DampingFactor Then Adjust
Return

</font></pre></code>

I've found that it's great to simulate stuff like this in Excel. I've temporarily posted a spreadsheet I've knocked up this morning to simulate this code ...
<A href='http://home.btconnect.com/PicAxe_Projects/Home.htm ' Target=_Blank>External Web Link</a>

This is a classic damped feedback system. I'm sure if you want to you can get the graph to oscillate ! (it can be great fun - I even simulated my anemometer like this).


 

Chris DeHut

Senior Member
Jeremey! Thank you very much!

I have been noodling on your code (and spread sheet) on and off this morning and I think that will do the trick. It sure seems tight enough to be efficient and from what I can see so far, it appears as though it will be much smoother than what I have right now.

Thanks again, VERY MUCH appreciated.

Chris
 
Top