How to home two motors together and start with a push button

Hey guys
I'm doing my first arduino project and I'm building an automated painter, where two stepper motors are pushing a crossbar over a piece of glass. I set up the motors using a CNC shield with two polulu motors. As seen on the following image.

The motors are running as the X and Y motor. I have connected a limit switch on one side and connected it to A0 analog input.

The code i'm using is currently only moving the X motor when homing. I would like them to move together so they are at the same position after the homing. Then I have to add a button to start the program which is currently runnnig automatically after homing. But i'm not sure how to make the code so that you don't have to hold the button, but just push it and then it will go to the desired position and then return home.


#include <SpeedyStepper.h>



//
// pin assignments
//
const int LED_PIN = 13;
const int MOTOR_X_STEP_PIN = 9;
const int MOTOR_Y_STEP_PIN = 6;
const int MOTOR_Z_STEP_PIN = 3;
const int MOTOR_X_DIR_PIN = 8;
const int MOTOR_Y_DIR_PIN = 5;
const int MOTOR_Z_DIR_PIN = 2;
const int STEPPERS_ENABLE_PIN = 10;
const int LIMIT_SWITCH_PIN = A0;
//const int LIMIT_SWITCH_Y_PIN = 10;
//const int LIMIT_SWITCH_Z_PIN = 11;
//const int SPINDLE_ENABLE_PIN = 12;
//const int SPINDLE_DIRECTION_PIN = 13;



//
// create the stepper motor objects
//
SpeedyStepper stepperX;
SpeedyStepper stepperY;



void setup() 
{
  //
  // setup the LED pin and enable print statements
  //
  pinMode(LED_PIN, OUTPUT);   
  pinMode(STEPPERS_ENABLE_PIN, OUTPUT);       // be sure to do this
  pinMode(LIMIT_SWITCH_PIN, INPUT_PULLUP);
  Serial.begin(9600);


  //
  // connect and configure the stepper motor to there IO pins
  //
  stepperX.connectToPins(MOTOR_X_STEP_PIN, MOTOR_X_DIR_PIN);
  stepperY.connectToPins(MOTOR_Y_STEP_PIN, MOTOR_Y_DIR_PIN);


  //
  // enable the stepper motors
  //
  digitalWrite(STEPPERS_ENABLE_PIN, LOW);     // be sure to do this


  // Homing the motors using a limit Switch 

  // First you must tell the library "how many steps it takes to move one
  // millimeter".  My setup is configured with a lead-screw having 
  // 25 full-steps/mm and 1x microstepping.
  //
  stepperX.setStepsPerMillimeter(25 * 1);    // 1x microstepping
  stepperY.setStepsPerMillimeter(25 * 1);    // 1x microstepping


  //
  // set the speed and acceleration rates for the stepper motor
  //
  stepperX.setSpeedInMillimetersPerSecond(20);
  stepperX.setAccelerationInMillimetersPerSecondPerSecond(10.0);
  stepperY.setSpeedInMillimetersPerSecond(20);
  stepperY.setAccelerationInMillimetersPerSecondPerSecond(10.0);


  //
  // move the motor toward the limit switch to find the "Home" position
  //
  const float homingSpeedInMMPerSec = 5.0;
  const float maxHomingDistanceInMM = 380;   // since my lead-screw is 38cm long, should never move more than that
  const int directionTowardHome = -1;        // direction to move toward limit switch: 1 goes positive direction, -1 backward
  
  if(stepperX.moveToHomeInMillimeters(directionTowardHome, homingSpeedInMMPerSec, maxHomingDistanceInMM, LIMIT_SWITCH_PIN) != true && stepperY.moveToHomeInMillimeters(directionTowardHome, homingSpeedInMMPerSec, maxHomingDistanceInMM, LIMIT_SWITCH_PIN) != true)
  {
    //
    // this code is executed only if homing fails because it has moved farther 
    // than maxHomingDistanceInMM and never finds the limit switch, blink the 
    // LED fast forever indicating a problem
    //
    while(true)
    {
      digitalWrite(LED_PIN, HIGH);
      delay(50);
      digitalWrite(LED_PIN, LOW);
      delay(50);
    }
  }


  //
  // homing is now complete, the motor is stopped at position 0mm
  //
  delay(500);
  stepperX.moveToPositionInMillimeters(10.0); // Moving the crossbar away from LS to start next loop


  //
  // if you want your 0 origin someplace else, you can change it 
  //
  //stepper.setCurrentPositionInMillimeters(325);

  
}

void loop() 
{
  //
  // Note 1: It is assumed that you are using a stepper motor with a 
  // 1.8 degree step angle (which is 200 steps/revolution). This is the
  // most common type of stepper.
  //
  // Note 2: It is also assumed that your stepper driver board is  
  // configured for 1x microstepping.
  //
  // It is OK if these assumptions are not correct, your motor will just
  // turn less than a full rotation when commanded to. 
  //
  // Note 3: This example uses "relative" motions.  This means that each
  // command will move the number of steps given, starting from it's 
  // current position.
  //

 

  //
  // how to run two stepper motors
  //
  Serial.println("Running the X & Y steppers");
  runBothXAndYSteppers();
}

void runBothXAndYSteppers() 
{
  //
  // use the function below to move two motors with speed coordination
  // so that both stop at the same time, even if one moves farther than
  // the other
  //

  //
  // turn both motors 250,000 steps
  //
  long stepsX = 2500 * 100;
  long stepsY = 2500 * 100;
  float speedInStepsPerSecond = -5000;
  float accelerationInStepsPerSecondPerSecond = 1000;
  moveXYWithCoordination(stepsX, stepsY, speedInStepsPerSecond, accelerationInStepsPerSecondPerSecond);
  delay(1000);
  }

  //
// move both X & Y motors together in a coordinated way, such that they each 
// start and stop at the same time, even if one motor moves a greater distance
//
void moveXYWithCoordination(long stepsX, long stepsY, float speedInStepsPerSecond, float accelerationInStepsPerSecondPerSecond)
{
  float speedInStepsPerSecond_X;
  float accelerationInStepsPerSecondPerSecond_X;
  float speedInStepsPerSecond_Y;
  float accelerationInStepsPerSecondPerSecond_Y;
  long absStepsX;
  long absStepsY;

  //
  // setup initial speed and acceleration values
  //
  speedInStepsPerSecond_X = speedInStepsPerSecond;
  accelerationInStepsPerSecondPerSecond_X = accelerationInStepsPerSecondPerSecond;
  
  speedInStepsPerSecond_Y = speedInStepsPerSecond;
  accelerationInStepsPerSecondPerSecond_Y = accelerationInStepsPerSecondPerSecond;


  //
  // determine how many steps each motor is moving
  //
  if (stepsX >= 0)
    absStepsX = stepsX;
  else
    absStepsX = -stepsX;
 
  if (stepsY >= 0)
    absStepsY = stepsY;
  else
    absStepsY = -stepsY;


  //
  // determine which motor is traveling the farthest, then slow down the
  // speed rates for the motor moving the shortest distance
  //
  if ((absStepsX > absStepsY) && (stepsX != 0))
  {
    //
    // slow down the motor traveling less far
    //
    float scaler = (float) absStepsY / (float) absStepsX;
    speedInStepsPerSecond_Y = speedInStepsPerSecond_Y * scaler;
    accelerationInStepsPerSecondPerSecond_Y = accelerationInStepsPerSecondPerSecond_Y * scaler;
  }
  
  if ((absStepsY > absStepsX) && (stepsY != 0))
  {
    //
    // slow down the motor traveling less far
    //
    float scaler = (float) absStepsX / (float) absStepsY;
    speedInStepsPerSecond_X = speedInStepsPerSecond_X * scaler;
    accelerationInStepsPerSecondPerSecond_X = accelerationInStepsPerSecondPerSecond_X * scaler;
  }

  
  //
  // setup the motion for the X motor
  //
  stepperX.setSpeedInStepsPerSecond(speedInStepsPerSecond_X);
  stepperX.setAccelerationInStepsPerSecondPerSecond(accelerationInStepsPerSecondPerSecond_X);
  stepperX.setupRelativeMoveInSteps(stepsX);


  //
  // setup the motion for the Y motor
  //
  stepperY.setSpeedInStepsPerSecond(speedInStepsPerSecond_Y);
  stepperY.setAccelerationInStepsPerSecondPerSecond(accelerationInStepsPerSecondPerSecond_Y);
  stepperY.setupRelativeMoveInSteps(stepsY);


  //
  // now execute the moves, looping until both motors have finished
  //
  while((!stepperX.motionComplete()) || (!stepperY.motionComplete()))
  {
    stepperX.processMovement();
    stepperY.processMovement();
  }
}

Thanks

The setup can be seen here

I didn't read your code, but thanks for posting it as a reference. Typically, the requirement to hold down a button, is because the program tests for a switch state, not a change of state. Please consult the "state change example" that ships with the IDE.

Hey guys
I'm working on a project having two motors run together. My plan is that when the Arduino nano is connected the motors should home using a limit switch and then when pushing a push button they should both move forward to the end of the screw and return to home. I'm having trouble for the motor to stop at the limit switch.





#include <AccelStepper.h>

const int MOTOR_X_STEP_PIN = 9;
const int MOTOR_Y_STEP_PIN = 6;
//const int MOTOR_Z_STEP_PIN = 3;
const int MOTOR_X_DIR_PIN = 8;
const int MOTOR_Y_DIR_PIN = 5;
//const int MOTOR_Z_DIR_PIN = 2;
const int MOTOR_X_ENABLE_PIN = 10;
const int MOTOR_Y_ENABLE_PIN = 7;
//const int MOTOR_Z_ENABLE_PIN = 4;
const float maxspeed = 5000.0;
float speedF = 2000.0;
float speedB = -2000.0;
const int LS_PIN = A0;
const int ST_PIN = A7;
int LBS = 0; // Previous button state


AccelStepper Xstepper(AccelStepper::DRIVER, MOTOR_X_STEP_PIN, MOTOR_X_DIR_PIN);
AccelStepper Ystepper(AccelStepper::DRIVER, MOTOR_Y_STEP_PIN, MOTOR_Y_DIR_PIN);

void setup()
{  
  Serial.begin(9600);
  pinMode(MOTOR_X_ENABLE_PIN, OUTPUT);
  pinMode(MOTOR_Y_ENABLE_PIN, OUTPUT);
  digitalWrite(MOTOR_X_ENABLE_PIN, LOW);
  digitalWrite(MOTOR_Y_ENABLE_PIN, LOW);
  Xstepper.setMaxSpeed(maxspeed);
  Ystepper.setMaxSpeed(maxspeed);
  


}

  

void loop()
{  
  Xstepper.setAcceleration(500.0);
  Xstepper.setSpeed(-2000);
  Ystepper.setAcceleration(500.0);
  Ystepper.setSpeed(-2000);
  Xstepper.runSpeed();
  Ystepper.runSpeed();
  int LS = analogRead(LS_PIN);
  int ST = analogRead(ST_PIN); 

  if (LS >= 50){
    homing();
    delay(5);
  }
  if (ST != LBS){
    if(ST >=50){
      Serial.println("on");
      run();
    } else {
      Serial.println("off");
    }
    delay(5);
  }
  LBS = ST;
  //if (LS>=0 && ST>=50){
    //run();
//}
}

void homing()
{
  
  Xstepper.stop();
  Ystepper.stop();
  //Xstepper.moveTo(10);
  //Xstepper.setAcceleration(50.0);
  //Ystepper.moveTo(10);
  //Ystepper.setAcceleration(50.0);
  delay(5);
  

}

void run()
{
  Xstepper.setAcceleration(500.0);
  Xstepper.setSpeed(2500);
  Ystepper.setAcceleration(500.0);
  Ystepper.setSpeed(2500);
  Xstepper.runSpeed();
  Ystepper.runSpeed();
}

This lines should be placed on loop.

Why are you using analogRead for buttons?

Show us the circuit.

I'm using this CNC shield and therefore I only have analog inputs to use. I have updated the code. So it is working now. The motors are stopping when the limit switch is activated, but I can't get the start button activated as an edge detection.

digitaRead can de used with analog pins. It only depends of the circuit.

Where's the limit switch and button in this schematic?

Days ago I was doing a code to post in your another topic but I haven't posted because I was getting wrong behaviour on simulator.

Try it and let me know how it behaves in real hardware.

#include <AccelStepper.h>
#include <Bounce2.h>
//#include <LiquidCrystal_I2C.h>

//LiquidCrystal_I2C lcd(0x27, 16, 2);

#define NUM_SWITCHES 3

#define  STEPS_PER_MM_X 200
#define  STEPS_PER_MM_Y 200
#define  STEPS_PER_MM_Z 200

#define HOME_DIRECTION_X -1
#define HOME_DIRECTION_Y -1
#define HOME_DIRECTION_Z -1

const int MOTOR_X_DIR_PIN = 8;
const int MOTOR_X_STEP_PIN = 9;

const int MOTOR_Y_DIR_PIN = 5;
const int MOTOR_Y_STEP_PIN = 6;

const int MOTOR_Z_DIR_PIN = 2;
const int MOTOR_Z_STEP_PIN = 3;

const int STEPPERS_ENABLE_PIN = 10;

const int endSwitchPin[NUM_SWITCHES] = {A0, A1, A2};

const int buttonPin = A3;

Bounce2::Button button = Bounce2::Button();

Bounce2::Button endSwitch[NUM_SWITCHES] = {Bounce2::Button()};

AccelStepper myStepperX = AccelStepper(1, MOTOR_X_STEP_PIN, MOTOR_X_DIR_PIN);
AccelStepper myStepperY = AccelStepper(1, MOTOR_Y_STEP_PIN, MOTOR_Y_DIR_PIN);
AccelStepper myStepperZ = AccelStepper(1, MOTOR_Z_STEP_PIN, MOTOR_Z_DIR_PIN);

int distance = 0;
bool distChanged = false;

void homeXY()
{
  bool homeX = false;
  bool homeY = false;

  myStepperX.setAcceleration(50);
  myStepperX.setSpeed(100);

  myStepperY.setAcceleration(50);
  myStepperY.setSpeed(100);

 // lcd.setCursor(0, 0);
 // lcd.print("Homing axis XY  ");
  Serial.println("Homing XY");

  while ((homeX == false) || (homeY == false))
  {
    endSwitch[0].update();

    if (endSwitch[0].read() == LOW)
    {
      homeX = true;
    }
    else
    {
      myStepperX.move(STEPS_PER_MM_X * HOME_DIRECTION_X);
      myStepperX.run();
    }

    endSwitch[1].update();

    if (endSwitch[1].read() == LOW)
    {
      homeY = true;
    }
    else
    {
      myStepperY.move(STEPS_PER_MM_Y * HOME_DIRECTION_Y);
      myStepperY.run();
    }
  }

  myStepperX.setCurrentPosition(0);
  myStepperY.setCurrentPosition(0);
  
 // lcd.setCursor(0, 0);
 // lcd.print("Homing XY finish");
  Serial.println("Homing XY finished");
}

void homeZ()
{
  bool homeZ = false;

  myStepperZ.setAcceleration(50);
  myStepperZ.setSpeed(100);

  //lcd.setCursor(0, 0);
 // lcd.print("Homing axis Z   ");
  Serial.println("Homing Z");

  while (homeZ == false)
  {
    endSwitch[2].update();

    if (endSwitch[2].read() == LOW)
    {
      homeZ = true;
    }
    else
    {
      myStepperZ.move(STEPS_PER_MM_Z * HOME_DIRECTION_Z);
      myStepperZ.run();
    }
  }
  myStepperZ.setCurrentPosition(0);

 // lcd.setCursor(0, 0);
 // lcd.print("Homing Z finish ");
  Serial.println("Homing Z finished");
}

void setup()
{
  pinMode(STEPPERS_ENABLE_PIN, OUTPUT);
  digitalWrite(STEPPERS_ENABLE_PIN, LOW);

  Serial.begin(9600);

 // lcd.init();
 // lcd.backlight();

  for (byte i = 0; i < NUM_SWITCHES; i++)
  {
    endSwitch[i].attach(endSwitchPin[i], INPUT_PULLUP);
    endSwitch[i].setPressedState(LOW);
    endSwitch[i].interval(5);
  }

  button.attach(buttonPin, INPUT_PULLUP);
  button.setPressedState(LOW);
  button.interval(5);

  myStepperX.setMaxSpeed(1000);

  myStepperY.setMaxSpeed(1000);

  myStepperZ.setMaxSpeed(1000);

  //lcd.setCursor(0, 0);
 // lcd.print("Homing axis");
  Serial.println("Homing axis");

  homeXY();
  homeZ();

 // lcd.setCursor(0, 0);
 // lcd.print("Homing Complete!");
  Serial.println("Homing Complete!");
}

void loop()
{
  button.update();

  if (button.pressed() && (distChanged == false))
  {
   // lcd.setCursor(0, 0);
   // lcd.print("Move:+10mm at XY");
    Serial.println("Move:+10mm at XY");

    distChanged = true;
    distance += 10;
  }

  if (distChanged == true)
  {
    myStepperX.setSpeed(1000);
    myStepperX.moveTo(distance * STEPS_PER_MM_X);
    myStepperX.runSpeedToPosition();

    myStepperY.setSpeed(1000);
    myStepperY.moveTo(distance * STEPS_PER_MM_Y);
    myStepperY.runSpeedToPosition();

    if ((myStepperX.currentPosition() == (distance * STEPS_PER_MM_X))  &&
        (myStepperY.currentPosition() == (distance * STEPS_PER_MM_Y)))
    {
      homeXY();
      distChanged = false;
    }
  }
}

Limit Switch is connected to A0 and Button to A7 they are both grounded with the button going through a 1K resistor and the other end in 5V

I tried running it.
Only the Y motor is moving and it is not registering the limit switch.

I'm pretty sure you can only use analog inputs as digital inputs on an Arduino Uno and not on the nano.

You are pretty wrong! Both boards has ATmega328.

Did you the wiring of button and limit switches according to my schematic?

don't both boards use the same processor, ATmega328P

@doms95, please do not cross-post. Threads merged.

You have 3 limit switches in your schematic I only have one?

And I had to wire the button with a pulldown resistor since it wasn't working with just analog input and ground.

I found this on Arduinos website which is why I assumed as much

How would you then read the analog pins digitally ?

You can change this value on code.

#define NUM_SWITCHES 3

No problem, it wiil just change the pressed state to HIGH.

endSwitch[i].setPressedState(LOW);
button.setPressedState(LOW);

A schematic of this could be useful.

Using digitalRead function?

BTW, on your first code there's 3 limit switches. I don't know how do you pretend to home 3 axis with a single switch.

const int LIMIT_SWITCH_PIN = A0;
//const int LIMIT_SWITCH_Y_PIN = 10;
//const int LIMIT_SWITCH_Z_PIN = 11;

I am only using two motors and they run in the same direction all the time so I only need to home in one axis. As shown on the photo above.