CNC Shield + 4 Steppermotors + 4 Endstops --> Code doesn't work

Dear Forum,

I have worked on a sketch that is supposed to control something similiar like an H-Bot, but much easier. There is just one lace for the x-axis and another for the y-axis. It is just supposed to move a sensor through the ‘coordinate system’ and stop every few centimeters to let the sensor make a mesurement. And so it goes through the x-Axis until it hits a enstop, where it is supposed to drive back to the starting point, go one step up the y-axis and then start again on x.

Befor a homing procedure is installed.

The onl problem is: the Sketch doesnt work. There is no error occuring and I don’t know why, but the stepper motors are just not starting to move.

This is the code:

// These are the control values for easy access
#define xlimit_invert 1 //Can be changed to 1 to make the limit switches normally closed.
#define ylimit_invert 1
#define threshold 20 //No of steps the motor will shift back after touching the end stop switch
#define xsteps 100  //No of steps for each partition
#define ysteps 100
#define speedx 500  //Can be adjusted to speed up the motors. Value is between 400 to 4000. Lower is faster
#define speedy 500

//Pin definations. Same as the CNC shield.
#define x_step 2
#define x_dir 5
#define y_step 3
#define y_dir 6
#define x_limit 9
#define y_limit 10

bool xlimit_reached =false;
bool ylimit_reached =false;
void setup() {
  // put your setup code here, to run once:
  //Define pin modes.
  pinMode(x_step, OUTPUT);
  pinMode(x_dir, OUTPUT);
  pinMode(y_step, OUTPUT);
  pinMode(y_dir, OUTPUT);
  pinMode(x_limit, INPUT_PULLUP);
  pinMode(y_limit, INPUT_PULLUP);
}

void loop() {
  // put your main code here, to run repeatedly:
  homex(); //Initial Homing of x axis
  homey(); //Initial Homing of y axis
  while(ylimit_reached !=true)
  {
    while(xlimit_reached !=true)
    {
      xdrive(xsteps); //Take x steps after every 30 seconds. until end stop is triggered.
      delay(30000);
    }
    homex(); //Home x after every one complete linear movement.
    ydrive(ysteps); //Move y axis 1 position.
  }
  homey(); //Home y axis
  
}
//Returns the limit condition of x axis
bool xlimit()
{
  if (digitalRead(x_limit) == HIGH && xlimit_invert == 0)
  {
    return false;
  }
  if (digitalRead(x_limit) == LOW && xlimit_invert == 0)
  {
    return true;
  }
  if (digitalRead(x_limit) == HIGH && xlimit_invert == 1)
  {
    return true;
  }
  if (digitalRead(x_limit) == LOW && xlimit_invert == 1)
  {
    return false;
  }
}
//Returns the limit condition of y axis
bool ylimit()
{
  if (digitalRead(y_limit) == HIGH && ylimit_invert == 0)
  {
    return false;
  }
  if (digitalRead(y_limit) == LOW && ylimit_invert == 0)
  {
    return true;
  }
  if (digitalRead(y_limit) == HIGH && ylimit_invert == 1)
  {
    return true;
  }
  if (digitalRead(y_limit) == LOW && ylimit_invert == 1)
  {
    return false;
  }
}
//Homes x axis and joggs the motor to clear of the limit switch
void homex()
{
  xdirection(0);
  while (xlimit())
  {
    digitalWrite(x_step, HIGH);
    delayMicroseconds(speedx);
    digitalWrite(x_step, LOW);
    delayMicroseconds(speedx);
  }
  xdirection(1);
  for (int x = 0; x < threshold; x++)
  {
    digitalWrite(x_step, HIGH);
    delayMicroseconds(speedx);
    digitalWrite(x_step, LOW);
    delayMicroseconds(speedx);
  }
}
//Homes x axis and joggs the motor to clear of the limit switch
void homey()
{
  ydirection(0);
  while (ylimit())
  {
    digitalWrite(y_step, HIGH);
    delayMicroseconds(speedy);
    digitalWrite(y_step, LOW);
    delayMicroseconds(speedy);
  }
  ydirection(1);
  for (int x = 0; x < threshold; x++)
  {
    digitalWrite(y_step, HIGH);
    delayMicroseconds(speedy);
    digitalWrite(y_step, LOW);
    delayMicroseconds(speedy);
  }
}
//Used to change the direction of the motor
void xdirection(int x)
{
  if (x == 0)
  {
    digitalWrite(x_dir, LOW);
  }
  else
  {
    digitalWrite(x_dir, HIGH);
  }
}
void ydirection(int x)
{
  if (x == 0)
  {
    digitalWrite(y_dir, LOW);
  }
  else
  {
    digitalWrite(y_dir, HIGH);
  }
}
//Moves motor given steps until limit switch is triggered
void xdrive(long x)
{
  xdirection(1);
  while (x == 0)
  {
    digitalWrite(x_step, HIGH);
    delayMicroseconds(speedx);
    digitalWrite(x_step, LOW);
    delayMicroseconds(speedx);
    x--;
    if (xlimit())
    {
      xlimit_reached=true;
      x = 0;
      xdirection(0);
      for (int y = 0; y < threshold; y++)
      {
        digitalWrite(x_step, HIGH);
        delayMicroseconds(speedx);
        digitalWrite(x_step, LOW);
        delayMicroseconds(speedx);
      }
    }
  }
}
void ydrive(long x)
{
  ydirection(1);
  while (x == 0)
  {
    digitalWrite(y_step, HIGH);
    delayMicroseconds(speedy);
    digitalWrite(y_step, LOW);
    delayMicroseconds(speedy);
    x--;
    if (ylimit())
    {
      ylimit_reached=true;
      x = 0;
      ydirection(0);
      for (int y = 0; y < threshold; y++)
      {
        digitalWrite(y_step, HIGH);
        delayMicroseconds(speedy);
        digitalWrite(y_step, LOW);
        delayMicroseconds(speedy);
      }
    }
  }

}

I have no clue what is wrong. Why are the motors not even starting to move? Do you have any suggestions?
I am very grateful for every help I can get, as I am at the end of my knowledge.

Thanks in advance!

Using an Arduino UNO and a CNC Shield!

Ok so I added a few lines:

#define Motor_Enable_pin 8

pinMode(Motor_Enable_pin, OUTPUT);
digitalWrite(Motor_Enable_pin, LOW);

But now it's only working until the x-Axis and the y-Axis hit each 1 endstop. And then the motors just stop working.

tommybahama123:
Ok so I added a few lines:

Please post the latest version of your program in your next Reply.

Have you written a shorter program that just works one motor?

You seem to be using WHILE fairly liberally in your program. That is almost certainly a bad idea because WHILE and FOR block the Arduino until they complete. Much better to use IF and allow loop() to do the iteration.

Have a look at how the code is organized in Several Things at a Time

Note how each function runs very briefly and returns to loop() so the next one can be called. None of the functions tries to complete a task in one call. And there may be dozens of calls to a function before it is actually time for it to do anything.

...R
Stepper Motor Basics
Simple Stepper Code

Hi Robin2,

thank you for the quick answer.

This is the code right now:

// These are the control values for easy access
#define xlimit_invert 1 //Can be changed to 1 to make the limit switches normally closed.
#define ylimit_invert 1
#define threshold 20 //No of steps the motor will shift back after touching the end stop switch
#define xsteps 100  //No of steps for each partition
#define ysteps 100
#define speedx 500  //Can be adjusted to speed up the motors. Value is between 400 to 4000. Lower is faster
#define speedy 500

//Pin definations. Same as the CNC shield.
#define x_step 2
#define x_dir 5
#define y_step 3
#define y_dir 6
#define x_limit 9
#define y_limit 10
#define Motor_Enable_pin 8

bool xlimit_reached =false;
bool ylimit_reached =false;
void setup() {
  // put your setup code here, to run once:
  //Define pin modes.
  pinMode(x_step, OUTPUT);
  pinMode(x_dir, OUTPUT);
  pinMode(y_step, OUTPUT);
  pinMode(y_dir, OUTPUT);
  pinMode(x_limit, INPUT_PULLUP);
  pinMode(y_limit, INPUT_PULLUP);

  pinMode(Motor_Enable_pin, OUTPUT);
  digitalWrite(Motor_Enable_pin, LOW);


}

void loop() {


  
  // put your main code here, to run repeatedly:
  homex(); //Initial Homing of x axis
  homey(); //Initial Homing of y axis
  while(ylimit_reached !=true)
  {
    while(xlimit_reached !=true)
    {
      xdrive(xsteps); //Take x steps after every 30 seconds. until end stop is triggered.
      delay(30000);
    }
    homex(); //Home x after every one complete linear movement.
    ydrive(ysteps); //Move y axis 1 position.
  }
  homey(); //Home y axis
  
}
//Returns the limit condition of x axis
bool xlimit()
{
  if (digitalRead(x_limit) == HIGH && xlimit_invert == 0)
  {
    return false;
  }
  if (digitalRead(x_limit) == LOW && xlimit_invert == 0)
  {
    return true;
  }
  if (digitalRead(x_limit) == HIGH && xlimit_invert == 1)
  {
    return true;
  }
  if (digitalRead(x_limit) == LOW && xlimit_invert == 1)
  {
    return false;
  }
}
//Returns the limit condition of y axis
bool ylimit()
{
  if (digitalRead(y_limit) == HIGH && ylimit_invert == 0)
  {
    return false;
  }
  if (digitalRead(y_limit) == LOW && ylimit_invert == 0)
  {
    return true;
  }
  if (digitalRead(y_limit) == HIGH && ylimit_invert == 1)
  {
    return true;
  }
  if (digitalRead(y_limit) == LOW && ylimit_invert == 1)
  {
    return false;
  }
}
//Homes x axis and joggs the motor to clear of the limit switch
void homex()
{
  xdirection(0);
  while (xlimit())
  {
    digitalWrite(x_step, HIGH);
    delayMicroseconds(speedx);
    digitalWrite(x_step, LOW);
    delayMicroseconds(speedx);
  }
  xdirection(1);
  for (int x = 0; x < threshold; x++)
  {
    digitalWrite(x_step, HIGH);
    delayMicroseconds(speedx);
    digitalWrite(x_step, LOW);
    delayMicroseconds(speedx);
  }
}
//Homes x axis and joggs the motor to clear of the limit switch
void homey()
{
  ydirection(0);
  while (ylimit())
  {
    digitalWrite(y_step, HIGH);
    delayMicroseconds(speedy);
    digitalWrite(y_step, LOW);
    delayMicroseconds(speedy);
  }
  ydirection(1);
  for (int x = 0; x < threshold; x++)
  {
    digitalWrite(y_step, HIGH);
    delayMicroseconds(speedy);
    digitalWrite(y_step, LOW);
    delayMicroseconds(speedy);
  }
}
//Used to change the direction of the motor
void xdirection(int x)
{
  if (x == 0)
  {
    digitalWrite(x_dir, LOW);
  }
  else
  {
    digitalWrite(x_dir, HIGH);
  }
}
void ydirection(int x)
{
  if (x == 0)
  {
    digitalWrite(y_dir, LOW);
  }
  else
  {
    digitalWrite(y_dir, HIGH);
  }
}
//Moves motor given steps until limit switch is triggered
void xdrive(long x)
{
  xdirection(1);
  while (x == 0)
  {
    digitalWrite(x_step, HIGH);
    delayMicroseconds(speedx);
    digitalWrite(x_step, LOW);
    delayMicroseconds(speedx);
    x--;
    if (xlimit())
    {
      xlimit_reached=true;
      x = 0;
      xdirection(0);
      for (int y = 0; y < threshold; y++)
      {
        digitalWrite(x_step, HIGH);
        delayMicroseconds(speedx);
        digitalWrite(x_step, LOW);
        delayMicroseconds(speedx);
      }
    }
  }
}
void ydrive(long x)
{
  ydirection(1);
  while (x == 0)
  {
    digitalWrite(y_step, HIGH);
    delayMicroseconds(speedy);
    digitalWrite(y_step, LOW);
    delayMicroseconds(speedy);
    x--;
    if (ylimit())
    {
      ylimit_reached=true;
      x = 0;
      ydirection(0);
      for (int y = 0; y < threshold; y++)
      {
        digitalWrite(y_step, HIGH);
        delayMicroseconds(speedy);
        digitalWrite(y_step, LOW);
        delayMicroseconds(speedy);
      }
    }
  }
}

Now the x-axis motor stops after hitting one of the x-endstops, and the y-axis motor starts after that and stops when one y-endstop is hitted (so the homing procedure seems to work). But after that nothing happens anymore.

So the problem must start in this part:

//Moves motor given steps until limit switch is triggered
void xdrive(long x)
{
  xdirection(1);
  while (x == 0)
  {
    digitalWrite(x_step, HIGH);
    delayMicroseconds(speedx);
    digitalWrite(x_step, LOW);
    delayMicroseconds(speedx);
    x--;
    if (xlimit())
    {
      xlimit_reached=true;
      x = 0;
      xdirection(0);
      for (int y = 0; y < threshold; y++)
      {
        digitalWrite(x_step, HIGH);
        delayMicroseconds(speedx);
        digitalWrite(x_step, LOW);
        delayMicroseconds(speedx);
      }
    }
  }
}

Do you have any suggestion for how to cut the WHILE here? Shoud I try to just use IF all the time like in the example you send me? But how do i return to loop then? I would have to include a much more extensive loop.

I unfortunately have no program for only one motor. THis would have been an easier start probably?

In the ydrive function you check the ylimit and use it to set ylimit_reached true. There's nothing in your code that ever sets it false again, so once it's true, loop checks it repeatedly but does nothing more.

So I just include a ylimit_reached = false in the end?

I would guess that each home function should reset its corresponding limit variable.

How can I do this in the code?

tommybahama123:
I unfortunately have no program for only one motor. THis would have been an easier start probably?

It's not too late to create one now, and it may ultimately get you to the end product more quickly.

Your code only seems to have an X and a Y axis so why are there 4 stepper motors?

Every time I look at your program it seems to me it is far more complex than it needs to be if all it is doing is moving a motorX from A to B, then back to B then moving motorY a little bit.

...R

Oh wow I'm Sorry, it's only 2 Stepper Motors of course.

Yeah that's what I think as well, but especially the homing procedure is quite difficult to figure out.

Do you have any suggestions on that?

tommybahama123:
Yeah that's what I think as well, but especially the homing procedure is quite difficult to figure out.

From your description of the project you just need to get the motor to move to HomeA and then move to HomeB (at the other end) and then repeat.

So write a function that makes the motor move step by step until LimitSwitchA is detected then change the direction, change the limit switch to be tested and repeat.

...R