PDA

View Full Version : Make an acceleration/deceleration ramp : any ideas?



pxidr84
- 31st March 2011, 18:36
Hi,

I'm currently making a 3-phase VFD for an AC motor.
The program is 70-80% done, but I've to make an acceleration/deceleration ramp.

In other words, I start with a minimum value defined by the user (for exemple : 10), and I reach the maximum value defined by the user (for exemple 1200) linearly in x seconds (again defined by the user).

Here an exemple :
http://img709.imageshack.us/img709/7537/rampf.png

So any ideas how I can do that simply?
-With a low-priority interrupt?
-With a for...next loop?
-etc.

Thanks for your future help.

Jerson
- 1st April 2011, 08:53
If you do not intend running any tasks in the background while doing the acc/deceleration, the following idea may work



Rate = ((Max-Min) *1000)/ Time ' the 1000 is since I assume a mS time base
Here the Time variable is specified in seconds.

Now, using a 1mS time base, you can do this



for x = 0 to rate
Output = Output + Rate ' increase the output by a fraction we calculated
pause 1 ' this is the 1mS time base I talked of
next
Rate could be -ve to decelerate.

pxidr84
- 1st April 2011, 12:34
If you do not intend running any tasks in the background while doing the acc/deceleration, the following idea may work



Rate = ((Max-Min) *1000)/ Time ' the 1000 is since I assume a mS time base
Here the Time variable is specified in seconds.

Now, using a 1mS time base, you can do this



for x = 0 to rate
Output = Output + Rate ' increase the output by a fraction we calculated
pause 1 ' this is the 1mS time base I talked of
next
Rate could be -ve to decelerate.

Hello,

Thanks for your idea, I will try this into my program, but unfortunately I think that the "pause" command will make problems, because a lot of things are running in the background during this acc/deceleration (like the sine PWM generation high priority interrupt, using timer 1).

I think use this in a low frequency and low priority interrupt (with timer 0), maybe the "pause" command will be useless?

Note I'm using Darrel Taylor's interrupts.

J. Mark Wolf
- 1st April 2011, 14:04
My approach would be to generate the "points" you need for the line equation, given your slope and time parameters, in Excel. Then print a CSV file of the results, then copy the CSV file into your program as a table. It'll take some minor editing to generate your table but no big deal, and get the values from the table with Lookup or Lookup2. You can even change the slope of your ramp easily by adjusting the dwell time at each point, etc.

I do this sort of thing a lot for thermistor temperature tables, etc. Saves the time of executing the extensive formula for thermistor values.

mark_s
- 1st April 2011, 14:54
Can you give more info?

What is the motor being used for?

How does the user change the speed?

Typical servo systems use a PID routine.

Henrik Olsson posted a great PID program example on the forum. As I recall the thread mentioned motors and DT interupts.

pxidr84
- 1st April 2011, 17:14
I don't want to use a PID routine or a lookup table (because a lookup table is hungry of program memory space). It's a open-loop inverter.

The user changes the frequency reference by turning a potentiometer connected to a ADCIN port.

Exemple : http://www.youtube.com/watch?v=GeJjEJba4x4

Note the acceleration and deceleration ramp of the output frequency, that changes the speed of the AC motor.

I like to have a routine (in a low-priority interrupt for exemple, to have the most accurate timings) that increments a value from the actual output frequency (for exemple 20Hz) to the frequency reference (for exemple 60Hz, defined by the user) in x seconds (for exemple 10 seconds, can be modified in real-time), and that without using any "pause" command (because my PIC has a lot things to do during this time).

Jerson
- 1st April 2011, 18:07
You can delegate the timekeeping and ramping to the ISR. What you need to pass to it is the 'target' value and 'step size' Step Size could be +ve or -ve depending on which way you want it to move.

the ISR could tick every millisec or maybe more depending on how fast you want to change the output.

Charles Linquis
- 2nd April 2011, 04:03
I don't know how fast your ramp needs to be - but..

I would use a timer interrupt - say 1 millisecond

Multiply ramp time (in seconds) X 1000 to get the number of steps
Take

(endvalue - startvalue)/numberofsteps to get step size
Initialize a counter with the start value and increment the step size in each interrupt.

Depending on your needs, you may have to add some extra increments, because the step size will be an integer, and when multiplied by the number of steps may not exactly equal the
end value.

pxidr84
- 2nd April 2011, 14:05
I don't know how fast your ramp needs to be - but..

I would use a timer interrupt - say 1 millisecond

Multiply ramp time (in seconds) X 1000 to get the number of steps
Take

(endvalue - startvalue)/numberofsteps to get step size
Initialize a counter with the start value and increment the step size in each interrupt.

Depending on your needs, you may have to add some extra increments, because the step size will be an integer, and when multiplied by the number of steps may not exactly equal the
end value.

My maximum acceleration slope is incrementing a variable from 0 to 1200 in one second with a resolution of 1 (steps of 1).

I've tried to "translate" your algorithm into this :


'Variable init
freq var word
maxfreq var word
minfreq var word
stepnum var word
stepsize var word
time var word

'Variables def
minfreq=10
maxfreq=1200
time=10

'Calculate steps
stepnum=time*1000
stepsize=(maxfreq-minfreq)/stepnum

'Init counter
freq=minfreq

main:

' Counter
freq=freq+stepsize

'Update LCD
lcdout $fe,$2,"Frequency: ",dec5 freq

' 1ms time base (simulates an interrupt)
pause 1

goto main


It is correct? Because the result of "stepsize" is a float in this case (0.119)...

Charles Linquis
- 2nd April 2011, 18:34
According to my calculations -

endval = 1200
startval = 20


endval - startval = 1180
ramp time in milliseconds = 1000

1180/1000 = 1.18 (so 1180/1000 = 1 = increment)
1180//1000 = 180 (=remainder = fractional)



fractional = 0
oldfractional = 0

frequency = 20 ; start value

ISR:

Frequency = frequency + increment ; increment the main part

fractional = fractional + remainder ; Deal with the fractional part
If fractional dig3 != oldfractional ; keep adding up the partial until we reach 1000
oldfractional = fractional ; update so we can see the next change
frequency = frequency + 1 ; add a count - since we broke 1000
Endif


This will increment by one every program loop and then add an extra count every 5 (or so) loops. I haven't tested the algorithm, but I believe it should deal properly with the 'wrap' when "fractional" overflows.

pxidr84
- 2nd April 2011, 20:45
According to my calculations -

endval = 1200
startval = 20


endval - startval = 1180
ramp time in milliseconds = 1000

1180/1000 = 1.18 (so 1180/1000 = 1 = increment)
1180//1000 = 180 (=remainder = fractional)



fractional = 0
oldfractional = 0

frequency = 20 ; start value

ISR:

Frequency = frequency + increment ; increment the main part

fractional = fractional + remainder ; Deal with the fractional part
If fractional dig3 != oldfractional ; keep adding up the partial until we reach 1000
oldfractional = fractional ; update so we can see the next change
frequency = frequency + 1 ; add a count - since we broke 1000
Endif


This will increment by one every program loop and then add an extra count every 5 (or so) loops. I haven't tested the algorithm, but I believe it should deal properly with the 'wrap' when "fractional" overflows.

I've tested this :

DEFINE OSC 32
DEFINE LCD_DREG PORTC
DEFINE LCD_EREG PORTD
DEFINE LCD_RSREG PORTD
DEFINE LCD_EBIT 0
DEFINE LCD_RSBIT 1
DEFINE ADC_BITS 10
DEFINE LCD_COMMANDUS 10000
DEFINE LCD_DATAUS 2000

'Variable init
freq var word
maxfreq var word
minfreq var word
remain var word
increm var word
time var word
potsense var word
frac var word
oldfrac var word
delta var word

'Variables def
minfreq=10
maxfreq=1200


'Calculate steps
delta=maxfreq-minfreq
time=1000

increm=delta/time
remain=delta//time

frac=0
oldfrac=0
freq=10

main:

' Counter
freq=freq+increm
frac=frac+remain
if frac dig 3 != oldfrac then
oldfrac=frac
freq=freq+1
endif

' 1ms time base (simulates an interrupt)
pause 1

lcdout $fe,$2,"Frequency: ",dec5 freq

goto main

And it seems to work well, the "freq" value get incremented, and if I change the "time" variable, the "freq" value increments more or less quickly.

But the "freq" increments without stopping, and this over 1200!

Charles Linquis
- 2nd April 2011, 21:17
stop the incrementing or stop the interrupt when freq >= maxfreq

pxidr84
- 3rd April 2011, 17:28
stop the incrementing or stop the interrupt when freq >= maxfreq

I've tried this on my real PIC with a potentiometer :


DEFINE OSC 32
DEFINE LCD_DREG PORTC
DEFINE LCD_EREG PORTD
DEFINE LCD_RSREG PORTD
DEFINE LCD_EBIT 0
DEFINE LCD_RSBIT 1
DEFINE ADC_BITS 10

' ADC registers configuration
ADCON0=%11101
ADCON1=%10000
ADCON2=%10000110
ADCHS=%1010101
ANSEL0=%11110000

' Variable init
freq var word
rfreq var word
maxfreq var word
minfreq var word
dum6 var word
dum7 var word
accel var word
decel var word
frac var word
oldfrac var word
potsense var word

' Variables def
maxfreq=1200
minfreq=10
accel=1000
decel=1000

' Start freq
freq=minfreq

main:

' Start ADC conversion
ADCON0.1=1
WHILE ADCON0.1=1:WEND

' Store ADC results
potsense.HighByte=ADRESH
potsense.LowByte=ADRESL

' Convert pot result
rfreq=(potsense<<6)**maxfreq

' Acceleration ramp
if freq<rfreq then
dum6=(rfreq-minfreq)/accel
dum7=(rfreq-minfreq)//accel
freq=freq+dum6
frac=frac+dum7
if frac dig 3<>oldfrac then oldfrac=frac:freq=freq+1
endif

' Deceleration ramp
if freq>rfreq then
dum6=(maxfreq-rfreq)/decel
dum7=(maxfreq-rfreq)//decel
freq=freq-dum6
frac=frac-dum7
if frac dig 3<>oldfrac then oldfrac=frac:freq=freq-1
endif

' Display results
lcdout $fe,$2,"Frequency: ",dec5 freq
lcdout $fe,$c0,"Ref: ",dec5 rfreq

pause 1

goto main

And unfortunately the timing is not very accurate, it depends of the "maxfreq" variable defined. I can have a 1 or 2 seconds gap.
And above 1000, the "accel"/"decel" values doesn't increase the time of the ramp.

Charles Linquis
- 3rd April 2011, 23:19
If you use an interrupt, the timing is guaranteed.

Your LCD can't possibly update every millisecond.