Limit Switch for Homing

Hello,

I have a stepper motor controlling a belt driven system that allows 360 degrees rotation. I would like to add a rotary limit switch (RuoFeng Micro Limit Switch Long Hinge Roller Momentary SPDT Snap Action LOT Pack of 10  : Amazon.co.uk: DIY & Tools) to take into account the number of rotation conducted. This way, I would be able to reverse the rotations conducted in order to home the stepper motor. I am using the accelstepper library to control the motor, but I have no idea if this homing feature is possible with a belt driven system. If so, how can I do it?

Thanks for any input.

Could you attach a photo sensor/LED combination to the drive system, or perhaps a Hall Effect magnetic sensor. My guess is that an Internet search would turn up examples.

Wouldn't it possible just with the limit switch provided in the link?

Thanks

a limit switch (mechanical, optical or magnetic) is typically used to indicate the limit of travel.

it could also be used to locate the origin since a stepper motor can be powered up at any arbitrary position. on subsequent start up, a "homing" step might move the motor in a particular position until the switch becomes active and setting a known position. the motor might then be returned to an origin position

The Accelstepper library keeps track of the current position in a long integer, good for over 2 billion steps on either side of zero. To go back to the position last set as zero: stepper.moveTo(0);

I run a homing at setup, and then set the current position zero once I reached the limit switch (stepper1.setCurrentPosition(0)). I am then able to control the robot as expected. However, when I press the button to home, I set stepper1.moveTo(0), but the motor doesn't actually move back to where expected. Would know know how to solve this? thanks

? without seeing the code ?

Does it move CLOSE to where you expected? That might mean your stepper is missing steps. That could be cause by acceleration or max speed being set too high or the stepper not having enough torque for the task.

Doesn't move at all. Not sure. Is there other way to keep it track of the rotation?

Sounds like a mistake in your sketch. We might be able to help if you show your sketch.

I am pasting only the relevant bits:

//homing once at startup, then do not run this code anymore 
  if (flag == 0) {
    servo.write(0);
    while (digitalRead(limitSwitch1) == HIGH) {
    stepperX.setSpeed(-1000);
    stepperX.runSpeed();
    stepperX.setCurrentPosition(0);
    }
    while(digitalRead(limitSwitchRound) == HIGH) {
      stepperY.setSpeed(-1000);
      stepperY.runSpeed();
      stepperY.setCurrentPosition(0);
    }
    flag = 1;
  }

With this section of the code, I home at startup, and then I would like to save the positions of both stepper motors as zero.

Then,

if (HomingCounter == 1) {
      digitalWrite(HomingLed, HIGH);
      servo.write(0);

      //do { //homing stepper y 
      stepperY.moveTo(0);
      stepperY.setSpeed(1000);
      stepperY.runSpeed();
      //} while (digitalRead(limitSwitchRound) == HIGH);

      
      do { //homing stepper x 
      stepperX.setSpeed(-1000);
      stepperX.runSpeed();
    } while (digitalRead(limitSwitch1) == HIGH);

   if (digitalRead(limitSwitch1) == LOW && digitalRead(limitSwitchRound) == LOW) {
    digitalWrite(SwitchLed, HIGH);
    digitalWrite(HomingLed, LOW);
    HomingCounter = 0;
  }
  
  }

When the Homing button, is pressed, homing led is activated and I want to return to 0 position. With stepperX I can do it as its a linear driver system. StepperY instead rotates a belt and I would like to rotate back at 0 position.

The stepperX homes correctly, stepperY instead keeps rotation never stopping.

I would try changing to:

  //homing stepper y
  stepperY.runToNewPosition(0);

  //homing stepper x
  stepperX.runToNewPosition(0);

Note that .runToNewPosition(0) is a combination of .moveTo(0); and .runToPosition(). It sets the destination position and repeats .run() until the position is reached.

The motor doesn't move at all. It seems it's not saving the initial position when I complete the homing at startup.

Well, the part of the code you showed already looks OK to me. If you don't want to show all of your code, could you write a different sketch that shows the same problem? Something like this:

#include <AccelStepper.h>

AccelStepper  stepperX(AccelStepper::FULL4WIRE, 4, 5, 6, 7);
AccelStepper  stepperY(AccelStepper::FULL4WIRE, 8, 9, 10, 11);

const byte limitSwitch1 = A0;
const byte limitSwitchRound = A1;
const byte HomingLed = 13;

// homing once at startup, then do not run this code anymore
void home()
{
  while (digitalRead(limitSwitch1) == HIGH)
  {
    stepperX.setSpeed(-1000);
    stepperX.runSpeed();
    stepperX.setCurrentPosition(0);
  }
  while (digitalRead(limitSwitchRound) == HIGH)
  {
    stepperY.setSpeed(-1000);
    stepperY.runSpeed();
    stepperY.setCurrentPosition(0);
  }
}

void rehome()
{
  digitalWrite(HomingLed, HIGH);

  //homing stepper y
  stepperY.runToNewPosition(0);

  //homing stepper x
  stepperX.runToNewPosition(0);

  if (digitalRead(limitSwitch1) == LOW && digitalRead(limitSwitchRound) == LOW)
  {
    digitalWrite(HomingLed, LOW);
  }
}

void setup()
{
  pinMode(limitSwitch1, INPUT_PULLUP);
  pinMode(limitSwitchRound, INPUT_PULLUP);
  pinMode(HomingLed, OUTPUT);

  // Demonstrate the problem

  home();

  // Put some code here to move the steppers
  // away from 'home' so the rehome() has 
  // something to do.

  rehome();
}

void loop() {}

Yes using this testing code it actually works and the steppers home back. I am not sure why it doesn't work with my original code.

Here's my code for the actual project where I am controlling 2 steppers and 1 servo with joystick + there are buttons (Power on/off, increase speed, decrease speed and homing).

The motors correctly home at startup, then led, buttons and Oled messages work perfectly the only issue is when I click the homing button, the motor doesn't actually home.


#include <AccelStepper.h>
#include <Servo.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1331.h>
#include <SPI.h>

#define sclk 52
#define mosi 51
#define cs   53
#define rst  46
#define dc   41


// Color definitions
#define BLACK           0x0000
#define BLUE            0x001F
#define RED             0xF800
#define GREEN           0x07E0
#define CYAN            0x07FF
#define MAGENTA         0xF81F
#define YELLOW          0xFFE0
#define WHITE           0xFFFF

Adafruit_SSD1331 display = Adafruit_SSD1331(&SPI, cs, dc, rst);

unsigned long lastServoMove = 0;
int pos = 90;    // variable to store the servo position
int PowerCounter = 1;
int HomingCounter = 0;
int IncreaseSpeedCounter = 0;
int DecreaseSpeedCounter = 0;
int flag = 0;

int CurrentSpeed = 500;
int PowerState = 0;
int lastPowerState = 0;
int IncreaseSpeedState = 0;
int DecreaseSpeedState = 0;
int HomingState = 0;
int lastHomingState = 0;
int lastIncreaseSpeedState = 0;
int lastDecreaseSpeedState = 0;

const byte limitSwitch1 = 4;
const byte limitSwitch2 = 9;
const byte limitSwitchRound = 42;
const byte SwitchLed = 38; 
const byte analogX_pin = A1;
const byte analogY_pin = A0;
const byte analogZ_pin = A2;
const byte PowerButton = 22;
const byte PowerOnLed = 34;
const byte PowerOffLed = 32;
const byte IncreaseSpeedButton = 24;
const byte DecreaseSpeedButton = 7;
const byte HomingButton = 28;
const byte HomingLed = 36;

//initialising stepper motors 
AccelStepper stepperX(1,5,2);
AccelStepper stepperY(1,6,3);

//intialising servo motor 
Servo servo;
int servoPin = 11;

//variables
int analogX = 0;  //x-axis valueint 
int analogY = 0;  //y-axis value
int analogZ = 0;  //z-axis value
int analogX_AVG = 0; //x-axis average value (middle)
int analogY_AVG = 0; //y-axis average value (middle)
int analogZ_AVG = 0; //z-axis average value (middle)


void setup() {
  // put your setup code here, to run once:
  
Serial.begin(9600);
display.begin();


pinMode(analogX_pin,INPUT);
pinMode(analogY_pin,INPUT);
pinMode(analogZ_pin,INPUT);
pinMode(limitSwitch1,INPUT_PULLUP);
pinMode(limitSwitch2, INPUT_PULLUP);

pinMode(SwitchLed, OUTPUT);
digitalWrite(SwitchLed, LOW);
pinMode(PowerOnLed, OUTPUT); 
pinMode(PowerOffLed, OUTPUT);
digitalWrite(PowerOffLed, HIGH); 
pinMode(HomingLed, OUTPUT);

//--------------------4 buttons used--------------------
 pinMode(PowerButton, INPUT_PULLUP);
 pinMode(IncreaseSpeedButton, INPUT_PULLUP);
 pinMode(DecreaseSpeedButton, INPUT_PULLUP);
 pinMode(HomingButton, INPUT_PULLUP);
 digitalWrite(IncreaseSpeedButton, LOW);
 digitalWrite(HomingButton, LOW);
 digitalWrite(DecreaseSpeedButton, LOW);

InitialValues(); //calculating the middle/average value for three analog pins 

//stepper parameters 
stepperX.setMaxSpeed(5000);
stepperX.setAcceleration(1000);
stepperX.setSpeed(CurrentSpeed);
delay(500);
stepperY.setMaxSpeed(5000);
stepperY.setAcceleration(1000);
stepperY.setSpeed(CurrentSpeed);
delay(500);

//servo parameters 
servo.attach(servoPin);


}

void loop() {

  //state detection for power button
  PowerState = digitalRead(PowerButton);
  if (PowerState != lastPowerState) {
    if (PowerState == HIGH) {
      PowerCounter ++;
    }
    delay(50);
  }
  lastPowerState = PowerState;

  //state detection for increase speed button
  IncreaseSpeedState = digitalRead(IncreaseSpeedButton);
  if (IncreaseSpeedState != lastIncreaseSpeedState) {
    if (IncreaseSpeedState == HIGH) {
      IncreaseSpeedCounter ++;
    }
    delay(50);
  }
  lastIncreaseSpeedState = IncreaseSpeedState;

  //state detection for homing button
  HomingState = digitalRead(HomingButton);
  if (HomingState != lastHomingState) {
    if (HomingState == HIGH) {
      HomingCounter ++;
    }
    delay(50);
  }
  lastHomingState = HomingState;

  //state detection for decrease speed button
  DecreaseSpeedState = digitalRead(DecreaseSpeedButton);
  //Serial.println(DecreaseSpeedState);
  if (DecreaseSpeedState != lastDecreaseSpeedState) {
    if (DecreaseSpeedState == HIGH) {
      DecreaseSpeedCounter ++;
    }
    delay(50);
  }
  lastDecreaseSpeedState = DecreaseSpeedState;

  //if the power button has been pressed, then you are allowed to control the motors 
  if (PowerCounter % 2 == 0) {
  digitalWrite(PowerOnLed, HIGH);
  digitalWrite(PowerOffLed, LOW);

  //homing once at startup, then do not run this code anymore 
  if (flag == 0) {

  display.fillScreen(BLACK);
  display.setCursor(0,0);
  display.print("Homing");
  
    servo.write(0);
    while (digitalRead(limitSwitch1) == HIGH) {
    stepperX.setSpeed(-1000);
    stepperX.runSpeed();
    stepperX.setCurrentPosition(0);
    }
    while(digitalRead(limitSwitchRound) == HIGH) {
      stepperY.setSpeed(-1000);
      stepperY.runSpeed();
      stepperY.setCurrentPosition(0);
    }

  display.fillScreen(BLACK);
  display.setCursor(0,0);
  display.print("Done Homing");
  delay(2000);
  display.fillScreen(BLACK);
 
    flag = 1;
  }

  //function to control the stepper motors with the joystick 
  readAnalogStepper();

  if (IncreaseSpeedCounter == 1) {
    CurrentSpeed += 100;
    Serial.println(CurrentSpeed);
    IncreaseSpeedCounter = 0;

    display.fillScreen(BLACK);
    display.setCursor(0,0);
    display.print("Increased Speed" );
    delay(2000);
    display.fillScreen(BLACK);
    
  }
  
   if (HomingCounter == 1) {

      display.fillScreen(BLACK);
      display.setCursor(0,0);
      display.print("Homing");
      
      digitalWrite(HomingLed, HIGH);
      servo.write(0);

     //homing stepper y
    stepperY.runToNewPosition(0);

    //homing stepper x
    stepperX.runToNewPosition(0);
 
   if (digitalRead(limitSwitch1) == LOW && digitalRead(limitSwitchRound) == LOW) {
    digitalWrite(SwitchLed, HIGH);
    digitalWrite(HomingLed, LOW);
    HomingCounter = 0;

    display.fillScreen(BLACK);
    display.setCursor(0,0);
    display.print("Done Homing");
    delay(2000);
    display.fillScreen(BLACK);
  }
  
  }
  
  if (DecreaseSpeedCounter == 1) {
    CurrentSpeed -= 100;
    Serial.println(CurrentSpeed);
    //stepperX.setSpeed(CurrentSpeed);
    DecreaseSpeedCounter = 0;

    display.fillScreen(BLACK);
    display.setCursor(0,0);
    display.print("Decreased Speed" );
    delay(2000);
    display.fillScreen(BLACK);
  }
  
  stepperX.runSpeed();
  stepperY.runSpeed();

  //to controlt the servo motor 
  if (millis() - lastServoMove > 250 ) {
  //run servo 
  runServo();
} 
 
  
  } else {
    digitalWrite(PowerOnLed, LOW);
    digitalWrite(PowerOffLed, HIGH);
    digitalWrite(SwitchLed, LOW);
    digitalWrite(HomingLed, LOW);
  }
}

void readAnalogStepper() {

//reading stepper position from joystick 
analogX = analogRead(analogX_pin);
analogY = analogRead(analogY_pin);

//---------controlling stepper motor x-----------------

//if value is at least 25 away from the average value with allow the update of speed and moving to poinetd direction
if(abs(analogX - analogX_AVG)>25) {
 if (digitalRead(limitSwitch1) == HIGH && digitalRead(limitSwitch2) == HIGH)  {
  stepperX.setSpeed(5*(analogX - analogX_AVG)); 
  digitalWrite(SwitchLed, LOW);
}
else {
  if (digitalRead(limitSwitch1) != HIGH) {
    digitalWrite(SwitchLed, HIGH);
  if ((analogX - analogX_AVG)>analogX_AVG) {
    stepperX.setSpeed(5*(analogX - analogX_AVG)); 
  } else {
    stepperX.setSpeed(0);
  }
}
else if (digitalRead(limitSwitch2) != HIGH) {
  digitalWrite(SwitchLed, HIGH);
  if ((analogX - analogX_AVG)<analogX_AVG) {
    stepperX.setSpeed(5*(analogX - analogX_AVG)); 
  } else {
    stepperX.setSpeed(0);
  }
}
}
}
else {
  stepperX.setSpeed(0);
}

//----------------controlling stepper motor y--------------------------------

if(abs(analogY - analogY_AVG)>25) {
  stepperY.setSpeed(5*(analogY - analogY_AVG)); 
  //Serial.println(sum);
}
else {
  stepperY.setSpeed(0);
}
}


//---------controlling servo motor-----------------------------
void runServo() {
  analogZ = analogRead(analogZ_pin);
  if ((analogZ - analogZ_AVG) > 50) {
    if (pos<=190) {
    pos+=10;
  } else {
    //Serial.println("Max Pos");
  }
  }
  else if((analogZ - analogX_AVG)<-50) {
    if (pos>=30) {
    pos-=10;
  } else {
    //Serial.println("Min pos");
  }
  }
 servo.write(pos);
 lastServoMove = millis();    //reset the timer
}


//Function to calculate the initial avarage value of the joystick 
void InitialValues() {

  float tempX = 0; //set temporary x value to 0 
  float tempY = 0; //set temporary y value to 0 
  float tempZ = 0; //set temporary z value to 0

  //read the analog value initial 50 times and get the average to have accurate middle value 
  for (int i=0;i<50;i++) {
    tempX += analogRead(analogX_pin);
    delay(10);
    tempY += analogRead(analogY_pin);
    delay(10);
    tempZ += analogRead(analogZ_pin);
   
  }

  analogX_AVG = tempX/50;
  analogY_AVG = tempY/50;
  analogZ_AVG = tempZ/50;
    
}

Thanks

Why are you setting the four button input pins to INPUT_PULLUP and then turning off the pull-up resistors for three of the four?

They were read always as active and just giving issues with the code in general. This solved the issue. Would this be causing the homing issue?

For the three that you don't want the pull-ups enabled, just use the pinMode() "INPUT" instead of "INPUT_PULLUP". If the buttons have their own pull-up or pull-down resistors then that should not bother the homing code.

When you press the Homing button does the display show the "Homing" message?

I changed it just to INPUT seems working fine anyways, thanks. And yes, the "homing" message displays and also the led lights up. Could the issue be related to the fact that runToNewPosition blocks until its at position (so using it in a event loop won't work). Maybe I could try to use MoveTo instead?

No. The 'while' loops in your initial homing code block and don't cause a problem.

Could you show me that sketch? Maybe I can spot a significant difference between your big sketch and the testing code.