stepper-control-with-acceleration

Satchid

Member
Hippy & Alistairsam



I am using the folowing pogram from post #56 on page

http://www.picaxeforum.co.uk/showthread.php?15591-stepper-control-with-acceleration-and-variable-freq-square-wave-output/page6

I tryed to figure out how i could set the max speed of the steppermotor? But did not succeeded.
The program is working fine but I would like to change the max rpm. could one of you please help me here?
I would allso like to know how i can change the accelleration.

Alistairsam here is your code unchanged.
Code:
'28x2
' picaxe pin assignment for stepper driver inputs
' Stepper Driver - Allegro A4983 driver 
' High speed slew below uses 1/16 micro stepping
' enablepin = pinC.0
' Dirpin = pinC.1  -> High - CCW, Low - CW
' Clckpin = pinC.2
' MS0pin = pinC.3
' MS1pin = pinC.4
' MS2pin = pinC.5

' Full stepping - MS0,MS1,MS2 low 
' 1/16th stepping - MS0, MS1, MS2 high - for tracking speed, hi and low speeds
' 1/8th stepping - MS0 high, MS1 high, MS2 low

'pwmdiv ranges @ 8Mhz
'pwmdiv 16 -> 500 - 1940 Hz
'pwmdiv 4 -> 1950 - 7800 Hz 

setfreq m8

Symbol BB = w0
Symbol percal2 = w2
Symbol perd = w3
Symbol Fmin = w4
Symbol Fmax = w5
Symbol F = w6
Symbol Dutyreq =w7
Symbol Duty = w8 
Symbol dutycal1 = w9
Symbol dutycal2 = w10
Symbol F2 = w11
Symbol Fdiff = w12


'Enter max freq as max freq / 10 kHz
'Enter duty as duty % * 10

let dirsB = %00000000
let Dutyreq = 300
let Fmin = 50
let Fmax = 2400


Setpinslow:
pwmout C.2,off
let dirsC = %10111111
let pinsC = %10000001 'Turn LED on C.7 on, Enable off
goto keyscan:


keyscan:
Do
for BB = 1 to 10000 step 1
pause 100
if pinB.3 = 1 then highCW
if pinB.4 = 1 then HighCCW
if pinB.5 = 1 then LowCW
if pinB.6 = 1 then LowCCW
if pinB.7 = 1 then TrackCW
if BB = 10000 then goto slp
next BB
Loop



HighCW:
pauseus 5000
if pinB.3 = 0 then Setpinslow:
let pinsC = %10111000 'set enable low and DIR low, 1/16 step
gosub pwroutine
Do
if pinB.3 = 0 then Decel:
pwmout C.2, perd, duty
Loop


HighCCW:
pauseus 5000
if pinB.4 = 0 then Setpinslow:
let pinsC = %10111010 'set enable low and DIR high, 1/16 step
gosub pwroutine
Do
if pinB.4 = 0 then Decel:
pwmout C.2, perd, duty
Loop



LowCW:
pauseus 5000
let pinsC = %10111000 'set enable low and DIR low, 1/16th step
Do
  if pinB.5 = 0 then Setpinslow:
  Toggle C.2
  PauseUs 10
 Loop

LowCCW:
pauseus 5000
let pinsC = %10111010 'set enable low and DIR high, 1/16th step
Do
if pinB.6 = 0 then Setpinslow:
Toggle C.2
 PauseUs 10
Loop


TrackCW:
pauseus 5000
let pinsC = %10111000 'set enable low and DIR low, 1/16th step
Do
if pinB.7 = 0 then Setpinslow:
 Toggle C.2
 Pauseus 500
Loop



pwroutine:

 sertxd ("Div16")
 F = Fmin
Do
 Select Case F
 Fdiff = F >> 2
 Case > 186  goto Div4
 Case < 187 : F = F + Fdiff
 End Select 
percal2 = 12504 / F
perd = percal2 - 1
dutycal1 = Dutyreq / 25
dutycal2 = perd + 1
duty = dutycal1 * dutycal2 /10
sertxd (#w6,",",#w3,",",#w8)
pwmout pwmdiv16, C.2,perd,duty
Loop


Div4:
sertxd ("Div4")
Do
 Select Case F
 Fdiff = F >> 3
 Case > Fmax  Return
 Case > 758 goto NoDiv
 Case < 759 : F = F + Fdiff
 End Select 
percal2 = 50000 / F
perd = percal2 - 1
dutycal1 = Dutyreq / 25
dutycal2 = perd + 1
duty = dutycal1 * dutycal2 / 10
sertxd (#w6,",",#w3,",",#w8)
pwmout pwmdiv4, C.2,perd,duty
Loop


NoDiv:
sertxd ("NoDiv")
Do
 if pinB.3 = 0 and pinB.4 = 0 then Decel
 Select Case F
 Fdiff = F >> 5
 Case > Fmax  Return
 Case < Fmax : F = F + Fdiff
End Select 
percal2 = 20000 / F 
perd = percal2 * 10
perd = perd - 1
dutycal1 = Dutyreq / 25
dutycal2 = perd + 1
duty = dutycal1 * dutycal2 / 10
sertxd (#w6,",",#w3,",",#w8)
pwmout C.2,perd,duty

Loop

return


Decel:
sertxd ("decel")
Do
 Select Case F
 Fdiff = F >> 4
 Case < 790 goto Setpinslow
 Case > 790 : F = F - Fdiff
End Select 
percal2 = 20000 / F 
perd = percal2 * 10
perd = perd - 1
dutycal1 = Dutyreq / 25
dutycal2 = perd + 1
duty = dutycal1 * dutycal2 / 10
sertxd (#w6,",",#w3,",",#w8)
pwmout C.2,perd,duty
Loop


     
slp:

hInt0Flag = 0
HIntSetup %00010001 ' Wake on B.0 (HINT0) going high
let pinsC = %00000001
disablebod
Sleep 0
'Do : Loop Until hint0Flag = 1
enablebod
goto setpinsl

Thank you
Willy
 
Last edited:

AllyCat

Senior Member
Hi Willy,

The speed of the stepper motor seems to be set by the period, pulse-width and division ratio in the PWM settings. To set a maximum speed you will need to set MINIMUM values for those parameters (perhaps using the MIN function). But those three parameters are inter-related and need to be carefully calculated; depending on the range and resolution of speeds required, it might be preferable to select from a "list" of pre-calculated speed parameters, for example using SELECT...CASE or LOOKUP tables.

Cheers, Alan.
 

hippy

Technical Support
Staff member
I am not familiar with the code but assuming PWMOUT sets the rate of stepping, it should just be a case of limiting the PWMOUT period as suggested and adjusting duty to match that. For 50% duty it would "duty = 2 * period".
 

Circuit

Senior Member
I find that the easiest method to control stepper motors is by using TOGGLE within a DO:LOOP and then using a time delay variable to set the speed; incrementing or decrementing as needed to change acceleration/deceleration. On a 20x2 running at 64MHz, a bare DO:LOOP can drive a square wave with TOGGLE at 7.47 KHz. I have not yet found a need for anything like such a speed when driving steppers even when using microstepping. It is much simpler than using PWM. What sort of speed are you looking for?
 
Last edited:

rq3

Senior Member
I find that the easiest method to control stepper motors is by using TOGGLE within a DO:LOOP and then using a time delay variable to set the speed; incrementing or decrementing as needed to change acceleration/deceleration. On a 20M2 running at 64MHz, a bare DO:LOOP can drive a square wave with TOGGLE at 7.47 KHz. I have not yet found a need for anything like such a speed when driving steppers even when using microstepping. It is much simpler than using PWM. What sort of speed are you looking for?
A 20M2 can run at 64 MHz? What am I missing?
 

Satchid

Member
hi Circuit,

I find that the easiest method to control stepper motors is by using TOGGLE within a DO:LOOP and then using a time delay variable to set the speed; incrementing or decrementing as needed to change acceleration/deceleration. On a 20x2 running at 64MHz, a bare DO:LOOP can drive a square wave with TOGGLE at 7.47 KHz. I have not yet found a need for anything like such a speed when driving steppers even when using microstepping. It is much simpler than using PWM. What sort of speed are you looking for?
I forsee about 2000HZ, I am using a 28x2

I can not start the stepper motor at full speed at once, I need the speed to slope from 0 to 2000 in 1" and from 2000 to 0 in 1". Can I do that with your approache?
 
Last edited:

hippy

Technical Support
Staff member
I can not start the stepper motor at full speed at once, I need the speed to slope from 0 to 2000 in 1" and from 2000 to 0 in 1". Can I do that with your approache?
Probably not the right execution speed but something like this should work ...

Code:
For w0 = 0 To 2000
  w1 = 2000 - w0
  High STEPPER : PauseUs w0
  Low  STEPPER : PauseUs w1
Next
 

AllyCat

Senior Member
Hi,

I am using the folowing pogram from post #56 on page ...
That program uses 1 / 16 microstepping, whch then implies the use of a dedicated chip and PWM commands (with a PICaxe). Do you need microstepping? If so, then you have a "difficult" program to write because the PWM commands need to use various different divison ratios and can never get to very low frequencies (or rpm).

If you don't need microstepping then there are other far better methods (including those already mentioned in this thread), and maybe not even needing the Allegro chip.

Cheers, Alan.
 

oracacle

Senior Member
hi Circuit,



I forsee about 2000HZ, I am using a 28x2

I can not start the stepper motor at full speed at once, I need the speed to slope from 0 to 2000 in 1" and from 2000 to 0 in 1". Can I do that with your approache?
some clarity is needed, how many rotations would be needed for 1". for the macro rail I built that would be about 63 turns of the lead screw (and it has 1/64 micro stepping).
You also need ensure that 2khz does not exceed both the controller and motor specifications.
even then I suspect that with both being able to deal with higher pulse speed you wont get the results unless you at least double the specified voltage of the motor. Again with the macro rail, the motor coils were quoted as 2.4v, the driver and it is given 7.2 but runs slightly better at 12v

also at the top of the code there is this little thing

Code:
'Enter max freq as max freq / 10 kHz
'Enter duty as duty % * 10

let dirsB = %00000000
let Dutyreq = 300
let Fmin = 50
let Fmax = 2400
as far as a quick glance can tell, it does the acceleration in division of Fmax alongside variable duty cycle.

the thread also seems to indicate that an allegro A4983 with code apparently able to deal with 1/16 and 1/8 micro stepping
 

AllyCat

Senior Member
Hi,

Code:
For w0 = 0 To 2000
  w1 = 2000 - w0
  High STEPPER : PauseUs w0
  Low  STEPPER : PauseUs w1
Next
Won't that just generate a "PWM" signal of 50 Hz which sweeps through a range of duty cycles over a period of 40 seconds?

We really need to know how this "stepper" is to be used because there are a number of potential "issues":

Firstly, the "frequency" is determined by the time delay (e.g. PAUSEUS) between pulse edges, so if you want the frequency to increase "linearly" with time then the delay needs to reduce as 1 / frequency. Thus a frequency of "zero" is a problem. Maybe something like FOR w0 = 1 TO 40 : w1 = 2000 / w0 : PAUSEUS w1 : etc. would be better, but to optimise the "speed profile" a lookup table method may be better, as mentioned in #3.

Generally, stepper motors are not really very satisfactory as "variable speed" motors, because they don't have the "self-compensating" characterists of a dc motor (primarily caused by its back-emf when rotating). Also, there are different ways to drive the coils (e.g. one coil at a time, or two at a time, or a combination, or full micro-stepping) and at low frequencies the "overdrive" required to overcome the inductance of the coils at high speeds is no longer needed. That may lead to very high power losses (and overheating) but may be acceptable if just accelerating over a period of a few seconds.

Cheers, Alan.
 

hippy

Technical Support
Staff member
Code:
For w0 = 0 To 2000
  w1 = 2000 - w0
  High STEPPER : PauseUs w0
  Low  STEPPER : PauseUs w1
Next
Won't that just generate a "PWM" signal of 50 Hz which sweeps through a range of duty cycles over a period of 40 seconds?
Good point. It should perhaps be -

Code:
For w0 = 2000 To 1 Step -1
  High STEPPER : PauseUs w0
  Low  STEPPER : PauseUs w0
Next
 

AllyCat

Senior Member
Hi,

Won't that give one cycle of 40 ms (25 Hz) the next of 39.98 ms (25.01 Hz), the third of 39.96 ms (25.025 Hz), etc., which eventually reaches 20 us (plus 1 ms or more for the rest of each code loop, so say 1 kHz) after 2000 cycles, which I believe will total at least 42 seconds (with a maximum "rate of change of frequency" somewhere between the two ends) ?

IMHO some form of "logarithmic" coding is required, perhaps using 1 / f (as in #13) or the X2's DCD or NCD commands, etc.. But, as mentioned in #13, a starting frequency of zero is meaningless, so we need to know from the OP, the required starting and terminal frequencies, the "shape" of the speed profile and the number of pulses required for each revolution of the motor.

Cheers, Alan.
 

Circuit

Senior Member
Firstly, I have built several stepper motors running using the simple high/low or toggle format and accelerating and slowing using the insertion of a PAUSEUS as Hippy suggests. But I have never been running a stepper as fast as 2KHz, even with 1/32 stepping.
Therefore, I thought to check out just what the various permutations of code can do, using HIGH/LOW, TOGGLE, OR PULSOUT.
A look at the A4983 datasheet indicates that the minimum pulse width for both HIGH and LOW in the logic timing is 1us. There is no problem, therefore, with the pulse width with any of the methods; the highest output frequency was produced with pulsout and with the 20X2 running at 16MHz a PULSOUT pin,1 is 2.5us wide. At 64MHz it is necessary to use a PULSOUT pin,2 to get a pulse that is 1.25us wide but this has little effect on the performance.

Method 1; TOGGLE in a do/loop
This produces a decent square wave at 7870 Hz at SETFREQ M64 and 1865Hz at SETFREQ M16.

Method 2: HIGH/LOW in a do/loop
This generates 9970Hz at SETFREQ M64 and 2498Hz at SETFREQ M16. Much faster than the TOGGLE (I seem to recall this being discussed some weeks ago).

Method 3: PULSOUT in a do/loop
This is the winner (speedwise) with 12460 pulses per second with PULSOUT pin,2 at SETFREQ M64 and with PULSOUT pin,1 at M16 I get 3216Hz.

Method 4: HIGH/LOW in a FOR/NEXT loop
with a PULSOUT pin, 2 at SETFREQ M64 this generates pulses at 7280 pulses per second and with PULSOUT pin,1 at SETFREQ M16 I get 1846pps

In conclusion, it is easy to get a pulse train at up to 2000 pps with most all the methods. It is really easy to adjust the speed by inserting PAUSEUS values as per Hippy's code. I have mostly used the PULSOUT in a FOR/NEXT loop because I am using the stepper to position accurately and repeatedly. I do use acceleration and deceleration. Yes, Alan is right; a logarithmic approach is probably best but I seem to get good results by simply using a linear decrement of PAUSEUS and it works satisfactorily.
 

AllyCat

Senior Member
Hi,

Probably; I did say it wouldn't have the correct execution time :)
Indeed, but an "error" of 4,200 % needs some thinking about (which I've been doing as I have similar project requirements "on the back burner" at the moment)*. ;)

We don't know why the OP chose a PWM control method, whether microstepping is actually required, or why (or how) it must "accelerate" up to a maximum speed. However, we have been told that the maximum frequency is 2 kHz and the acceleration should occur during a (rather short) period of 1 second:

Normally, one would aim for constant acceleration (i.e. a linear increase of speed with time) since this corresponds to constant torque, for example where the wheels or tyres of a train or car might start to slip. However, this involves a continuous increase of the power input, so typically a car's acceleration will "roll over" (like a log curve) as gear-changes reduce the torque at the wheels.

Conversely, an exponential rise of speed (i.e. increasing acceleration) as is produced by linearly changing the period of an "oscillator" (or a FOR .. TO .. STEP .. NEXT loop) as proposed in several of the posts above, is rather unusual in real life. The only example I can think of is a space rocket where the thrust remains constant, but the total weight (strictly mass) reduces considerably as the fuel is burnt, so the acceleration progressively increases (Acceleration = Force / Mass).

Perhaps the problem is best explained by calculating some real numbers for the "speed profile" as described above. Consider the 1 second acceleration period divided into 10 "timeslots" of 100 ms each, up to a maximum of 2000 Hz. The first timeslot would be at 200 Hz (which has a period of 5 ms) and contain 20 cycles; the second 400 Hz (period 2.5 ms) and 40 cycles, etc.. So a full table can be created, where both minimum and maximum speed columns are included to show the limiting conditions :

Code:
Time (ms)	0	100	200	300	400	500	600	700	800	900	1000
Frequency (Hz)	0	200	400	600	800	1000	1200	1400	1600	1800	2000
Period (us)  infinity 	5000	2500	1667	1250	1000	833	714	625	555	500
Cycles 		0	20	40	60	80	100	120	140	160	180	200
PAUSEUS delay	-	450	200	117	75	50	33	21	12	5	0
The final row shows the ADDITIONAL time delay which would be needed in a program loop which has been designed (with "padding" if necessary) to execute at the fastest required speed, i.e. 500 us for the specified 2 kHz. The figures assume a 4 MHz clock (as might be needed to achieve the lower frequencies with the PWM oscillator method) but can obviously be multipled by 8 for a 32 MHz clock, etc..

Note that the delay is nearly Logarithmic (or exponential if working backwards from the high frequency end), approximately halving for each subsequent timeslot. But also the number of cycles is increasing each time. That can be achieved with two nested FOR loops (and some additional maths) and should be quite straighforward to code for the "PWM oscillator" method, but it looks doubtful if that could be implemented in a 500 us (2 kHz) program loop, even with an X2 at 64 MHz.

An alternative is to change the timeslots so each contains a fixed number of cycles, but if we want to retain the lowest frequency and linear profile, then the number of timeslots increases considerably, e.g. for 20 cycles per timeslot as above, the total number would be 55 (or 45 excluding the last column). For this number of values a LOOKUP is probably too slow, so a READ{TABLE} would be needed, or of course one could attempt to write some mathematical expressions to calculate the values "on the fly".

All quite "do-able" but it doesn't seem worth proceeding much further until the background to the design requirements is explained.

Cheers, Alan.

* My own issue is how to use a PICaxe (alone) to electrically control a small stepper motor over a wide range of speeds. But that's for another thread and another time. ;)
 
Last edited:

rq3

Senior Member
Firstly, I have built several stepper motors running using the simple high/low or toggle format and accelerating and slowing using the insertion of a PAUSEUS as Hippy suggests. But I have never been running a stepper as fast as 2KHz, even with 1/32 stepping.
Therefore, I thought to check out just what the various permutations of code can do, using HIGH/LOW, TOGGLE, OR PULSOUT.
A look at the A4983 datasheet indicates that the minimum pulse width for both HIGH and LOW in the logic timing is 1us. There is no problem, therefore, with the pulse width with any of the methods; the highest output frequency was produced with pulsout and with the 20X2 running at 16MHz a PULSOUT pin,1 is 2.5us wide. At 64MHz it is necessary to use a PULSOUT pin,2 to get a pulse that is 1.25us wide but this has little effect on the performance.

Method 1; TOGGLE in a do/loop
This produces a decent square wave at 7870 Hz at SETFREQ M64 and 1865Hz at SETFREQ M16.

Method 2: HIGH/LOW in a do/loop
This generates 9970Hz at SETFREQ M64 and 2498Hz at SETFREQ M16. Much faster than the TOGGLE (I seem to recall this being discussed some weeks ago).

Method 3: PULSOUT in a do/loop
This is the winner (speedwise) with 12460 pulses per second with PULSOUT pin,2 at SETFREQ M64 and with PULSOUT pin,1 at M16 I get 3216Hz.

Method 4: HIGH/LOW in a FOR/NEXT loop
with a PULSOUT pin, 2 at SETFREQ M64 this generates pulses at 7280 pulses per second and with PULSOUT pin,1 at SETFREQ M16 I get 1846pps

In conclusion, it is easy to get a pulse train at up to 2000 pps with most all the methods. It is really easy to adjust the speed by inserting PAUSEUS values as per Hippy's code. I have mostly used the PULSOUT in a FOR/NEXT loop because I am using the stepper to position accurately and repeatedly. I do use acceleration and deceleration. Yes, Alan is right; a logarithmic approach is probably best but I seem to get good results by simply using a linear decrement of PAUSEUS and it works satisfactorily.
I plugged this rough code into an exisiting circuit using a Picaxe 20M2 driving a TI DRV8825 driving a 400 step per revolution motor:

Code:
#Picaxe 20M2
#no_data
setfreq m32

main:
    do 
        for w1=2000 to 1 step -1     ;step delay in 1.25 usec increments
             pulsout C.4,1                ;make a step
                pauseus w1
                    next w1                ;accelerate
        for w1=1 to 2000
            pulsout C.4,1
                pauseus w1
                    next w1                ;decelerate
    loop
I took a short video of the motor ramping up and down, but it's likely too large to post.
 

AllyCat

Senior Member
Hi,

What did it show? My estimation of that code is the Low frequency will be about 330 Hz, the High about 2.6 kHz and the "ramp" times about 3 seconds each. But, it will only spend around 300 ms running above half of the maximum speed (i.e. > ~1.3 kHz).

Try adding the following code between the accelerate and decelerate sections, which should give a period of around 3 seconds running constantly at the "maximum" speed.

Code:
        for w1=1 to 8000         ;   Around 3 seconds at 2.6 kHz
            pulsout C.4,1
            pauseus 1               ;  Maximum speed
        next w1
You could also add a delay loop for the minimum (or zero) speed, but that's not likely to reveal anything "unexpected".

Cheers, Alan.
 

PieM

Senior Member
About pauseus :

on a 14M2 @ 4MHz:
Pauseus 05 = 1044 µs
Pauseus 10 = 1094 µs
Pauseus 50 = 1533 µs
Pauseus 100 = 2038 µs
Pauseus 200 = 3022 µs
Pauseus 500 = 6189 µs
Pauseus 1000 = 10726 µs
Pauseus 10000 = 100635 µs
 

AllyCat

Senior Member
Hi,

Yes, the incremental step is close to 10 us, but there is some additional "overhead" (which may not be constant). I measured (post #12) PAUSEUS 1 at about 720 us and PAUSEUS 2 at 730 us, etc., but PAUSEUS 0 at 630 us, which is significantly slower than PAUSE 0 that I timed at around 300 us (the fastest M2 PICaxe command I've found so far).

PICaxe stores numbers as variable-width tokens, which may explain why commands using integer values of less than 2, and less than 256 (and < 16?) may execute faster than when larger values are used. However, numerical calculations are always performed on Word values, so there is no speed advantage in using byte variables in calculations.

For this thread I checked a few more execution times; FOR .. TO .. STEP .. NEXT takes around 1700 us per pass (@ 4 MHz = Instruction cycles) and (IIRC) PULSOUT N around 600 + 10*N us. But beware of READ{TABLE} with a WORD qualifier, which can be rather slow because the compiler increments and then decrements the "pointer" each time.

Cheers, Alan.
 
Last edited:

AllyCat

Senior Member
Hi,

on a 14M2 @ 4MHz:
Pauseus 05 = 1044 µs
Pauseus 10 = 1094 µs
Pauseus 50 = 1533 µs
Pauseus 100 = 2038 µs
Pauseus 200 = 3022 µs
Pauseus 500 = 6189 µs
Pauseus 1000 = 10726 µs
Pauseus 10000 = 100635 µs
I didn't want to say that those figures are "wrong", because measuring consistent PICaxe execution times is almost impossible, due to the variable-width tokens and many other factors. Also (as with many PICaxe instructions), it's possible to use either a variable (eg W2) or a "literal" constant (ie a number) as the parameter. So I've been rechecking my measurements and the above figures do seem rather high. Here are the figures that I've just measured on a 20M2, using the method I linked above.

Code:
pauseus w2 =0 = 641us 
pauseus w2 =1 = 731us 
pauseus w2 =2 = 741us 
pauseus w2 =5 = 771us 
pauseus w2 =10 = 821us 
pauseus w2 =50 = 1221us 
pauseus w2 =100 = 1721us 
pauseus w2 =200 = 2721us 
pauseus w2 =500 = 5721us 
pauseus w2 =1000 = 10721us 
pauseus w2 =5000 = 50721us 
pause w2 =0 = 420us 
pause w2 =1 = 1408us 
pause w2 =2 = 2414us 
pause 0 = 361us 
pause 1 = 1342us 
pause 2 = 2384us 
pauseus 0 = 545us 
pauseus 1 = 646us 
pauseus 2 = 709us 
pauseus 5 = 709us 
pauseus 10 = 757us 
pauseus 50 = 1248us 
pauseus 100 = 1751us 
pauseus 200 = 2725us 
pauseus 500 = 5863us 
pauseus 1000 = 10804us 
pauseus 5000 = 50821us
The results using the variable (w2) are completely consistent (but may be different if even a tiny change is made to the program structure). However, the values using a "constant" differ considerably because of the variable token widths and boundaries. Note that the same result for PAUSEUS 2 and 5 is NOT a bug (just a coincidence), they will be quite different if the program is changed even slightly !

For anyone who wants to check the method (or adapt it for their own measurements) here is my test program. Maybe one day I will "tidy it up" to be a little less obscure, but I've found it to be a very useful tool. However it will only run a "real" M2, not an X2 or the simulator. Note the "sanity checks" which may show if a system interrupt has occurred and occasionally the program may produce a result exactly 256 in error.

Code:
#picaxe 20m2			; Or any other M2
#no_data

symbol TMR1L = $16		; SFRs only tested with M2 PICAXEs
symbol TMR1H = $17
symbol T1CON = $18

exectimes:
;	pause 100    ; Make a tiny change to this (or any) line and the results may be different !
	for b25 = 0 to 256 step 64		; Sanity check with different initial Timer values
	w13 = 0					; Null delay (subroutine call, etc.)
	b1 = b25					; Not used
	b2 = b25					; Not used
	sertxd(cr,lf,"Skew= ",#b25," Overhead= ")
	gosub start
	gosub measure
	gosub show
	w13 = w11						; Set NUL time
	for b1 = 0 to 10
		lookup b1,(0,1,2,5,10,50,100,200,500,1000,5000),w2
		sertxd(cr,lf,"pauseus w2 =",#w2," = ")		; Test 0 Code
		gosub start
		pauseus w2 
		gosub measure
		gosub show
	next b1

	sertxd(cr,lf,"pause w2 =0 = ")			; Test 1 Code
	w2 = 0
	gosub start
	pause w2
	gosub measure
	gosub show
	
	sertxd(cr,lf,"pause w2 =1 = ")			; Test 1 Code
	w2 = 1
	gosub start
	pause w2
	gosub measure
	gosub show

	sertxd(cr,lf,"pause w2 =2 = ")			; Test 1 Code
	w2 = 2
	gosub start
	pause w2
	gosub measure
	gosub show
			
	sertxd(cr,lf,"pause 0 = ")				; Test 2 Code
	gosub start
	pause 0
	gosub measure
	gosub show
	
	sertxd(cr,lf,"pause 1 = ")				; Test 3 Code
	gosub start
	pause 1
	gosub measure
	gosub show	

	sertxd(cr,lf,"pause 2 = ")				; Test 4 Code
	gosub start
	pause 2
	gosub measure
	gosub show
				
	sertxd(cr,lf,"pauseus 0 = ")				; Test 5 Code
	gosub start
	pauseus 0
	gosub measure
	gosub show

	sertxd(cr,lf,"pauseus 1 = ")				; Test 6 Code
	gosub start
	pauseus 1
	gosub measure
	gosub show
	
	sertxd(cr,lf,"pauseus 2 = ")				; Test 7 Code
	gosub start
	pauseus 2
	gosub measure
	gosub show	
	
	sertxd(cr,lf,"pauseus 5 = ")				; Test 8 Code
	gosub start
	pauseus 5
	gosub measure
	gosub show	
	
	sertxd(cr,lf,"pauseus 10 = ")				; Test 9 Code
	gosub start
	pauseus 10
	gosub measure
	gosub show

	sertxd(cr,lf,"pauseus 50 = ")				; Test 10 Code
	gosub start
	pauseus 50
	gosub measure
	gosub show
	
	sertxd(cr,lf,"pauseus 100 = ")			; Test 11 Code
	gosub start
	pauseus 100
	gosub measure
	gosub show	
	
	sertxd(cr,lf,"pauseus 200 = ")			; Test 12 Code
	gosub start
	pauseus 200
	gosub measure
	gosub show

	sertxd(cr,lf,"pauseus 500 = ")			; Test 13 Code
	gosub start
	pauseus 500
	gosub measure
	gosub show
	
	sertxd(cr,lf,"pauseus 1000 = ")			; Test 14 Code
	gosub start
	pauseus 1000
	gosub measure
	gosub show	
	
	sertxd(cr,lf,"pauseus 5000 = ")			; Test 15 Code
	gosub start
	pauseus 5000
	gosub measure
	gosub show

	sertxd(cr,lf,"Nul Test: ")				; Sanity check
	gosub start
	gosub measure
	gosub show	
	sertxd(cr,lf)

	pause 10000
	next b25	

; Subroutines
start:
	pokesfr TMR1L,b25				; Sanity check
	pokesfr TMR1H,0
	return
measure:
	peeksfr TMR1H,b22				; Read 1st Hi byte
	peeksfr TMR1L,b24				; Read Low byte
	peeksfr TMR1H,b23				; Read 2nd Hi byte
report:
	if b24 < 128 then inc b22 endif
	w11 = b22 + b23 / 2				; Average Start High
	b23 = b22
	b22 = b24					; Start Low byte
	w11 = w11 - w13 - b25
	return
show:	
	sertxd (#w11,"us ")	
	return
Cheers, Alan.
 

stan74

Senior Member
I tried some ebay cheap steppers with this or some similar code
Code:
;28x2 A.0 to A3 are unipolar motor pins 
#picaxe 28x2
Symbol oYellowLED       = C.2

symbol posrotor         = b0
symbol direc            = b1
symbol outbyte          = b2
symbol motorspeed       = b3
symbol tempmotorspeed   = b4
'
'      Misc Constants
Symbol False            = 0
Symbol True             = 1
'
'      Timer Constants
Symbol mskBGTimer       = %10000000 'When only the timer is running (normally would have hInt0 & 1 config as well)
Symbol flgBGTimer       = %10000000 'When only the timer is running (normally would have hInt0 & 1 config as well)
Symbol tmrIntOn1stTick  = 65535     'Interrupt to be caused by roll over on first major tick
Symbol tmr10mS_16        = 64911     '= 65536 - (Treq * 1,000,000 / Clk / 256)
'Symbol tmr100mS_8x4     = 62411     '= 65536 - (Treq * 1,000,000 / Clk / 256)
                                    ' Where: Treq = Required Time in microseconds; Clk = 16,000,000.
'
Init: let dirsa=%11111111
      let posrotor=1
      let direc=1
      let motorspeed=0
      let tempmotorspeed=motorspeed
      setfreq m16
      '
      'Start the background timer (runs continuously)
      TOFlag = False
      Timer = tmrIntOn1stTick             '
      SetTimer tmr10mS_16                 'Expires after (every) 100 milliseconds
      SetIntFlags flgBGTimer, mskBGTimer  'Set timer 0 to interrupt
      '
      ' **** Main Loop ****
do
;let direc=1
;for w6=1 to 65535
;next w6
;pause 2000

;let direc=0
;for w6=1 to 65535
;next w6
;pause 2000
loop  

 
Interrupt:  High oYellowLED
            If tempmotorspeed > 0 then
               dec tempmotorspeed
            Else
               let tempmotorspeed=motorspeed
               if direc=0 then
                  inc posrotor
                  if posrotor=8 then
                     let posrotor=1
                  endif 
               else
               dec posrotor
               if posrotor=0 then
                  let posrotor=8
                  endif
               endif
               lookup posrotor,(0,%00000011,%00000010,%00000110,%00000100,%00001100,%00001000,%00001001),outbyte
               pinsa=outbyte
            EndIf
Int_Enable: TOFlag = False                            'Clear the flag
            Timer = tmrIntOn1stTick                   'Reset the timer
            SetIntFlags flgBGTimer, mskBGTimer        'Set timer 0 to interrupt
            Low oYellowLED
            return
I got 2 motor code as well,same but 2 motors,more pins
 

rq3

Senior Member
Wow. It's really amazing how far off the responses to the OP question have become. He wanted to accelerate a stepper from a dead stop to some given speed, using a dedicated stepper driver. His question was valid, because most stepper motors won't go from zero to max step rate in one go. From what I understand, his question was how to fix that. NOT how to phase sequence stepper coils or anything like that. Go back to the original post, and try again folks.
 

AllyCat

Senior Member
Hi,

Hmm, the code seems to run at maximum speed (100 Hz ?) when "motorspeed" is set to zero, half-speed if set to 1 , 1/3 speed for 2, etc., but I can't see any code for acceleration / deceleration. Also, there appears to be a bug, so it uses only 7 phases (Coil on A.0 is never driven alone).

Cheers, Alan.
 

AllyCat

Senior Member
.. the OP question was valid, because most stepper motors won't go from zero to max step rate in one go. From what I understand, his question was how to fix that...
+1 . But the OP does rather appear to have lost interest in the thread, with no answers to questions since page 1. If he really does need a step rate of 2 kHz and a speed "ramp" in one second, then the PICaxe instruction timings might be quite critical (probably ruling out interrupts).

Cheers, Alan.
 

Satchid

Member
Thank you all very very much. None of the posts are in vain. some where not strictly on topic, but I learned allot from them.

I did not responded that much because I am building the hardware to test. It is almost done so far that I can test the code.

What I have is a triangular platform (about 1m per side) with a driving wheel (driven with a stepper motor) in the front corner. This front driven wheel has a vertical axis and is driven by a stepper motor to make the steering action (there is a driving stepper and a steering stepper).

The speed of the platform will be around 1 or 2 meter/minute. I need also a short starting speed for the driving motor.

There is a line following system that will activate the stepper via a picaxe base (picaxe28x2) with a pulse train. I plan between 7 and 12 sensors. The more sensors that are sensing a deviation, the farther the "steering wheel turns to bring the cart back on track. At the moment I have no Idea how fast that will be. The max motor rpm on a stepper can get higher when the motor speed is ramped up then when it is started instantaneous.
 

AllyCat

Senior Member
Hi Willy,

Thanks for the reply. With hindsight it probably would have been better to add your questions to the original 2010 thread because much of the background detail is there (and it might even have sent a "wakeup" email notification to Alistairsam).

Unfortunately the program itself is rather poorly documented and with many "magic numbers" (maybe related to the PICaxe PWM, the stepper, the driver or the OPs application), so I doubt if anybody bothered to analyse the code fully (certainly I didn't). I still haven't read all of that thread, but I hope you did!

However, I have now looked in more detail at the program listing and it may indeed be a good starting point for what you require. The original designer had to move from an M1 to an X2 chip (because M2s were not available then), but now an M2 may be "good enough", or an X2 might simplify the structure by using the timer in place of PWM. Personally, I think that the designer confused the program by using the X2-specific >> (right shift) operator in place of a simple / (divide).

I tryed to figure out how i could set the max speed of the steppermotor? But did not succeeded.
I'm rather surprised by this because line 42 of the program says let Fmax = 2400 so the change shouldn't be difficult. However, the comment a few lines above does confuse the issue with ''Enter max freq as max freq / 10 kHz', which is obviously wrong (it implies a max frequency of 24 MHz). I can't guess what the writer intended (particularly as frequencies are specified simply in Hz a few lines earlier and could be the same here), nor whether it is the microstepping "clock" frequency or the basic stepping (coil poles) frequency. :confused: So I can't predict what changes may be needed, but it should be reasonably easy if you have some real hardware in front of you.

I would allso like to know how i can change the accelleration.
I mentioned in previous threads that the code probably needs to use either a "lookup" method or a "calculation" method to achieve a "logarithmic" PWM-period and it actually uses both. The decelleration section of the program has a clear label, but there is not one for acceleration (which is actually most of the second half of the program ! ). At low speed (frequency) it accelerates in steps of 25 % (+F >> 2), at medium speed, steps of 12% (+F >> 3) and high speed steps of 3% (+F >> 5) which relates to slowly increasing the drive power, as I described in #18. But the control could be more flexible by using a simple "/" rather than the enforced binary power law of the ">>" .

Here are a few of the crucial lines of code with some comments added:

Code:
'28x2
 let Fmin = 50
 let Fmax = 2400

 F = Fmin
 Select Case F
 Fdiff = F >> 2                       ; Present Frequency / 4  (= 25%)
 Case < 187 : F = F + Fdiff       ; Increase F by 25%
.......
 Fdiff = F >> 3                       ; Present Frequency / 8  (= 12%)
 .....
 Fdiff = F >> 5                       ; Present Frequency / 32  (= 3%)
 Case > Fmax  Return              ; Max speed has been reached
 percal2 = 20000 / F               ; PWM period is <constant> / Frequency

Decel:
 Fdiff = F >> 4                        ; Present Frequency / 16  (= 6%)
 Case > 790 : F = F - Fdiff        ; Reducee F by 6%
The rate of acceleration doesn't appear to be set by any specific delay (PAUSE) commands, just by the raw executiion times of the PICaxe instructions. I've found those times quite hard to predict for the SELECT .. CASE program structure, except that it does seem quite "slow" comapred with IF .. THEN, or particularly ON .. GOTO. ;)

Cheers, Alan.
 
Last edited:

hippy

Technical Support
Staff member
Sometimes it may be better to forget how someone has done something in a past project and focus more on what you have and need it to achieve, just use what has been done as a reference rather than a solution.

Something which needs to move at a metre per minute would not seem to require that much stepper speed by my reckoning though that would depend upon gearing ratios. It might be worth starting with what gear ratio you have or would be appropriate, then determine what step rates you actually require.
 

oracacle

Senior Member
I would start by not just getting the hardware done and as hippy suggests with figuring out how fast you need the motor to go. You are going to need to know the diameter of the drive wheel and the gear ratio (if you used gear) to calculate the speed that the motor need to turn.

if the wheel is 8cm in diameter, you would need 4 turns per second (for 1m/s), or 800hz pulse with direct drive - this is, as shown by Circuit is achievable with toggle option.

while it seems great to use code that others have written and are known to work, unless you understand them completely and have taken into the account of the application of the system you will most likely be better off starting from scratch - its s great way to learn.
 

Satchid

Member
Hi,
I need 1700 Hz for motor input. Surely the motor without the cariage will start with that freq. But the inertia of the cariage and the load might make that the the motor is stalling at startup. That is why I need to build the thing to test. At the end it might work wihout ramp up but I doubt it.
Concernig making ing the program, you are both right to start a program from scratch and make it to wath I need. But my programskils are verry small.
Thank you all,
Willy
 

rq3

Senior Member
Hi,
I need 1700 Hz for motor input. Surely the motor without the cariage will start with that freq. But the inertia of the cariage and the load might make that the the motor is stalling at startup. That is why I need to build the thing to test. At the end it might work wihout ramp up but I doubt it.
Concernig making ing the program, you are both right to start a program from scratch and make it to wath I need. But my programskils are verry small.
Thank you all,
Willy
Let's make the maths easier, and assume you need 1600 steps per second (rather than 1700). A typical 200 steps per revolution stepper, (1.8 degree per step), driven by the appropriate chip which provides the required H-bridge actuation at each "step" pulse, would require 200 pulses to complete a full revolution. At 1600 pulses per second, that would be 1600/200=8 revolutions per second, or 480 RPM (revolutions per minute). Very few stepper motors will leap to this speed instantaneously.

If you are microstepping, the motor driver chip would require faster step pulses to maintain the same speed. If you require 1/32 microstepping, the driver chip would require 200*32=6400 step per second pulses to drive the motor at the same 480 revolutions per minute. Very, very, very few stepper motors will leap to this speed instantaneously.

A common misunderstanding is that folks assume that steppers are voltage driven. They are not. They are current driven. Which is why stepper driver chips take control of the motor current, and prefer very high (10-100 volts) motor supply voltage. The driver chip determines when the motor inductance has received enough current to make the step; in general, the higher the motor voltage, the better (faster stepping, within the driver's voltage limits).
 

hippy

Technical Support
Staff member
if the wheel is 8cm in diameter, you would need 4 turns per second (for 1m/s), or 800hz pulse with direct drive
I agree with your maths, but the speed required is 1 metre per minute, not 1 metre per second, so a stepping rate for a directly coupled stepper of about 14 steps per second.

If there were 100:1 gearing that would require some 1400 steps per second with about 0.00005 mm travel per step.

It seems that the gearing could be reduced from 100:1 to make the stepping rate more manageable.
 

stan74

Senior Member
Hippy said in a previous thread that you apply pulses and "they fly". I never figured them using cheap unipolar motor/gearboxes from ebay and the info provided by forum users who know how to use them makes it seem even more complicate,well to me. You'd think if you send a pulse to the say 4 pins so the coils are energised in the sequence that makes the rotor turn to next position then the next pulse quicker up to a maximum frequency of pulses in order to the pins as needed for full or half wave then a maximum is achieved. Indeed I got to 140Hz and the motor stood still and whined. As erco said.like his ex. Get it turning then speed it up. I hate them. Good luck. How do you keep them going...don't mention that.
 

Satchid

Member
Hi All, I want to thank all af you that tryed to help me!
I am abandon the picaxe in this in favor of a old standard pc with windows xp or something use mach3 to drive the dolly only for the driving.
I will use the "x" axis. there I can program the speed and distanses to accellerat and desellerate easilly.

I can not do that for the steering that I asked about in http://www.picaxeforum.co.uk/showthread.php?30093-Steering-a-dolly-by-means-of-a-black-line-lt .

But, and specially from Hippy I learned allot . It is not allways easy because a 73Year old brain is not as flexible anymore, and de lanuige is not as aesy as my own, but I learn.

Gratefull,
Willy
 
Top