Why stepper takes only one step - 2 stepper millis() controll.

Hello,
this is one of my first codes for running stepper motors connected to CNC shield.
Forgive me some extra code, but I’m using a template for all my experiments with CNC shield.

The idea of this code is to controll 2 stepper motors by serial commands. After typing number of steps, motors should run tohether, according to given values - for ex. “34,56”.
But in this case, they don’t. They do only one step.

Steppers must act at the same time.
Some of my first attempts gave me effect, that after putting a command, motor X moved, and after it finished, motor Y started its action.

My need is to move those motors at the same time, so after looking at the forum I’ve found millis() method which seemed to be solution for me.

Here is my code:

//step pins
#define X_stp 2
#define Y_stp 3
#define Z_stp 4
#define A_stp 12

//direction pins
#define X_dir 5
#define Y_dir 6
#define Z_dir 7
#define A_dir 13

//endstop pins
#define X_lim 9
#define Y_lim 10
#define Z_lim 11
#define A_lim 17

//enable pin
#define EN  8

//common speed
int spd = 5;

//number of steps per stepper
int allXpos = 96;
int allYpos = 96;
int allZpos = 96;
int allApos = 96;

//Direction values
int Xdir = 1;
int Ydir = 1;
int Zdir = 1;
int Adir = 1;

//steps to be taken
int Xsteps = 0;
int Ysteps = 0;
int Zsteps = 0;
int Asteps = 0;

//current position
int curXpos;
int curYpos;
int curZpos;
int curApos;

//position form command
int nxtXpos;
int nxtYpos;
int nxtZpos;
int nxtApos;

unsigned long nxtXMillis = 0;
unsigned long nxtYMillis = 0;
unsigned long speed = 5;

void setup() {
Serial.begin(115200);
Serial.setTimeout(5);

pinMode(EN,OUTPUT);

pinMode(X_stp,OUTPUT);
pinMode(X_dir,OUTPUT);
pinMode(X_lim, INPUT_PULLUP);

pinMode(Y_stp,OUTPUT);
pinMode(Y_dir,OUTPUT);
pinMode(Y_lim, INPUT_PULLUP);
    
pinMode(Z_stp,OUTPUT);
pinMode(Z_dir,OUTPUT);
pinMode(Z_lim, INPUT_PULLUP);

pinMode(A_stp,OUTPUT);
pinMode(A_dir,OUTPUT);
pinMode(A_lim, INPUT_PULLUP);
 

while (digitalRead(Y_lim) == 0)
	stepY();
  
curXpos = 7;
curYpos = 7;
curZpos = 7;
curApos = 7;
}

void stepX()
{
	if (millis() - nxtXMillis > speed)
		{
		nxtXMillis = millis();
		digitalWrite(EN, 0);
		digitalWrite(X_stp, 1);
		digitalWrite(X_stp, 0);
		}
}

void stepY()
{
	if (millis() - nxtYMillis > speed)
		{
		nxtYMillis = millis();
		digitalWrite(EN, 0);
		digitalWrite(Y_stp, 1);
		digitalWrite(Y_stp, 0);
		}
}


void loop() 
{
digitalWrite(EN, 1);
  
while (Serial.available() > 0) 
  {
	int Xstp = Serial.parseInt();
	for (int x=0;x<Xstp;x++)
		stepX();
	
	int Ystp = Serial.parseInt();	
	for (int y=0;y<Ystp;y++)
		stepY();
	}
}

After runnig this code my stepper/steppers take only one step after giving them some order via serial monitor. Millis control for stepping works fine, because homing at the setup does the job. There must be something wrong with my for() loop. At first glance, seems legit… but I can’t find an error.

You can’t mix a blocking FOR loop and non-blocking millis() like that. The FOR loop will complete its counting before the time for the next step arises.

Have a look at the examples in Serial Input Basics - simple reliable ways to receive data. There is also a parse example to illustrate how to extract numbers from the received text.

The technique in the 3rd example will be the most reliable.

You can send data in a compatible format with code like this

Serial.print('<'); // start marker
Serial.print(value1);
Serial.print(','); // comma separator
Serial.print(value2);
Serial.println('>'); // end marker

If you send the two step values in one message like <34,56> and then parse the values (as in my tutorial) before giving any commands to the motors you will be able to get both motors to work at the same time.

The sort of code needed to get the motors to work at the same time is something like this

if (millis() - prevStepMillis >= stepIntervalMillis) {
   prevStepMillis += stepIntervalMillis;
   if (motorXsteps > 0) {
       // code for one step for motor X
       motorXsteps --;
   }
   // repeat for motorY
}

…R

For me, when I want 2 stepper motors to step at the same time, I use a stepper Y cable and, in code just treat them as one motor.

Realistically, if X was driven first and then Y, that's not a same time operation of the 2 motors.

Idahowalker: Realistically, if X was driven first and then Y, that's not a same time operation of the 2 motors.

Well that is how you wrote the code in your Original Post.

And it is not how it works in the code suggestion that I gave you.

...R

Thank you Robin for advice. Seems like I still dont catch the millis idea. I had a feeling that there is something wrong. I'll try again.

As for examples. I've created three different codes for methods of parsing serial data (one of them is mentioned example no 3 with limiters). But none of them worked for me. Probably because of misunderstanding of blocking functions and millis usage. My first attempts were based on delays. It was disaster!

Majoris: As for examples. I've created three different codes for methods of parsing serial data (one of them is mentioned example no 3 with limiters). But none of them worked for me. Probably because of misunderstanding of blocking functions and millis usage. My first attempts were based on delays. It was disaster!

Pick the program that represents your best attempt and post it. It's impossible to help without seeing your code.

...R

Hello again.
It is going to be complicated to describe my problems. There are few of them. I think it will be best to start from stepper motors issue.
My concept:
I wrote a Windows software which ‘hooks’ to another Windows program and listens to few chosen memory addresses, which are meant to be illustrated by stepper motors movement.
I use a CNC shield device. Stepper movement control is based on absolute positions - my method is shown in the code.
My software which is reading memory listens to any changes on choosen addresses and sends it over serial port. Arduino listens to this port, and controls 4 steppers movement. In theory. I almost succeed to control 1 stepper. When it comes another stepper all messes up. Serial informations on stepper positions are sent very fast - 30-40 / second. Information contains: direction of movement and position (1 to 96). There are same signal for each of four steppers.

OK. Now the Arduino codes.
I’ve read a lot. I’ve tried a lot. I’m not a programmer at all. I’m just learning. Ive tried all the serial parsing methods I’ve found on the Internet. In attaching I share my best codes. Those are pretty old versions based on ‘delays’. Last code is based on ‘millis’, but it was unsuccesfull attempt.

My goal for now is to make all 4 steppers to move the same time, basing on received data from serial port.

OK. And now some information on control signals.

code_1.ino is controlled by such command:
1,23,0,11,0,34,0,54
this is divided to pairs. Each pair has information on direction 1 or 0, and stepper position 1 to 96. And it is repeated 4 times (4 pairs).

code_2.ino
command: <A,0,53,0,11,0,53,0,71,>
The same only with limiters (example 3 :)). And this char A, which I couldn’ get rid of the original code :).

code_3.ino
command: x0d,76
x means motorX (there are X, Y, Z, A motors in all examples), 0d is direction. It can be “0d” or “1d”. And stepper position after the comma.

So here it is. All those codes have been tested, and confirmed as non working :smiley: for me. They do work as stepper controller. They move steppers to propper positions (controlled from serial monitor), but after receiving fast serial commands it is not working properly.
For now, I’d like to handle millis multitasking for stepper movement. Later on I get to serial communication issues, but this is going to be another topic.

ps.
Sorry for any language mistakes, misspelling etc. I’m Polish and English is not my native language. I’m doing my best.
And I’m aware that all my codes looks terrible for programmers. I know it can be written simplier, shorter and nicer. But this is all I can do for now.

code_1.ino (13.1 KB)

code_2.ino (12.8 KB)

code_3.ino (9.2 KB)

Majoris: So here it is. All those codes have been tested, and confirmed as non working :D for me. They do work as stepper controller. They move steppers to propper positions (controlled from serial monitor), but after receiving fast serial commands it is not working properly. For now, I'd like to handle millis multitasking for stepper movement. Later on I get to serial communication issues, but this is going to be another topic.

Before I look at your programs I would like to know why you have posted 3 programs? Can't we just focus on one of them for now? If so, which one?

...R

Robin2: Can't we just focus on one of them for now? If so, which one?

So let it be code_3.ino. My last version with millis() attempt.

I have had a look at your code_3.ino but it is so badly indented that I can't see where one part starts and another ends. Please post another version after using the AutoFormat tool.

Separately, it is not a good idea to use the String (capital S) class on an Arduino as it can cause memory corruption in the small memory on an Arduino. This can happen after the program has been running perfectly for some time. Just use cstrings - char arrays terminated with '\0' (NULL).

When using Cstrings you must use strcmp() to compare values rather than ==

The Serial examples in my link use cstrings.

...R

Corrected version after Auto Format. Hope it makes the code more readable. Anyway, after looking at the code, you probably already see that I’m noob.
So if I may ask, explain things like for a noob. I’m not a lazy guy, I will do my ‘homework’ but if I get overwhelmed with some complicated info, I’ll probably fail again.

Thanx that you’re helping.

code_3.ino (9.78 KB)

Thanks for the updated code. I will try to look at it later today but I have another (non computer) job that I must finish today.

I will bookmark this so I can find it.

...R

I have finally got a chance to look at your code.

I don't understand the purpose of this line (and its colleague)

if (part1.equalsIgnoreCase("x1d"))

From your Original Post I had the impression that you are sending "34,56"

Please give an example of what you are actually sending to the Arduino program.

...R

Not in this one. Serial commands for this version of program are like that: x1d,45 So it means, that we run stepper X clockwise (0 or 1) to position 45.

y0d,15 Motor Y, anticlockwise (this time 0) to position 15.

This is a way different version of code, comparing to my first post. My first post question was more like "why the code does not work at all", and later we moved to millis issues. Next question was, "what I do wrong with millis usage", because my motors does not run together. So I searched my best codes to show you the problem.

Majoris: This is a way different version of code, comparing to my first post.

Getting a computer program to work requires a systematic step-by-step approach. What you seem to be doing is more like using a scatter-gun and hoping you hit something useful.

Most of what you need is in Reply #1

...R

Robin2: Pick the program that represents your best attempt and post it. It's impossible to help without seeing your code.

So I have chosen, because I had few tries. I'm a bit surprized and disapointed with such opinion:

Robin2: What you seem to be doing is more like using a scatter-gun and hoping you hit something useful.

But forget it... I'm not going to bother you again. Thank you for your time Robin.

Take care

Majoris: So I have chosen, because I had few tries. I'm a bit surprized and disapointed with such opinion:

Suppose you go back to what I suggested in Reply #1 and start from there?

My small CNC lathe works with 3 stepper motors and data sent from the PC over a serial connection using the general approach I suggested in Reply #1

...R

I will.