Controlling multiple speed-independent stepper motors simultaneously with Arduino.

Many robotic projects require the control of multiples digital and discrete outputs to work simultaneously, the motor interfaces are not an exception due big robotic instrumentation used today, the widespread Arduino control interface has the ability to handle steppers motors even with its own reference function librarys, but when it comes to a much more basic type of control over multiple speed's motors some arrangements need to be done.

The basic operation of a stepper motor and its advantages like position control and torque holding make them a common choise on robotic and industrial aplications, however, the digital control of this kind of motors are no as simplest as regular DC machines and this instruments has not in built feedback interface. The control of this motors are given in at least two steps, the Micro Controller wich give the digital comunication and control interface and the Driver wich allow the controller to handle big power switching, commonly need it for this kind of motor.

DC brush motors rotate continuously when voltage is applied to their terminals. Stepper motors, on the other hand, effectively have multiple "toothed" electromagnets arranged around a central gear-shaped piece of iron. The electromagnets are energized by an external control circuit, such as a microcontroller. To make the motor shaft turn, first, one electromagnet is given power, which makes the gear's teeth magnetically attracted to the electromagnet's teeth. When the gear's teeth are aligned to the first electromagnet, they are slightly offset from the next electromagnet. So when the next electromagnet is turned on and the first is turned off, the gear rotates slightly to align with the next one, and from there the process is repeated. Each of those rotations is called a "step", with an integer number of steps making a full rotation. In that way, the motor can be turned by a precise angle.

The use use of multiple delay funtions on a single Arduino code means that the code has to hold the code until that conditions complay and then reasume the following code. This kind of control is the most basic and well known for controlling single speed motors, and it works pretty well, the delays set the rythm for the step shift perfectly. But when multiple motors have to be handle the use of delays over the processing code means that any step has to be preceded by the delay time of the previous motor need it to complete a step and even this way the switch for velocity means the use of diferent types of hold time.

The key to succesfully control any number of steppers its to program just ONE virtual motor that gives the rythm that any other will move, like in a car, the angular speed of the wheels its a relation of the actual angular speed of the motor by the use of a CLUTH. A virtual motor moving at the top speed, that will be the reference for the other two motors, this single virtual motor has it owns regular stepper function with a single delay (actually this delay its there for the correctly serial comunication flow), the other motors work on the relation named CLUTCH wich will geve them a fraction of the virtual top speed, this is done by counting the times that the virtual motor give a step and deciding how much of them will be ignored before making a single step with it.


The CLUTH relation can be a single INT value, or a ecuation based on the time that the program has be running like int next example:




1 int m11 = 2; 39 timer1 = 0; 77 digitalWrite(m24, LOW);
2 int m12 = 3; 40 } 78 dm2 = 2;
3 int m13 = 4; 41 } 79 timer2 = 0;
4 int m14 = 5; 42 if (timer1 == clutch1) { 80 }
5 int m21 = 6; 43 if (dm1 == 2) { 81 }
6 int m22 = 7; 44 digitalWrite(m11, LOW); 82 if (timer2 == clutch2) {
7 int m23 = 8; 45 digitalWrite(m12, HIGH); 83 if (dm2 == 2) {
8 int m24 = 9; 46 digitalWrite(m13, LOW); 84 digitalWrite(m21, LOW);
9 int dm1 = 1; 47 digitalWrite(m14, LOW); 85 digitalWrite(m22, HIGH);
10 int dm2 = 1; 48 dm1 = 3; 86 digitalWrite(m23, LOW);
11 int timer1 = 0; 49 timer1 = 0; 87 digitalWrite(m24, LOW);
12 int timer2 = 0; 50 } 88 dm2 = 3;
13 int clutch1 = 2; 51 } 89 timer2 = 0;
14 int clutch2 = 2; 52 if (timer1 == clutch1) { 90 }
15 int time = 0; 53 if (dm1 == 3) { 91 }
16 int a = 0; 54 digitalWrite(m11, LOW); 92 if (timer2 == clutch2) {
17 void setup() { 55 digitalWrite(m12, LOW); 93 if (dm2 == 3) {
18 pinMode(m11, OUTPUT); 56 digitalWrite(m13, HIGH); 94 digitalWrite(m21, LOW);
19 pinMode(m12, OUTPUT); 57 digitalWrite(m14, LOW); 95 digitalWrite(m22, LOW);
20 pinMode(m13, OUTPUT); 58 dm1 = 4; 96 digitalWrite(m23, HIGH);
21 pinMode(m14, OUTPUT); 59 timer1 = 0; 97 digitalWrite(m24, LOW);
22 pinMode(m21, OUTPUT); 60 } 98 dm2 = 4;
23 pinMode(m22, OUTPUT); 61 } 99 timer2 = 0;
24 pinMode(m23, OUTPUT); 62 if (timer1 == clutch1) { 100 }
25 pinMode(m24, OUTPUT); 63 if (dm1 == 4) { 101 }
26 Serial.begin(9600); 64 digitalWrite(m11, LOW); 102 if (timer2 == clutch2) {
27 } 65 digitalWrite(m12, LOW); 103 if (dm2 == 4) {
28 void loop() { 66 digitalWrite(m13, LOW); 104 digitalWrite(m21, LOW);
29 a = int((sin(radians(time/12))+1)*5)+1; 67 digitalWrite(m14, HIGH); 105 digitalWrite(m22, LOW);
30 time = time+1; 68 dm1 = 1; 106 digitalWrite(m23, LOW);
31 clutch2 = 1+a; 69 timer1 = 0; 107 digitalWrite(m24, HIGH);
32 if (timer1 == clutch1) { 70 } 108 dm2 = 1;
33 if (dm1 == 1) { 71 } 109 timer2 = 0;
34 digitalWrite(m11, HIGH); 72 if (timer2 == clutch2) { 110 }
35 digitalWrite(m12, LOW); 73 if (dm2 == 1) { 111 }
36 digitalWrite(m13, LOW); 74 digitalWrite(m21, HIGH); 112 timer1 = timer1+1;
37 digitalWrite(m14, LOW); 75 digitalWrite(m22, LOW); 113 timer2 = timer2+1;
38 dm1 = 2; 76 digitalWrite(m23, LOW); 114 delay(3);




115 }