Running several Steppers simultaneously, easy and simple.

Hi people. This might be nothing new, but if it can help running 3D-printers and CNC-Routers even on the smallest Arduinos.
Check it out.

#######################################

/*
This is the simplest way I could find to run multiple Steppers simultaneously
with different speeds and diffenrent directions with no lost steps on even
the smallest Arduino availible.

use:
void Multi_Step(
float Time, <-- Time to run the motors (same time for all)
unsigned long int Steps_X, <-- Steps for X-Axes
unsigned long int Steps_Y, <-- Steps for Y-Axes
unsigned long int Steps_Z, <-- Steps for Z-Axes
unsigned long int Steps_A <-- Steps for A/E-Axes
){

Multi_Step(1000,100,200,300,400) will run
100 steps on X-Motor &
200 steps on Y-Motor &
300 steps on Z-Motor &
400 steps on A/E-Motor
within 1000 miliseconds (one second)

Down't forget to set the pins for directions, before running the motors.

*/

unsigned int Xstep=1;
unsigned int Xdir=2;
unsigned int Ystep=3;
unsigned int Ydir=4;
unsigned int Zstep=5;
unsigned int Zdir=6;
unsigned int Astep=7;
unsigned int Adir=8;
unsigned int Amp=9;

void setup() {
pinMode(Xstep, OUTPUT);
pinMode(Xdir, OUTPUT);
pinMode(Ystep, OUTPUT);
pinMode(Ydir, OUTPUT);
pinMode(Zstep, OUTPUT);
pinMode(Zdir, OUTPUT);
pinMode(Astep, OUTPUT);
pinMode(Adir, OUTPUT);
pinMode(Amp, OUTPUT);

digitalWrite(Amp, 1);
digitalWrite(Xdir, 0);
digitalWrite(Ydir, 0);
digitalWrite(Zdir, 0);
digitalWrite(Adir, 0);
}

void Multi_Step(
float Time,
unsigned long int Steps_X,
unsigned long int Steps_Y,
unsigned long int Steps_Z,
unsigned long int Steps_A
){
unsigned long int Loops=Timefloat(6.5);// use 6.5 on 16Mhz
boolean XS=1;
boolean YS=1;
boolean ZS=1;
boolean AS=1;
float DividerX=float(float(Loops)/float(Steps_X
4));
float DividerY=float(float(Loops)/float(Steps_Y4));
float DividerZ=float(float(Loops)/float(Steps_Z
4));
float DividerA=float(float(Loops)/float(Steps_A*4));
unsigned long int V2X;
unsigned long int V2Y;
unsigned long int V2Z;
unsigned long int V2A;
unsigned long int VX=0;
unsigned long int VY=0;
unsigned long int VZ=0;
unsigned long int VA=0;
for (unsigned long int T=0;T<=Loops;T++){
V2X=T/float(DividerX);
V2Y=T/float(DividerY);
V2Z=T/float(DividerZ);
V2A=T/float(DividerA);
if (V2X!=VX){
digitalWrite(Xstep, XS);
XS=XS xor 1;
}
if (V2Y!=VY){
digitalWrite(Ystep, YS);
YS=YS xor 1;
}
if (V2Z!=VZ){
digitalWrite(Zstep, ZS);
ZS=ZS xor 1;
}
if (V2A!=VA){
digitalWrite(Astep, AS);
AS=AS xor 1;
}
VX=V2X;
VY=V2Y;
VZ=V2Z;
VA=V2A;
}
}

//run some example-turns
void loop() {
Multi_Step(5000,1600,800,400,200);
Multi_Step(4000,1600,800,400,200);
Multi_Step(3000,1600,800,400,200);
Multi_Step(2000,1600,800,400,200);
Multi_Step(3000,1600,800,400,200);
Multi_Step(4000,1600,800,400,200);

Multi_Step(5000,1600,800,400,200);
Multi_Step(4000,1400,1000,200,400);
Multi_Step(3000,1200,1200,400,200);
Multi_Step(2000,1000,1400,200,400);
Multi_Step(3000,800,1600,400,200);
Multi_Step(4000,600,1800,200,400);
}

But Bressenham's does all that without resorting to slow floating point - its
the standard technique. You haven't set the direction pins from the
actual sign of the arguments to Multi_step().

With either method you need to manage acceleration too or you'll mis-step anyway.

Its illuminating to see how the RepRap code does this as it handles acceleration
as well as XYZ in one unified framework, for instance

I've been thinking of using micros() (or something derived from it) to manage the steps of multiple motors.

I agree with @MarkT that integer arithmetic is essential for speed.

I must get round to writing a test program.

I must also have a look at the code Mark has linked to.

...R

Just to give a bit of motivation for the RepRap DDA code:

DDA = digital differential analyser, basically a method that's
done all in integer arithmetic based on difference equations -
which enables the order of an operation to be dropped by one
when computing the same thing with slightly different inputs
each time round.

Bresenham's line drawing algorithm is the classic example, and
is adapted from graphics to stepper control very easily.

Normally following an arbitrary ratio involves multiplying
by the ratio. However stepping along a line on a given ratio
can be done by adds, compares and conditional subtracts, rather
like the innards of a hand-coded muldiv routine. The sequence of
stepping multiple steppers on fixed ratios is basically the exact same
problem so Bressenham's can do that too.

But DDA techniques can do more, for instance following curves,
such as Bresenham's circle algorithm, where square-root is again
replaced by adds/subtracts in integers.

The somewhat related and equally powerful technique of DDS
(direct digital synthesis) can be used to manage the time domain,
and DDS is really based on DDA approach, but for calculating
a phase/angle that changes over time, and this is then used to
generate waveforms, typically sine/cosine, but here can generate
the step pulses. DDS relies on running a set of calculations at
a fixed rate in time, typically just updating phase by a phase-increment.

So one basic approach to generating stepper signals could be
to use a high-frequency timer interrupt to run DDS to determine
when to update a Bressenham's algorithm. The phase-increment
variable is ramped up and down to synthesize acceleration, the
Bressenham's does the work of coordinating between several
steppers. Running such a loop at 50kHz or more isn't beyond
the realms of possibility since the work is all add/sub compare.

@MarkT

I've had a quick look at that Github link. It looks like it is intended to figure out how to get "there" from "here" where there is the variable called target and here is wherever the tool-tip is presently located.

I confess to being lazy and don't fancy ploughing through several other pages of Reprap code so I would appreciate it if you would tell me if I am way off beam. If so I may do some more research.

Assuming I have roughly the right idea of what it does my inclincation is to do all that stuff on the PC which has plenty of time and resources to do maths. The PC can then just pass some simple numbers for the Arduino to implement the appropriate numbers of steps for each motor.

...R