Go Down

Topic: [HELP] Code to control stepper motors (Read 3278 times) previous topic - next topic

khondoke

Hello Folks,

I am using EasyDriver and Arduino UNO to control a stepper motor (200 step/rev). My target is to run in a specific speed up to specific steps. For example, I want to run 20 rpm for 300 step (or 1.5 rev, or 2400 micro-steps etc.)

By using Timer1 library and attached code I have been able to run for specific time.
Code: [Select]
#include "TimerOne.h"

int Distance = 0;    // Record the number of steps we've taken
int time_count = 0;
int i =0;

void setup() {               
  // initialization for stepper motor
  pinMode(8, OUTPUT);     
  pinMode(9, OUTPUT);
 
  digitalWrite(8, LOW);
  digitalWrite(9, LOW);
 
  // initialization of timer1
  Timer1.initialize (50000);    // initialize timer1, and set a 1/2 second period
  Timer1.attachInterrupt (callback);   // attaches callback() as a timer overflow interrupt
  Serial.begin (9600);    // open the serial port at 9600 bps:
}

void callback () {
  time_count = time_count + 1;    // increment timer_count value
}
void loop() {
  digitalWrite(9, HIGH);
  delayMicroseconds(10000);         
  digitalWrite(9, LOW);
  delayMicroseconds(10000);
  Distance = Distance + 1;    // record this step
 
  Serial.print ("\ntime value is now:");    // prints a label
  Serial.print (time_count);      // prints a label
 
  if(time_count >200)
  {
        Serial.print("\n Timer Out");    // prints a label
Serial.print(time_count);    // prints a label
for(;;)
        {
          Serial.print("now stop");
          Serial.print("Timer Out\n");

          delay(1000);

      }
  }
 
}
After that it stops. I could not control directly by commanding number of steps/micro-steps to run. In addition, using this code, if I change the delayMicroseconds (in void loop), the speed of motor is supposed to change. But it is not??? :'(

Can anyone help me to correct or to give me a full code to control my stepper motor? That would be GREAT help for me. Thank you very much for your time.

I used this wiring and the details of my stepper (0.4A/phase and 30 ohm/phase) is here
-Mohammad

bfrye

#1
Nov 19, 2014, 10:29 pm Last Edit: Nov 19, 2014, 10:31 pm by bfrye
Personally I have never used a timer to control steppers, it may be a completely wonderful way to do it but I have no experience with that. You might try simplifying this and do it in a loop:

loop()
{
   for(int i = 0; i < 200; ++i)
   {
      digitalWrite(9, HIGH);
      delayMicroseconds(10000);         
      digitalWrite(9, LOW);
      delayMicroseconds(10000);
   }

   Serial.print("Done!");
   delay(1000);
}

Another option is the use a stepper class like AccelStepper I have used that on multiple projects and it is fantastic.

khondoke

@bfrye,

Thanks. Can you please write the full code?
Frankly speaking, I want to avoid dependency on time, rather I want to do based on step count. Your code seems very simple...great. Please write full code. Thanks again.
loop()
{
   for(int i = 0; i < 200; ++i)
   {
      digitalWrite(9, HIGH);
      delayMicroseconds(10000);          
      digitalWrite(9, LOW);
      delayMicroseconds(10000);
   }

   Serial.print("Done!");
   delay(1000);
}

Another option is the use a stepper class like AccelStepper I have used that on multiple projects and it is fantastic.
-Mohammad

Robin2

#3
Nov 19, 2014, 11:32 pm Last Edit: Nov 19, 2014, 11:34 pm by Robin2
You seem to have chosen an awfully complicated way to do something simple.

If you want to move a single step this code will do it

Code: [Select]
digitalWrite(stepPin, HIGH);
digitalWrite(stepPin, LOW);

Note that there is no delay() between the lines - it is not necessary.

Now the speed of your motor can be controlled by the interval between steps.

You can use millis() (or micros() for very short intervals) to manage the timing without using delay(). See the second example in this demo.

...R
Two or three hours spent thinking and reading documentation solves most programming problems.

khondoke

Hello,
Thank you again. I have run my motor successfully using the simple code attached here.
Code: [Select]
int i =0;
void setup() {               
  // initialization for stepper motor
  pinMode(8, OUTPUT);     
  pinMode(9, OUTPUT);
  digitalWrite(8, LOW);
  digitalWrite(9, LOW);
  Serial.begin (9600);
}

void loop()
{
  for (int i =0; i <= 1600; ++i)
    {
    digitalWrite(9, HIGH);
    delayMicroseconds (1000);
    digitalWrite(9, LOW);
    delayMicroseconds (1000);
    }
  Serial.print ("Done!");
  delay (1000);
}

Now I have two issues. Before that FYI, my motor has micro-stepping of 1600 steps in single rev.

Issue 1: Using above code it rotates exactly one rev (thats good) but after that it takes a break of 1 sec (as commanded) and then again it starts from beginning and continues to rotate.
To command him for a single loop, I put those statements into void setup() like this.
Code: [Select]
int i =0;
void setup() {               
  // initialization for stepper motor
  pinMode(8, OUTPUT);     
  pinMode(9, OUTPUT);
  digitalWrite(8, LOW);
  digitalWrite(9, LOW);
  Serial.begin (9600);

  for (int i =0; i <= 1600; ++i)
    {
    digitalWrite(9, HIGH);
    delayMicroseconds (1000);
    digitalWrite(9, LOW);
    delayMicroseconds (1000);
    }
  Serial.print ("Done!");
  delay (1000);
}

void loop()
{
}

Now it works. Is it the right way to do that?

Issue 2: I need to control the speed in terms of rpm. To do that I calculated the relationship between required rpm and the delayMicroseconds () between each HIGH and LOW statement as follows:

Quote
2000 micro-seconds or 2*10^(-3) sec= 1 micro-step, means:
((2x10^-3)/60) min = 1 micro-step,
So, 1 min = 30,000 micro-step,
But, 1600 microstep = 1 rev,
So, 30,000 micro-step = 30,000/1600 rev = 18.75 rev,
So, speed is: 18.75 rev/min (rpm),
So, the relationship is: delayMicroseconds () = 60/(2*rpm*(10^(-6))*1600). And for delayMicroseconds(1000) the rpm is 18.75.

Now I tried the formula using rpm = 18.75, which is supposed to make delayMicroseconds (1000).
like this:
Code: [Select]
delayMicroseconds (60/(2*18.75*(10^(-6))*1600)); instead of using
Code: [Select]
delayMicroseconds (1000);. But it didn't work. The results from these two did not match.

Would you please show me the way to do that? I am confused which data type (float or etc??) should I use? In a nutshell, I want to input rpm, then the program will calculate corresponding delayMicroseconds() and will be running. Any Help, please...
-Mohammad

notpit

#5
Nov 20, 2014, 08:28 am Last Edit: Nov 20, 2014, 09:19 am by notpit
1 microsecond = 10^-6 seconds
1 second = 1,000,000 or 1*10^6 microseconds
1 min = 60000000 micro seconds or 6*10^7

I could be wrong as it's been a long while since I've done any of this, but I believe your formula there is giving you a result in seconds, not micro seconds.

Is that not writing delayMicroseconds(.001)?

Having said that, if you can achieve the same result with less computation,  I believe you may have better performance in the end. The less that must be calculated the faster and leaner your program is. If that's in your loop, then that calculation is happening every cycle. Which probably isn't that big of a deal, but setting that value in a variable during your setup would be best practice. You can make a call to change that value upon any interface action later.

You may want to consider this tutorial using the Stepper class: http://arduino.cc/en/Tutorial/MotorKnob

You could go on from there changing your RPM with any input.

 

Robin2

#6
Nov 20, 2014, 11:37 am Last Edit: Nov 20, 2014, 11:39 am by Robin2
Code: [Select]
delayMicroseconds (60/(2*18.75*(10^(-6))*1600));

This sort of complex code is silly because you can't see what is happening. Break it into two separate lines

Code: [Select]
delayVal = 60/(2*18.75*(10^(-6))*1600);
delayMicroseconds (delayVal);


then temporarily add a third line

Code: [Select]
delayVal = 60/(2*18.75*(10^(-6))*1600);
Serial.println(delayVal);
delayMicroseconds (delayVal);


Now what do you see?

My guess is that the arithmetic is not being carried out correctly because the compiler is trying to use int values which don't work with float values and are probably not big enough to hold intermediate results.

AND ...  ^ is not correct - it should be **

Finally, a lot of that calculation could be worked out on your calculator and entered as a number

...R
Two or three hours spent thinking and reading documentation solves most programming problems.

khondoke

#7
Nov 20, 2014, 09:31 pm Last Edit: Nov 20, 2014, 09:38 pm by khondoke
Hello notpit, Thanks for your reply and suggestion. Actually, I need to use two motors using drivers with single Arduino UNO. But the example you mentioned is using single motor with single Arduino UNO with no driver but potentiometer. Actually, I will be needing to use as more as possible motors with single Arduino. SO I can't go for that program, I think. Thank you though for your suggestion. And about the calculation, I believe those are correct in my formula.

Hello Robin2, thank you too for your reply. Yes, I tried as your suggestion. It's not working. Then, I used an excel file to calculate automatically all those stuffs. So, I think I will use both (Arduino program and Excel file) during running my project. Thanks again.

If someone needs the same simple (of course, it wasn't that simple to me at the beginning) program and related excel file in jpg (if anyone needs this, feel free to send your email ID personally) format for any project like single extrusion of 3D printing, I am going to share here.

Code: [Select]
int i =0;
void setup() {                
  // initialization for stepper motor
  pinMode(8, OUTPUT);    
  pinMode(9, OUTPUT);
  digitalWrite(8, LOW);
  digitalWrite(9, LOW);
  Serial.begin (9600);
  for (int i =0; i <= 3582; ++i)
    {
    digitalWrite(9, HIGH);
    delayMicroseconds (750);
    digitalWrite(9, LOW);
    delayMicroseconds (750);
    }
  Serial.print ("Done!");
}

void loop()
{
}


Two variables here, you need to calculate from excel file.
(1) The limiting value of i (which is 3582 in above program)
(2) The delay between each HIGH and LOW pulse denoted by "d" in excel (which is 750 in above program)

.....
-Mohammad

Go Up