Instructables

multiple processes in arduino?

Is there an easy way to run multiple voids at the same time on an arduino uno? preferrably without aditional libraries, but I cannot flash AVR code to it (must be through IDE).  I do NEED to run the processes at the same time, no they do not share pins or variables, and the timing does not need to be precise.  I am trying to run two steppers at the same time, but different speeds, but the big catch is that I don't have "smart" drivers, just a 2003 and 293, so they each require a separate void to move, and they cannot be run simultaneously without running both voids at the same time.  Basically, I'm NOT looking for an alternative, just a way to run two voids at the same time (or switching back and forth very quickly without being affected by "delay();".   

look into timers and interrupts
http://letsmakerobots.com/node/28278
https://www.sparkfun.com/tutorials/326
Heres a better example http://playground.arduino.cc/Code/TimedAction#Example
jduffy54 (author)  spiffomatic641 year ago
Actually, thats about perfect. I was aware of pin-based interrupts, but not of timed interrupts.
Do you know if it will run the two voids simultaneously if the timings coincide?
Im not sure about perfect timings, but as far as I could tell they ran in sync
jduffy54 (author)  spiffomatic641 year ago
I just checked, and though it doesn't multithread, it works fine for what I'm doing.
frollard1 year ago
If you can call it a thread; the arduino AVR processor is a SINGLE threaded device - there are internal and external interrupts that can cause code to execute out of order; but for the most part it's all linear.

I know you're set in wanting multiple concurrent procedures; it's not going to happen. Procedures just don't run in parallel on a limited platform like this.

What you can (need to) do is break down the timing of your steppers into one, single linear timeline, extrapolating for events that instead of
'stepper one move 5 steps' at the same time as 'stepper two move 3 steps'
you have
stepper one step @ time zero
stepper two step @ time one
stepper one step @ time two
stepper one step @ time three
stepper two step @ time three
stepper one step @ time four
stepper two step @ time four
stepper one step @ time five

The frequency used to divide those steps out is the inverse of the period of time, so if you know you want 200 steps per second, then each step takes 1/200th of a second. You can calculate this speed on the fly based on the (usually gcode) instruction of goto xy at speed s. Knowing when in the future an event will happen means you can plan for it, and execute the timing in a linear fashion. so if the current x position is 0 and you need to move 100 steps in .25 seconds, the interval between steps will be 250 milliseconds / 100 = 2.5 milliseconds per step
if at the same time the y direction needs to move from say 0 to 86, it needs to move 86 steps in that same 250 milliseconds = 2.91 milliseconds.

loop
--check inputs for stepper destination
does the stepper need to move (is it at destination)?
-if stepper needs to move, set the time in mS of when the next step will take place-
'if it time for a stepper to move?'
'then move that stepper a step and update the time for it to move next'
'update where the stepper is here'
end if
end loop

note how loop doesn't do much - it just goes very very fast checking whether it needs to move to a goal coordinate, whether it's time to move the stepper(s), if so it does a quick move, then prepares to listen for the next move. You can do as many of these as you want concurrently because each check takes only a few clock cycles and you never actually use a delay which could ignore steps.

There are some REALLY clever tricks used by 3d printer firmwares using hardware timers to do this with complex interrupts because the timing is so tight.
jduffy54 (author)  frollard1 year ago
I am aware that it is a single threaded device, I was asking if I can switch between "threads" very quickly, without being affected by the timing. If I could not, I did plan on "falling back" to the method you described, by switching between steps, but that requires a fancier algorithm and more timr programming than I have now, so I would prefer the original question, of which spiffomatic64's answer seemed pretty close. The timing thing for yours may be a little more difficult than you'd expect, because in my rig, one of the steppers needs to be 1/2 microstepped, while the other needs 4 steps to achieve the same distance. Thus, stepping motor two always requires a delay.

Thanks for your help anyway, I appreciate all the answers recieved here, and have taken the timing equation thing into account.
"I was asking if I can switch between "threads" very quickly, without being affected by the timing."

no. You cannot. period. You must calculate the steps asynchronously - by knowing WHEN they need to step. As for microstepping or half stepping - consider using internal timers to create (essentially) the pwm output that holds at some point between steps, then use your main loop to change what those timers are to do the microstepping.
Long story short, it's a PITA and it's why most all 3d printers use separate 'smart' stepper drivers to offload the microstepping.
jduffy54 (author)  frollard1 year ago
The microstepping isn't what causes a delay, its that the other motor must take four phase-changes for every micro-step of the first motor. Since the motor cannot move instantly, it requires a delay between each step, and I will just use the other answer's thing on timed interrupts.
you just need to decide how long a step is in microseconds...

amount of time you want to take
* 200 steps per rev
* x microsteps per step
/ number of revolutions you want


...you just divide it further, microsteps just changes how long you linger on each step.
Read my first reply.
you don't code step,delay,step,delay,step -- because you can do NOTHING during delay();
instead you code:
check time, if time to step, then step and set time flag for next step time

so any timeframe can be had for ANY number of motors, you just maintain a number indicating what millis() or micros() the next step will be.

unsigned long curtime = micros();
motor1nextTime = 100; //100 microseconds until first step
motor1interval = 50 //50 microseconds between steps
motor1nextTime = 100; //100 microseconds until first step
motor1interval = 300 //300 microseconds between steps

void loop() {
curtime = micros();
if (curtime > motor1nextTime) { //time has elapsed
//do whatever it takes to step the motor here, like call stepper1.step
motor1nextTime = curtime + motor1interval;
} //end if
curtime = micros();
if (curtime > motor2nextTime) { //time has elapsed
//do whatever it takes to step the motor here, like call stepper2.step
motor2nextTime = curtime + motor2interval;
} //end if


} //end loop

Note, no delays; it loops so it never misses a timed important interval -- and sets the flag for when the next time it needs to fire. quick like a bunny.
jduffy54 (author)  frollard1 year ago
I'm not all that concerned about hitting steps at exactly the right time, more so just getting it to run in a roughly straight line. It takes a lot more work to change the entire way the code runs than to just change the way the motors are triggered, so I'm STILL going with the other option with timed interrupts
Look for "Real Time Operating systems" for AVR. They exist,.
WWC1 year ago
#include

const int stepsPerRevolution1 = 200;
const int stepsPerRevolution2 = 400;

Stepper myStepper1(stepsPerRevolution, 9,10,);// This is for a 2 wire setup.

Stepper myStepper2(stepsPerRevolution, 11,12,);// This is for a 2 wire setup.

int pos1 = -XX; XX is a value 0 to 100
int pos2 = XX;
int pos3 = -XX;
int pos4 = XX;

myStepper1.step(pos1);
myStepper2.step(pos3);

I am NOT an expert so i hope this is not very far off.
This is my best GUESS to start you off.
I am not sure what you mean about additional libraries, In addition to the libraries you all ready have? This will require the library, but that comes with the IDE.
Should use an LD293 for each stepper.
I would hope more qualified people will chime in for a better more complete answer.
jduffy54 (author)  WWC1 year ago
I'm not currently using the stepper librairy, and I have written my own code for stepping the motors. The library I was talking about is one to run multiple voids at a specific interval, despite the timing of the others, not how to use the ones already in arduino.
Also, I cannot order stuff online very often, so I have made do with a 293, 2003, and three relays for now. If I were to do it again, I'd order several 293s, but I only had one when I started this, and don't want to risk breaking it at this stage (200+ hours of hardware and software, plus $30 in electronics+2 arduinos (fried one), and the rest of the time on code).