I just pushed a new library to drive stepper motor on linear devices. There are plenty of library for this purpose, but I decided to write my own with the following features :
Interrupt driven : all the timing are done with interrupt, for perfect timing. It use 8-bit timer2, as it has the better interrupt priority, and is not commontly used by other libraries (I just know tone lib which is using this timer)
Autocorrection of missed steps by using two limit switches (one at each end of the linear device). The limit switches are interrupt driven
Multi motor support. The c++ class has been written to support multiple instance, any unused instance don't take any memory space. Each motor could be driven with its own speed.
Support acceleration and braking phases.
The hardware is a suitable stepper driver such as A4988 or similar (or a custom bridge). The only requirement is that the step should occur only on the rising edge of the step pin (low to high level). The lib will immedialely put the step pin to low level after that. It has been done to optimize timing during ISR and so give for execution time to the main loop.
There is a lot to say about this new library, I'm going to write a wiki page on my github. For now, a lot of documentation is already in the files (readme and header file).
Feel free to download it (or pull it with git : the better way !). If any help is required, please post on this topic so that other user could take a look on it.
I've had a brief look at this and you are using a reserved mode of timer2 (100) - you should to use mode 101,
which allows either TIMER2_COMPA or TIMER2_OFV interrupts to be used.
Interesting that CTC mode for timer2 is broken/incorrectly documented, I had not happened on that one before.
Since you are using a regular interrupt, I wondered why you didn't use DDS technique which gives
linear acceleration?
Using timer2 was dicted by the interrupt priority. I pulled my hair starting developping with it because the AVR documentation is wrong !!!!!
I finally understand that mode 100 is the CTC mode (in atmel datasheet, CTC mode is 10, but I can assure you that it is not working !).
Nevertheless I'm very interesting of what you are talking about DDS technique. I don't know what is is, but I also pulled my hair (I don't have much more hair on my head) to try to do easy quite constant acceleration. Could you tell me more or put a link on it ?
Thanks in advance.
For all the other user (including you may be), I took some time to write a 2 pages wiki. It is not complete, but it could be a start.
if (state == IDLE)
return ;
if (state == ACCELERATING)
{
velocity += acceleration ;
if (abs(velocity) >= top_speed)
{
state = COASTING ;
velocity = velocity > 0 ? top_speed : -top_speed ;
}
}
int old_phase = phase ;
phase += velocity ;
if ((old_phase ^ phase) < 0) // test for phase wrapping (sign bit flips)
{
boolean forward = velocity < 0 ;
digitalWrite (direction_pin, forward) ;
step_count += forward ? 1 : -1 ;
digitalWrite (step_pin, HIGH) ;
}
if (state == COASTING)
{
// test for time to decelerate, the most complex bit
}
if (state == DECELERATING)
{
int old_veloc = velocity ;
velocity += acceleration ;
if ((velocity ^ old_veloc) < 0) // if velocity sign changes, we passed/reached zero
state = IDLE ;
}
digitalWrite (step_pin, LOW) ;
You probably need long, not int for all the variables for enough speed and acceleration
resolutions, and all the calculations are in steps/interrupt, so scaling by the interrupt
frequency is needed.
The way I detect flips above, I effectively have phase representing units of step/2^15.
You can think of phase as position, velocity as frequency, and the comparison with the
'normal' DDS used to synthesize waveforms is obvious. Driving an accelerating stepper
is just a linear frequency sweep in those terms.
The complexity is in getting enough resolution and calculating when to start
decelerating so you don't skip or add steps.
At its heart the technique is simply:
velocity += acceleration ;
position += velocity ;
being the discrete-difference analog way of saying position is the integral of velocity
and velocity is the integral of acceleration.
Thanks for your reply. That's not far from what I am doing. I'll take a look carefully.
BTW, I'm trying to keep the interrupt routine as light timing as possible, to be able to drive many motors with the same board without delaying the main loop.
Did you try my lib with acceleration? it run fine, even if the acceleration is non constant.
I have to choose to increase interrupt delay and better acceleration. You may help me to do the right choice by comparing constant acceleration and custom one !