I have a DDS based motor controller with an Arduino. Working great to control AC synchronous motors. Now I notice that I will likely have to implement an acceleration/deceleration routine for the motor to control spin up and spin down. Does anyone know the best techniques / code ideas for how to best implement this? The general idea is to start at a specified low RPM, accelerate in steps to the target RPM and do the reverse for deceleration. (note, cannot use Delay function as this has been disabled in the project to prevent problems with the DDS timing)
It's a lot of code, lots of features so maybe I will just show some key parts of code that have to do with running the motor:
Code that turns motor on or off (user action first case only shown):
switch (Action) {
case 1:
// Start/Stop Pressed
Action = 0; // clear action code
if (runState1 == 0) { // Check if motor is OFF
sineON(); // turn on PWMs - RUN ON !!!!
speedChg = 0; // reset speed change flag - new run
}
if (runState1 == 1) { // Check if motor is ON
sineOFF(); // turn off PWMs - RUN OFF !!!!
if (speedChg == 1) { // speed was changed during last run - can decide to store in EEPROM or not here.
// enter code here for storing speed change values if desired. Future Option?
}
}
updateLCD(); // update the display
ledSW();
break;
Motor Turn On and Off Functions:
//******************************************************************
// sineON function;
// Function turns Sine generators ON and sets status bit.
// Returns 1 for on
//******************************************************************
boolean sineON() {
sbi(TIMSK2,TOIE2); // enable Timer2 Interrupt - TURN SINE WAVES ON !!!!
runStatus |= (1 << 1); // Set RUN flag bit 1 in run status register - sine ON
return true;
}
//******************************************************************
// sineOFF function;
// Function turns Sine generators OFF and clears status bit.
// Returns 0 for off
//******************************************************************
boolean sineOFF() {
cbi(TIMSK2,TOIE2); // disable Timer2 Interrupt - TURN SINE WAVES OFF !!!!
runStatus &= ~(1 << 1); // reset RUN flag bit 1 in run status register - sine OFF
return false;
}
Interrupt service routine for DDS operation:
//******************************************************************
// Timer2 Interrupt Service at 31372,550 KHz = 32uSec
// this is the timebase REFCLOCK for the DDS generator
// FOUT = (M (REFCLK)) / (2 exp 32)
// runtime : 8 microseconds?? ( inclusive push and pop)
//******************************************************************
ISR(TIMER2_OVF_vect) {
sbi(PORTB,5); // Test / set PORTB,5 (pin13) LED - test pin high to observe timing with a oscope
phaccu = phaccu + tword_m; // soft DDS, phase accumulator with 32 bits
icntA = phaccu >> 24; // use upper 8 bits for phase accumulator as frequency information
icntB = icntA - phaseShift; // calculate offset for lookup table value by -phaseShift setting for PWM B sine
// where value of 64 = 90 degrees, each digit =~ 1.406 degrees
// read value from ROM sine table and send to PWM DAC A
OCR2A=pgm_read_byte_near(sine256 + icntA);
// read value of sine table xx degrees out of phase to output 2nd sine on PWM DAC B
OCR2B=pgm_read_byte_near(sine256 + icntB);
if (icnt1++ == 125) { // increment variable c4ms every 4 milliseconds - used to compute 1 sec. delay for analogRead
c4ms++;
icnt1 = 0;
}
cbi(PORTB,5); // reset PORTB,5 test pin (pin13) LED
}
Hope that is enough code to give you an idea of what is happening. In any case looking to see if their is a formula/method/technique for properly doing an accel decel. Thanks
BitChanger:
In any case looking to see if their is a formula/method/technique for properly doing an accel decel. Thanks
It's just like any control algorithm.
In this case you need to start with a current actual speed and a target speed as inputs, and have an output that controls the motor in some way. For example it might be that you have a PWM regulator that effectively gives you torque control - or you might have a stepper motor where you control the speed explicitly.
Your algorithm needs to control the motor control output in order to drive the motor speed towards your target. You could use a PID algorithm for this (there's a library that implements this on Arduino) or just hand-code your own - code in knowledge of what acceleration profile you want the motor to follow and vary the motor control to follow that profile.
PS
To me, functions that return constant values unrelated to what happened in the function smack of poor design - particularly when the return value is not actually used. To design robust code, your called code needs to indicate the normal and abnormal events that have occurred, and the calling code needs to deal with them. Returning garbage hides the places where the return value matters. Ignoring a return value that doesn't matter hides the places where you're ignoring return values that do matter.
changing tword_m up and down you could vary freq., and motor speed consequently.
Good stuff, done!
Thanks.
As for speed change, yes, as I was writing this post, my ideas started to clear up and I could see how to implement the speed change within the 'sineON' 'sineOFF' routine. Just sorting out my options now but it should work fine.
Thanks for the help.
SoundBound
BitChanger:
In any case looking to see if their is a formula/method/technique for properly doing an accel decel. Thanks
It's just like any control algorithm.
In this case you need to start with a current actual speed and a target speed as inputs, and have an output that controls the motor in some way. For example it might be that you have a PWM regulator that effectively gives you torque control - or you might have a stepper motor where you control the speed explicitly.
Your algorithm needs to control the motor control output in order to drive the motor speed towards your target. You could use a PID algorithm for this (there's a library that implements this on Arduino) or just hand-code your own - code in knowledge of what acceleration profile you want the motor to follow and vary the motor control to follow that profile.
PS
To me, functions that return constant values unrelated to what happened in the function smack of poor design - particularly when the return value is not actually used. To design robust code, your called code needs to indicate the normal and abnormal events that have occurred, and the calling code needs to deal with them. Returning garbage hides the places where the return value matters. Ignoring a return value that doesn't matter hides the places where you're ignoring return values that do matter.
Thank you Peter H. for the PID information, just what I was looking for, a proper technique to code. I will see if I will use the library or just write my own code for it.
As for the return values, you are correct. The code is in a rough alpha state and contains code that is in place as my thoughts and options were developing. Some of these ideas never took form and I still have to go through the code to clean out the superfluous stuff such as those never developed return data.
Yankee:
I had never heard of a DDS motor controller before. What is it?
AC synchronous motors are used in many vinyl turntables. The speed regulation of the motor is controlled by the frequency of the sine wave of it's AC supply (usually 60Hz from the line voltage). I have built a variable frequency dual sine wave generator to drive such motors so I can accurately set the RPMs of a turntable by varying the sine frequency. A DDS generates a very precise sine wave via digital synthesis. I use the Arduino to generate the two out of phase sine waves that are then amplified to drive the motor.
You can see detailed information about my project and my progress here at my audio blog, if it interests you:
Just a quick note to say that I got the acceleration code up and running. Thanks for the tips and info that helped me sort this out in my brain so that I could push out the necessary code !!